Lightbox = Class.create({
    initialize: function( options ) {
        this.options = Object.extend( {zIndex:50,opacity:0.5}, arguments[0] || {});
    },

    _make_shade: function() {
        this.shade = new Element( 'div', {
            'id': 'lightbox_shade',
            'style': 'display:none;background-color:black;position:absolute;top:0px;left:0px;'
        } );

        this.shade.style.zIndex = this.options.zIndex;

        document.body.appendChild( this.shade );

        if( Prototype.Browser.IE )
            this.blocking_iframe = new BlockingIframe( this.shade );
    },

    _make_visible: function() {
        if ( !this.shade )
            this._make_shade();

        this.shade.style.width = Element.getWidth( document.body ) + "px";
        this.shade.style.height = Element.getHeight( document.body ) + "px";
        this.shade.setOpacity( this.options.opacity );
        this.shade.style.display = '';

        if( this.blocking_iframe )
            this.blocking_iframe.update();
    },

    _make_invisible: function() {
        if( this.shade ) {
            this.shade.style.display = 'none';

            if( this.blocking_iframe )
                this.blocking_iframe.update();
        }
    },

    show: function () {
        var options = Object.extend({
            before_show: function(){},
            after_show: function(){}
        }, arguments[0] || {});

        options.before_show();

        this._make_visible();

        options.after_show();
    },

    hide: function() {
        var options = Object.extend({
            before_hide: function(){},
            after_hide: function(){}
        }, arguments[0] || {});

        options.before_hide();

        this._make_invisible();

        options.after_hide();
    }
});

BlockingIframe = Class.create( {
    initialize: function( layer ) {
        this.layer = layer;
    },

    _make_iframe: function() {
        this.iframe = document.createElement( "iframe" );

        this.iframe.style.zIndex = this.layer.style.zIndex - 1;
        this.iframe.style.display = "none";
        this.iframe.style.position = "absolute";
        this.iframe.frameborder = "0";
        this.iframe.style.backgroundColor = "transparent";
        this.iframe.src="javascript:''";

        this.iframe.style.filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';

        document.body.appendChild( this.iframe );
    },

    update: function() {
        if ( !this.iframe )
            this._make_iframe();

        with( this.iframe ) {
            style.left = this.layer.style.left;
            style.top = this.layer.style.top;
            style.width = this.layer.offsetWidth + "px";
            style.height = this.layer.offsetHeight + "px";
            style.display = this.layer.style.display;
        }
    }
} );

Popup = Class.create( {
    initialize: function( layer_id ) {
        this.defaults = {
/*
            links: '',
            link_id: '',
            anchor_id: '',
            close_id: '',
            drag_id: '',
*/
            anchor_align: {
                x: -1,
                y: 1
            },

            popup_align: {
                x: -1,
                y: -1
            },

            link_event: 'click',
            adjust_on_resize: true,
            close_on_clickoff: false
/*
            lightbox: true,
            onShow: null,
            onHide: null,
            autohide_timeout: 3000
*/
        };

        this.options = Object.extend(this.defaults, arguments[1] || {});

        this.layer = $(layer_id);
        this.layer.style.zIndex = '100';
        this.layer.style.position = 'absolute';
        this.layer.style.display = 'none';

        if ( this.options.lightbox ) {
            this.lightbox = new Lightbox( { zIndex: this.layer.style.zIndex - 1, opacity: this.options.lightbox.opacity } );
        }
        else if( Prototype.Browser.IE )
            this.blocking_iframe = new BlockingIframe( this.layer );

        if ( this.options.drag_id )
            this.setDrag( this.options.drag_id );

        if ( this.options.close_id )
            this.setClose( this.options.close_id );

        this.links = {};
        if( this.options.links )
            this.addLinks( this.options.links );

        Event.observe( window, 'resize', this._onResize.bind( this ), false );
    },

    _update_blocking_iframe: function( draggable ) {
        if( this.blocking_iframe )
            this.blocking_iframe.update();
    },

    _resetAutoHideTimer: function() {
        if( this.hide_timeout ) {
            clearTimeout( this.hide_timeout );

            delete this.hide_timeout;
        }
    },

    _startAutohideTimer: function() {
        var link = this._buildOptions( arguments[0] );

        this.hide_timeout = setTimeout( this._onAutoHide.bind( this ), link.autohide_timeout );
    },

    _onAutoHide: function() {
        this.hide();

        delete this.hide_timeout;
    },

    addLinks: function( links ) {
        for( var i = 0 ; i < links.length ; i ++ ) {
            var link = links[i];
            var defaults = Object.extend( {}, this.defaults );
            link = Object.extend( defaults, link );
            var link_id = link.link_id;
            var onLinkClick = this.show.bind(this, link);
            Event.observe( $(link_id), link.link_event, onLinkClick );
            link.onLinkClick = onLinkClick;

            if( link.autohide_timeout ) {
                link.onMouseOverLink = this._resetAutoHideTimer.bind(this);
                Event.observe( $(link_id), 'mouseover', link.onMouseOverLink );

                link.onMouseOverPopup = this._resetAutoHideTimer.bind(this);
                Event.observe( this.layer, 'mouseover', link.onMouseOverPopup );

                link.onMouseOutLink = this._startAutohideTimer.bind(this, link);
                Event.observe( $(link_id), 'mouseout', link.onMouseOutLink );

                link.onMouseOutPopup = this._startAutohideTimer.bind(this, link);
                Event.observe( this.layer, 'mouseout', link.onMouseOutPopup );
            }

            this.links[link_id] = link;
        }
    },

    removeLink: function( link_id ) {
        var link = this.links[link_id];
        Event.stopObserving( $(link.link_id), link.link_event, link.onLinkClick );

        if( link.autohide_timeout ) {
            Event.stopObserving( $(link_id), 'mouseover', link.onMouseOverLink );

            Event.stopObserving( this.layer, 'mouseover', link.onMouseOverPopup );

            Event.stopObserving( $(link_id), 'mouseout', link.onMouseOutLink );

            Event.stopObserving( this.layer, 'mouseout', link.onMouseOutPopup );
        }

        delete this.links[link_id];
    },

    removeLinks: function() {
        var link_ids;

        if( arguments[0] )
            link_ids = arguments[0];
        else
            link_ids = $H(this.links ).keys();

        for( var i = 0 ; i < link_ids.length ; i ++ )
            this.removeLink( link_ids[i] );
    },

    setDrag: function ( drag_id ) {
        if ( typeof(drag_id) == 'string' )
            drag_id = [ drag_id ];

        for ( var i = 0 ; i < drag_id.length ; i ++ )
            this.dragger = new Draggable( this.layer, {
                handle: $(drag_id[i]),
                change: this.on_drag.bind( this ),
                endeffect: false
            } );
    },

    on_drag: function() {
        this._update_blocking_iframe();
    },

    setClose: function ( close_id ) {
        if ( typeof(close_id) == 'string' )
            close_id = [ close_id ];

        for ( var i = 0 ; i < close_id.length ; i ++ ) {
            $(close_id[i]).observe( 'click', this.hide.bind(this) );
        }
    },

    moveTo: function( x, y ) {
        this.layer.style.left = x + "px";
        this.layer.style.top = y + "px";

        this._update_blocking_iframe();
    },

    _onResize: function() {
        if( this.options.adjust_on_resize && this.layer.style.display != "none" ) {
            if( this.current_anchor ) {
                var offset = this.current_anchor.cumulativeOffset();

                var x = offset[0] - this.popup_anchor_offset.x;
                var y = offset[1] - this.popup_anchor_offset.y;

                x = x < 0 ? 0 : x;
                y = y < 0 ? 0 : y;

                this.moveTo( x, y );
            }
        }
    },

    _buildOptions: function() {
        var options = {};
        Object.extend( options, this.options );
        Object.extend(
            options,
            arguments[0] || ( $H(this.links).keys().length ? this.links[$H(this.links).keys()[0]] : {} )
        );

        return options;
    },

    _checkClickOff: function( e ) {
        var clicked = Event.element(e);

        if (
            (clicked == this.layer || !Element.descendantOf(clicked, this.layer)) &&
            $H(this.links).keys().find(function (link) {
                return clicked.id == link || Element.descendantOf(clicked, link);
            }) == null
        )
            this.hide();
    },

    show: function() {
        var anchor_options = this._buildOptions( arguments[0] );

        if( anchor_options.onShow )
            anchor_options.onShow( this );

        if ( anchor_options.toggle && !this.layer.style.display ) {
            this.hide();
            return;
        }

        if( this.layer.style.display == "none" ) {
            this.moveTo( -1200, -1200 );

            this.layer.style.display = "";
        }

        var anchor_id = anchor_options.anchor_id || anchor_options.link_id;
        var anchor = $( anchor_id );
        if( anchor ) {
            var offset = anchor.cumulativeOffset();

            this.current_anchor = anchor;
            this.anchor_offset = offset;
            this.popup_anchor_offset = { x: offset[0], y: offset[1] };

            var popup_align = anchor_options.popup_align;

            if ( popup_align ) {
                var anchor_align = anchor_options.anchor_align;

                if ( popup_align.x == 'center' ) {
                    offset[0] = Math.round(document.viewport.getScrollOffsets().left +
                        ((document.viewport.getWidth() - this.layer.getWidth()))/2);
                }
                else if ( anchor_align ) {
                    if( anchor_align.x > -1 ) {
                        offset[0] += anchor.offsetWidth / ( anchor_align.x ? 1 : 2 );
                    }

                    if( popup_align.x > -1 ) {
                        offset[0] -= this.layer.offsetWidth / ( popup_align.x ? 1 : 2 );
                    }
                }

                if ( popup_align.y == 'center' ) {
                    offset[1] = Math.round(document.viewport.getScrollOffsets().top +
                        ((document.viewport.getHeight() - this.layer.getHeight()))/2);
                }
                else if ( anchor_align ) {
                    if( anchor_align.y > -1 ) {
                        offset[1] += anchor.offsetHeight / ( anchor_align.y ? 1 : 2 );
                    }

                    if( popup_align.y > -1 ) {
                        offset[1] -= this.layer.offsetHeight / ( popup_align.y ? 1 : 2 );
                    }
                }
            }

            if ( anchor_options.offset ) {
                offset[0] += anchor_options.offset.x;
                offset[1] += anchor_options.offset.y;
            }

            if ( offset[0] < 0 ) {
                offset[0] = 0;
            }
            if ( offset[1] < 0 ) {
                offset[1] = 0;
            }

            if ( this.lightbox ) {
                this.lightbox.show({ after_show: this.moveTo.bind( this, offset[0], offset[1] ) });
            }
            else {
                this.moveTo( offset[0], offset[1] );
            }

            this.popup_anchor_offset.x -= offset[0];
            this.popup_anchor_offset.y -= offset[1];

            if ( anchor_options.close_on_clickoff ) {
                this.click_off_initial = true;
                this.click_off_callback = this._checkClickOff.bindAsEventListener( this );
                Event.observe(document.body, 'click', this.click_off_callback);
            }
        }
    },

    hide: function() {
        this.layer.style.display = "none";
        this._update_blocking_iframe();

        var options = this._buildOptions( arguments[0] );

        if( options.onHide )
            options.onHide( this );

        if ( this.lightbox ) {
            this.lightbox.hide();
        }

        if ( this.click_off_callback != null )
            Event.stopObserving(document.body, 'click', this.click_off_callback);
    }
} );


