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();
    }
    
}


