//
// Options
// =======
// rewrite:
// A function that takes src of small image and a ref to the
// image and returns the src to the full image based.
// Default returns the same string, so override.
//
// fullcls:
// CSS class for the fullsize image.

var PostShow = new Class({
    Implements: [Options, Chain, Events],
    options: {
        rewrite: function(src){return src},
        caption: function(img){return ''},
        limits: {width: .8, height: .8},
        fullcls: 'postshow-full-img',
        navcls: 'postshow-nav',
        capcls: 'postshow-caption',
        nav: true,
        captions: true
    },
    initialize: function(imgs, options){
        this.setOptions(options);
        this.imgs = $$(imgs);
        this.caption(this.imgs);
        this.body = document.id(document.body);
        this.setupEvents(this.imgs);
    },        
    caption: function(imgs){
        var self = this;
        imgs.each(function(img, index){
           var caption = self.options.caption(img, index); 
           img.store('caption', caption);
           img.retrieve('caption');
        });
    },
    setupEvents: function(imgs){
        imgs.addEvent('click', function(evt){
            this.start(evt.target);
        }.bind(this));
        window.addEvent('keydown', function(evt){
            this.handleKey(evt);
        }.bind(this));
    },
    handleKey: function(evt){
        var handlers = {
            'esc': this.close,
            'left': this.prev,
            'right': this.next,
            'up': this.prev,
            'down': this.next
        }
        var handler = handlers[evt.key];
        if(handler){
            evt.preventDefault();
            handler.apply(this);
        }
    },
    start: function(img){
        this.clicked = img;
        this.setCurIndexWithImage(img);
        this.scrim = this.overlay();
        this.expose(img);
    },
    setCurIndexWithImage: function(curimg){
        this.imgs.each(function(img, index){
             if(img === curimg){
                 this.index = index;  
             }
        }.bind(this));
    },
    setCurIndex: function(index){
        this.index = index;
    },
    getCurIndex: function(){
        return this.index;
    },
    getCurImage: function(){
        return this.getImage(this.getCurIndex());
    },
    getImage: function(index){
        return this.imgs[index];
    },
    getCurFull: function(index){
        return this.full;
    },
    overlay: function(){
        // Create an overlay to fade out the page elements
        var o = new Element('div',{
            styles: {
                position: 'fixed', 
                top: 0,
                left: 0,
                width: '100%',
                height: '100%',
                opacity: 0,
                background: this.body.getStyle('background-color')
            }
        });
        this.body.grab(o);
        o.tween('opacity', 0, .8);
        o.addEvent('click', function(){this.close()}.bind(this));
        o.addEvent('keydown', function(){this.handleKey(evt)}.bind(this));
        return o;
    },
    close: function(){
        this.scrim.fade("out");
        this.full.fade("out");
        this.navbar.fade("out");
        this.clicked.setStyle('visibility', 'visible');
    },
    expose: function(img){
        var pos = img.getCoordinates();
        // Clone the image and store a reference to the original.
        var pImage = img.clone();

        img.setStyle('visibility', 'hidden');
        this.body.grab(pImage);
        this.positionSubImage(pImage, pos);
        this.centerSubImage(pImage, pos);
    },
    positionSubImage: function(img, startpos){
        var pStyles = {
            'z-index': 10,
            'position': 'absolute',
            'top': startpos.top,
            'left': startpos.left,
        }
        img.setStyles(pStyles);
        return img;
    },
    centerSubImage: function(img, startpos){
        var offset = this.centerOffset(startpos);
        var src = this.options.rewrite(img.get('src'), img);
        var title = img.get('title');
        var mover = new Fx.Move(img, {
            'relativeTo': img,
            'offset': offset,
            'onComplete': function(){this.loadFull(title, src, img)}.bind(this)
        });
        mover.start();
    },
    loadFull: function(title, src, relTo){
        var full = Asset.image(src, {
           'class': this.options.fullcls,
           'title': title, 
           'onload': function(full){this.handleFullLoad(full, relTo)}.bind(this)
        });
    },
    handleFullLoad: function(full, relTo){
        this.full = full;
        this.body.grab(full); 
        var coords = relTo.getCoordinates();
        var origCoords = full.getCoordinates();
        full.setStyles({
            'width': coords.width,
            'height': coords.height
        });
        full.position({
            'relativeTo':relTo,
            'offset': {x:0, y:0}
        });
        full.replaces(relTo);
        origCoords.left = coords.left; origCoords.top = coords.top;
        var newCoords = this.calcDimensions(full, origCoords);
        var captionStr = this.getCurImage().retrieve('caption');
        this.navbar = this.createNavBar(newCoords, captionStr);
        newCoords = this.adjustForCaption(newCoords, this.navbar);
        this.positionNavBar(this.navbar, newCoords);

        full.morph({
            'width': newCoords.width,
            'height': newCoords.height,
            'left': newCoords.left,
            'top': newCoords.top,
            'complete': this.showNav()
        });
    },
    adjustForCaption: function(coords, navbar){
        coords.top = coords.top - (navbar.getCoordinates().height / 2);
        return coords;
    },
    calcDimensions: function(img, coords){
        img.set('morph', {
                'duration': 'short',
                'transition': Fx.Transitions.Cubic.easeInOut
        });

        var winsize = window.getSize();
        var longdim = this.longdim(winsize, coords);
        
        var limits = {};
        limits.width = winsize.x * this.options.limits.width;
        limits.height = winsize.y * this.options.limits.height;

        var ratio = coords.width / coords.height
        var newcoords = this.resize(longdim, coords, ratio, limits);

        var center = this.getCenter();
        newcoords.left = center.left - (newcoords.width/2);
        newcoords.top = center.top - (newcoords.height/2);
        return newcoords;

    },
    showNav: function(navbar){
        this.navbar.fade('in');
    },
    createNavBar: function(coords, captionStr){
        if(this.navbar){
            this.navbar.destroy(); 
            this.navbar = null;
        }
        var navbar = new Element('div', {
                class: this.options.navcls,
                styles: {
                    position: 'absolute',
                    width: coords.width,
                    opacity: 0
                },
        });
        var caption = this.createCaption(captionStr);
        var nav = this.createNav();
        navbar.grab(caption)
        navbar.grab(nav)
        this.body.grab(navbar);
        return navbar;
    },
    positionNavBar: function(navbar, coords){
        var offset = navbar.getCoordinates().height;
        navbar.setStyles({
            top: (coords.top + coords.height) - offset,
            left: coords.left
        });
    },
    createCaption: function(captionstr){
        var caption = new Element('p', {
            class: this.options.capcls, 
            text: captionstr
        });
        return caption;
    },
    createNav: function(){
        var nav = new PrevNext({}, this.prev.bind(this),
                                   this.next.bind(this),
                                   this.close.bind(this));
        nav.update(this.getCurIndex(), this.imgs.length);
        return document.id(nav);
    },
    prev: function(){
        var prevIndex = this.getCurIndex() - 1;
        if(prevIndex < 0) return;
        this.setCurIndex(prevIndex);
        this.change();
    },
    next: function(){
        var nextIndex = this.getCurIndex() + 1;
        if(nextIndex > this.imgs.length - 1) return;
        this.setCurIndex(nextIndex);
        this.change();
    },
    change: function(){
        var img = this.getCurImage();
        var src = this.options.rewrite(img.get('src'));
        var displayed = this.getCurFull();
        this.loadFull(img.get('title'), src, displayed);
    },
    resize: function(longdim, coords, ratio, limits){
        var newcoords = {}
        // shortdim is whatever the longdim isn't
        var shortdim = longdim === 'width' ? 'height' : 'width';
        // get the longer dimension size by using whatever is smaller
        // between the actual coords or the limit in the long dimension
        newcoords[longdim] = limits[longdim] < coords[longdim] ? limits[longdim] : coords[longdim];
        // calculate remaining dim and preserve ratio
        newcoords[shortdim] = newcoords[longdim] * ratio;
        return newcoords; 
    },
    longdim: function(winsize, coords){
        // compare image dimensions to window dimensions and 
        // return name of dimension with greater difference.
        var xdiff = coords.width - winsize.x;
        var ydiff = coords.height - winsize.y;
        return xdiff > ydiff ? 'width' : 'height';
    },
    // Utility Functions
    relViewport: function(coords){
        // fixes a set of coords for current window scroll.
        coords.top = coords.top + window.scrollY;
        coords.left = coords.left + window.scrollX;
        coords.bottom = coords.bottom + window.scrollY;
        coords.right = coords.right + window.scrollX;
        return coords; 
    },
    getCenter: function(){
        // get the center of the viewport
        var center = {
            left: window.getSize().x / 2,
            top: window.getSize().y / 2
        };
        return this.relViewport(center);
    },
    centerOffset: function(coords){
        // return object with x,y that refer to offset from
        // coords in args to center of viewport
        var center = this.getCenter();
        return {
            x: (center.left - coords.left) - coords.width/2,
            y: (center.top - coords.top) - coords.height/2
        }; 
     }
}); 

var PrevNext = new Class({ options: {
        prevnextcls: 'prevnext',
        prevcls: 'prevnext-prev',
        nextcls: 'prevnext-next',
        prevtext: 'prev',
        nexttext: 'next',
        closecls: 'prevnext-close',
        closetext: 'close'
    },
    initialize: function(options,
                   prevCallback,
                   nextCallback,
                   closeCallback){
        this.elem = new Element('ol', {class: this.options.prevnextcls});
        this.prevCallback = prevCallback;
        this.nextCallback = nextCallback;
        this.closeCallback = closeCallback;
    },
    update: function(current, total){
        this.elem.empty();
        if(total == 0) return null;

        var opts = this.options;
        if(current > 0){
            var prevBtn = this.makeBtn(opts.prevcls,
                                    opts.prevtext,
                                    function(){this.prevCallback()}.bind(this));
            this.elem.grab(prevBtn);
        }
        if(current<total - 1){
            var nextBtn = this.makeBtn(opts.nextcls,
                                    opts.nexttext,
                                    function(){
                                        this.nextCallback()
                                    }.bind(this));
            this.elem.grab(nextBtn);
        }
        
        var closeBtn = this.makeBtn(opts.closecls,
                                    opts.closetext,
                                    function(){
                                        this.closeCallback()
                                    }.bind(this));
        this.elem.grab(closeBtn);
    },
    makeBtn: function(class, text, callback){
        var btn = new Element('li', {
            class: class,
            text: text
        });
        btn.addEvent('click', callback);
        return btn;
    },
    toElement: function(){
        return this.elem;
    }
               
});

window.addEvent('domready', function(){
    var opts = {
        'rewrite': function(src){
           var parts = src.split('/'); 
           parts.splice(parts.length - 1, 0, 'full');
           url = parts.join('/');
           return url;           
        },
        'caption': function(img, index){
           return img.getParent().get('text').trim();
        }
    }
    var ps = new PostShow('img', opts);
});

