$.namespace("ProspectDirector");
$.namespace("ProspectDirector.Types");

/**
EVERYTHING STARTS HERE!
@class RUNTIME
@namespace ProspectDirector
*/
ProspectDirector.RUNTIME = Class.extend({

    init: function (options) {
    }

});

/**
This method <b><u>MUST</u></b> be called before any other client side script is called.
@static
@method start
@param args {Object}
@param args.environmentVariables
*/
ProspectDirector.RUNTIME.start = function (environmentVariables) {

    environmentVariables = environmentVariables ? environmentVariables : {};

    ProspectDirector.RUNTIME.ENVIRONMENT = $.extend(ProspectDirector.RUNTIME.ENVIRONMENT, environmentVariables);

    ProspectDirector.RUNTIME.MODULES = {};

    /* global ajax setup */

    $.ajaxSetup({
        cache: false,
        error: function (jqXHR, status, thrownError) {
            new PD.Web.AjaxErrorHandler({
                config: this,
                jqXHR: jqXHR
            });
        }
    });

    /* global ajax event handlers */

    $(document).ajaxSend(function (e, xhr, settings) {

        var guid = ProspectDirector.RUNTIME.guid();

        xhr.guid = guid;

        setTimeout(function () {
            if (xhr.state() === "pending" && xhr.guid === guid) {
                ProspectDirector.Types.Core.Notifications.action("Your request is being processed... please wait.", "~/application/icons/32x32/CLOCK.PNG");
            }
        }, 1500);

    });

    /* window event handlers */

    $(document).ready(function () {

        ProspectDirector.RUNTIME.loadModule(new ProspectDirector.Modules.Core.Main(), "Main");
        ProspectDirector.RUNTIME.loadModule(new ProspectDirector.Types.Core.Navigator(), "Navigator");

    });

    /* break out of IFRAME? */
    if (window.top !== window.self) {
        window.top.location = window.self.location;
    }

};

/**
Loads a new instance of a module and adds the instance to the RUNTIME.MODULES object.
@static
@method loadModule
@param fqn {String} The fully qualified name of the module to load.
@param args {Object} A dictionary used to pass arguments to the module constructor.
@param [id] {String} An ID to identify the module after it has been added to the RUNTIME object. If this parameter is omitted the name of the module will be used instead.
@return {Object} The instantiated module.
*/
ProspectDirector.RUNTIME.loadModule =
function (module, id) {

    ProspectDirector.RUNTIME.MODULES[id] = module;
    
    return ProspectDirector.RUNTIME.MODULES[id];

};

/**
Takes a fully qualified type name and returns the type.
@static
@method type
@param fqn {String} The fully qualified type name.
@return {Type}
*/
ProspectDirector.RUNTIME.type =
function (fqn) {

    var pieces = fqn.split("."),
    source = window,
    i = 0;

    for (i = 0; i < pieces.length; i++) {
        source = source[pieces[i]];
    }

    return source ? source : null;

};

/**
Takes a fully qualified type name and returns an instance.
@static
@method instantiate
@param fqn {String} The fully qualified type name.
@param args {Object} The arguments object.
@return {Object}
*/
ProspectDirector.RUNTIME.instantiate =
function (fqn, args) {

    var type = fqn;
    
    if ($.type(type) === "string") {
        type = ProspectDirector.RUNTIME.type(fqn);
    }

    return type ? new type(args) : null;

};

/**
Resolves URLs that begin with a tilde character to the virtual directory name of the application.
@static
@method resolveUrl
@param url {String}
@return {String} The resolved URL.
*/
ProspectDirector.RUNTIME.resolveUrl =
function (url) {

    var vd = ProspectDirector.RUNTIME.ENVIRONMENT.VIRTUAL_DIRECTORY;

    if (url === undefined || url === null) {
        return url;
    }

    if (url.indexOf("~/") === 0 && vd !== null) {
        url = "/" + vd + url.substr(1);
    }

    return url;

};

/**
Makes an HTTP `GET` request through a hidden `IFRAME`. This method is useful for downloading files and other similar workflows where AJAX alone is not suitable.
@static
@method iframeRequest
@param url {String} The URL to request.
@param params {Object} A set of key/value pairs that will converted into query string paramters and appended to the URL passed via the `url` parameter.
*/
ProspectDirector.RUNTIME.iframeRequest =
function (url, params) {

    var url = ProspectDirector.RUNTIME.resolveUrl(url),
        utilityFrame = null,
        utilityFrameId = "utilityframe",
        utilityFrameHtml = "<iframe id=\"" + utilityFrameId + "\" style=\"display:none;\"></iframe>";

    utilityFrame = $("#" + utilityFrameId);

    if (utilityFrame.length === 0) {
        $(utilityFrameHtml).appendTo("body");
    };

    params = $.extend({
        "iframe-request": true
    }, params);

    utilityFrame = $("#" + utilityFrameId);

    if (url.indexOf("?") > 0) {
        utilityFrame.prop("src", url + (params ? "&" + $.param(params) : ""));}
    else {
        utilityFrame.prop("src", url + (params ? "?" + $.param(params) : ""));
    }
    
};

/**
Stores runtime environment variables. It is expected that properties exposed by this class are set.
@static
@class ENVIRONMENT
@namespace ProspectDirector.RUNTIME
**/
ProspectDirector.RUNTIME.ENVIRONMENT = {

    /** 
    The virtual directory of the application.
    @property VIRTUAL_DIRECTORY
    @final
    */
    VIRTUAL_DIRECTORY: null,


    /** 
    The user name of the current logged in user.
    @property USER_NAME
    @final
    */
    USER_NAME: null,

    /** 
    The user id of the current logged in user.
    @property USER_ID
    @final
    */
    USER_ID: null

};

ProspectDirector.RUNTIME.guid = function () {

    var S4 = function () {
        return Math.floor(
                Math.random() * 0x10000 /* 65536 */
            ).toString(16);
    };

    return (
        S4() + S4() + "-" +
        S4() + "-" +
        S4() + "-" +
        S4() + "-" +
        S4() + S4() + S4()
    );

};

ProspectDirector.RUNTIME.DATE_EXTRACTION_REGEX = new RegExp("([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})");

ProspectDirector.RUNTIME.getFixedLocalDate = function (time) {

    var matches = null;
    var result = new Date(time);

    if (time != null) {
        matches = ProspectDirector.RUNTIME.DATE_EXTRACTION_REGEX.exec(time);
        result.setFullYear(matches[1], matches[2] - 1, matches[3]);
        result.setHours(matches[4], matches[5], matches[6]);
    }

    return result;

};