(function ($)
{
    var s = "loading...";

    var defaults = {
        xPostLoad: 'postLoad'
		, target: ".xdynamic"
		, xmodal: false
    };

    var FormDefaults = {
        target: ".xdynamic"
		, beforeSubmit: function (formData, form, options)
		{
		    xLoaderUtil.log('submitting form to ' + this.target);
		    if (typeof ($(form).validate) == 'function')
		    {
		        xLoaderUtil.log('Validating Form. Errors:' + $(form).validate().errorList.length);

		        return ($(form).validate().errorList.length == 0);
		    }
		    xLoaderUtil.log('not validating form');
		    return true;
		}
		, success: function (responseText, status, xhr, $form)
		{
		    xLoaderUtil.log('form submit ' + status);
		    $(this).xOnFormLoad();
		}
		, error: function (xhr, status, error)
		{
		    xLoaderUtil.log('form submit ' + status);
		    var sError = xhr.responseText;
		    // TODO: Replace this with growl or dialog
		    $('html').html(sError);
		}
    };

    $.fn.xLoadingMessage = function (sMessage)
    {
        if (typeof (sMessage) != 'undefined')
        {
            s = sMessage
        }
        return s;
    }

    $.fn.xSetOptions = function (new_options)
    {
        element = $(this);

        if (typeof (new_options) != 'undefined')
        {
            $.each(new_options, function (event, fn)
            {
                if (typeof (fn) == 'function')
                    element.bind(event, fn);
            });
        }

        options = $.extend({}, defaults, element.data('wLoad:options'), new_options);
        element.data('wLoad:options', options);

        $(this).addClass(options.target);

        return this;
    }

    $.fn.xLoadSetup = function (new_options)
    {
        // protect against null options
        new_options = new_options | {};
        this.each(function ()
        {

            var loadElement = $(this);
            targetId = loadElement.attr("id");

            var idcount = 0;

            // set a links
            loadElement.find("a")
				.filter(function () { return ($(this).attr('target') != '_top'); })
				.xSetOptions(new_options).each(function ()
				{
				    // make sure we have an ID
				    if ($(this).attr('id') == '' || $(this).attr('id') == undefined)
				    {
				        idcount++;
				        $(this).attr('id', targetId + 'a_' + idcount);
				        xLoaderUtil.log('found link, set id #' + $(this).attr('id'));
				    }
				    else
				    {
				        xLoaderUtil.log('found link #' + $(this).attr('id'));
				    }
				    // make sure we dont do setup twice
				    if ($(this).attr('xLS') == undefined)
				    {
				        $(this).attr('xLS', 'done');
				        xLoaderUtil.log('setting anchor link to x Load : #' + $(this).attr('id'));

				        $(this).click(function ()
				        {
				            thisoptions = $(this).data('wLoad:options');
				            if ((typeof (thisoptions) != 'undefined' && thisoptions.xmodal) || $(this).attr('target') == '_modal')
				            {
				                xLoaderUtil.log('--- clicked ---');
				                xLoaderUtil.log('modal target: ' + $(this).attr('target'));

				                $(this).xALoadModal();
				            }
				            else
				            {
				                xLoaderUtil.log('--- clicked ---');
				                $(this).xALoad();
				            }

				            return false;
				        });
				    }
				    else
				    {
				        // make sure we dont do setup twice
				        xLoaderUtil.log('xLS done');
				    }
				});

            FormDefaults.target = '#' + targetId;
            var form_options = $.extend({}, loadElement.data('wLoad:options'), FormDefaults, new_options);

            // set form submit
            loadElement.find("form").ajaxForm(form_options);

        });

        return this;
    }

    $.fn.xLoad = function (sUrl, options, callback, ajaxData)
    {

        xElement = $(this);

        if (xElement.length < 1)
        {
            xLoaderUtil.log('no target for xLoad');
            return this;
        }

        if (typeof (options) == 'function')
        {
            callback = options;
            options = {};
        }
        else
        {
            callback = function () { };
        }

        loadData = $.extend({}, defaults, ajaxData);
        if (options == undefined)
        {
            xLoaderUtil.log('setting loadData undefined');
            loadData = undefined;
        }
        else
        {
            xLoaderUtil.log('using');
        }

        xLoaderUtil.log('USING xLOAD');

        xElement.html(s).load(sUrl, loadData, function ()
        {
            $(this).xLoadSetup(options);
            $(this).each(callback);
        });

        return this;
    }

    // ajax load html and then set all the sublinks to ajax load into a modal
    $.fn.xModalChildLoad = function (sUrl, options, callback)
    {

        if (typeof (callback) != 'function')
            callback = function () { };

        xMElement = $(this);
        thisoptions = $.extend({}, modalDefaults, options);

        //xLoaderUtil.dir(thisoptions);

        xLoaderUtil.log('USING MODAL CHILD LOAD');

        xMElement.load(sUrl, function ()
        {
            xLoaderUtil.log('setting modal options');
            $(this).xLoadSetup(thisoptions);
            callback();
        });

        return this;
    }

    // simply make child links modal
    $.fn.xModalLinks = function (options, callback)
    {
        // make sure we dont throw errors on the callback
        if (typeof (callback) != 'function')
            callback = function () { };

        // set the targets to modal to trigger modal loading
        this.find('a').each(function ()
        {
            $(this).attr('target', '_modal');
        });

        // set the options on the links
        thisoptions = $.extend({}, modalDefaults, options);
        $(this).xLoadSetup(thisoptions);

        // trigger the callback
        callback();
        // chain!
        return this;
    }

    $.fn.xALoad = function ()
    {
        xAElement = $(this);
        options = xAElement.data('wLoad:options');

        xLoaderUtil.log('USING xALOAD');
        sTarget = $(this).attr('target');

        if (sTarget.length)
        {
            xLoaderUtil.log('link has target: ' + sTarget);
            oContainer = $('#' + sTarget);
        }

        xLoaderUtil.log('load target ' + sTarget);

        if (typeof (oContainer) != 'undefined' && oContainer.length)
        {
            xLoaderUtil.log('found target. loading link to target #' + oContainer.attr('id'));
        }
        else
        {
            xLoaderUtil.log('loading link to ' + options.target);
            oContainer = $(this).parents(options.target);
        }

        xLoaderUtil.log('laoding url ' + escape($(this).attr('href')));

        sUrl = escape($(this).attr('href')).replace(' ', '%20');
        oContainer.load(sUrl, function ()
        {
            $(this).xLoadSetup(options);
        });

        return this;
    }

    $.fn.xALoadModal = function (new_options)
    {
        xAM_Element = $(this);
        options = xAM_Element.data('wLoad:options');
        var combine_options = $.extend({}, options, new_options);
        // xLoaderUtil.dir(options, 'Modal Options');
        xLoaderUtil.log('-- A LoadModal --');
        $.xModalStack($(this).attr('href'), combine_options);
    }

    $.fn.xOnFormLoad = function (thisoptions)
    {
        xF_Element = $(this);
        options = xF_Element.data('wLoad:options');
        xLoaderUtil.log('running setup on #' + xF_Element.attr('id'));

        xF_Element.xLoadSetup(options);
    }

    $.xLoadModal = function (sUrl, oData, fCallback)
    {
        //xLoaderUtil.dir(oData, 'Modal Options');
        $.xModalStack(sUrl, { data: oData, modalCallBack: fCallback });
    }

    // configure modal defaults
    var modalDefaults = {
        xmodal: true
		, content_id: 'dialog_prim'
		, dialog_id: 'dialog'
		, convert_buttons: true
		, convert_caption: true
		, remove_links: true
		, modalOps: {
		    position: ['center', 20],
		    modal: true,
		    bgiframe: true,
		    width: 400,
		    buttons: {
		        "Close": function ()
		        {
		            $(this).dialog("close");
		        }
		    },
		    close: function (event, ui)
		    {
		        $(this).remove();
		    }
		}
		, modalCallBack: function () { xLoaderUtil.log('empty modal callback'); }
		, ajaxFormOptions: {}
    };

    $.fn.xModalStep = function (url, options)
    {
        newOptions = jQuery.extend({}, modalDefaults, options);

        if (typeof (url) == 'function')
        {
            $(this).parents('.ui-dialog-content').dialog("close").parent('body').each(function ()
            {
                url(newOptions);
            });
        }

        $(this).parents('.ui-dialog-content').dialog("close").parent('body').xAjaxModal(url, newOptions);

    }

    $.xAjaxModal = function (sUrl, new_options)
    {
        $.xModalStack(sUrl, new_options);
    }

    $.fn.xAjaxModal = function (sUrl, new_options)
    {
        $.xAjaxModal(sUrl, new_options);
    }

    $.xModalStack = function (sUrl, new_options)
    {
        StackModalOptions = $.extend({}, modalDefaults, new_options);
        modleOptions = $.extend({}, modalDefaults.modalOps, StackModalOptions.modalOps);

        sContentId = StackModalOptions.content_id || 'dialog_content';
        sDialogTitle = modleOptions.title || '...';
        sDialogId = StackModalOptions.dialog_id || 'dialog';
        ModalCB = StackModalOptions.modalCallBack

        ajaxFormOptions = $.extend({
            target: '#' + sContentId
            , success: function (oResponse, textStatus)
            {
                // this; // the options for this ajax request
                xLoaderUtil.log('response success');

                $(this)
		.dialog('option', 'buttons', {
		    'Done': function ()
		    {
		        $(this).dialog('close'); ModalCB(oResponse);
		    }
		}).xConvertModalButtons(this);
            }
		, error: function (XMLHttpRequest, textStatus, errorThrown)
		{
		    // this; // the options for this ajax request
		    xLoaderUtil.log('response error');
		    $('#' + sContentId).html(XMLHttpRequest.status + ' : ' + textStatus + ' ' + errorThrown);
		}

        }, StackModalOptions.ajaxFormOptions); // ajaxFormOptions

        // TODO: keep a count of dialogs, to make DOM IDs unique for multiple Dialogs open
        // DOM CLEANUP
        if ($('#' + sDialogId).length > 1)
        {
            xLoaderUtil.log('--FOUND dialog ... closing');
            $('#' + sDialogId).dialog('close').remove();
            $('#' + sContentId).remove();
        }

        xLoaderUtil.log('USING xMODAL STACK');
        MyModleOptions = $.extend({}, modleOptions); // copy the options to avoid refrencing

        $('<div></div>').attr({
            'id': sDialogId,
            'title': sDialogTitle
        }).hide().appendTo('body').each(function ()
        {
            $('<div></div>').attr({
                'id': sContentId
		    , 'class': 'xContainer'
            }).appendTo(this).html(s).load(sUrl, StackModalOptions.data, function (responseText, textStatus, XMLHttpRequest)
            {

                if (textStatus != 'error')
                {
                    xLoaderUtil.log('textStatus:' + textStatus);

                    if (StackModalOptions.remove_links)
                    {
                        // TODO: add some more configuration for what to do with anchor tags
                        $(this).find('a').remove();
                    }

                    oModal = $('#' + sDialogId);
                    // TODO: make a links stack modals
                    if (StackModalOptions.convert_buttons)
                    {
                        // get the form buttons, make dialog buttons then remove the form buttons
                        oModal.xConvertModalButtons(ajaxFormOptions);
                    }

                    if (StackModalOptions.convert_caption)
                    {
                        oModal.xConvertModalTitle(MyModleOptions);
                    }
                }
                else
                {
                    $(this).html('An error has occured.');
                }
            });

        }).dialog(MyModleOptions);

        // todo - maybe push the dialog into the LIFO stack and add annother content div

        return this;
    };

    // modify a jQuery UI dialog containing a form, moving the buttons to dialog buttons
    $.fn.xConvertModalButtons = function (ajaxFormOptions)
    {

        //xLoaderUtil.dir(ajaxFormOptions);

        oModal = $(this);

        oButtons = $.extend({}, oModal.dialog("option", "buttons"));

        xLoaderUtil.log('Modal found ' + oModal.length + '');

        oModal.find('form input[type=submit]').each(function ()
        {

            // TODO: make button value pass on submit
            ButtonFaceTitle = $(this).attr('value');
            ButtonName = $(this).attr('name');

            xLoaderUtil.log('converting button ' + ButtonFaceTitle);
            sHiddenInput = '<input type="hidden" name="' + ButtonName + '" value="' + ButtonFaceTitle + '">'

            xLoaderUtil.log('adding button ' + ButtonFaceTitle);

            oButtons[ButtonFaceTitle] = function ()
            {
                xLoaderUtil.log('button clicked: ' + ButtonFaceTitle);
                xLoaderUtil.log('appending ' + sHiddenInput);

                oForm = $(this).find('form');
                $(sHiddenInput).appendTo(oForm);
                oForm.ajaxSubmit(ajaxFormOptions);
            };

            oButtons[ButtonFaceTitle].name = ButtonName;
            oButtons[ButtonFaceTitle].value = ButtonFaceTitle;

        }).remove();

        oModal.dialog('option', 'buttons', oButtons);

        return this;
    };

    $.fn.xConvertModalTitle = function (modalOptions)
    {

        oModal = $(this);

        if (oModal.find('caption, .caption').length == 1 &&
					(typeof (modalOptions.title) == 'undefined' ||
			  	modalOptions.title == "..." ||
			  	modalOptions.title == ""))
        {
            sTitle = oModal.find('caption, .caption').html();
            oModal.dialog('option', 'title', sTitle);
            oModal.find('caption, .caption').remove();
        }
        else
        {
            xLoaderUtil.log(modalOptions.title + ' not fixing header :' + oModal.find('caption').length);
        }

        return this;
    }

    var ASPdefaults = {
        xTarget: 'x_asp_target',
        cache: false,
        type: "POST",
        url: "./Users.asmx/ping",
        data: "{}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (msg)
        {
        },
        error: function (XMLHttpRequest, textStatus, errorThrown)
        {
            xLoaderUtil.log('ajax error, status: \n' + textStatus + '\n - error: \n' + errorThrown)
        }
    };

    $.fn.xLoadASP_XML = function (sUrl, sData, callback, options)
    {
        xLoaderUtil.log('- calling XML WS');
        newOptions = options | {};
        newOptions.dataType = 'XML';
        $(this).xLoadASP_WS(sUrl, sData, callback, newOptions);
        return this;
    };

    $.fn.xLoadASP_JSON = function (sUrl, sData, callback, options)
    {
        xLoaderUtil.log('- calling JSON WS');
        newOptions = options | {};
        newOptions.dataType = 'json';
        newOptions.contentType = 'application/json; charset=utf-8';
        $(this).xLoadASP_WS(sUrl, sData, callback, newOptions);
        return this;
    };

    $.xLoadImgArray = function (aImages)
    {
        var arr = jQuery.makeArray(aImages);
        var allImgs = [];
        baseURL = '';
        c = 0;
        jQuery(arr).each(function ()
        {
            allImgs[c] = new Image(); //new img obj
            allImgs[c].src = (this[0] == '/' || this.match('http://')) ? this : baseURL + this;     //set src either absolute or rel to css dir
            c++;
        });
        return this;
    };

    $.fn.xLoadASP_WS = function (sUrl, sData, callback, options)
    {

        $(this).html(s);

        // TODO: verify the scope on this and race conditions
        var x_Element = $(this);

        (function ()
        {

            var myCallback, myData

            //make sure we have a callback function		
            if (typeof (callback) == 'function')
            {
                myCallback = callback;
            }
            else
            {
                myCallback = function () { }
            }

            // TODO: auto serialize objects
            // make sure we have a data object string
            if (typeof (sData) == 'undefined' || sData.length < 2)
            {
                myData = '{}';
            }
            else
            {
                myData = sData;
            }


            x_Element_id = x_Element.attr("id");

            xLoaderUtil.log(' setting element id to - ' + x_Element_id);

            //console.dir(x_Element);

            // setup to put message in element
            function outputData(msg)
            {
                xLoaderUtil.log('-- + fireing callback function to ' + this.xTarget)

                // check for the asp security hack
                if (typeof (msg.d) == 'undefined')
                {
                    AnswerValue = msg
                }
                else
                {
                    // hack is present - assign
                    AnswerValue = msg.d
                }

                // check to see if it is a standard complex JSON obj
                if (typeof (AnswerValue.sHtml) == 'undefined')
                {
                    $(this.xTarget).html(AnswerValue);
                }
                else
                {
                    // there is more data here, only display the HTML
                    $(this.xTarget).html(AnswerValue.sHtml);
                }

                myCallback(AnswerValue);
            }

            xLoaderUtil.log('- setting options ');

            // munge options together prefering anything passed in
            new_options = $.extend({}, ASPdefaults, {
                xTarget: '#' + x_Element_id,
                url: sUrl,
                data: sData
					, contentType: "application/json; charset=utf-8"
					, dataType: 'json'
					, success: outputData
            }, options);

            xLoaderUtil.log('- calling ajax');

            $.ajax(new_options);

        })();

        return this;
    }

})(jQuery);

if (typeof (xLoaderUtil) == 'undefined')
{
    var xLoaderUtil = {
        bDebug: false,
        log: function (string)
        {
            if (this.bDebug && typeof (console) != 'undefined' && window.console && window.console.log)
            {
                console.log(string);
            }
        },
        dir: function (object)
        {
            if (typeof (console) != 'undefined' &&
				typeof (console.dir) == 'function')
            {
                console.dir(object);
            }
        }
    };
}
