/*
* jQuery Frame Dialog 1.1.2
*
* Copyright (c) 2009 SolutionStream.com & Michael J. Ryan (http://www.solutionstream.com/)
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
* 
* Requires:
*   jquery ui dialog
*
*   jQuery.FrameDialog namespaced
*       .create()   function will create an iframe, pass on the options 
*                   and return from a jQueryUI Dialog.
*                   additional url option
*
*   TODO:   - Add logic to allow for relative URLs.
*
*   CUSTOMIZATION:
*       see FrameDialog._defaultOptions below for additional changes from ui dialog defaults
*       Returns a jQuery.dialog extension, with the same options passed in.
*
*       refer to jQueryUI Dialog for more customization options
*
*
*   LOCALIZATION: create a window.localization object
*               localization.OK         override text for the OK button
*               localization.Cancel     override text for the Cancel button
*
*
*   FROM PARENT WINDOW: use the full url, including protocol://host/ portions
*               jQuery.FrameDialog
*                   .create({
*                       url: baseURL + 'framed-modal-test.aspx',
*                       title: 'test title',
*                       ... Other jQueryUI Dialog Options ...
*                   })
*                   .bind('dialogclose', function(event, ui) {
*                       alert("result: " + event.result);
*                   });
*
*   INSIDE MODAL:
*               jQuery.FrameDialog.setResult(value);    //sets the result value
*               jQuery.FrameDialog.clearResult();       //clears the result value
*               jQuery.FrameDialog.closeDialog();       //close the dialog (same as OK)
*               jQuery.FrameDialog.cancelDialog();      //cancel the dialot (same as Cancel
*
*
*
*   !!!!!!!!!! WARNING WARNING WARNING WARNING !!!!!!!!!!
*   Modal must set the result from the same host address in order to access 
*   the parent for setting the result.
*/
(function($) {

    //create FrameDialog namespace
    $.FrameDialog = $.FrameDialog || {};

    //array for return values, placeholder
    $.FrameDialog._results = $.FrameDialog._results || {};

    //set localized variables
    var OK = (window.localization && window.localization.OK) || "OK";
    var Cancel = (window.localization && window.localization.CANCEL) || "Cancel";
    var buttons = {};
    var winSize = { w:$(window).width(), h:$(window).height() };
    buttons[OK] = function() {
                $(this).dialog("close");
            };
    buttons[Cancel] = function() {
                var frame = $(this);
                $.FrameDialog.clearResult(frame.attr("id"));
                frame.dialog("close");
            };

    //default options
    $.FrameDialog._defaultOptions = {
        modal: true,
        closeOnEscape: false,
        position: 'center',
        buttons: buttons
    };

    var retry = false;
    $.FrameDialog.create = function(options) {
        try {
            //generate unique id
            var uid = Math.random().toString(16).replace(".", "") + (new Date()).valueOf().toString(16);

            //extend frame dialog options with passed in options.
            var opts = $.extend(
                $.FrameDialog._defaultOptions,
                options || {}
            );

            var url = (opts && opts.url) || null;
            if (url === null)
                throw new Error("MODAL ERROR: Option 'url' not specified!"); //diagnostic error

            //clean up redundant forward slashes in the url.
            url = url.replace(/(^|[^:])\/+/g, "$1/");

            //remove url argument from options to be passed to dialog.
            try {
                delete opts.url;
            } catch (err) { }

            //create iframe object
            //  object type="text/html doesn't seem to work in IE :(
            //  using iframe, which seems to work cross browser, tested in IE7, and Firefox 3.0.7
            var iframe = $("<iframe frameborder='0' scrolling='auto' background='transparent' />")
                .attr("id", uid + "-VIEW")
                .attr("name", uid + "-VIEW")
                .attr("src", url)
                .css("margin", "0")
                .css("border", "0")
                .css("padding", "0")
                .css("top", "0")
                .css("left", "0")
                .css("right", "0")
                .css("bottom", "0")
                .css("width", "100px")
                .css("height", "100px")
                ;

            var overlay = $("<div>&nbsp;</div>")
                .css("position", "absolute")
                .css("margin", "0")
                .css("border", "0")
                .css("padding", "0")
                .css("top", "0")
                .css("left", "0")
                .css("right", "0")
                .css("bottom", "0")
                .css("width", "100%")
                .css("height", "100%")
                .css("display", "none")
                ;

            var ret = $("<div />")
                .attr("id", uid)
                .css("margin", "0")
                .css("border", "0")
                .css("padding", "0")
                .css("top", "0")
                .css("left", "0")
                .css("right", "0")
                .css("bottom", "0")
                .css("overflow", "hidden")
                .hide()
                .append(iframe)
                .append(overlay)
                .appendTo(document.body)
                .bind("dialogbeforeclose", function(event, ui) {
                    var frame = $(this);
                    var uid = frame.attr("id");

                    //default close (firefox) - clear response
                    if (event && event.originalTarget && event.originalTarget.nodeName && event.originalTarget.nodeName == "SPAN")
                        $.FrameDialog.clearResult(uid);

                    //default close (IE7) - clear response
                    if (event && event.originalEvent && event.originalEvent.currentTarget && event.originalEvent.currentTarget.tagName && event.originalEvent.currentTarget.tagName == "A")
                        $.FrameDialog.clearResult(uid);

                    //get the response value, attach to the object.
                    var result = $.FrameDialog._results[uid] || null; //result or an explicit null

                    return result;
                })
                .bind('dialogclose', function(event, ui) {
                    var frame = $(this);
                    var uid = frame.attr("id");
                    var result = $.FrameDialog._results[uid] || null; //result or an explicit null
                    frame.attr("result", result);

                    //Cleanup remnants in 15 seconds
                    //      Should be enough time for the results of the close to finish up.
                    window.setTimeout(
                        function() {
                            //cleanup the dialog
                            frame.dialog('destroy');

                            //destroy the iframe, remove from the DOM
                            frame.remove();
                            overlay.remove();
                            ret.remove();

                            //remove the placeholder for the result
                            try {
                                delete $.FrameDialog._results[uid];
                            } catch (err) { /*nothing to delete*/ }
                        },
                        100
                    );

                    return result;
                })
                .dialog(opts)
                ;

            /*** BEGIN FIX FOR jQueryUI 1.7 Dialog's sizing bug *************************************************/
            //store the window width at the start
            var winw = $(document).width();
            var wrap = ret.parent(".ui-resizable");

            //set the window to the appropriate size - fix bug with jQueryUI's Dialog
            //  uses an overlay over the iframe, to prevent focus change.
            wrap.css('width', (opts.minWidth || opts.width || 200) + 'px')
                    .css('height', (opts.minHeight || opts.height || 120) + 'px')
                    .bind('dragstart', function() {
                        overlay.show();
                    })
                    .bind('dragstop', function() {
                        overlay.hide();
                    })
                    .bind('resizestart', function() {
                        overlay.show();
                    })
                    .bind('resize', function() {
                        iframe.css('height', ret.height() + 'px')
                                    .css('width', ret.width() + 'px');
                    })
                    .bind('resizestop', function() {
                        overlay.hide();
                        iframe.css('height', ret.height() + 'px')
                                .css('width', ret.width() + 'px');
                    });


            //force resize event.
            window.setTimeout(function(){ 
                wrap.trigger('resizestop');
            }, 100);

            //get window's new width
            var ww = wrap.width();

            //reset the center position, if needed
            if (opts.position == 'center' || (opts.position && (opts.position[0] == 'center' || opts.position[1] == 'center'))) {
                var pos = parseInt(parseFloat(winw - ww) / 2);
                if (pos < 0) pos = 0;

                wrap.css('left', pos + 'px');
            }

            //reset right position, as needed
            if (opts.position == 'right' || (opts.position && (opts.position[0] == 'right' || opts.position[1] == 'right'))) {
                var pos = winw - ww - 5; //set to rightmost, - 5 px
                if (pos < 0) pos = 0;

                wrap.css('left', pos + 'px');
            }
            /*** END FIX FOR jQueryUI 1.7 Dialog's sizing bug *************************************************/
            retry = false; //reset the retry state.
            return ret;
        } catch (err) {
            //cleanup any left over ui elements...
            try { ret.dialog('destroy'); } catch(err) {}
            try { ret.remove(); } catch(err) {}
            try { overlay.remove(); } catch(err) {}
            try { iframe.remove(); } catch(err) {}

            //it was a TypeError (seems to be happening with the modal's overlay mask, retry once.
            if (err instanceof TypeError && !retry) {
                retry = true;
                return $.FrameDialog.create(options); //retry once only
            }

            throw err; //rethrow error if something else
        }
    }

    //retrieves the uid for the current frame within the parent.
    $.FrameDialog._getUid = function() {
        //find the current frame within the parent window
        if (window.parent && window.parent.frames && window.parent.document && window.parent.document.getElementsByTagName) {
            var iframes = window.parent.document.getElementsByTagName("IFRAME");
            for (var i = 0; i < iframes.length; i++) {
                var id = iframes[i].id || iframes[i].name || i;
                if (window.parent.frames[id] == window) {
                    return id.replace("-VIEW", "");
                }
            }
        }
        return null; //no match
    }

    //Returns the current dialog handle in the parent window as a jquery object.
    $.FrameDialog.current = function() {
        if (window.parent && window.parent.jQuery)
            return window.parent.jQuery("#" + $.FrameDialog._getUid());
        
        return null;
    }

    //clear the result value
    //  uid - id for child window, or empty for current in parent.
    $.FrameDialog.clearResult = function(uid) {
        if (uid) {
            //clear child's value
            try {
                delete $.FrameDialog._results[uid];
            } catch (err) { /*nothing to delete*/ }
        } else {
            //clear for current dialog
            var uid = $.FrameDialog._getUid();

            if (uid != null && window.parent && window.parent.jQuery && window.parent.jQuery.FrameDialog && window.parent.jQuery.FrameDialog._results) {
                try {
                    delete window.parent.jQuery.FrameDialog._results[uid];
                } catch (err) { /*nothing to delete*/ }
            }
        }
    }

    //helper function to set response value to the parent
    //  value - result value for the given FrameDialog
    //  uid - child id, or empty for current FrameDialog
    $.FrameDialog.setResult = function(value, uid) {
        if (uid) {
            //set child value
            jQuery.FrameDialog._results[uid] = value;
        } else {
            //set value from inside
            var uid = $.FrameDialog._getUid();

            if (uid != null && window.parent && window.parent.jQuery && window.parent.jQuery.FrameDialog && window.parent.jQuery.FrameDialog._results) {
                window.parent.jQuery.FrameDialog._results[uid] = value;
            }
        }
    }

    //same as clicking OK button
    //  uuid - for a child node, or empty for current
    $.FrameDialog.closeDialog = function(uid) {
        if (uid) {
            //close child
            jQuery("#" + uid).dialog('close');
        } else {
            //close self            
            var uid = $.FrameDialog._getUid();
            if (uid != null && window.parent && window.parent.jQuery) {
                window.parent.jQuery("#" + uid).dialog('close');
            }
        }

        return false;
    }

    //same as clicking Cancel button
    //  uid - for a child node, or empty for current frame
    $.FrameDialog.cancelDialog = function(uid) {
        $.FrameDialog.clearResult(uid);
        $.FrameDialog.closeDialog(uid);
        return false;
    }


    //extension methods for shortcuts in dealing with a framedialog handle
    $.fn.setResult = function(result) {
        return this.each(function() {
            $.FrameDialog.setResult(result, $(this).attr("id"));
        });
    }

    $.fn.clearResult = function() {
        return this.each(function() {
            $.FrameDialog.clearResult($(this).attr("id"));
        });
    }
    
    $.fn.closeDialog = function() {
        return this.dialog('close');
    }

    $.fn.cancelDialog = function() {
        return this.clearResult().closeDialog();
    }
    
    //get the window context for the object/iframe in question
    $.fn.window = function() {
        //this item is a frame or iframe
        if (this.attr('tagName') == "IFRAME" || this.attr('tagName') == "FRAME")
            return window.frames[this.attr('name') || this.attr('id')];
            
        //get the first frame/iframe child
        var frame = this.find('iframe, frame')[0];
        return (frame && window.frames[frame.name || frame.id]) || null;
    }

})(jQuery);
