﻿/* 
Class:          PhotoSlideShow
Description:    Class to handler the loading and displaying of a series of photos

Instantiation:  var x = new PhotoSlideShow(location, arrayOfImages [, options]);
                where location = the id (or element) of the location for displaying the slideshow
                arrayOfImages is an array of object {id: 'image id', title: 'title', full: 'path to image' or left: 'path' and/or right: 'path'}

*/
var PhotoSlideShow = new Class({

    //implements
    Implements: [Options, Events],

    //options
    options: {
        fullImageCtrlCssClass: 'full-image',
        leftImageCtrlCssClass: 'left-image',
        rightImageCtrlCssClass: 'right-image',
        nextCtrlCssClass: 'next-btn',
        prevCtrlCssClass: 'prev-btn',
        locationHeightFullImage: '420px',
        locationHeightHalfImage: '442px',
        loadingSrc: 'images/loading-minimal.gif',
        feedbackCtrlSelector: null,
        onChange: $empty,
        onError: $empty
    },


    currentIndex: 0,
    images: new Array(),
    cache: new Array(),        /* array of image src */
    location: null,
    fullImageCtrl: null,
    leftImageCtrl: null,
    rightImageCtrl: null,
    nextCtrl: null,
    prevCtrl: null,
    feedbackCtrl: null,

    //initialization
    initialize: function(location, arrayOfImages, options) {
        this.location = $(location);
        this.images = arrayOfImages;

        //set options
        this.setOptions(options);

        //setup controls
        this._SetupControls();
        this.currentIndex = 0;
        this.feedbackCtrl = $(this.options.feedbackCtrlSelector);
        if ($defined(this.options.feedbackCtrlSelector) && !$defined(this.feedbackCtrl)) {
            console.error("Missing/Invalid Feedback Ctrl: " + this.options.feedbackCtrlSelector);
        }

        //load first slide
        this.ShowSlide(this.currentIndex);

    },

    _NormalizeIndex: function(newValue) {
        var ret = newValue;
        if (ret < 0) {
            ret = this.images.length - 1;
        } else if (ret >= this.images.length) {
            ret = 0;
        }
        return ret;
    },

    _onNextClick: function(evt) {
        evt = new Event(evt);

        //update index
        this.currentIndex = this._NormalizeIndex(this.currentIndex + 1);

        //fire event
        this.fireEvent("change", this.currentIndex, 10);

        //show slide
        this.ShowSlide(this.currentIndex);

    },
    _onPrevClick: function(evt) {
        evt = new Event(evt);

        //update index
        this.currentIndex = this._NormalizeIndex(this.currentIndex - 1);

        //fire event
        this.fireEvent("change", this.currentIndex, 10);

        //show slide
        this.ShowSlide(this.currentIndex);
    },

    _SetupControls: function() {
        if (this.location) {
            this.fullImageCtrl = this.location.getElement('.' + this.options.fullImageCtrlCssClass);
            this.leftImageCtrl = this.location.getElement('.' + this.options.leftImageCtrlCssClass);
            this.rightImageCtrl = this.location.getElement('.' + this.options.rightImageCtrlCssClass);
            this.nextCtrl = this.location.getElement('.' + this.options.nextCtrlCssClass);
            this.prevCtrl = this.location.getElement('.' + this.options.prevCtrlCssClass);

            //check each ctrl and create if needed
            if (!$defined(this.fullImageCtrl)) {
                console.debug("adding " + this.options.fullImageCtrlCssClass);
                this.fullImageCtrl = new Element("img", { 'class': this.options.fullImageCtrlCssClass });
                this.location.appendChild(this.fullImageCtrl);
            }
            if (!$defined(this.leftImageCtrl)) {
                console.debug("adding " + this.options.leftImageCtrlCssClass);
                this.leftImageCtrl = new Element("img", { 'class': this.options.leftImageCtrlCssClass });
                this.location.appendChild(this.leftImageCtrl);
            }
            if (!$defined(this.rightImageCtrl)) {
                console.debug("adding " + this.options.rightImageCtrlCssClass);
                this.rightImageCtrl = new Element("img", { 'class': this.options.rightImageCtrlCssClass });
                this.location.appendChild(this.rightImageCtrl);
            }
            if (!$defined(this.prevCtrl)) {
                console.debug("adding " + this.options.prevCtrlCssClass);
                this.prevCtrl = new Element("div", { 'class': this.options.prevCtrlCssClass });
                this.location.appendChild(this.prevCtrl);
            }
            if (!$defined(this.nextCtrl)) {
                console.debug("adding " + this.options.nextCtrlCssClass);
                this.nextCtrl = new Element("div", { 'class': this.options.nextCtrlCssClass });
                this.location.appendChild(this.nextCtrl);
            }

            //add click handlers
            this.nextCtrl.addEvent('click', this._onNextClick.bind(this));
            this.prevCtrl.addEvent('click', this._onPrevClick.bind(this));

            //hide images
            this._HideAllImages();
        }
    },
    _PreLoadImage: function(src) {
        if (!this.cache.contains(src)) {
            var dummy = new Asset.image(src,
               { onload: this._PreLoadComplete.pass(src, this) });
        }
    },
    _PreLoadComplete: function(src) {
        if (!this.cache.contains(src)) {
            this.cache.push(src);
        }
    },
    _PreLoad: function(index) {
        index = this._NormalizeIndex(index);
        var obj = this.images[index];
        if ($defined(obj.full)) {
            this._PreLoadImage(obj.full.src);
        }
        if ($defined(obj.left)) {
            this._PreLoadImage(obj.left.src);
        }
        if ($defined(obj.right)) {
            this._PreLoadImage(obj.right.src);
        }
    },

    _HideAllImages: function() {
        this.fullImageCtrl.setStyle("display", "none");
        this.leftImageCtrl.setStyle("display", "none");
        this.rightImageCtrl.setStyle("display", "none");
    },

    _DisplayImage: function(ctrl, obj) {
        var id = ($defined(obj.id)) ? obj.id : '?';
        var title = ($defined(obj.title)) ? obj.title : '';
        //first set the src to the loading ...
        if ($defined(this.options.loadingSrc)) { ctrl.set('src', this.options.loadingSrc); }
        ctrl.setStyle('display', 'block');
        ctrl.set('rel', id);
        ctrl.set('title', title);
        ctrl.set('alt', title);
        ctrl.set('src', obj.src);
    },

    ShowSlide: function(index) {
        index = this._NormalizeIndex(index);
        this._HideAllImages();
        var obj = this.images[index];
        if ($defined(obj.full)) {
            this._DisplayImage(this.fullImageCtrl, obj.full);
            this.location.tween('height', this.options.locationHeightFullImage);
        } else {
            if ($defined(obj.left)) {
                this._DisplayImage(this.leftImageCtrl, obj.left);
            }
            if ($defined(obj.right)) {
                this._DisplayImage(this.rightImageCtrl, obj.right);
            }
            this.location.tween('height', this.options.locationHeightHalfImage);
        }

        //display the feedback
        if ($defined(this.feedbackCtrl)) {
            this.feedbackCtrl.set('html', (index + 1) + ' of ' + this.images.length);
        } else {
            console.log((index + 1) + ' of ' + this.images.length)
        }

        //preload on either side
        this._PreLoad(this._NormalizeIndex(index + 1));
        this._PreLoad(this._NormalizeIndex(index - 1));
    }
});