/**
 * jQueryプラグイン - 実行ユーティリティ-.
 * 
 * このモジュールをscriptタグで指定すると次の関数が有効になる.
 * (1)jQuery.Runtime.lazyExecute
 *    任意の関数の遅延実行を行う.
 * (2)jQuery.Runtime.requireJS
 *    任意のJavascriptをロードする.
 * (3)jQuery.Runtime.requireCSS
 *    任意のCSSをロードする.
 */
(function() {
        
    // jQueryがロードされていなければ終了.
    var jQuery;
    if (!jQuery || typeof jQuery !== 'function') {
        if (window.___jQuery) {
            jQuery = window.___jQuery;
        } else {
            if ($) {
                jQuery = $.noConflict();
                if (jQuery && typeof jQuery === 'function') {
                    window.___jQuery = jQuery;
                }
            }
        }
        if (!jQuery) {
            return;
        }
    }
    
    // すでにプラグインされているまたはなんらかの参照をしている場合は終了.
    if (jQuery && jQuery.Runtime) {
        return jQuery.Runtime;
    }
    
    /**
     * コンストラクタFunction.
     */
    function Runtime() {
    }
    var runtime = new Runtime();
    
    // Rutimeをインスタンス化しプラグインする.
    plugin();
    
    /**
     * Rutimeをインスタンス化しプラグインする.
     */
    function plugin() {
        jQuery.Runtime = runtime;
    }
    
    /**
     * 指定のオブジェクトが有効かどうかを判定する.
     */
    Runtime.prototype.isEnabled = function(enableObjectNS) {
        var enabled;
        try {
            enabled = eval(enableObjectNS);
            if (enabled) {
                return true;
            }
            return false;
        } catch (e) {
            return false;
        }
    }
    
    /**
     * 'requireExecute'Functionのコールバック関数.<br>
     * ロードするJavascriptはkeyが'initialize',valueが無名FunctionであるJSON形式でなければならない.
     * 
     * @param jsonText JSON形式のテキスト
     * @param status
     */
    Runtime.prototype._callback_requireExecute = function(jsonText, status) {
        try {
            var initializer = eval('(' + jsonText + ').initialize');
            if (initializer) {
                initializer = initializer();
            }
        } catch (e) { // nop.
        }
    }
    
    /**
     * 指定JSON形式のJavascriptをロードし実行する.<br>
     * ロードするJavascriptはkeyが'initialize',valueが無名FunctionであるJSON形式でなければならない.
     * 
     * @param enableObjectNS 存在を確認するオブジェクトの文字列表現.
     * @param moduleURL ロードするJavascriptのURL.
     * @param '_callback_requireExecute'の実行結果にかかわらず,ロードした場合はtrue,そうでなければfalseを返却する.
     */
    Runtime.prototype.requireExecute = function(enableObjectNS, moduleURL) {
        if (false === runtime.isEnabled(enableObjectNS)) {
            var r;
            r = jQuery.ajaxSettings.async = false;
            r = jQuery.get(moduleURL, runtime._callback_requireExecute);
            r = jQuery.ajaxSettings.async = true;
            return true;
        }
        return false;
    }
    
    /**
     * 指定のオブジェクトの存在を確認後に指定されたFunctionを実行する.<br>
     * この関数は呼び出し元と非同期(呼び出し元に制御が戻らない)で動作する.
     * 
     * @param enableObjectNS 存在を確認するオブジェクトの文字列表現.
     * @param executeFunction 実行するFunction.
     * @param maxTryCount [optional]実行可能かを確認するチャレンジ最大回数(0.5sec毎にチャレンジする).[default]10回.
     * @param currentTryCount [optional]現在のチャレンジ回数.
     */
    Runtime.prototype.lazyExecute = function(enableObjectNS, executeFunction, maxTryCount, currentTryCount) {
        maxTryCount = maxTryCount || 10;
        currentTryCount = currentTryCount || 0;
        var enabled;
        try {
            enabled = eval(enableObjectNS);
        } catch (e) { // nop
        }
        if (enabled) {
            executeFunction();
            return;
        }
        if (maxTryCount < ++currentTryCount) {
            return;
        }
        var recursiveFunction = function() {
            lazyExecute(enableObjectNS, executeFunction, maxTryCount, currentTryCount);
        }
        window.setTimeout(recursiveFunction, 500); // 0.5 sec.
    }
    
    /**
     * 指定のJavascriptをロードする.<br>
     * 
     * @param moduleURL ロードするJavascriptのURL.
     * @param moduleCharset [optional]ロードするJavascriptの文字セット.[default]UTF-8.
     * @param moduleID [optional]ロードするJavascriptに付加するID.[default]'moduleURL'のスラッシュとドットをアンダースコア記号に置換した文字列.
     * @return 実行指示に成功した場合はロードしたscript要素,失敗した場合はfalseを返却する.
     */
    Runtime.prototype.requireJS = function(moduleURL, moduleCharset, moduleID) {
        if (!moduleURL) {
            return false;
        }
        moduleCharset = moduleCharset || 'utf-8';
        moduleID = moduleID || moduleURL.replace(/[\-\/\.]/gi, '_');
        // ロード済みの場合は新たにロードしない.
        if (document.getElementById(moduleID)) {
            return;
        }
        var headElement = document.getElementsByTagName('head')[0];
        if (!headElement) {
            // 'head'タグ未定義の場合は'body'取得を試みる.
            // 失敗した場合は終了.
            headElement = document.getElementsByTagName('body')[0];
            if (!headElement) {
                return false;
            }
        }
        // 'head'タグに追加することでロードする.
        var scriptElement = document.createElement('script');
        scriptElement.type = 'text/javascript';
        scriptElement.charset = moduleCharset;
        scriptElement.id = moduleID
        scriptElement.src = moduleURL;
        return headElement.appendChild(scriptElement);
    }
    
    /**
     * 指定のCSSをロードする.<br>
     * 
     * @param cssURL ロードするCSSのURL.
     * @param cssCharset [optional]ロードするCSSの文字セット.[default]UTF-8.IEの場合は
     * @param cssID [option]ロードするCSSに付加するID.[default]'moduleURL'のスラッシュとドットをアンダースコア記号に置換した文字列.
     * @return 実行指示に成功した場合はロードしたlink要素,失敗した場合はfalseを返却する.
     */
    Runtime.prototype.requireCSS = function(cssURL, cssCharset, cssID) {
        if (!cssURL) {
            return;
        }
        cssCharset = cssCharset || 'utf-8';
        cssID = cssID || cssURL.replace(/[\-\/\.]/gi, '_');
        // ロード済みの場合は新たにロードしない.
        if (document.getElementById(cssID)) {
            return;
        }
        var headElement = document.getElementsByTagName('head')[0];
        if (!headElement) {
            // 'head'タグ未定義の場合は'body'取得を試みる.
            // 失敗した場合は終了.
            headElement = document.getElementsByTagName('body')[0];
            if (!headElement) {
                return false;
            }
        }
        // 'head'タグに追加することでロードする.
        var linkElement = document.createElement('link');
        linkElement.rel = 'stylesheet';
        linkElement.type = 'text/css';
        linkElement.href = cssURL;
        linkElement.id = cssID;
        var r = headElement.appendChild(linkElement);
        return true;
    }
    return jQuery.Runtime;
})();

