Object.extend(
    document.viewport, {
        getPageSize: function() {
        	
            var xScroll, yScroll, windowWidth, windowHeight, pageHeight, pageWidth;

            if (window.innerHeight && window.scrollMaxY) {
                xScroll = document.body.scrollWidth;
                yScroll = window.innerHeight + window.scrollMaxY;
            } else if (document.body.scrollHeight > document.body.offsetHeight) { //all but Explorer Mac
                xScroll = document.body.scrollWidth;
                yScroll = document.body.scrollHeight;
            } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
                xScroll = document.body.offsetWidth;
                yScroll = document.body.offsetHeight;
            }

            if (self.innerHeight) { // all except Explorer
                windowWidth = self.innerWidth;
                windowHeight = self.innerHeight;
            } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
                windowWidth = document.documentElement.clientWidth;
                windowHeight = document.documentElement.clientHeight;
            } else if (document.body) { // other Explorers
                windowWidth = document.body.clientWidth;
                windowHeight = document.body.clientHeight;
            }

            // for small pages with total w/h less then w/h of the viewport
            pageHeight = (yScroll < windowHeight) ? windowHeight : yScroll;
            pageWidth  = (xScroll < windowWidth)  ? windowWidth  : xScroll;

            return [
                pageWidth, pageHeight, windowWidth, windowHeight
            ];
        }
    }
    );

var ProtoBox = Class.create();

ProtoBox.prototype = {
    initialize : function(options) {
        this.options = Object.extend(
        {
            hide_flash   : false,
            loading_img  : 'images/loading.gif',
            close_img    : 'images/closelabel.png',
            rel          : 'lightbox',
            my_id        : 'lightbox',
            protect      : false,

            force_update : false,

            max_width    : 0,
            max_height   : 0,

            ring         : true,
            drag         : false,

            overlay      : null,
            overlay_id   : 'overlay',
            ovl_opacity  : 0.8,
            ovl_speed    : 0.2,

            animate      : true,
            speed        : 8
        },
            
        options || {}
        );

        this.listening_kd = false;
        this._keydown     = this._onKeyDown.bindAsEventListener(this);

        this.body    = $$('body')[0];
        this.overlay = $(this.options.overlay);
        if (this.overlay == null) {
            this.overlay = $(document.createElement('div'));
            this.overlay.setAttribute('id', this.options.overlay_id);
            this.overlay.style.display = 'none';
            this.body.appendChild(this.overlay);
        }

        this.overlay.observe('click', this._closeSelf.bindAsEventListener(this));

        if (this.options.animate == false) {
            this.resize_duration = 0;
        } else {
            if (this.options.speed > 10) {
                this.options.speed = 10;
            }

            if (this.options.speed < 1) {
                this.options.speed = 1;
            }

            this.resize_duration = 0.1 * (11 - this.options.speed);
        }

        this.act_rel = '';
        this.active  = -1;
        this.links  = {};
        this._buildLayout();
        this.updateInfoList();
    },
    
    _buildLayout : function() {
        this.myself = $(Builder.node('div', { 
            id : this.options.my_id
        }, [
            Builder.node('div', {
                'class' : 'infoContainer'
            }, [
                Builder.node('div', {
                    'class' : 'infoTextContainer'
                }),
                Builder.node('div', {
                    'class' : ((true == this.options.protect) ? 'protector' : '')
                }),
                Builder.node('a', {
                    href : 'javascript:void(0)',
                    'class' : 'prevLink'
                }),
                Builder.node('a', {
                    href : 'javascript:void(0)',
                    'class' : 'nextLink'
                }),
                Builder.node('div', {
                    'class' : 'loading'
                }, [
                    Builder.node('img', {
                        alt : 'Loading...',
                        src : this.options.loading_img
                    })
                ]),
            ]),
            Builder.node('div', {
                'class' : 'infoDataContainer'
            }, [
                Builder.node('div', {
                    'class' : 'infoDetails'
                }, [
                    Builder.node('div', {
                        'class' : 'caption'
                    }),
                    Builder.node('div', {
                        'class' : 'numberDisplay'
                    })
                ]),
                Builder.node('img', {
                    'class' : 'bottomNavClose',
                    alt : 'Close',
                    src : this.options.close_img
                })
            ])
        ]));

        if (window.external && (typeof window.XMLHttpRequest == 'undefined') && document.all && navigator.userAgent.toLowerCase().indexOf('opera') == -1) {
            var iframe = document.createElement('iframe');
            iframe.className = 'ie_iframe';
            iframe.frameBorder = 0;
            this.myself.appendChild(iframe);
        }

        this.myself.setStyle({ 
            display : 'none'
        });
        if (this.options.drag == false) {
            this.myself.observe('click', this._closeSelf.bindAsEventListener(this));
        }

        this.body.appendChild(this.myself);

        this.infoContainer     = this.myself.down();
        this.infoDataContainer = this.infoContainer.next();
        this.the_info          = this.infoContainer.down();
        this.prevLink           = this.the_info.next().next();
        this.nextLink           = this.prevLink.next();
        this.loading            = this.nextLink.next();
        this.loadingLink        = this.loading.down();
        var infoDetails        = this.infoDataContainer.down();
        this.bottomNavClose     = infoDetails.next();
        this.caption            = infoDetails.down();
        this.numberDisplay      = this.caption.next();

        if (this.options.animate) {
            this.infoContainer.setStyle( {
                width : '250px',
                height : '250px'
            } );
            this.infoDataContainer.setStyle( { 
                width : '250px'
            } );
        } else {
            this.infoContainer.setStyle( {
                width : '40px',
                height : '40px'
            } );
            this.infoDataContainer.setStyle( { 
                width : '40px'
            } );
        }

        if (this.options.drag) {
            new Draggable(this.myself, {
                handle : this.infoContainer,
                onEnd : this._fixOverlay.bind(this)
            });
            this.infoContainer.style.cursor = 'move';
        }

        this.prevLink.observe('click', this._prev.bindAsEventListener(this));
        this.nextLink.observe('click', this._next.bindAsEventListener(this));

        [this.loadingLink, this.bottomNavClose].invoke('observe', 'click', this._closeSelf.bindAsEventListener(this));
    },
    
    _fixOverlay : function() {
    /*
        var ow = document.documentElement.offsetWidth;
        var oh = document.documentElement.offsetHeight;
        var sw = document.documentElement.scrollWidth;
        var sh = document.documentElement.scrollHeight;

        if (ow > sw) {
            sw = ow;
        }

        if (oh > sh) {
            sh = oh;
        }
    */
        
        this.overlay.setStyle({
            width : document.viewport.getPageSize()[0] + 'px',
            height : document.viewport.getPageSize()[1] + 'px'
        });
    },
    
    _closeSelf : function(e) {
        e.stop();
        this._end();
    },
    
    _startShow : function(e) {
        e.stop();
        if (true == this.options.force_update) {
            this.updateInfoList();
        }

        this._start(e.findElement('a'));
    },
    
    updateInfoList : function() {
        this.links  = [];
        this.active  = -1;
        this.act_rel = null;

        $$('a[rel^=' + this.options.rel + ']', 'area[rel^=' + this.options.rel + ']').each(
            function(node) {
                var rel   = node.getAttribute('rel') || this.options.rel;
                var href  = node.getAttribute('href') || '';
                var title = node.getAttribute('title') || '';

                if (rel.indexOf('[') != -1) {
                    if (typeof this.links[rel] == 'undefined') {
                        this.links[rel] = [];
                    }

                    this.links[rel].push({
                        'href' : href,
                        'title' : title
                    });
                }

                if (!node.protoboxed) {
                    node.observe('click', this._startShow.bindAsEventListener(this));
                    node.protoboxed = true;
                }
            }.bind(this)
            );
    },
    
    _start : function(element) {
        this._hideFlash();
		this._fixOverlay();
		
        var dims    = document.viewport.getDimensions();
        var scrolls = document.viewport.getScrollOffsets();

        new Effect.Appear(
            this.overlay,
            {
                duration : this.options.ovl_speed,
                from     : 0,
                to       : this.options.ovl_opacity
            }
        );

        var rel   = element.getAttribute('rel');
        this.href = element.getAttribute('href');
        var title = element.getAttribute('title');
        var idx   = -1;

        if (rel.indexOf('[') != -1) {
            if (typeof this.links[rel] == 'undefined') {
                this.links[rel] = [{
                    'href' : href,
                    'title' : title
                }];
            } else {
                var a = this.links[rel];
                var l = a.length;
                for (var i = 0; i < l; ++i) {
                    if (a[i].href == this.href) {
                        idx = i;
                        break;
                    }
                }

                if (idx == -1) {
                    idx = l;
                    a.push(this.href);
                }
            }
        } else {
            rel = title;
        }

        //var top  = scrolls.top + dims.height / 15;
        var top  = scrolls.top + 20;
        var left = scrolls.left;

        this.myself.setStyle({
            'left' : left + 'px',
            'top' : top + 'px'
        })
        this.myself.show();

        this._changeInfo(rel, idx);
    },
    
    _end : function() {
        this._disableKeyboardNav();
        this.myself.hide();
        new Effect.Fade(this.overlay, { 
            duration: this.options.ovl_speed
        });
        this._showFlash();
    },
    
    _changeInfo : function(rel, idx) {
        this.act_rel = rel;
        this.active  = idx;

        if (this.options.animate) {
            this.loading.show();
        }

        [this.the_info, this.prevLink, this.nextLink, this.infoDataContainer, this.numberDisplay].invoke('hide');
		
        var _this = this;
		
        new Ajax.Request(
            this.active < 0 ? this.href : this.links[rel][idx].href,
            {
                method: "get",
                onSuccess: function(transport) {
                    $(_this.the_info).innerHTML = transport.responseText;
                    $(_this.the_info).setStyle({
                        width : 300 + 'px',
                        height : 250 + 'px'
                    });
                    _this._resizeInfoContainer(400, 350);
                }
            }
            );
        
    },
        
    _resizeInfoContainer : function(w, h) {
        var width_current  = this.infoContainer.getWidth();
        var height_current = this.infoContainer.getHeight();

        var width_new  = w;
        var height_new = h;

        if (width_current != width_new + 2 || height_current != height_new + 1) {

            var x_scale = width_new / width_current * 100;
            var y_scale = height_new / height_current * 100;

            var w_diff = width_current - width_new;
            var h_diff = height_current - height_new;

            if (h_diff != 0) {
                new Effect.Scale(
                    this.infoContainer,
                    y_scale,
                    {
                        scaleX   : false,
                        duration : this.resize_duration,
                        queue    : 'front'
                    }
                );
            }

            if (w_diff != 0) {
                new Effect.Scale(
                    this.infoContainer,
                    x_scale,
                    {
                        scaleY   : false,
                        duration : this.resize_duration,
                        delay    : this.resize_duration
                    }
                );

                this.infoDataContainer.setStyle( {
                    width : width_new + 'px'
                } );
            }

            if (h_diff == 0 && w_diff == 0) {
                this._pause(
                    (navigator.appVersion.indexOf("MSIE") != -1) ? 250 : 100
                );
            }

            this.prevLink.style.height = height_new + 'px';
            this.nextLink.style.height = height_new + 'px';
            this.infoDataContainer.style.width = width_new + 'px';
        }
        this._showInfo();
    },
    
    _showInfo: function() {
        this.loading.hide();
        new Effect.Appear(
            this.the_info,
            {
                duration    : this.resize_duration,
                queue       : 'end',
                afterFinish : this._updateDetails.bind(this)
            }
        );
    },
    
    _updateDetails : function() {
        if (this.active >= 0) {
            var e = this.links[this.act_rel][this.active];
            if (e.title != ''){
                this.caption.update(e.title);
                this.caption.show();
            }

            if (this.links[this.act_rel].length && this.links[this.act_rel].length > 1) {
                this.numberDisplay.update("Event " + (this.active + 1) + " of " + this.links[this.act_rel].length);
                this.numberDisplay.show();
            }
        } else if (this.act_rel != '') {
            this.caption.update(this.act_rel);
            this.caption.show();
        }

        new Effect.Parallel(
            [
                new Effect.SlideDown(this.infoDataContainer, {
                    sync: true,
                    duration: this.resize_duration,
                    from: 0.0,
                    to: 1.0
                }),
                new Effect.Appear(this.infoDataContainer, {
                    sync: true,
                    duration: this.resize_duration
                })
            ],
            {
                duration    : this.resize_duration,
                afterFinish : this._updateNav.bind(this)
            }
        );
    },
    
    _prev : function(e) {
        Event.stop(e);
        this.__prev();
    },
    
    __prev : function() {
        if (this.active > 0) {
            this._changeInfo(this.act_rel, this.active - 1);
        } else if (this.options.ring == true && this.active == 0) {
            this._changeInfo(this.act_rel, this.links[this.act_rel].length - 1);
        }
    },
    
    _next : function(e) {
        Event.stop(e);
        this.__next();
    },
    
    __next : function() {
        if (this.active >= 0) {
            if (this.active != this.links[this.act_rel].length - 1) {
                this._changeInfo(this.act_rel, this.active + 1);
            } else if (this.options.ring == true) {
                this._changeInfo(this.act_rel, 0);
            }
        }
    },
    
    _updateNav: function() {
        if (this.active >= 0) {
            if (this.active > 0 || this.options.ring == true) {
                this.prevLink.show();
            }

            if (this.active != this.links[this.act_rel].length - 1 || this.options.ring == true) {
                this.nextLink.show();
            }
        }

        this._fixOverlay();
        this._enableKeyboardNav();
    },
    
    _enableKeyboardNav : function() {
        if (this.listening_kd == false) {
            this.listening_kd = true;
            Event.observe(document, 'keydown', this._keydown);
        }
    },
    
    _disableKeyboardNav : function() {
        if (this.listening_kd == true) {
            this.listening_kd = false;
            Event.stopObserving(document, 'keydown', this._keydown);
        }
    },
    
    _onKeyDown : function(e) {
        var keycode = e.keyCode;
        var key     = String.fromCharCode(keycode).toLowerCase();

        if (key == 'x' || key == 'c' || key == 'o' || keycode == Event.KEY_ESC) {
            this._end();
        } else if (key == 'p' || keycode == Event.KEY_LEFT) {
            this._disableKeyboardNav();
            this.__prev();
        } else if (key == 'n' || keycode == Event.KEY_RIGHT) {
            this._disableKeyboardNav();
            this.__next();
        }
    },
    
    _hideFlash : function() {
        if (true == this.options.hide_flash) {
            this.all_flash = $$("object", "embed").select(
                function(node) {
                    if (node.getStyle('visibility') == 'visible') {
                        node.style.visibility = 'hidden';
                        return true;
                    }

                    return false;
                }
                ) || [];
        }
    },
    
    _showFlash : function() {
        if (true == this.options.hide_flash) {
            this.all_flash.invoke('setStyle', { 
                visibility : 'visible'
            });
            this.all_flash = [];
        }
    },
    
    _pause : function(ms) {
        var date    = new Date();
        var curDate = null;
        do {
            curDate = new Date();
        } while (curDate - date < ms);
    }
};

var myLightbox;

function initLightbox(options) {
    myLightbox = new ProtoBox(options);
}


