/**
 * @fileoverview  mpSlideBox
 *
 * @package     mpSlideBox
 * @author      Murat Purc <murat@purc.de>
 * @copyright   © {%COPYRIGHT%}
 * @licence     GNU General Public License v2, 
 *              http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * @requires    Prototype JavaScript framework and script.aculo.us
 * @version     $Id$
 */


/**
 * Class mpSlideBox
 *
 * @class
 */
var mpSlideBox = Class.create({

	/**
	 * Slidebox element
	 *
	 * @type  {String}
	 */
	_slideBox: null,

	/**
	 * Width of slidebox
	 *
	 * @type  {Integer}
	 */
	_width: 0,

	/**
	 * Height of slidebox
	 *
	 * @type  {Integer}
	 */
	_height: null,

	/**
	 * List of slidebox items
	 *
	 * @type  {Array}
	 */
    _items: null,

	/**
	 * Spacer between two slides
	 *
	 * @type  {Integer}
	 */
    _spacer: 50,

	/**
	 * Duration of effect
	 *
	 * @type  {Float}
	 */
    _duration: 1,

	/**
	 * Position of current slide item
	 *
	 * @type  {Integer}
	 */
    _pos: 0,


	/**
	 * Interval for slideshow
	 *
	 * @type  {Integer}
	 */
    _interval: 5,

	/**
	 * List of available slide directions
	 *
	 * @type  {Array}
	 */
    _availableDirections: ["random", "lefttop-rightbottom", "left-right", "leftbottom-righttop", "top-bottom", "bottom-top", "righttop-leftbottom", "right-left", "rightbottom-lefttop"],

	/**
	 * Current slide direction
	 *
	 * @type  {String}
	 */
    _direction: "left-right",

	/**
	 * Periodical executer used for slideshow
	 *
	 * @type  {PeriodicalExecuter}
	 */
    _pe: null,

	/**
	 * Flag about current running animation
	 *
	 * @type  {Boolean}
	 */
    _animating: false,


	/**
	 * Constructor
	 *
	 * @param  {String}  element  ID of slide box element
	 * @param  {Object}  options  Options as json object, as follows:
     *                            - options.autostart = Flag to autostart a slideshow
     *                            - options.stopOnMouseover = Flag to stop current running slideshow on mouseover
     *                            - options.startOnMouseout = Flag to start slideshow on mouseout
     *                            - options.itemsClass = Classname of slidebox items
     *                            - options.startPos = Start position of item
     *                            - options.spacer = Spacer in pixel between two slides
     *                            - options.interval = Intervall in seconds for slideshow
     *                            - options.duration = Duration of slide effect
     *                            - options.useItemsSizes = Flag to calculate slide box dimensions using items
     *                            - options.width = Width of slidebox in pixel
     *                            - options.height = Height of slidebox in pixel
     *                            - options.direction = Slide direction, one of this._availableDirections items
	 */
	initialize: function(element, options) {
		if (typeof(options) == "undefined") {
		    throw("mpSlideBox.initialize: Missing options parameter");
            return;
        } else if (!$(element)) {
		    throw("mpSlideBox.initialize: Couldn't find slide box element having id '" + element + "'");
            return;
        } else if (typeof(options.itemsClass) == "undefined") {
		    throw("mpSlideBox.initialize: Missing option for class name of slide box items");
            return;
        }

        // slide box
        this._slideBox = element;
        
        // stop on mouseover
        if (typeof(options.stopOnMouseover) !== "undefined" && options.stopOnMouseover == true) {
            $(this._slideBox).observe("mouseover", this.stop.bind(this));
        }
        // start on mouseout
        if (typeof(options.startOnMouseout) !== "undefined" && options.startOnMouseout == true) {
            $(this._slideBox).observe("mouseout", this.start.bind(this));
        }

        // set slide box items
        this._items = $(this._slideBox).select("." + options.itemsClass);
        if (!this._items) {
            return;
        }

        // start position
        if (typeof(options.startPos) !== "undefined") {
            if (parseInt(options.startPos) >= 0 && parseInt(options.startPos) < this._items.length) {
                this._pos = parseInt(options.startPos);
            }
        }

        // space between two slides
        if (typeof(options.spacer) !== "undefined" && parseInt(options.spacer) > 0) {
            this._spacer = parseInt(options.spacer);
        }

        // periodical executer intervall
        if (typeof(options.interval) !== "undefined" && parseInt(options.interval) > 0) {
            this._interval = parseInt(options.interval);
        }

        // duration of effect
        if (typeof(options.duration) !== "undefined" && parseFloat(options.duration) > 0) {
            this._duration = parseFloat(options.duration);
        }

        // initialize dimensions of box
        this._initializeDimensions(options);
        $(this._slideBox).setStyle({width: this._width + "px", height: this._height + "px", minHeight: this._height + "px"});

        // initialize slide box items
        this._items.each(function(item, i){
            item.setStyle({position: "absolute", top: "0px", left: "0px", width: this._width + "px", height: this._height + "px"});
            if (i !== this._pos) {
                item.setStyle({left: "-" + this._width + "px"});
            }
        }.bind(this));

        // set direction
        if (typeof(options.direction) !== "undefined") {
            this._availableDirections.each(function(item){
                if (item == options.direction) {
                    this._direction = options.direction;
                }
            }.bind(this));
        }

        if (typeof(options.autostart) !== "undefined" && options.autostart == true) {
            this.start();
        }
	},


    /**
     * Starts the periodical sliding of slide box items
     */
    start: function(){
        if (this._animating) {
            return;
        }
        this.stop();
        this._pe = new PeriodicalExecuter(this.next.bind(this), this._interval);
    },


    /**
     * Stops the periodical sliding of slide box items
     */
    stop: function(){
        console.log('this._pe', this._pe);
        if (this._pe !== null) {
            this._pe.stop();
        }
    },


    /**
     * Displays the previous slide box item
     */
    previous: function(){
        if (this._animating) {
            return;
        }
        var currentPos = this._pos--;
        if (this._pos < 0) {
            this._pos = this._items.length - 1;
        }
        this._move(this._newSrollOptions(currentPos, this._pos, true));
    },


    /**
     * Displays the next slide box item
     */
    next: function(){
        if (this._animating) {
            return;
        }
        var currentPos = this._pos++;
        if (this._pos == this._items.length) {
            this._pos = 0;
        }
        this._move(this._newSrollOptions(currentPos, this._pos, false));
    },


    /**
     * Displays the slide box item by passed position
     *
     * @param  {Interger}  position  Position of item to show
     */
    showByPos: function(position){
        if (this._animating) {
            return;
        }
        if (position < 1 || position >= this._items.length) {
            return;
        }
        var currentPos = this._pos;
        this._pos = position--;

        this._move(this._newSrollOptions(currentPos, this._pos, false));
    },


    /**
     * Sets width and height of slide box by analyzing passed options
     *
     * @param  {Object}  options  Slide box options
     */
    _initializeDimensions: function(options) {
        // adapt to existing slide box item dimensions?
        var bUseItemsSizes = (typeof(options.useItemsSizes) !== "undefined" && options.useItemsSizes == true) ? true : false;
        if (bUseItemsSizes) {
            // loop thru each slide box  and set max dimensions
            this._items.each(function(item, i){
                if (this._width < item.getWidth()) {
                    this._width = item.getWidth();
                }
                if (this._height < item.getHeight()) {
                    this._height = item.getHeight();
                }
            }.bind(this));
        } else {
            // slide box width
            if (typeof(options.width) !== "undefined") {
                this._width = parseInt(options.width);
            } else {
                this._width = $(this._slideBox).getWidth();
            }

            // slide box height
            if (typeof(options.height) !== "undefined") {
                this._height = parseInt(options.height);
            } else {
                this._height = $(this._slideBox).getHeight();
            }
        }
    },


    /**
     * Returns the direction for next slide, @see this._availableDirections
     *
     * @returns  {String}  The direction identifier
     */
    _getDirection: function(){
        if (this._direction !== "random") {
            return this._direction;
        } else {
            var pos = 1 + parseInt((this._availableDirections.length - 1) * Math.random());
            console.log('_getDirection() direction', this._availableDirections[pos]);
            return this._availableDirections[pos];
        }
    },


    /**
     * Returns the scroll options struct for the next slide
     *
     * @param  {Integer}  curPos   Current slide item position
     * @param  {Integer}  nextPos  Next slide item position
     * @param  {Boolean}  reverse  Flag to reverse 
     *
     */
    _newSrollOptions: function(curPos, nextPos, reverse){
        var height = this._height + this._spacer;
        var width  = this._width + this._spacer;
        if (reverse == true) {
            height = - height;
            width  = - width;
        }

        // base scroll options
        var opt = {
            cur: {
                pos: curPos, x: 0, y: 0
            },
            next: {
                pos: nextPos, x1: 0, y1: 0, x2: 0, y2: 0
            }
        };

        // set current box options
        var dir = this._getDirection();
        if (dir == "lefttop-rightbottom") {
            opt.cur.x = height;
            opt.cur.y = width;
        } else if (dir == "left-right") {
            opt.cur.x = 0;
            opt.cur.y = width;
        } else if (dir == "leftbottom-righttop") {
            opt.cur.x = - height;
            opt.cur.y = width;
        } else if (dir == "top-bottom") {
            opt.cur.x = height;
            opt.cur.y = 0;
        } else if (dir == "bottom-top") {
            opt.cur.x = - height;
            opt.cur.y = 0;
        } else if (dir == "righttop-leftbottom") {
            opt.cur.x = height;
            opt.cur.y = - width;
        } else if (dir == "right-left") {
            opt.cur.x = 0;
            opt.cur.y = - width;
        } else if (dir == "rightbottom-lefttop") {
            opt.cur.x = - height;
            opt.cur.y = - width;
        }

        // set next box options
        dir = this._getDirection();
        if (dir == "lefttop-rightbottom") {
            opt.next.x1 = - height;
            opt.next.y1 = - width;
            opt.next.x2 = height;
            opt.next.y2 = width;
        } else if (dir == "left-right") {
            opt.next.x1 = 0;
            opt.next.y1 = - width;
            opt.next.x2 = 0;
            opt.next.y2 = width;
        } else if (dir == "leftbottom-righttop") {
            opt.next.x1 = height;
            opt.next.y1 = - width;
            opt.next.x2 = - height;
            opt.next.y2 = width;
        } else if (dir == "top-bottom") {
            opt.next.x1 = - height;
            opt.next.y1 = 0;
            opt.next.x2 = height;
            opt.next.y2 = 0;
        } else if (dir == "bottom-top") {
            opt.next.x1 = height;
            opt.next.y1 = 0;
            opt.next.x2 = - height;
            opt.next.y2 = 0;
        } else if (dir == "righttop-leftbottom") {
            opt.next.x1 = - height;
            opt.next.y1 = width;
            opt.next.x2 = height;
            opt.next.y2 = - width;
        } else if (dir == "right-left") {
            opt.next.x1 = 0;
            opt.next.y1 = width;
            opt.next.x2 = 0;
            opt.next.y2 = - width;
        } else if (dir == "rightbottom-lefttop") {
            opt.next.x1 = height;
            opt.next.y1 = width;
            opt.next.x2 = - height;
            opt.next.y2 = - width;
        }

        return opt;
    },


    _move: function(opt) {
        this._animating = true;
        new Effect.MoveBy($(this._items[opt.cur.pos]), opt.cur.x, opt.cur.y, {
            duration:   this._duration,
            transition: Effect.Transitions.sinoidal
        });

        $(this._items[opt.next.pos]).setStyle({top: opt.next.x1 + "px", left: opt.next.y1 + "px"});
        new Effect.MoveBy($(this._items[opt.next.pos]), opt.next.x2, opt.next.y2, {
            duration:   this._duration,
            transition: Effect.Transitions.sinoidal,
            afterFinish: function(){
                this._animating = false;
            }.bind(this)
        });
    }

});


if (!("console" in window) || !("firebug" in console)) {
(function(){
	window.console = {
		log:   function(){},
		debug: function(){},
		info:  function(){},
		warn:  function(){},
		error: function(){}
	}
})();
}
