var ProtoBox = Class.create();
ProtoBox.prototype = {
    initialize : function(options)
    {
        this.options = Object.extend(
            {
                hide_flash   : false,
                loading_img  : 'protobox/images/loading.gif',
                close_img    : 'protobox/images/closelabel.jpg',
                rel          : 'lightbox',
                my_id        : 'lightbox',
                protect      : true,

                max_width    : 0,
                max_height   : 0,

                cycle        : true,
                drag         : true,

                force_update : false,

                overlay      : null,
                overlay_id   : 'overlay',
                ovl_opacity  : 0.8,
                ovl_speed    : 0.2,

                animate      : true,
                speed        : 10
            },
            options || {}
        );

        this.listening_kd = false;
        this._keydown     = this._onKeyDown.bindAsEventListener(this);

        this.body    = $$('body')[0];
        this.overlay = $(this.options.overlay);

        if (null == this.overlay) {
            this.overlay = $(Builder.node('div', { id : this.options.overlay_id, style : 'display: none' }, []));
            this.body.appendChild(this.overlay);
        }

        this.overlay.observe('click', this._closeSelf.bindAsEventListener(this));

        if (false == this.options.animate || 'undefined' == typeof Effect) {
            this.resize_duration = 0;
            this.options.animate = false;
        }
        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.images  = {};

        this._buildLayout();
        this.updateImageList();
    },
    _buildLayout : function()
    {
        this.the_image          = Builder.node('img', { alt : '',  src : '' }); 
        this.prevLink           = Builder.node('a', { href : 'javascript:void(0)', 'class' : 'prevLink' });
        this.nextLink           = Builder.node('a', { href : 'javascript:void(0)', 'class' : 'nextLink' });
        this.loadingLink        = Builder.node('img', { alt : 'Loading...',  src : this.options.loading_img });
        this.loading            = Builder.node('div', { 'class' : 'loading' }, [this.loadingLink]);
        this.bottomNavClose     = Builder.node('img', { 'class' : 'bottomNavClose', alt : 'Close', title : 'Close', src : this.options.close_img });
        this.caption            = Builder.node('div', { 'class' : 'caption' });
        
        this.numberDisplay      = Builder.node('span', { 'class' : 'numberDisplay' });
        var imageDetails        = Builder.node('div', { 'class' : 'imageDetails' }, [this.caption, this.numberDisplay, this.fullsizedLink]);
        this.imageDataContainer = Builder.node('div', { 'class' : 'imageDataContainer' }, [imageDetails, this.bottomNavClose]);
        var protector           = Builder.node('div', { 'class' : ((true == this.options.protect) ? 'protector' : '') });
        this.imageContainer     = Builder.node('div', { 'class' : 'imageContainer' }, [this.the_image, protector, this.prevLink, this.nextLink, this.loading]);
        this.myself             = $(Builder.node('div', { id : this.options.my_id }, [this.imageContainer, this.imageDataContainer]));

        if (window.external && ('undefined' == typeof window.XMLHttpRequest) && document.all && -1 == navigator.userAgent.toLowerCase().indexOf('opera')) {
            var iframe = document.createElement('iframe');
            iframe.className = 'ie_iframe';
            iframe.frameBorder = 0;
            this.myself.appendChild(iframe);
        }

        this.myself.setStyle({ display : 'none' });
        if (false == this.options.drag) {
            this.myself.observe('click', this._closeSelf.bindAsEventListener(this));
        }

        this.body.appendChild(this.myself);

        if (this.options.animate) {
            this.imageContainer.setStyle( { width : '250px', height : '250px' } );
            this.imageDataContainer.setStyle( { width : '250px' } );
        }
        else {
            this.imageContainer.setStyle( { width : '40px', height : '40px' } );
            this.imageDataContainer.setStyle( { width : '40px' } );
        }

        if (this.options.drag && 'undefined' != typeof Draggable) {
            new Draggable(this.myself, { handle : this.imageContainer });
            this.imageContainer.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));
    },
    _closeSelf : function(e)
    {
        e.stop();
        this._end();
    },
    _startShow : function(e)
    {
        e.stop();
        if (true == this.options.force_update) {
            this.updateImageList();
        }

        this._start(e.findElement('a'));
    },
    updateImageList : function()
    {
        this.images  = [];
        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 (-1 != rel.indexOf('[')) {
                    if ('undefined' == typeof this.images[rel]) {
                        this.images[rel] = [];
                    }

                    this.images[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();

        var dims    = document.viewport.getDimensions();
        var scrolls = document.viewport.getScrollOffsets();

        if ('undefined' == typeof document.body.style.maxHeight) {
            this.body.parentNode.setStyle({ width : '100%', height : '100%', overflow : 'hidden' });
            this.body.setStyle({ width : '100%', height : '100%' });
        }

        if (true == this.options.animate) {
            new Effect.Appear(
                this.overlay,
                {
                    duration : this.options.ovl_speed,
                    from     : 0,
                    to       : this.options.ovl_opacity
                }
            );
        }
        else {
            this.overlay.show();
        }

        var rel   = element.getAttribute('rel');
        this.href = element.getAttribute('href');
        var title = element.getAttribute('title');
        var idx   = -1;

        if (-1 != rel.indexOf('[')) {
            if ('undefined' == typeof this.images[rel]) {
                this.images[rel] = [{ 'href' : href, 'title' : title }];
            }
            else {
                var a = this.images[rel];
                var l = a.length;
                for (var i=0; i<l; ++i) {
                    if (a[i].href == this.href) {
                        idx = i;
                        break;
                    }
                }

                if (-1 == idx) {
                    idx = l;
                    a.push(this.href);
                }
            }
        }
        else {
            rel = title;
        }

        
	var top  = scrolls.top + screenHeight() / 15;

	function screenHeight()
	{
	      var h; // высота
	      h = (window.innerHeight ? window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.offsetHeight));
	      return h;
	}

        var left = scrolls.left;

        this.myself.setStyle({ 'left' : left + 'px', 'top' : top + 'px' });
        this.myself.show();

        this._changeImage(rel, idx);
    },
    _end : function()
    {
        if ('undefined' == typeof document.body.style.maxHeight) {
            this.body.parentNode.setStyle({ width : '', height : '', overflow : '' });
            this.body.setStyle({ width : '', height : '' });
        }

        this._disableKeyboardNav();
        this.myself.hide();
        if (true == this.options.animate) {
            new Effect.Fade(this.overlay, { duration: this.options.ovl_speed });
        }
        else {
            this.overlay.hide();
        }

        this._showFlash();
    },
    _changeImage : function(rel, idx)
    {
        this.act_rel = rel;
        this.active  = idx;
        this.loading.show();

        [this.the_image, this.prevLink, this.nextLink, this.imageDataContainer, this.numberDisplay].invoke('hide');

        imgPreloader = new Image();

        imgPreloader.onload = function()
        {
            imgPreloader.onload = null;
            $(this.the_image).setAttribute('src', imgPreloader.src);
            var dims = document.viewport.getDimensions();

            var w = imgPreloader.width;
            var h = imgPreloader.height;
            var x = dims.width;
            var y = dims.height;

            if (w > x) {
                h *= (x / w);
                w  = x;
            }

            if (h > y) {
                w *= (y / h);
                h  = y;
            }

            if (0 != this.options.max_width) {
                h *= this.options.max_width/w;
                w  = this.options.max_width;
            }

            if (0 != this.options.max_height) {
                w *= this.options.max_height/h;
                h  = this.options.max_height;
            }

            $(this.the_image).setStyle({ width : w + 'px', height : h + 'px' });
            this._resizeImageContainer(w, h);
        }.bindAsEventListener(this);

        var src = (this.active < 0) ? this.href : this.images[rel][idx].href;
        imgPreloader.setAttribute('src', src);
        this.fullsizedLink.setAttribute('href', src);
    },
    _resizeImageContainer : function(w, h)
    {
        var width_current  = this.imageContainer.getWidth();
        var height_current = this.imageContainer.getHeight();

        var x_scale = w / width_current * 100;
        var y_scale = h / height_current * 100;

        var w_diff = width_current - w;
        var h_diff = height_current - h;

        if (0 != h_diff) {
            if (true == this.options.animate) {
                new Effect.Scale(
                    this.imageContainer,
                    y_scale,
                    {
                        scaleX      : false,
                        duration    : this.resize_duration,
                        queue       : 'front',
                        afterFinish : function() { this.imageContainer.setStyle({ height : h + 'px' }); }.bind(this)
                    }
                );
            }
            else {
                this.imageContainer.setStyle({ height : h + 'px' });
            }
        }

        if (0 != w_diff) {
            if (true == this.options.animate) {
                new Effect.Scale(
                    this.imageContainer,
                    x_scale,
                    {
                        scaleY      : false,
                        duration    : this.resize_duration,
                        delay       : this.resize_duration,
                        afterFinish : function() { this.imageContainer.setStyle({ width : w + 'px' }); }.bind(this)
                    }
                );
            }
            else {
                this.imageContainer.setStyle({ width : w + 'px' });
            }

            this.imageDataContainer.setStyle( { width : w + 'px' } );
        }

        if (0 == h_diff && 0 == w_diff) {
            this._pause(
                (-1 != navigator.appVersion.indexOf("MSIE")) ? 250 : 100
            );
        }

        this.prevLink.style.height = h + 'px';
        this.nextLink.style.height = h + 'px';
        this.imageDataContainer.style.width = w + 'px';
        this._showImage();
    },
    _showImage: function()
    {
        if (this.active >= 0) {
            if (this.images[this.act_rel].length - 1 > this.active) {
                var p_next = new Image();
                p_next.src = this.images[this.act_rel][this.active + 1].href;
            }

            if (this.active > 0) {
                var p_prev = new Image();
                p_prev.src = this.images[this.act_rel][this.active - 1].href;
            }
        }

        this.loading.hide();
        if (true == this.options.animate) {
            new Effect.Appear(
                this.the_image,
                {
                    duration    : this.resize_duration,
                    queue       : 'end',
                    afterFinish : this._updateDetails.bind(this)
                }
            );
        }
        else {
            this.the_image.show();
        }
    },
    _updateDetails : function()
    {
        if (this.active >= 0) {
            var e = this.images[this.act_rel][this.active];
            if ('' != e.title){
                this.caption.update(e.title);
                this.caption.show();
            }

            if (this.images[this.act_rel].length && this.images[this.act_rel].length > 1) {
                this.numberDisplay.update("Image " + (this.active + 1) + " of " + this.images[this.act_rel].length);
                this.numberDisplay.show();
            }
        }
        else {
            if ('' != this.act_rel){
                this.caption.update(this.act_rel);
                this.caption.show();
            }
        }

        if (true == this.options.animate) {
            new Effect.Parallel(
                [
                    new Effect.SlideDown(this.imageDataContainer, { sync: true, duration: this.resize_duration, from: 0.0, to: 1.0 }),
                    new Effect.Appear(this.imageDataContainer, { sync: true, duration: this.resize_duration })
                ],
                {
                    duration    : this.resize_duration,
                    afterFinish : this._updateNav.bind(this)
                }
            );
        }
        else {
            this.imageDataContainer.show();
            this._updateNav();
        }
    },
    _prev : function(e)
    {
        e.stop();
        this.__prev();
    },
    __prev : function()
    {
        if (this.active > 0) {
            this._changeImage(this.act_rel, this.active - 1);
        }
        else if (true == this.options.cycle && 0 == this.active) {
            this._changeImage(this.act_rel, this.images[this.act_rel].length - 1);
        }
    },
    _next : function(e)
    {
        e.stop();
        this.__next();
    },
    __next : function()
    {
        if (this.active >= 0) {
            if (this.active != this.images[this.act_rel].length - 1) {
                this._changeImage(this.act_rel, this.active + 1);
            }
            else if (true == this.options.cycle) {
                this._changeImage(this.act_rel, 0);
            }
        }
    },
    _updateNav: function()
    {
        if (this.active >= 0) {
            if (this.active > 0 || true == this.options.cycle) {
                this.prevLink.show();
            }

            if (this.active != this.images[this.act_rel].length - 1 || true == this.options.cycle) {
                this.nextLink.show();
            }
        }

        this._enableKeyboardNav();
    },
    _enableKeyboardNav : function()
    {
        if (false == this.listening_kd) {
            this.listening_kd = true;
            Event.observe(document, 'keydown', this._keydown);
        }
    },
    _disableKeyboardNav : function()
    {
        if (true == this.listening_kd) {
            this.listening_kd = false;
            Event.stopObserving(document, 'keydown', this._keydown);
        }
    },
    _onKeyDown : function(e)
    {
        var keycode = e.keyCode;
        var key     = String.fromCharCode(keycode).toLowerCase();

        if ('x' == key || 'c' == key || 'o' == key || Event.KEY_ESC == keycode) {
            this._end();
        }
        else if ('p' == key || Event.KEY_LEFT == keycode) {
            this._disableKeyboardNav();
            this.__prev();
        }
        else if ('n' == key || Event.KEY_RIGHT == keycode) {
            this._disableKeyboardNav();
            this.__next();
        }
    },
    _hideFlash : function()
    {
        if (true == this.options.hide_flash) {
            this.all_flash = $$("object", "embed").select(
                function(node)
                {
                    if ('visible' == node.getStyle('visibility')) {
                        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;
        do {
            curDate = new Date();
        } while (curDate - date < ms);
    }
};

var myLightbox;

function initLightbox(options)
{
    myLightbox = new ProtoBox(options);
}

