/**
 * modal.js
 * @author Brian Crescimanno <brian.crescimanno@autotrader.com>
 *
 * Creates a modal dialog box on the page.
 *
 */

if(typeof Prototype == undefined) throw("Modal requires the Prototype library");
if(typeof Effect == undefined) throw("Modal requires the Scriptaculous library");

var Modal = Class.create({
    initialize: function(options){
        this.options = this._extendOptions(options);
        this.docHeight = this._getDocHeight();
        this.newDiv = this._cacheDiv();
        this.overlay = this._cacheOverlay();
        this.iframes = this._cacheIFrames();
        this.modal = null;
        this.isShown = false;

        document.observe("modal:triggerhide", this._handleHideTrigger.bindAsEventListener(this));
    },

    hide: function(){
        this.isShown = false;
        this._hideOverlay();
    },

    resize: function(width, height){
        new Effect.Morph(this.modal, {
            style:'height: '+height+'px;',
            duration: 0.5,
            transition: Effect.Transitions.sinoidal
        });
        new Effect.Morph(this.modal, {
            style:'width: '+width+'px; left: ' + this._getNewLeftOffset(width)+ 'px',
            duration: 0.5,
            delay: 0.4,
            transition: Effect.Transitions.sinoidal
        });
    },

    scale: function(width, height){
        this.options.startWidth = width;
        this.options.startHeight = height;
    },

    show: function(el, parent, callback){
        if(!this.isShown){
            this._showOverlay(el, parent, callback);
            this.isShown = true;
        }
    },

    triggerHide: function(delay){
        if(!(delay>0)) delay = 0;
        delay = delay * 1000;
        setTimeout(function(){ this.hide(); }.bind(this), delay);
    },

    _cacheDiv: function() {
        return new Element('div');
    },

    _createModal: function(el, parent){
        var checkHeightForAuto = this.options.startHeight === "auto" ? this.options.startHeight : this.options.startHeight +"px";
        return new Element('div', {'class': "modal"}).setStyle({
                        height: checkHeightForAuto,
                        width: this.options.startWidth+"px",
                        top: this._getTopOffset(parent)+"px",
                        left: this._getLeftOffset(parent)+"px"
                    }).setOpacity(0).update(el);
    },

    _cacheIFrames: function(){
        var selects = document.getElementsByTagName("select");
        var iframes = [];
        for(var i=0; i< selects.length; i++){
            var s = $(selects[i]);
            var dims = s.getDimensions();
            var os = s.cumulativeOffset();
            iframes.push(new Element("iframe").setStyle({position: "absolute",
                                                         height: dims.height+"px",
                                                         width: dims.width+"px",
                                                         top: os.top+"px",
                                                         left: os.left+"px",
                                                         zIndex: 9998
            }));
        }
        return iframes;
    },

    _cacheOverlay: function(){
        return new Element('div', {'class': this.options.overlayClass}).setOpacity(0).setStyle({
            height: this.docHeight});
    },

    _extendOptions: function(options){
        return Object.extend({
            dynamic: false,
            startHeight: 500,
            startWidth: 500,
            fps: 75,
            overlaySpeed: 0.5,
            overlayClass: 'modal-overlay',
            overlayOpacity: 0.4,
            modalSpeed: 0.5
        }, options || {});
    },

    _getDocHeight: function(){
        var vH = document.viewport.getHeight();
        var dH = document.height;
        if (Prototype.Browser.IE){ return $(document.body).getHeight(); }
        else if(dH > vH && typeof dH != "undefined"){return dH+"px";}
        else {return "100%";}
    },

    _getTopOffset: function(parent){
        var pOffset = 0;
        var scroll = document.viewport.getScrollOffsets().top;
        var checkHeightForAuto = this.options.startHeight === "auto" ? 250 : this.options.startHeight; // chosing an arbitrary number here b/c getHeight nor getDimensions works on the created modal node. - CK
        var vOffset = Math.floor((document.viewport.getHeight() - checkHeightForAuto) / 2);
        return (scroll + vOffset - pOffset > 0) ?  (scroll + vOffset - pOffset) : 60;
    },

    _getLeftOffset: function(parent){
        var pOffset = 0;
        if(parent) pOffset = parent.cumulativeOffset().left;
        return Math.floor((document.viewport.getWidth() - this.options.startWidth - pOffset) / 2);
    },

    _getNewLeftOffset: function(width){
        return Math.floor((document.viewport.getWidth() - width) / 2);
    },

    _handleHideTrigger: function(e){
        if(this.isShown){
            this.triggerHide(0);
        }
    },

    _hideOverlay: function(){
        new Effect.Opacity(this.modal,{
            from: 1.0,
            to: 0.0,
            fps: this.options.fps,
            duration: this.options.modalSpeed
        });

        new Effect.Opacity(this.overlay, {
            from: this.options.overlayOpacity,
            to: 0.0,
            fps: this.options.fps,
            duration: this.options.overlaySpeed,
            delay: (this.options.modalSpeed /2),
            afterFinish: function(){
                this._modalCleanup();
            }.bind(this)
        });
    },

    _modalCleanup: function(){
        this.overlay.remove();
        this.newDiv.remove();
        this.modal.remove();
        this.iframes.each(function(iframe){
            iframe.remove(); 
        });
        this.modal = null;
    },

    _showOverlay: function(el, parent, callback){
        if(!callback) { callback = function(){} };
        if (Prototype.Browser.IE && this.docHeight != $(document.body).getHeight()){
            this.docHeight = this._getDocHeight();
            this.overlay = this._cacheOverlay();
        }
        if ((parent == null) || parent == ""){
            parent = Element.extend(document.body);
        } else  {
            parent = $(parent);
        }
        parent.appendChild(this.newDiv);
        document.body.insert(this.overlay);
        this.iframes.each(function(iframe){
            document.body.insert(iframe);
        });
        this.modal = this._createModal(el, parent);
        new Effect.Opacity(this.overlay, {
            from: 0.0,
            to: this.options.overlayOpacity,
            fps: this.options.fps,
            duration: this.options.overlaySpeed,
            afterFinish: function(){
                parent.appendChild(this.modal);
                new Effect.Opacity(this.modal,{
                    from: 0.0,
                    to: 1.0,
                    fps: this.options.fps,
                    duration: 0.5,
                    afterFinish: callback
                });
            }.bind(this)
        });
    }
});