/**
 * Dialog Class
 *
 * REQUIRED: prototype.js
 * REQUIRED: ave.js
 *
 */

// preloading loading image
(function() {
	var loading = new Image();
	loading.src = "/includes/img/loading.gif";
})();

AVE.Dialog = Class.create({
    defaults: {
        handleFormSubmits: true,
        handleAnchors: true,
        className: 'ave-dialog',
        id: 'ave-dialog',
        overlayClassName: 'ave-overlay',
        overlayId: 'ave-overlay'
    },

    initialize: function(options) {
        this.options = Object.extend(Object.clone(this.defaults), options || {});
        this.createDialog();
        this.createOverlay();

        // Cache the event listeners to unload them laters
        this._onresize = this.positionOverlay.bind(this);
        this._onscroll = this.setOffset.bind(this);
        this._onkeypress = this._keyPressed.bind(this);
        this._close = this.hideDialog.bind(this);

        if (this.options.handleFormSubmits)
            this.delegateFormSubmits();

        if (this.options.handleAnchors)
            this.delegateAnchors();

    },

    delegateFormSubmits: function() {
        var selector = new Template('##{id} button[type=submit], ##{id} input[type=submit]').evaluate(this.options);
        Event.register(document, selector, "click", function(e) {
            this.submitDialog(e.element().up('form'));
            e.stop();
        } .bind(this));

        selector = new Template('##{id} form').evaluate(this.options);
        Event.register(document, selector, "keypress", function(e) {
            if (e.keyCode == Event.KEY_RETURN && e.element().tagName.toUpperCase() != "TEXTAREA" && e.element().tagName.toUpperCase() != "SPAN") {
                this.submitDialog(e.element().up('form'));
                e.stop();
            }
        } .bind(this));
    },

    delegateAnchors: function() {
        // elements must use avebehavior="dialog-link" or the event will not be captured
        var selector = new Template('##{id} *[avebehavior="dialog-link"]').evaluate(this.options);
        Event.register(document, selector, "click", function(e) {
            // _target from delegation
            this.navigateFromDialog(e._target);
            e.stop();
        } .bind(this));
    },

    submitDialog: function(form, options) {
        this.saveTiny();
        var memo = {
            dialog: this,
            method: form.method || 'post',
            action: form.action,
            parameters: form.serialize(true)
        };

        Object.extend(memo, options || {});

        this.dialog.fire('dialog:submit', memo);
    },

    navigateFromDialog: function(el, options) {
        var memo = {
            parameters: {},
            dialog: this,
            action: el.readAttribute('href')
        };

        Object.extend(memo, options || {});
        this.dialog.fire('dialog:navigate', memo);
    },

    _notAuthorized: function() {
        window.location = '/Accounts/Login.mvc?ReturnUrl=' + window.location.pathname;
    },

    _dialogFailure: function() {
        //window.location = '/Errors.mvc/500';
        //  alert("Sorry! The server seems to have encountered an error. Please try again later.");
        //  this.hideDialog();
    },

    createOverlay: function() {
        this.overlay = new Element('div').addClassName(this.options.overlayClassName).writeAttribute('id', this.options.overlayId);
        this.dialog.insert({ before: this.overlay });
        this.hideOverlay();
        this.positionOverlay();

    },

    positionOverlay: function() {
        var dims = AVE.WindowProperties.getContentSize();

        // Find out if the dialog is larger than the content of the window
        var dialogDims = this.dialog.getDimensions();
        if (dims.width < dialogDims.width) dims.width = dialogDims.width;
        if (dims.height < dialogDims.height) dims.height = dialogDims.height + this.topOffset + (this.dialog.getStyle('margin-bottom').replace(/[^0-9]/gi, "") * 1);

        this.overlay.setStyle({
            width: dims.width + 'px',
            height: dims.height + 'px'
        });
        this.setInitialOffset();
    },

    hideOverlay: function() {
        this.overlay.hide();
    },

    showOverlay: function() {
        this.positionOverlay();
        this.overlay.show(); //new Effect.Appear(this.overlay, {duration: .3});
    },

    createDialog: function() {
        // I dunno if it would be faster to actually just use innerHTML
        this.dialog = new Element('div').addClassName(this.options.className).writeAttribute('id', this.options.id);

        /* Header */
        var header = new Element('div').addClassName('ave-dialog-line');
        //		var wrapHeader			= new Element('div', {className: 'ave-dialog-header'});
        var leftHeader = new Element('div').addClassName('ave-dialog-header-left');
        var rightHeader = new Element('div').addClassName('ave-dialog-header-right');
        var centerHeader = new Element('div').addClassName('ave-dialog-item ave-dialog-center-item');
        var centerHeaderPadding = new Element('div').addClassName('ave-dialog-header-padding');
        var centerHeaderContent = new Element('div').addClassName('ave-dialog-header-content');

        centerHeaderPadding.insert(centerHeaderContent);
        centerHeader.insert(centerHeaderPadding);
        header.insert(leftHeader).insert(centerHeader).insert(rightHeader);
        //		header.insert(wrapHeader);

        /* Content */
        // z-index style required to make sure autocompleter in dialog breaks over the dialog footer in IE
        var content = new Element('div').addClassName('ave-dialog-line').setStyle({ zIndex: '1' });
        var leftContent = new Element('div').addClassName('ave-dialog-item ave-dialog-content-piller ave-dialog-content-left');
        var rightContent = new Element('div').addClassName('ave-dialog-item ave-dialog-content-piller ave-dialog-content-right');
        var centerContent = new Element('div').addClassName('ave-dialog-item ave-dialog-center-item');
        var centerContentPadding = new Element('div').addClassName('ave-dialog-content-padding');
        this.dialogContent = new Element('div').addClassName('ave-dialog-main-content');
        this.dialogLoading = new Element('div').addClassName('ave-dialog-loading');
        centerContentPadding.insert(this.dialogContent).insert(this.dialogLoading);
        centerContent.insert(centerContentPadding);
        content.insert(leftContent).insert(centerContent).insert(rightContent);

        /* Footer */
        var footer = new Element('div').addClassName('ave-dialog-line');
        this.close = new Element('div').addClassName('ave-dialog-close');
        //this.close   			= new Element('img').addClassName('ave-dialog-close').writeAttribute({'src': '/includes/img/dialog_close.png', 'width': '13', 'height': '13', 'alt': 'Close This Window'});
        var leftFooter = new Element('div').addClassName('ave-dialog-footer-left');
        var rightFooter = new Element('div').addClassName('ave-dialog-footer-right');
        var centerFooter = new Element('div').addClassName('ave-dialog-item ave-dialog-center-item');
        var centerFooterPadding = new Element('div').addClassName('ave-dialog-footer-padding');
        var centerFooterContent = new Element('div').addClassName('ave-dialog-footer-content');

        centerFooterPadding.insert(centerFooterContent);
        centerFooter.insert(centerFooterPadding);
        footer.insert(this.close).insert(leftFooter).insert(centerFooter).insert(rightFooter);

        /* insert rows into the dialog */
        this.dialog.insert(header).insert(content).insert(footer);

        /* insert the dialog into the DOM */
        $(document.body).insert({ bottom: this.dialog });
        this.topOffset = 100;
        new Draggable(this.dialog, { handle: header, scroll: window, zindex: 10001 });
        Draggables.addObserver(this);
        header.setStyle({ cursor: 'move' });

    },

    setInitialOffset: function() {
        var topOffset = document.viewport.getScrollOffsets().top + this.topOffset + "px";

        var leftOffset = document.viewport.getScrollOffsets().left + ((document.viewport.getDimensions().width / 2) - (this.dialog.getWidth() / 2)) + "px";

        this.dialog.setStyle({
            top: topOffset,
            left: leftOffset
        });
    },

    onEnd: function() {
        this.setOffset();
    },

    setOffset: function() {
        var offset = this.dialog.positionedOffset();

        this.leftOffset = offset[0] - document.viewport.getScrollOffsets().left;
        this.topOffset = offset[1] - document.viewport.getScrollOffsets().top;

        var reposition = false;
        var browserSize = document.viewport.getDimensions();

        if ((this.topOffset + this.dialog.getDimensions().height) > browserSize.height) {
            this.topOffset -= (this.topOffset + this.dialog.getDimensions().height) - (browserSize.height);
            reposition = true;
        }

        if ((this.leftOffset + this.dialog.getDimensions().width) > browserSize.width) {
            this.leftOffset -= (this.leftOffset + this.dialog.getDimensions().width) - (browserSize.width);
            reposition = true;
        }

        if (this.leftOffset < 0) {
            this.leftOffset = 0;
            reposition = true;
        }

        if (reposition) new Effect.Move(this.dialog, { x: this.leftOffset, y: this.topOffset, mode: 'absolute', duration: .4 });
    },

    hideDialog: function() {
        if (Prototype.Browser.IE) this.showSelects();
        new Effect.Fade(this.dialog, { duration: .3 });
        new Effect.Fade(this.overlay, { duration: .3 });
        Event.stopObserving(window, 'resize', this._onresize);
        Event.stopObserving(window, 'keydown', this._onkeypress);
        Event.stopObserving(this.close, 'click', this._close);
        Event.stopObserving(this.overlay, 'click', this._close);
        this.saveTiny();
    },

    showDialog: function() {
        Event.observe(window, 'resize', this._onresize);
        Event.observe(document, 'keydown', this._onkeypress);
        Event.observe(this.close, 'click', this._close);
        Event.observe(this.overlay, 'click', this._close);
        if (Prototype.Browser.IE) this.hideSelects();
        this.showOverlay();
        this.dialog.show();
    },

    hideSelects: function() {
        $$('select').invoke('hide');
    },

    showSelects: function() {
        $$('select').invoke('show');
    },

    showLoading: function() {
        this.dialogLoading.clonePosition(this.dialogContent);
    },

    hideLoading: function() {
        this.dialogLoading.style.left = "-9999px";
    },

    getContent: function(url, options) {
        var opt = Object.extend({
            parameters: {},
            onSuccess: this.renderContent,
            onFailure: this._dialogFailure,
            on605: this.renderContent,
            on601: this._notAuthorized
        }, options || {});



        // Bind Dialog in all of the functions as this
        for (handler in opt) {
            if (typeof opt[handler] == 'function') opt[handler] = opt[handler].bind(this);
        }

        opt.parameters._aveajax = true;
        this.showDialog();

        this.dialog.fire('dialog:request', { dialog: this });

        // update() causes an error in IE6 if script tags or iframes are present
        this.dialogContent.childElements().invoke('remove');

        this.showLoading();

        new Ajax.Request(url, opt);

    },

    renderContent: function(content) {

        this.hideLoading();
        this.dialogContent.update(content.responseText);

        this.positionOverlay();
        this.dialog.fire('dialog:render', { dialog: this });
    },

    _keyPressed: function(e) {
        if (e.keyCode == Event.KEY_ESC) this.hideDialog();
    },

    cleanUp: function() {
        this.dialog.fire('dialog:cleanup', { dialog: this });
        this.dialog.remove();
        this.overlay.remove();
        if (this.options.handleFormSubmits) {
            var selector = new Template('##{id} button[type=submit], ##{id} input[type=submit]').evaluate(this.options);
            Event.unregister(document, selector, "click");

            selector = new Template('##{id} form').evaluate(this.options);
            Event.unregister(document, selector, "keypress");
        }

        if (this.options.handleAnchors) {
            var selector = new Template('##{id} a, ##{id} *[avebehavior="dialog-link"]').evaluate(this.options);
            Event.unregister(document, selector, "click");
        }
    },

    saveTiny: function() {
        try {
            if (tinyMCE && tinyMCE.activeEditor != null)
                tinyMCE.triggerSave();
        } catch (e) {//get a weird "ReferenceError: tinyMCE is not defined" error without the try/catch
        }
    }

});

AVE.Dialog.Handler = (function() {
	var causes = $w('dialog:submit dialog:navigate');
	var responses = new Hash();
	
    var base = function(options, e) {
		options = Object.extend({
			parameters: e.memo.parameters
		}, options._object || {});

		var dialog = e.memo.dialog;
        dialog.getContent(e.memo.action, options);
    };

	var handler = base.curry({}); // Default is to just load next screen in the dialog;
    document.observe('dialog:submit', handler);
    document.observe('dialog:navigate', handler);
    
    return {
        unset: function(response) {
			if(arguments[1] && causes.include(arguments[1]))
				causes = [arguments[1]];
				
			causes.each(function(evt){
				document.stopObserving(evt, handler);
			});
			
			if(response) { 
				responses.unset('on'+response.capitalize());
			} else {
				responses = new Hash();
			}
			handler = base.curry(responses);
			
			causes.each(function(evt){
				document.observe(evt, handler);
			});
        },
        
		//AVE.Dialog.Handler.set('success', function(){ console.log(this); // the dialog object });
		//AVE.Dialog.Handler.set('success', function(){ console.log(this); // the dialog object }, "dialog:submit"); // only capture form submits
		//AVE.Dialog.Handler.set('success', function(){ console.log(this); // the dialog object }, "dialog:navigate"); // only capture anchor clicks
		//AVE.Dialog.Handler.unset('success');
		//AVE.Dialog.Handler.unset('success', "dialog:navigate");
		//AVE.Dialog.Handler.unset();
		
        set: function(response, func) {
			if(arguments[2] && causes.include(arguments[2]))
				causes = [arguments[2]];
				
			causes.each(function(evt){
				document.stopObserving(evt, handler);
			});
			
			responses.set('on'+response.capitalize(), func);
			handler = base.curry(responses);
			
			causes.each(function(evt){
				document.observe(evt, handler);
			});
        }
    };
})();

AVE.Dialog.Uniq = (function() {
	var instance;
	
	return {
	    createInstance: function() {
	        if(instance)
	           instance.cleanUp();
	        
	        instance = null;
	        instance = new AVE.Dialog(arguments[0] || {});
	        return instance;        
	    },
	    
		getInstance: function() {
			if(!instance)
				instance = AVE.Dialog.Uniq.createInstance(arguments[0] || {});
			return instance;
		}
	};
})();