// platyFramework 의 공용 클래스
// <script src="<?=$this->request->systemUrl?>/modules/ptycommon/resources/ptyCommon.js?<?=time()?>"></script>

$(document).on('click', '.ptySubmit', function (e) {
    e.preventDefault();

    $("#ptyShowDialogDlg").modal('hide');

    var formId = $(this).attr('formId');
    if (ptyIsEmpty(formId)) {
        alert ("needs to set formId");
        return;
    }

    var form = $("#" + $(this).attr('formId'))[0];
    if (ptyIsNull(form)) {
        alert ('cannot find formId = ' + formId);
        return;
    }

    var data = new FormData(form);
    $(this).prop("disabled", true);
    var action = $(this).attr('action');
    if (ptyIsEmpty(action)) {
        action = form.action;
    } else {

    }


    $.ajax({
        type: "POST",
        enctype: 'multipart/form-data',
        url: action, // form.action,
        data: data,
        dataType: 'json',
        processData: false,
        contentType: false,
        cache: false,
        timeout: 600000,
        success: function (data) {
            if (typeof data !== typeof undefined) {
                if (typeof data.action !== typeof undefined && data.action !== false) {
                    if (data.action == "ptyShowDialog") {
                        ptyShowDialog(data.titleContentUrl, data.title, data.content, data.positiveTitle, data.positiveUrl, data.positiveJsonUrl, data.positiveButton);
                        return;
                    }
                }

                /*
                if (typeof data.title !== typeof undefined && data.title !== false) {
                    $("#ptyShowDialogByRemoteContentDlg_title").text(data.title);
                }

                if (typeof data.content !== typeof undefined && data.content !== false) {
                    $("#ptyShowDialogByRemoteContentDlg_content").html(data.content);
                }

                $("#ptyShowDialogByRemoteContentDlg").fadeIn();
                */
            }

            $(this).prop("disabled", false);
        },
        error: function (e) {
            console.log("ERROR : ", e);
            $(this).prop("disabled", false);
            alert("요청이 실패되었습니다.");
        }
    });
});



$(document).on('click', '.ptySubmitAndContent', function (e) {
    e.preventDefault();

    $("#ptyShowDialogDlg").modal('hide');

    var form = $("#" + $(this).attr('formId'))[0];
    var data = new FormData(form);
    $(this).prop("disabled", true);
    var action = $(this).attr('action');
    if (typeof action === typeof undefined) {
        action = form.action;
    } else {

    }


    $.ajax({
        type: "POST",
        enctype: 'multipart/form-data',
        url: action, // form.action,
        data: data,
        dataType: 'json',
        processData: false,
        contentType: false,
        cache: false,
        timeout: 600000,
        success: function (data) {
            if (typeof data !== typeof undefined) {
                if (typeof data.action !== typeof undefined && data.action !== false) {
                    if (data.action == "ptyShowDialog") {
                        ptyShowDialog(data.titleContentUrl, data.title, data.content, data.positiveTitle, data.positiveUrl, data.positiveJsonUrl);
                        return;
                    }
                }

                if (typeof data.title !== typeof undefined && data.title !== false) {
                    $("#ptyShowDialogByRemoteContentDlg_title").text(data.title);
                }

                if (typeof data.content !== typeof undefined && data.content !== false) {
                    $("#ptyShowDialogByRemoteContentDlg_content").html(data.content);
                }

                $("#ptyShowDialogByRemoteContentDlg").fadeIn();
            }

            $(this).prop("disabled", false);
        },
        error: function (e) {
            console.log("ERROR : ", e);
            $(this).prop("disabled", false);
            alert("요청이 실패되었습니다.");
        }
    });
});


var ptyShowDialog_positiveJsonUrl = '';
var ptyShowDialog_positiveUrl = '';
$(document).on('click', '.ptyShowDialog', function (e) {
    e.preventDefault();

    ptyShowDialog(
        $(this).attr('titleContentUrl'),
        $(this).attr('title'),
        $(this).attr('content'),
        $(this).attr('positiveTitle'),
        $(this).attr('positiveUrl'),
        $(this).attr('positiveJsonUrl')
    );
});

function ptyIsNull(str) {
    if (str == typeof undefined || typeof str == "undefined" || str == null)
        return true;
    else
        return false;
}

function ptyIsEmpty(str) {
    if (str == typeof undefined || typeof str == "undefined" || str == null || str == '')
        return true;
    else
        return false;
}


function ptyShowDialog(titleContentUrl, title, content, positiveTitle, positiveUrl, positiveJsonUrl, positiveButton) {
    if (!ptyIsEmpty(titleContentUrl)) {
        $.getJSON(titleContentUrl, function (data) {
            ptyShowDialog('', data.title, data.content, data.positiveTitle, data.positiveUrl, data.positiveJsonUrl, data.positiveButton);
            return;
        });
        return;
    }



    console.log("positiveTitle = " + positiveTitle);
    console.log("positiveButton = " + positiveButton);

    $("#ptyShowDialogDlg_title").text(title);

    if (ptyIsEmpty(content)) {
        $("#ptyShowDialogDlg_content").css("display", "none");
    }
    else {
        $("#ptyShowDialogDlg_content").attr('disabled', false);
        $("#ptyShowDialogDlg_content").text(content);
    }

    if (ptyIsEmpty(positiveButton)) {
        console.log("hide positive");
        $("#ptyShowDialogDlg_positive").css("display", "none");
    }
    else {
        console.log("show positive");
        $("#ptyShowDialogDlg_positive").attr('disabled', false);
        $("#ptyShowDialogDlg_positive").css("display", "inline");
        $("#ptyShowDialogDlg_positive").replaceWith(positiveButton);
    }

    /*
    else if (ptyIsNull(positiveTitle)) {
        $("#ptyShowDialogDlg_positive").css("display", "none");
    } else {
        $("#ptyShowDialogDlg_positive").attr('disabled', false);
        $("#ptyShowDialogDlg_positive").css("display", "inline");
        $("#ptyShowDialogDlg_positive").text(positiveTitle);
    }
    */

    ptyShowDialog_positiveUrl = positiveUrl;
    ptyShowDialog_positiveJsonUrl = positiveJsonUrl;
    ptyShowDialog_positiveButton = positiveButton;

    $("#ptyShowDialogDlg_content").html(content);
    $("#ptyShowDialogDlg").modal();
}

$(document).on('click', '#ptyShowDialogDlg_positive', function (e) {
    e.preventDefault();
    $(this).attr('disabled', true);

    console.log("clicked positive. ptyShowDialog_positiveUrl = " + ptyShowDialog_positiveUrl + ", ptyShowDialog_positiveJsonUrl = " + ptyShowDialog_positiveJsonUrl);

    if (!ptyIsEmpty(ptyShowDialog_positiveUrl)) {
        window.location.href = ptyShowDialog_positiveUrl;
    }
    else {
        $.getJSON(ptyShowDialog_positiveJsonUrl, function (data) {
            $("#ptyShowDialogDlg").modal('hide');

            // console.log("data = ");
            // console.log(data);

            if (typeof data !== typeof undefined) {
                if (typeof data.action !== typeof undefined && data.action !== false) {
                    if (data.action == "ptyShowDialog") {
                        ptyShowDialog(data.titleContentUrl, data.title, data.content, data.positiveTitle, data.positiveUrl, data.positiveJsonUrl);
                        return;
                    }
                }

                if (typeof data.script !== typeof undefined && data.script !== false) {
                    eval(data.script);
                    return;
                }

                if (typeof data.title !== typeof undefined && data.title !== false) {
                    $("#ptyShowDialogByRemoteContentDlg_title").text(data.title);
                }

                if (typeof data.content !== typeof undefined && data.content !== false) {
                    $("#ptyShowDialogByRemoteContentDlg_content").html(data.content);
                }

                // $("#ptyShowDialogByRemoteContentDlg").modal();
            }
            // }).success(function () {
            //     $('input:text:visible:first').focus();
        });
    }
});


/**
 * 라디오 버튼에 값을 설정합니다
 *
 * @param name
 * @param value
 */
function ptySetInputRadio(name, value) {
    jQuery(function ($) {
        $('input:radio[name="' + name + '"][value="' + value + '"]').prop('checked', true);
    });
}

function ptyGetInt(s) {
    if (typeof s == "number") {
        if (isNaN(s))
            return 0;
        return s;
    }
    if (s == '') {
        return 0;
    }
    s = s.replace("원", "");
    var rtn = parseFloat(s.replace(/,/gi, ""));

    if (isNaN(rtn)) {
        return 0;
    }
    else {
        return rtn;
    }
}

/**
 * 모든 text 의 value 를 placeholder 로 교체합니다. 개발시에 사용됩니다
 */
function ptyAllInputValueFromPlaceHolder(additional)
{
    $('input[type="text"]').each(function() {
        var $this = $(this);
        $this.attr("value", $this.attr("placeholder") + additional);
    });

    $('textarea').each(function() {
        var $this = $(this);
        $this.val($this.attr("placeholder") + additional);
    });
}

var ptyUpdateQueryStringParam = function (key, value) {
    var baseUrl = [location.protocol, '//', location.host, location.pathname].join(''),
        urlQueryString = document.location.search,
        newParam = key + '=' + value,
        params = '?' + newParam;

    // If the "search" string exists, then build params from it
    if (urlQueryString) {
        keyRegex = new RegExp('([\?&])' + key + '[^&]*');

        // If param exists already, update it
        if (urlQueryString.match(keyRegex) !== null) {
            params = urlQueryString.replace(keyRegex, "$1" + newParam);
        } else { // Otherwise, add it to end of query string
            params = urlQueryString + '&' + newParam;
        }
    }
    window.history.replaceState({}, "", baseUrl + params);
};

/*
function ptyGetInputRadioValue(name) {
    var _ptyGetInputRadioValue = null;
    jQuery(function ($) {
        // var $radio = $('input:radio[name="' + name + '"])');
        var $radio = $('input:radio[name="' + name + '"]:checked');
        // console.log(($radio));
        var val = ($radio).val();
        _ptyGetInputRadioValue = val;
        // console.log(_ptyGetInputRadioValue);
        return false;
    });
    return _ptyGetInputRadioValue;
}
*/

/**
 * 뒤로 이동
 */
function ptyGoBack() {
    history.go(-1);
}



$(function () {
    $(".ptyGoBack").click(function () {
        history.go(-1);
    });



});



/**
 *
 * Post 를 손쉽게 호출 및 true, false 리턴
 *
 $(document).ready(function () {
        ptyPost("<?=PLATYFRAMEWORK_APP_URL?>/api/where", {arg1: "arg1Value", "arg2": "arg2Value"}, function (result, value) {
            if (result === true) {
                updateItem(value);
            }
        });
    });

 or

 $(function () {
        $("input[name=email]").val("cpueblo@platyhouse.com");
        $("input[name=password1]").val("abcd");
        $("input[name=password2]").val("sabcd");
        $("input[name=email]").focus();

        $("#frm").submit(function (e) {
            e.preventDefault();
            $("#errorMessage").text("");
            ptyPost("<?=$this->request->classUrl?>/signUpProcess/", {params: $(this).serialize()},
                function (result, json) {
                    if (result === true) {
                        console.log(json);
                        $("select#subCategory").ptyReplaceOption2(json.subCategories);
                    }
                    else
                    {
                        $("#errorMessage").text(json.errorMessage);
                        $("#errorMessage").animateCss("bounceIn");
                    }
                });
            return false;
        });
    });

 */
function ptyPost(url, args, onResult) {
    var _onResult = onResult;
    $.post(url, args, function (data) {
        if (data != '') {
            try {
                var ret = JSON.parse(data);

                if (ret.script) {
                    eval(ret.script);
                }

                if (ret.alertMsg)
                    alert(ret.alertMsg);

                if (ret.goBack == true) {
                    history.go(-1);
                }

                if (ret.return == 'true') {
                    _onResult(true, ret);
                }
                else
                    _onResult(false, ret);
            }
            catch (e) {
                alert('일시적으로 장애가 발생하였습니다. 잠시후 다시 시도하십시오');
            }
        }
        return false;
    });
    return true;
}


(function($, window) {
    /**
     * select 내의 옵션을 변경합니다
     *
     ex)
     var options = [
     {text: "one", value: 1},
     {text: "two", value: 2}
     ];

     $("#foo").ptyReplaceOptions(options);
     */

    $.fn.ptyReplaceOption = function(options) {
        var self, $option;
        var value = $(this).val();

        this.empty();
        self = this;

        $.each(options, function(index, option) {
            if (option.value === value) {
                $option = $("<option selected></option>")
                    .attr("value", option.value)
                    .text(option.text);
            }
            else {
                $option = $("<option></option>")
                    .attr("value", option.value)
                    .text(option.text);
            }
            self.append($option);
        });
    };

    $.ptyGetUrlParam = function (name) {
        var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
        return results[1] || 0;
    };


    /**
     * select 내의 옵션을 변경합니다
     *
     ex)
     var options = [
     {"abcd"},
     {"cdef"}
     ];

     $("#foo").ptyReplaceOptions(options);
     */
    $.fn.ptyReplaceOption2 = function(options) {
        var self, $option;
        var value = $(this).val();

        this.empty();
        self = this;

        $.each(options, function(index, option) {

            if (option === value) {
                $option = $("<option selected></option>")
                    .attr("value", option)
                    .text(option);
            }
            else
            {
                $option = $("<option></option>")
                    .attr("value", option)
                    .text(option);
            }

            self.append($option);
        });
    };

    $.ptyGetInputRadioValue = function(nsame) {
        // console.log(name);
        console.log($('input[name=workKeyword]:checked').val());

        /*
        var $radio = $('input:radio[name="' + name + '"]:checked');
        // var $radio = $('input:radio[name=' + name + ']:checked');
        var val = $radio.val();
        console.log(($radio));
        console.log(val);
        return val;
        */
    }

})(jQuery, window);

$.fn.extend({

    /**
     * 에니메이션을 처리하는 함수 : animateCss()
     * <link type="text/css" rel="stylesheet" href="<?=$this->request->systemUrl?>/modules/ptycommon/resources/animate.css">
     *
     * @param animationName
     * @param callback
     * @returns {animateCss}
     */
    animateCss: function(animationName, callback) {
        var animationEnd = (function(el) {
            var animations = {
                animation: 'animationend',
                OAnimation: 'oAnimationEnd',
                MozAnimation: 'mozAnimationEnd',
                WebkitAnimation: 'webkitAnimationEnd',
            };

            for (var t in animations) {
                if (el.style[t] !== undefined) {
                    return animations[t];
                }
            }
        })(document.createElement('div'));

        this.addClass('animated ' + animationName).one(animationEnd, function() {
            $(this).removeClass('animated ' + animationName);

            if (typeof callback === 'function') callback();
        });

        return this;
    },

});

/**
 * html 을 excel 로 내보냅니다
 *
 usage)

 $("#exportExcel").click(function () {
	ptyExportToExcel("수당단가표_< ? =date("Ymd_His") ? >.xls", $(".table2").html());
});
 * @param htmls
 */
function ptyExportToExcel(fileName, htmls) {
    // var htmls = "";
    var uri = 'data:application/vnd.ms-excel;base64,';
    var template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}</table></body></html>';
    var base64 = function (s) {
        return window.btoa(unescape(encodeURIComponent(s)))
    };

    var format = function (s, c) {
        return s.replace(/{(\w+)}/g, function (m, p) {
            return c[p];
        })
    };

    var ctx = {
        worksheet: 'Worksheet',
        table: htmls
    }


    var link = document.createElement("a");
    link.download = fileName; // "export.xls";
    link.href = uri + base64(format(template, ctx));
    link.click();
}

/**
 * jQuery dump plugin. Inspect object properties in a popup window.
 *
 * Copyright (c) 2012 Block Alexander
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 */
(function ($) {
    var __jqdump__dump_OFF = false;         // global OFF switch
    var position = { left: 100, top: 120 }; // popup window position
    var defaultDepth = 2;                   // default dump depth

    /**
     * Dump object content in popup window with prettyprint and subnavigation
     *
     * <example>
     * // dump navigator properties
     * $.dump(window.navigator, 1, "window.navigator");
     *
     * // this may be used to disable all following function calls
     * $.dump("off");
     * </example>
     *
     * @param(obj): object to dump, or "off" string to disable all dump calls
     * @param(iDepth): number, optional dumping depth, default 2
     * @param(sHistoryPath): string, optional global properties path relative to the initial dump object value, used for display only.
     * @returns: null
     */
    $.dump = function (obj, iDepth, sHistoryPath) {
        if (typeof(obj) == "string" && /^off$/i.test(obj)) { __jqdump__dump_OFF = true; }
        return __jqdump__dump(obj, iDepth, sHistoryPath);
    };

    /**
     * Dump object content in popup window with prettyprint and subnavigation
     *
     * <example>
     * $("#element").dump(1);
     * // same as
     * $.dump($("#element"), 1, "(#element)");
     * </example>
     *
     * Call type: window.dump/$.dump( ... )
     * @param(iDepth): number, optional dumping depth, default 2
     * @returns: null
     */
    $.fn.dump = function (iDepth) {
        return __jqdump__dump(this, iDepth, this.selector? "("+ this.selector +")" : "");
    };

    /**
     * Dump object content in popup window with prettyprint and subnavigation
     *
     * @param(obj): object to dump
     * @param(iDepth): number, optional dumping depth, default 2
     * @param(sHistoryPath): string, optional global properties path relative to the initial dump object value, used for display only.
     * @returns: null
     */
    function __jqdump__dump (obj, iDepth, sHistoryPath) {
        if (__jqdump__dump_OFF) { return null; }

        // store current object value to allow continious/recursive dump browsing via window.opener.__jqdump__
        __jqdump__ = {data: obj, dump: __jqdump__dump };

        // provide defaults as needed
        iDepth = (typeof(iDepth) == "number" && iDepth > 0? parseInt(iDepth, 10) : defaultDepth);
        sHistoryPath = (typeof(sHistoryPath) == "string" && sHistoryPath.length > 0? sHistoryPath : "OBJECT");

        // adjust new window position
        position = { top: (position.top - 30) % 120, left: (position.left - 10) % 100 };

        // try to popup blank page
        var dumpWindow = window.open("about:blank", "_blank"
            , "width=600,height=800,menubar=0,left="+ position.left +",top="+ position.top
            +",location=0,toolbar=0,status=0,scrollbars=1,resizable=1", true);

        // popup blocked?
        if (!dumpWindow || dumpWindow.closed == true) {
            if (confirm("Dump Window couldn't showup cause of popup blocker.\nContinue using current window?")) {
                dumpWindow = window;
            } else {
                return null;
            }
        }

        // fill the page with dump content
        dumpWindow.document.write("<html><head><title>"+ sHistoryPath +" @ "+ DateToHMSMString(new Date()) +"</title>"
            +"<meta http-equiv='Content-Type' content='text/html;charset=utf-8'/>"
            +"<style type='text/css'>"
            +" body{background-color:#fff;color:#000;font-size:12px;margin-top:24px;}"
            +" #toolbar{position:fixed;top:0px;right:0px;z-index:9999;}"
            +" span.p.a:hover,span.p.a:hover+span {background-color: #B5F5FF;}"
            +" a{text-decoration:none;}"
            +" a:hover{text-decoration:underline;}"
            +" .h{display:none;}"                     // hidden element
            +" .a{cursor:pointer;}"                   // link like element
            +" .s{color:#740;}"                       // string
            +" .k{color:#427;font-weight:bold;font-style:italic;}"      // key-word
            +" .c{color:#666;font-style:italic;}"     // comment
            +" .u{color:#259;}"                       // reserved value
            +" .p{color:#155;font-weight:bold;}"      // punctuation
            +" .d{color:#800;font-weight:bold;}"      // diggit
            +" .e{color:#900;font-style:italic;background-color:#FAA;}" // exception
            +" .t{color:#080;font-weight:bold;}"      // true boolean value
            +" .f{color:#800;font-weight:bold;}"      // false boolean value
            +" .arg{color:#000;font-weight:normal;}"  // number of function arguments
            +"</style></head><body>"
            +"<div id='toolbar'>"
            +" <input type='button' id='btnClose' value='Close' onclick='window.close();'/>"
            +" <input type='button' value='Collapse All' onclick='ToggleCollapse(true);'/>"
            +" <input type='button' value='Expand All' onclick='ToggleCollapse(false);'/>"
            +"</div>"
            +"<code><pre>"+ sHistoryPath +" <span class='p'>=</span> "
            + __jqdump__next(obj, "  ", iDepth, "__jqdump__.data", sHistoryPath)
            +"<span class='p'>;</span></pre></code>"
            // provide data and code to the parent window
            +"<sc"+"ript type='text/javascript'><!-"+"-"
            +"\n __jqdump__ = (window.opener? window.opener.__jqdump__ : window.__jqdump__);"
            +"\n if (!__jqdump__) { __jqdump__ = {data: null, dump: function (o) { if (JSON) { alert(JSON.stringify(o)); } } }; }"
            +"\n "
            // focus the close button to allow fast window close by pressing button [space]
            +"\n window.onload = function () {"
            +"\n   window.focus();"
            +"\n   document.getElementById('btnClose').focus();"
            +"\n }"
            +"\n "
            +"\n function ToggleCollapse (bCollapse) {"
            +"\n   var span = document.getElementsByTagName('span');"
            +"\n   for (var i = 0; i < span.length; i++) {"
            +"\n     if (span[i].getAttribute('title') != 'collapse/expand' || (i == 1 && bCollapse)) { continue; }"
            +"\n     span[i].nextSibling.className = bCollapse? 'h' : '';"
            +"\n   }"
            +"\n }"
            +"\n-"+"-></sc"+"ript></body></html>"
        );

        // finalize writings
        dumpWindow.document.close();

        // ensure new window has data and code to continue further dumps
        dumpWindow.__jqdump__ = {
            data: __jqdump__.data
            , dump: __jqdump__.dump
            //*dbg*/, history: sHistoryPath
        };

        /**
         * @param(obj): object to dump
         * @param(sIndent): string, used for object properties alignment indentation
         * @param(iDepth): number, dumping depth, defaults to 2
         * @param(sContextPath): string, evaluable object properties path relative to the current obj value, used onclick event
         * @param(sHistoryPath): string, global properties path relative to the initial dump obj value, used for display only
         */
        function __jqdump__next (obj, sIndent, iDepth, sContextPath, sHistoryPath) {
            var objType = typeof(obj);
            if (null == obj && objType != "undefined") { return "<span class='u'>null</span>"; }

            switch (objType) {
                case "object": break;
                case "undefined": return "<span class='u'>undefined</span>";
                case "string": return obj.length? "\"<span class='s'>"+ htmlEscape(obj) +"</span>\"" : "\"\"";
                case "number": return "<span class='d'>"+ obj.toString() +"</span>";
                case "boolean": return "<span class='"+ (obj? "t" : "f") +"'>"+ obj.toString() +"</span>";
                // allow dumping of function return value (simple function call without arguments)
                case "function": return format(
                    "<a href='javascript:;' class='k'"
                    +" onclick='__jqdump__.dump((function(){try{return {0}();}catch(xcp){return {EXCEPTION_WRAPPER:xcp.toString()};}})()"
                    +","+ defaultDepth +",this.title);' title='{1}()'>func"+"tion({2})</a>"
                    , sContextPath
                    , sHistoryPath
                    , (obj.length? "<span class='arg'>"+ obj.length +"</span>"  : "")
                );
                default: return "<span class='e'>/* Unknown object type: {"+ objType +"}*/</span>";
            }

            if (obj instanceof Date) { return "new Date(\""+ obj.toUTCString() +"\")"; }

            if (iDepth == 0) { // stop here and allow deeper dumping by a click
                return format("<a href='javascript:;' class='p' title='show more'"
                    +" onclick='__jqdump__.dump((function(){try{return {0};}catch(xcp){return {EXCEPTION_WRAPPER:xcp.toString()};}})(),"
                    + defaultDepth +",\"{1}\");'"
                    +">{ ... }</a>"
                    , sContextPath
                    , sHistoryPath.replace(/"/g, "\\\""));
            }

            var bIsArray = (obj instanceof Array)
                , sNewContextPath, sNewHistoryPath
                , obja = [], prop;

            var rv = [
                "<span class='p a' title='collapse/expand'"
                +" onclick='this.nextSibling.className=(this.nextSibling.className==\"h\"?\"\":\"h\")'"
                +">&#160;"+ (bIsArray? "[" : "{") +"&#160;</span><span>\n"
            ];

            try {
                // making sorted array of object property names
                if (bIsArray) {
                    for (var i = 0; i < obj.length; i++) { obja.push(i); }
                } else {
                    for (prop in obj) { obja.push(prop); }
                    obja.sort(function (a, b) {
                        return (isNaN(a)? (a.toLowerCase() >= b.toLowerCase()? 1 : -1) : (Number(a) >= Number(b))? 1 : -1);
                    });
                }

                // quering object with names via sorted array
                for (var c = 0, length = obja.length; c < length; c++) {
                    try {
                        prop = obja[c];
                        // skip self properties
                        if (/__jqdump__/.test(prop)) { continue; }

                        if (bIsArray) { // array index:
                            sNewContextPath = format("{0}[\"{1}\"]", sContextPath, prop);
                            sNewHistoryPath = format("{0}[\"{1}\"]", sHistoryPath, prop);
                            rv.push(format(
                                "{0}<span class='a c' onclick='alert(this.title);' title='{1}'>/*{2}*/</span> "
                                , sIndent, sNewHistoryPath, prop
                            ));
                        } else {// object property:
                            if (/(\W)|(^\d)/.test(prop)) {//- as string
                                sNewContextPath = format("{0}[\"{1}\"]", sContextPath, prop);
                                sNewHistoryPath = format("{0}[\"{1}\"]", sHistoryPath, htmlEscape(prop));
                                rv.push(format(
                                    "{0}<span class='s a' onclick='alert(this.title);' title='{1}'>\"{2}\"</span> <span class='p'>:</span> "
                                    , sIndent, sNewHistoryPath, htmlEscape(prop)
                                ));
                            } else {//- as conventional variable name
                                sNewContextPath = format("{0}.{1}", sContextPath, prop);
                                sNewHistoryPath = format("{0}.{1}", sHistoryPath, htmlEscape(prop));
                                rv.push(format(
                                    "{0}<span class='a' onclick='alert(this.title);' title='{1}'>{2}</span> <span class='p'>:</span> "
                                    , sIndent, sNewHistoryPath, htmlEscape(prop)
                                ));
                            }
                        }

                        rv.push(__jqdump__next(obj[prop], sIndent +"  ", iDepth - 1, sNewContextPath, sNewHistoryPath));
                    } catch (xcp) {
                        rv.push(format("<span class='e'>/*{0} - {1}*/</span>", xcp.name, xcp.message));
                    }

                    rv.push((c < (obja.length-1)? "<span class='p'>,</span>\n" : "\n"));
                }
            } catch (xcp) {
                rv.push(format("<span class='e'>/*{0} - {1}*/</span>", xcp.name, xcp.message));
            }

            rv.push(format("{0}</span><span class='p'>{1}</span>", sIndent.replace("  ", ""), (bIsArray? "]" : "}")));

            return rv.join("");
        };

        /**
         * Escape native string characters before writing it as html text
         */
        function htmlEscape (str) {
            // trying to speedup the process by checking the length
            return str.length? str.replace(/&/g, "&amp;").replace(/\</g, "&lt;").replace(/\>/g, "&gt;") : str;
        };

        /**
         * Replaces each format item "{n}" in `this` string with the string equivalent of a corresponding
         * parameters object's value. For example "{0}" reffers to the second argument, "{1}" to the third.
         *
         * @note: format identifier "{i}" may be repeated multiple times in any order as long as it reffers
         * to corresponding position of the argument
         * @param(0): first parameter is a format-string, containing meta information of insertion positions
         * @param(...): any type, other arguments reffered by the format-string will be evaluated to string
         * @return: string, formating result
         */
        function format (/* ... */) {
            var match = null, rv = arguments[0];

            for (var c = 1, length = arguments.length; c < length; c++) {
                match = new RegExp("\\{"+ (c - 1) +"\\}", "g");
                if (match.test(rv)) {
                    rv = rv.replace(match, typeof(arguments[c]) == "undefined" ? "(undefined)" : arguments[c].toString());
                }
            }

            match = null;
            return rv;
        };

        /**
         * Time to string in HH:MM:SS.mmm format
         * @param(d): date object
         */
        function DateToHMSMString (d) {
            var iHours = d.getHours(), iMinutes = d.getMinutes(), iSeconds = d.getSeconds(), iMSeconds = d.getMilliseconds();

            return (iHours < 10? "0" : "") + iHours +":"+ (iMinutes < 10? "0" : "") + iMinutes
                +":"+ (iSeconds < 10? "0" : "") + iSeconds
                +"."+ (iMSeconds < 100? "0" : "") + (iMSeconds < 10? "0" : "") + iMSeconds;
        }

        return null;
    };

})(jQuery);
