/**
 * carrousel handling. used to scroll over 3 stacks (html container)
 * like this:
 * -- prevStack: [1, 2, 3] invisible
 * -- mainStack: [4, 5, 6, 7] visible
 * -- nextStack: [8, 9, 10] invisible
 * 
 * this class pushes nodes from one stack to another. 
 * using this.id to adress all stack
 * linked with carrousel view helper from video.de
 *
 * @see stackPreviousIdSuffix, stackNextIdSuffix
 * @param string id - unique id of this carrousel  
 */
Emv.Carrousel = function (id)
{
    this.id   = id;
    this.loop = false;
    this.stackPreviousIdSuffix  = '_previous';
    this.stackNextIdSuffix      = '_next';

    this.setLoop = function (bool) {
        this.loop = bool;
    };
    
    this.getLoop = function () {
        return this.loop;
    };
    
    this.getId = function()
    {
    	return this.id;
    };

    this.init = function(loop)
    {
        if ("undefined" != typeof(loop)) {
            
            this.setLoop(loop);
        }

        if(!this.hasPreviousItem() && !this.hasNextItem())
        {
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.NOT_ENOUGH_ITEMS, {}, this.id);
        }
        else if(!this.hasPreviousItem() && !this.getLoop())
        {
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.BEGINNING_REACHED, {}, this.id);
        }
        else if(!this.hasNextItem() && !this.getLoop())
        {
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.END_REACHED, {}, this.id);
        }

        var main = this.getMainStack();

        childNodes = YAHOO.util.Dom.getChildren(main);
        for (nodeNum = 0; nodeNum < childNodes.length; nodeNum++)
        {
            YAHOO.util.Dom.addClass(childNodes[nodeNum], 'carrousel-item-' + nodeNum);
        }
    };
    
    this.checkStatus = function()
    {
    	if(!this.hasPreviousItem() && !this.hasNextItem())
        {
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.NOT_ENOUGH_ITEMS, {}, this.id);
        }
        else if(!this.hasPreviousItem())
        {
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.BEGINNING_REACHED, {}, this.id);
        }
        else if(!this.hasNextItem())
        {
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.END_REACHED, {}, this.id);
        }
    };

    /**
     * Removes ALL items from all stacks!
     */
    this.clearItems = function()
    {
    	var nextStackDom   = this.getNextStack();
    	var prevStackDom   = this.getPreviousStack();
    	var main           = this.getMainStack();

    	main.innerHTML = '';
    	nextStackDom.innerHTML = '';
    	prevStackDom.innerHTML = '';
	};

    /**
     * Add one or more items to the stack
     */
    this.addItems = function(newItems)
    {
    	var nextStackDom   = this.getNextStack();
//    	var prevStackDom   = this.getPreviousStack();
//    	var main           = this.getMainStack();

    	nextStackDom.innerHTML = newItems;

    	Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.CARROUSEL_LOADED, {}, this.id);
    	this.nextItem();
    	this.checkStatus();
    };

    /**
     * showing next item from Next-Stack
     */
    this.nextItem = function()
    {
    	var nextStackDom   = this.getNextStack();
    	var prevStackDom   = this.getPreviousStack();
    	var main           = this.getMainStack();
    	
    	if (!this.hasNextItem() && this.getLoop()) {
    	    
    	    this.moveNodesToStack(prevStackDom, nextStackDom);
    	}

    	var nextNode = this.getFirstStructuredNode(nextStackDom);
        if (nextNode !== null)
    	{
	    	var firstMainNode = this.getFirstStructuredNode(main);
    		this.appendNodeToStack(nextNode, main);

	    	if (firstMainNode !== null) {

	    		this.appendNodeToStack(firstMainNode, prevStackDom);
	    	}

	        childNodes = YAHOO.util.Dom.getChildren(main);
            for (nodeNum = 0; nodeNum < childNodes.length; nodeNum++)
            {
                YAHOO.util.Dom.replaceClass(childNodes[nodeNum], 'carrousel-item-' + (nodeNum + 1), 'carrousel-item-' + nodeNum);
            }
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.OFFSET_CHANGED, {}, this.id);
        }
        if(!this.hasNextItem() && !this.getLoop())
        {
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.END_REACHED, {}, this.id);
        }
    };

    this.previousItem = function()
    {
        var nextStackDom   = this.getNextStack();
        var prevStackDom   = this.getPreviousStack();
        var main           = this.getMainStack();

        if (!this.hasPreviousItem() && this.getLoop()) {
            
            this.moveNodesToStack(nextStackDom, prevStackDom);
        }

        var nextNode = this.getLastStructuredNode(prevStackDom);
        if (nextNode !== null)
        {
            var lastMainNode = this.getLastStructuredNode(main);
            this.prependNodeToStack(nextNode, main);

            if (lastMainNode !== null) {

            	this.prependNodeToStack(lastMainNode, nextStackDom);
            }

            childNodes = YAHOO.util.Dom.getChildren(main);
            for (nodeNum = 0; nodeNum < childNodes.length; nodeNum++)
            {
                YAHOO.util.Dom.replaceClass(childNodes[nodeNum], 'carrousel-item-' + (nodeNum - 1), 'carrousel-item-' + nodeNum);
            }
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.OFFSET_CHANGED, {}, this.id);
        }

        if(!this.hasPreviousItem() && !this.getLoop())
        {
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.BEGINNING_REACHED, {}, this.id);
        }
    };

    this.hasNextItem = function()
    {
        var nextNode = this.getFirstStructuredNode(this.getNextStack());
        return (nextNode !== null);
    };

    this.hasPreviousItem = function()
    {
        var nextNode = this.getLastStructuredNode(this.getPreviousStack());
        return (nextNode !== null);
    };

    this.prependNodeToStack = function(node, stack)
    {
        var firstInStack = this.getFirstStructuredNode(stack);
        stack.insertBefore(node, firstInStack);
    };

    this.appendNodeToStack = function(node, stack)
    {
        stack.appendChild(node);
    };
    
    this.moveNodesToStack = function(fromStack, toStack)
    {
        fromNodes = YAHOO.util.Dom.getChildren(fromStack);

        for (nodeNum=0; nodeNum<fromNodes.length; nodeNum++)
        {
            this.appendNodeToStack(fromNodes[nodeNum], toStack);
        }
    };

    /**
     * returns first childNode from given element which is not a textNode
     * @param dom-container
     * @return dom-node
     */
    this.getFirstStructuredNode = function(dom) {

    	childNodes = YAHOO.util.Dom.getChildren(dom);

        if (childNodes[0]) {

        	return childNodes[0];
        }

        return null;
    };

    this.getLastStructuredNode = function(dom) {

    	childNodes = YAHOO.util.Dom.getChildren(dom);

        if (childNodes[childNodes.length - 1]) {

        	return childNodes[childNodes.length - 1];
        }

        return null;
    };

    this.appendNode = function(child)
    {
        var main = document.getElementById(this.id);
        main.appendChild(child);
    };

    this.prependNode = function(child)
    {
        var main = document.getElementById(this.id);
        main.appendChild(child);
    };

    //--- getting all relevant stacks

    this.getMainStack = function()
    {
        return document.getElementById(this.id);
    };

    this.getNextStack = function()
    {
        return document.getElementById(this.id + this.stackNextIdSuffix);
    };

    this.getPreviousStack = function()
    {
        return document.getElementById(this.id + this.stackPreviousIdSuffix);
    };

    this.handleEvent = function(event)
    {
    	if(event.name == Emv.Carrousel.Event.BUTTON_CLICKED)
        {
        	var type = event.params.button.type;
        	if(Emv.Registry.getObject(event.sourceId).isActive() && type == Emv.Carrousel.Button.typeNextItem)
        	{
        		this.nextItem();
        	}
        	else if(Emv.Registry.getObject(event.sourceId).isActive() && type == Emv.Carrousel.Button.typePreviousItem)
        	{
        		this.previousItem();
        	}
        }
    };
};

/**
 * base carrousel button class - implements all logic
 * has to be extended for getting button implementation
 * @param id - html button id
 * @param type - type of button (prev/next)
 */
Emv.Carrousel.Button = function(id, type)
{
    this.id = id;
    this.type = type;
    this.carrousel;

    /**
     * boolean - showing current active state
     * true - button is active an able to be clicked
     * false - opposite ...
     * @param boolean
     */
    this.active = true;

    this.isActive = function()
    {
        return this.active;
    };

    this.getId = function()
    {
        return this.id;
    };

    this.setCarrousel = function(c)
    {
        this.carrousel = c;
    };

    this.setActive = function(bool)
    {
    	
        if(bool && this.active != bool)
        {
            if(this.type == Emv.Carrousel.Button.typePreviousItem)
            {
                document.getElementById(this.id).src = this.activePrevious;
            }
            else if(this.type == Emv.Carrousel.Button.typeNextItem)
            {
                document.getElementById(this.id).src = this.activeNext;
            }
        }
        else if(this.active != bool)
        {
            if(this.type == Emv.Carrousel.Button.typePreviousItem)
            {
                document.getElementById(this.id).src = this.inactivePrevious;
            }
            else if(this.type == Emv.Carrousel.Button.typeNextItem)
            {
                document.getElementById(this.id).src = this.inactiveNext;
            }
        }
        this.active = bool;
    };

    this.handleClick = function()
    {
        if(this.active)
        {
            Emv.Observer.Controller.fireEvent(Emv.Carrousel.Event.BUTTON_CLICKED, {button: this}, this.id);
        }
    };

    this.handleEvent = function(event)
    {
        if(event.name == Emv.Carrousel.Event.NOT_ENOUGH_ITEMS)
        {
            this.setActive(false);
        }
        else if(event.name == Emv.Carrousel.Event.BEGINNING_REACHED)
        {
            if(this.type == Emv.Carrousel.Button.typePreviousItem)
            {
                this.setActive(false);
            }
        }
        else if(event.name == Emv.Carrousel.Event.END_REACHED)
        {
            if(this.type == Emv.Carrousel.Button.typeNextItem)
            {
                this.setActive(false);
            }
        }
        else if(event.name == Emv.Carrousel.Event.OFFSET_CHANGED)
        {
            this.setActive(true);
        }
    };
};

/**
 * Buttons for vertical scrolling direction.
 */
Emv.Carrousel.Button.Vertical = function(id, type)
{
    this.id = id;
    this.type = type;
    this.activePrevious    = '/_assets/pics/carousel/carousel-arrow-up.gif';
    this.inactivePrevious  = '/_assets/pics/carousel/carousel-arrow-up-disabled.gif';
    this.activeNext        = '/_assets/pics/carousel/carousel-arrow-down.gif';
    this.inactiveNext      = '/_assets/pics/carousel/carousel-arrow-down-disabled.gif';
};

/**
 * Buttons for horizontal scrolling direction.
 */
Emv.Carrousel.Button.Horizontal = function(id, type)
{
    this.id = id;
    this.type = type;
    this.activePrevious    = '/_assets/pics/carousel/carousel-arrow-left.gif';
    this.inactivePrevious  = '/_assets/pics/carousel/carousel-arrow-left-disabled.gif';
    this.activeNext        = '/_assets/pics/carousel/carousel-arrow-right.gif';
    this.inactiveNext      = '/_assets/pics/carousel/carousel-arrow-right-disabled.gif';
};

/**
 * Buttons for horizontal (small buttons) scrolling direction.
 */
Emv.Carrousel.Button.Horizontal.Small = function(id, type)
{
    this.id = id;
    this.type = type;
    this.activePrevious    = '/_assets/pics/carousel/carousel-left.gif';
    this.inactivePrevious  = '/_assets/pics/carousel/carousel-left-disabled.gif';
    this.activeNext        = '/_assets/pics/carousel/carousel-right.gif';
    this.inactiveNext      = '/_assets/pics/carousel/carousel-right-disabled.gif';
};

/**
 * Buttons for horizontal (big buttons) scrolling direction.
 */
Emv.Carrousel.Button.Horizontal.Bigger = function(id, type)
{
    this.id = id;
    this.type = type;
    this.activePrevious    = '/_assets/pics/carousel/carousel-arrow-left-bigger.gif';
    this.inactivePrevious  = '/_assets/pics/carousel/carousel-arrow-left-bigger-disabled.gif';
    this.activeNext        = '/_assets/pics/carousel/carousel-arrow-right-bigger.gif';
    this.inactiveNext      = '/_assets/pics/carousel/carousel-arrow-right-bigger-disabled.gif';
};

// Extending buttons from default button 
Emv.Carrousel.Button.Vertical.prototype          = new Emv.Carrousel.Button();
Emv.Carrousel.Button.Horizontal.prototype        = new Emv.Carrousel.Button();
Emv.Carrousel.Button.Horizontal.Small.prototype  = new Emv.Carrousel.Button();
Emv.Carrousel.Button.Horizontal.Bigger.prototype = new Emv.Carrousel.Button();

/**
 * Carrousel - possible events.
 */
Emv.Carrousel.Event =
{
    NOT_ENOUGH_ITEMS  : 'not_enough_items_in_playlist',
    BUTTON_CLICKED    : 'button_clicked',
    BEGINNING_REACHED : 'beginning_reached',
    END_REACHED       : 'end_reached',
    CARROUSEL_LOADED  : 'loaded',
    //called when a real sliding was done - not just on click
    OFFSET_CHANGED    : 'offset_changed'
};

// Button types for next and previous scrolling direction
Emv.Carrousel.Button.typePreviousItem = 'previousItem';
Emv.Carrousel.Button.typeNextItem     = 'nextItem';
