$.fn.slidingFeature = function()
{
    new SlidingFeature(this);
    return this;
};

/**
 * You can have any (reasonable) number of featureElement structures within the slidingFeature.
 * The image map is optional
 */
SlidingFeature = function($node, selectedIndex)
{
    this.$node = $node;
    this.selectedIndex = selectedIndex || 0;
    this.elements = this.makeElements();
    this.selected = this.elements[this.selectedIndex];
    this.playControl = this.makePlayControl(this);

    this.create();
    this.timeoutID = null;
    this.intervalID = null;
    this.startCycle();
};

// These "constants" need to be synced with the css file.
SlidingFeature.HEADER_WIDTH = 40;
SlidingFeature.BODY_WIDTH = 663;
SlidingFeature.KEYLINE_WIDTH = 2;

SlidingFeature.TOTAL_WIDTH = SlidingFeature.HEADER_WIDTH + SlidingFeature.BODY_WIDTH;
SlidingFeature.SLIDE_TIME = 600; // in milliseconds
SlidingFeature.CYCLE_TIME = 10000; // in milliseconds
SlidingFeature.WAIT_TIME = 10000; // time to wait from the user clicks a feature until cycle restarts

SlidingFeature.prototype.makeElements = function()
{
    var elements = [];

    var $featureElements = $(".featureElement", this.$node);

    var leftPosition = 0;
    var rightPosition = SlidingFeature.TOTAL_WIDTH -
    (SlidingFeature.HEADER_WIDTH + SlidingFeature.KEYLINE_WIDTH) * $featureElements.length;

    $featureElements.each(function(index, el) {
            elements.push(new FeatureElement($(el), leftPosition, rightPosition, index));

            leftPosition += SlidingFeature.HEADER_WIDTH + SlidingFeature.KEYLINE_WIDTH;
            rightPosition += SlidingFeature.HEADER_WIDTH + SlidingFeature.KEYLINE_WIDTH;
        });

    for(var i = 0; i < elements.length; i ++) {
        if(i > 0)
            elements[i].leftElement = elements[i - 1];
        else
            elements[i].leftElement = null;

        if(i < elements.length - 1)
            elements[i].rightElement = elements[i + 1]
            else
                elements[i].rightElements = null;
    }

    return elements;
};

SlidingFeature.prototype.makePlayControl = function()
{
    var self = this;
    var playControl = new PlayControl($("#toggleSlide"), function() {
            return self.intervalID != null;
        });

    playControl.onPlay = function() {
        self.cycle();
        self.startCycle();
    };
    playControl.onPause = function() {
        self.stopCycle();
    };

    return playControl;
};

SlidingFeature.prototype.create = function()
{
    for(var i = 0; i < this.elements.length; i ++) {
        var element = this.elements[i];
        if(i <= this.selectedIndex)
            element.placeLeft();
        else
            element.placeRight();

        element.listen();

        var self = this;
        // onSelected gets called by callback by the featureElement when
        // it is in place and is the main feature shown (post-slide)
        element.onSelected = function() {
            self.selected = this;
        }
        element.onClick = function() {
            self.stopCycle();
            self.waitAndCycle();
        }
    }

  
};

SlidingFeature.prototype.startCycle = function()
{
    var self = this;
    this.intervalID = window.setInterval(function() {
            self.cycle();
        }, SlidingFeature.CYCLE_TIME);
};

SlidingFeature.prototype.stopCycle = function()
{
    window.clearInterval(this.intervalID);
    this.intervalID = null;
};

SlidingFeature.prototype.waitAndCycle = function()
{
    var self = this;
    if(!this.timeoutID)
        this.timeoutID = window.setTimeout(function() {
                self.timeoutID = null;
                self.startCycle();
            }, SlidingFeature.WAIT_TIME);
};

SlidingFeature.prototype.cycle = function()
{
    if(this.selected.rightElement)
        this.selected.rightElement.select();
    else
        this.elements[0].select();
};


FeatureElement = function($element, leftPosition, rightPosition, zIndex)
{
    this.$element = $element;
    this.leftPosition = leftPosition;
    this.rightPosition = rightPosition;
    this.$keylineLeft = $("<div class='keylineLeft'></div>").hide().appendTo($element);
    this.$keylineRight = $("<div class='keylineRight'></div>").hide().appendTo($element);
    this.$element.css("z-index", zIndex);
    this.leftElement;
    this.rightElement;
};

// "static" variable, prevent moving multiple elements
FeatureElement.isSliding = false;

FeatureElement.PLACE_LEFT = -1;
FeatureElement.PLACE_RIGHT = 1;

FeatureElement.prototype.listen = function()
{
    var self = this;
    $(".featureHeader", this.$element).click(function() {
            self.onClick();
            self.select();
        });
};

FeatureElement.prototype.select = function()
{
    if(FeatureElement.isSliding)
        return;

    if(this.place == FeatureElement.PLACE_LEFT) {
        if(this.rightElement) {
            var self = this;
            this.rightElement.slideRight(function() { self.onSelected() });
        }
    }
    else {
        var self = this;
        // Alert the SlidingFeature that the new element has been selected manually
        this.slideLeft(function() { self.onSelected() });
    }
};

FeatureElement.prototype.slideLeft = function(callback)
{
    if(this.place == FeatureElement.PLACE_RIGHT) {
        var self = this;

        if(this.leftElement)
            this.leftElement.slideLeft();
                        
        this.slide(this.leftPosition, function() {
                self.place = FeatureElement.PLACE_LEFT;
                self.$keylineLeft.show();
                self.$keylineRight.hide();
                if(callback)
                    callback();
            });
    }
};

FeatureElement.prototype.slideRight = function(callback)
{
    if(this.place == FeatureElement.PLACE_LEFT) {
        var self = this;

        if(this.rightElement)
            this.rightElement.slideRight();

        this.slide(this.rightPosition, function() {
                self.place = FeatureElement.PLACE_RIGHT;
                self.$keylineRight.show();
                self.$keylineLeft.hide();
                if(callback)
                    callback();
            });
    }
};

FeatureElement.prototype.placeLeft = function()
{
    this.$element.css("left", this.leftPosition + "px");
    this.place = FeatureElement.PLACE_LEFT;
    this.$keylineLeft.show();
};

FeatureElement.prototype.placeRight = function()
{
    this.$element.css("left", this.rightPosition + "px");
    this.place = FeatureElement.PLACE_RIGHT;
    this.$keylineRight.show();
};

FeatureElement.prototype.slide = function(endPosition, callback)
{
    FeatureElement.isSliding = true;
    var self = this;
    this.$element.animate({left: endPosition}, SlidingFeature.SLIDE_TIME,
                          function() {
                              FeatureElement.isSliding = false;
                              if(callback)
                                  callback();
                          });
};

FeatureElement.prototype.onSelected = function() { };
FeatureElement.prototype.onClick = function() { };


PlayControl = function($element, isPlaying)
{
    this.$element = $element;
    this.isPlaying = isPlaying;
    this.listen();
};

PlayControl.prototype.listen = function()
{
    window.playControl = this;


    var self = this;
    this.$element.click(function() {
            if(self.isPlaying()) {
                self.onPause();
                self.$element
                    .removeClass('pause')
                    .addClass('play');
            }
            else {
                self.onPlay();
                self.$element
                    .removeClass('play')
                    .addClass('pause');
            }
            
            return false;
        });
};

PlayControl.prototype.onPlay = function() { };
PlayControl.prototype.onPause = function() { };
