function Director(){

	// Defining states for StateAutomaton:
    var stIntro = new State("Intro");
    var stPlayerStopped = new State("PlayerStopped");
    var stPlayerPaused = new State("PlayerPaused");
    var stPlayerMuted = new State("PlayerMuted");
    var stPlaysStream = new State("PlaysStream");
    var stPlaysItem = new State("PlaysItem");
    var stMenuShown = new State("MenuShown");
    var stMenuItemSelected = new State("MenuItemSelected");

    this.radio = new Menu("radio");
    this.menu = new Menu('menu');

    this.onlinePlayerFrame;
    this.stopButton;

    var meDirector = this;

    this.animUtil = new AnimationUtil(this);
	this.sndPlayer;
	this.lastStateToGoBackTo = stPlayerStopped;
    this.stateAutomat;

    function initStateAutomat(){

		// allowed to go to which state:
        stIntro.setAllowedFollowing(            [stPlayerStopped.name] );
        stIntro.setSelfActivationAllowed(true);

        stPlayerStopped.setAllowedFollowing(    [stPlaysStream.name, stMenuShown.name, stMenuItemSelected.name] );
        stPlaysStream.setAllowedFollowing(      [stPlayerStopped.name, stPlayerPaused.name, stPlayerMuted.name,  stMenuShown.name] );
        stPlaysItem.setAllowedFollowing(        [stPlayerStopped.name, stPlayerPaused.name, stPlayerMuted.name,  stMenuShown.name, stPlaysStream.name] );

        stPlayerPaused.setAllowedFollowing(     [stPlaysStream.name, stPlaysItem.name, stMenuShown.name ] );
        stPlayerMuted.setAllowedFollowing(      [stPlaysStream.name, stPlaysItem.name, stMenuShown.name ] );

        stMenuShown.setAllowedFollowing(        [stMenuItemSelected.name, stPlayerStopped.name, stPlaysStream.name, stPlayerPaused.name, stPlayerMuted.name, stPlaysItem.name ] )
        stMenuItemSelected.setAllowedFollowing( [stPlaysItem.name] );

        // what to do if state becomes active:
        stIntro.setActivationBehaviour(meDirector._stIntroActions);
        stPlayerStopped.setActivationBehaviour(meDirector._stPlayerStoppedActions);
        stPlayerPaused.setActivationBehaviour(meDirector._stPlayerPausedActions);
        stPlayerMuted.setActivationBehaviour(meDirector._stPlayerMutedActions);
        stPlaysStream.setActivationBehaviour(meDirector._stPlaysStreamActions);
        stPlaysItem.setActivationBehaviour(meDirector._stPlaysItemActions);
        stMenuShown.setActivationBehaviour(meDirector._stMenuShownActions);
        stMenuItemSelected.setActivationBehaviour(meDirector._stItemSelectedActions);


        meDirector.stateAutomat = new StateAutomaton();

        // set state automatons states:
        meDirector.stateAutomat.addState(stIntro);
        meDirector.stateAutomat.addState(stPlayerStopped);
        meDirector.stateAutomat.addState(stPlayerPaused);
        meDirector.stateAutomat.addState(stPlayerMuted);
        meDirector.stateAutomat.addState(stPlaysStream);
        meDirector.stateAutomat.addState(stPlaysItem);
        meDirector.stateAutomat.addState(stMenuShown);
        meDirector.stateAutomat.addState(stMenuItemSelected);
    }

    // -------------------------------------------------------------------------
    // 								STATE: Intro
    // -------------------------------------------------------------------------
    this.doStart = function(){

        // we wanna start with rotation animation in every case
    	var startState = meDirector.stateAutomat.currentState;

        if(startState.name != stIntro.name){
        	meDirector.animUtil.startLogoAnimation();
        	meDirector.animUtil.makeItemsVisible();
        	meDirector.animUtil.runCurrentStrategyWithAllItems();
        	meDirector.animUtil.showUIElements();
        	meDirector.animUtil.showUIControls();
        	meDirector.menu.hide();
        }
        this.stateAutomat.goToState(startState);
   	}

    this._stIntroActions = function(){

        if(DEBUG) { console.debug("STATE: Init with intro"); }
        var timeline = new Timeline(self);

        // logo animation:
        if(DEBUG) { timeline.addEvent(1, function(){ console.debug("logo animation INIT"); } ); }
        timeline.addEvent(logoAnimationStartMs, meDirector.animUtil.startLogoAnimation);
        if(DEBUG) { timeline.addEvent(1, function(){ console.debug("logo animation DONE."); } ); }

        if(!skipIntro) {
            // intro:
            if(DEBUG) { timeline.addEvent(1, function(){ console.debug("intro INIT"); } ); }
            meDirector.animUtil.doIntro(timeline);
            if(DEBUG) { timeline.addEvent(1, function(){ console.debug("intro DONE."); } ); }
        }

        // show actors:
        if(DEBUG) {  timeline.addEvent(1, function(){ console.debug("show actors INIT"); } ); }
        timeline.addEvent(initActorsAnimationMs, meDirector.animUtil.makeItemsVisible);
        if(DEBUG) { timeline.addEvent(1, function(){ console.debug("show actors DONE."); } ); }


		// interface
        if(DEBUG) {  timeline.addEvent(1, function(){ console.log("show interface INIT"); } ); }
      	meDirector.animUtil.showInterface(timeline);
      	if(DEBUG) {  timeline.addEvent(1, function(){ console.log("show interface DONE."); } ); }

        timeline.addEvent(1, meDirector.goToPlayerStop);
        timeline.play();
    }

    // -------------------------------------------------------------------------
    // 								STATE: PlayerMuted
    // -------------------------------------------------------------------------
    this.togglePlayerMute = function(){
    	if(meDirector.getState() == stPlayerMuted){
    		meDirector.sndPlayer.unmute();
    		meDirector.stateAutomat.goToState(lastStateToGoBackTo);
    	} else {
    		lastStateToGoBackTo = meDirector.getState();
    		meDirector.stateAutomat.goToState(stPlayerMuted);
    	}
    }
    this._stPlayerMutedActions = function(){
	    if(DEBUG) { console.log("STATE: PlayerMuted"); }
    	if(!meDirector.sndPlayer.isMuted()){
    		meDirector.sndPlayer.mute();
    	}
    }

    // -------------------------------------------------------------------------
    // 								STATE: PlayerPaused
    // 									   - same as PlayerMuted
    // -------------------------------------------------------------------------
    this.togglePlayerPause = function(){
    	meDirector.togglePlayerMute();
    }
    this._stPlayerPausedActions = function(){};

    // -------------------------------------------------------------------------
    // 								STATE: PlayerStopped
    // -------------------------------------------------------------------------
    this.goToPlayerStop = function(){
	    meDirector.stateAutomat.goToState(stPlayerStopped);
    }

    this._stPlayerStoppedActions = function(){

    	if(DEBUG) { console.log("STATE: PlayerStopped"); }
    	if(meDirector.sndPlayer.isPlaying()){
	        meDirector.sndPlayer.stop();

            // hide player:
	        meDirector.onlinePlayerFrame.src = "about:blank";
	        meDirector.onlinePlayerFrame.style.zIndex = 1;
	        meDirector.onlinePlayerFrame.style.display='none';

            $$('a.teaser').invoke('show');
    	}

        meDirector.animUtil.hideSliders();
    	meDirector.animUtil.doStandingHoverOnCircle();

    	meDirector.animUtil.shuffle();
    }

    // -------------------------------------------------------------------------
    // 								STATE: PlaysStream
    // -------------------------------------------------------------------------
    this.goToPlayStream = function(){
    	meDirector.stateAutomat.goToState(stPlaysStream);
    }

    this._stPlaysStreamActions = function(){
		    if(DEBUG) { console.log("STATE: PlaysStream"); }

    	meDirector.menu.hide();
    	meDirector.animUtil.getLogo().hideNeighbor();

      	if(!meDirector.sndPlayer.isPlayingStream()) {

            // show player frame:
	        meDirector.onlinePlayerFrame.src = "player.action";
	        meDirector.onlinePlayerFrame.style.zIndex = 100;
            meDirector.onlinePlayerFrame.style.display='block';

            // hide teasers:
            $$('a.teaser').invoke('hide');

	        meDirector.sndPlayer.playStream();
	    }

        meDirector.animUtil.showSliders();

        meDirector.animUtil.outItemsBackToStrategy();
        meDirector.animUtil.shuffle();
    }

    // -------------------------------------------------------------------------
    // 								STATE: PlaysItem
    // -------------------------------------------------------------------------
    this.goToPlayItem = function(itemId){
	    meDirector.sndPlayer.itemToPlayId = itemId;
	    // meDirector.sndPlayer.playArchive(itemId);
    	meDirector.stateAutomat.goToState(stPlaysItem);
    }

	  this._stPlaysItemActions = function(){

  	    if(DEBUG) {
  		     console.log("STATE: PlaysItem (No. " + meDirector.sndPlayer.itemToPlayId + ")");
        }

		meDirector.animUtil.doStandingHoverOnCircle();
		meDirector.putLogoToCorner();

    	if(meDirector.sndPlayer.isPlayingArchive()
    		&& meDirector.sndPlayer.getPlayingArchiveId() == meDirector.sndPlayer.itemToPlayId){	// this archive-item is playing already
        	return;
         }

        meDirector.onlinePlayerFrame.src = "about:blank";
        meDirector.onlinePlayerFrame.style.zIndex = 1;
        meDirector.onlinePlayerFrame.hide();
        // meDirector.stuffPlayer.style.display="block";
		meDirector.sndPlayer.playArchive(); 	// set a number before in players var: itemToPlayId
    }

	// -------------------------------------------------------------------------
    // 								STATE: MenuShown
    // -------------------------------------------------------------------------
    this.toggleMenu = function(){
        var state = meDirector.getState();
  		if(state.name != stMenuShown.name){
  			meDirector.lastStateToGoBackTo  = state;
  			meDirector.stateAutomat.goToState(stMenuShown);
  		} else {
  			meDirector.menu.hide();
  			meDirector.stateAutomat.goToState(meDirector.lastStateToGoBackTo);
  		}
    }

    this._stMenuShownActions = function(){

        if(DEBUG) {
            console.log("STATE: MenuShown");
        }

    	meDirector.menu.show();
    	meDirector.animUtil.lineAllItemsUp();
    }


	// -------------------------------------------------------------------------
    // 								STATE: MenuItemSelected
    // -------------------------------------------------------------------------
    this.goToMenuItemSelected = function(itemId){
	    meDirector.stateAutomat.goToState(stMenuItemSelected);
	    meDirector.goToPlayItem(itemId);
    }

    this._stItemSelectedActions = function(){
    	if(DEBUG) { console.log("STATE: MenuItemSelected"); }
    	meDirector.menu.hide();
    }

	// ---------------------------------------------------------------------------------------------
	// ---------------------------------------------------------------------------------------------

    this.toggleRadio = function(){
        meDirector.radio.toggle();
    }

    /**
     * @param archiveItemId, if it's not given the director will have it's normal behaviour (show intro etc.). If an id is given, it will start with playing this doodad
     */
    this.init = function(doPlay){

        if(DEBUG) {
            console.log("starting init director");
        }

        this.animUtil.init();
        this.sndPlayer = this.animUtil.sndPlayer;

        this.stopButton = $('stop');
        this.onlinePlayerFrame = $('onlinePlayer');

		var startingState = stIntro;
		if(doPlay){
			startingState = stPlaysStream;
		}
		initStateAutomat();

		meDirector.lastStateToGoBackTo = stPlayerStopped;
		meDirector.stateAutomat.setStartState(startingState);

        if(DEBUG) {
            console.log("init director DONE.");
        }
    }


    // Actors Events:
    this.evtActorClick = function(){
    	if(!meDirector.sndPlayer.isPlaying()){
    		meDirector.sndPlayer.playSoundRandom();
    	}
    }

    this.evtActorWithBubbleMouseOver = function(){
        if(!meDirector.sndPlayer.isPlayingStream() && !meDirector.animUtil.isAnimating()){
            this.showNeighbor();
        }
    }

    this.evtActorWithBubbleMouseOut = function(){
        this.hideNeighbor();
    }

    this.evtLogoClick = function(){
    	var state = meDirector.getState();
    	if(state.name == stPlaysStream.name) {
    		meDirector.goToPlayerStop();
    		return;
    	} else if(state.name == stPlaysItem.name){
    		location.href = 'home.action';
    	}
    	meDirector.goToPlayStream();
    }

    this.evtArchiveItemClick = function(id){
    	var isNew = true;
		if(meDirector.sndPlayer.isPlayingArchive()
    	  && meDirector.sndPlayer.getPlayingArchiveId() == id){	// this archive-item is playing already
			isNew = false;
		}
		var oldWindow = window;
		var newWin = window.open('/4duk/home.action?archiveItemId=' + id, window.name);
		newWin.history = oldWindow.history;
    }

    this.evtToggleDoAnimation = function(){

	     if(meDirector.animUtil.getAnimator().isRunning()){
             meDirector.animUtil.stopAnimation();
             meDirector.stopButton.update("ctарт");
         } else {
             meDirector.animUtil.resumeAnimation();
             meDirector.stopButton.update("stoп");
         }

    }


	// ------------------------------------------------------------------------------------------
	// 											helpers:
	// ------------------------------------------------------------------------------------------

	this.putLogoToCorner = function(){
		var logo = meDirector.animUtil.getLogo();
        var dim = meDirector.animUtil.getWindowDimensions();
        var position = dim.getTopRightPoint();
        position = position.add(new Point( (logo.xOffset *2), -1 * (logo.yOffset *2) ));
        logo.movementStrategy.center = position;
        logo.hideNeighbor();
	}

	this.getPossibleStrategies = function(){
        var strategyNames = ["StrategyTwister", "StrategyRotationY", "StrategyRotationX", "StrategyHorizontalHop", "StrategyVerticalHop"];
        return strategyNames;
    }

  	this.getStartingStrategy = function(){
        return this.animUtil.getAnimator().getStrategyById( this.getPossibleStrategies()[0] );
    }

  	this.getState = function(){
  		return this.stateAutomat.getCurrentState();
  	}

    this.logItems = function(){
        meDirector.animUtil.logItems();
    }

}

