/**
 *
 */
var APP = (function() {
    
    //
    appConfig = {
        'debugEnabled': true    // Whether or not to use console for debugging
    };

    /**
     * ----------------------------------------------------------------------------------
     * Console
     * ----------------------------------------------------------------------------------
     */
    this.Console = (function() {
    
        /**
         * ------------------------------------------------------------------------------
         * _checkEnabled
         *
         * @return bool. 
         * ------------------------------------------------------------------------------
         */
        function _checkEnabled() {
        
            if (typeof appConfig.debugEnabled == 'undefined') {
                return false;
            } else {
                return Boolean(appConfig.debugEnabled);
            }
        }
        
        /**
         * ------------------------------------------------------------------------------
         * _log
         *
         * @param string msg_ The message to use. 
         * ------------------------------------------------------------------------------
         */
        function _log(msg_) {

            if (typeof window.console.log == 'undefined') {
                return;
            }

            if (_checkEnabled()) {
                var _msg = _getMsg(msg_);
                window.console.log(_msg);
            }
        }
        
        /**
         * ------------------------------------------------------------------------------
         * _info
         *
         * @param string msg_ The message to use. 
         * ------------------------------------------------------------------------------
         */
        function _info(msg_) {

            if (typeof window.console.info == 'undefined') {
                return;
            }

            if (_checkEnabled()) {
                var _msg = _getMsg(msg_);
                window.console.info(_msg);
            }
        }

        /**
         * ------------------------------------------------------------------------------
         * _warn
         *
         * @param string msg_ The message to use. 
         * ------------------------------------------------------------------------------
         */
        function _warn(msg_) {

            if (typeof window.console.warn == 'undefined') {
                return;
            }

            if (_checkEnabled()) {
                var _msg = _getMsg(msg_);
                window.console.warn(_msg);
            }
        }
        
        /**
         * ------------------------------------------------------------------------------
         * _error
         *
         * @param string msg_ The message to use. 
         * ------------------------------------------------------------------------------
         */
        function _error(msg_) {

            if (typeof window.console.error == 'undefined') {
                return;
            }

            if (_checkEnabled()) {
                var _msg = _getMsg(msg_);
                window.console.error(_msg);
            }
        }
        
        /**
         * ------------------------------------------------------------------------------
         * _debug
         *
         * @param string msg_ The message to use. 
         * ------------------------------------------------------------------------------
         */
        function _debug(msg_) {

            if (typeof window.console.debug == 'undefined') {
                return;
            }

            if (_checkEnabled()) {
                var _msg = _getMsg(msg_);
                window.console.debug(_msg);
            }
        }
        
        /**
         * ------------------------------------------------------------------------------
         * _clear
         * ------------------------------------------------------------------------------
         */
        function _clear() {

            if (_checkEnabled()) {
                try {
                    window.console.clear();
                } catch (err) {
                    //
                }
            }
        }
        
        /**
         * ------------------------------------------------------------------------------
         *      
         * ------------------------------------------------------------------------------
         */
        function _init() {
        
            if (!window.console) { window.console = {}; }
            
            //
            APP.Console.info('APP.Console:init()');
        }
        
        /**
         * ------------------------------------------------------------------------------
         *
         * @internal
         * @param mixed msg_
         * @return string
         * ------------------------------------------------------------------------------
         */
        function _getMsg(msg_) {
        
            var _msg = msg_;
            if (typeof _msg == 'string') {
                if (_msg.length < 1) {
                    _msg = 'Empty message string';
                }
            }
            
            return _msg;
        }
        
        /**
         * ------------------------------------------------------------------------------
         *
         * ------------------------------------------------------------------------------
         */
        return {
            'init': _init,
            'log': _log,
            'info': _info,
            'warn': _warn,
            'error': _error,
            'debug': _debug,
            'clear': _clear
        };

    })();

    /**
     * ----------------------------------------------------------------------------------
     * Registry
     * ----------------------------------------------------------------------------------
     */
    this.Registry = (function() {

        var _registry;
        
        /**
         * ------------------------------------------------------------------------------
         *
         * ------------------------------------------------------------------------------
         */
        function _init() {

            _registry = [];
            
            if (typeof window.tfd_tk !== 'undefined') {
                _registry['token'] = window.tfd_tk;
            } else {
                _registry['token'] = 0;
            }
            
            APP.Console.info('APP.Registry:init()');
        }
        
        /**
         * ------------------------------------------------------------------------------
         * _get
         *
         * @param string key_
         *      The key name to get.
         * @param mixed default_
         *      Return value is key_ was not found (optional).
         *      Defaults to undefined.    
         * ------------------------------------------------------------------------------
         */
        function _get(key_, default_) {
        
            var args = {
                'key': undefined,
                'default': undefined
            };
            
            switch (arguments.length) {
                case 1:
                    args.key = key_;
                    break;
                case 2:
                    args.key = key_;
                    args.default = default_;
                    break;
                default:
                    APP.Console.error('APP.Registry._get - not enough arguments');
                    return args.default;
                    break;
            }
        
            //
            if (typeof key_ != 'string') {
                APP.Console.error('APP.Registry._get - argument[0] is not a string');
                return args.default;
            }
            
            if (typeof _registry[args.key] != 'undefined') {
                return _registry[args.key];
            } else {
                if (typeof _registry[args.default] != 'undefined') {
                    return args.default;
                } else {
                    return undefined;
                }
            }
        }
        
        /**
         * ------------------------------------------------------------------------------
         *
         * ------------------------------------------------------------------------------
         */
        function _set(key_, value_, override_) {
        
            var args = {
                'key': undefined,
                'value': undefined,
                'override': false
            };
            
            switch (arguments.length) {
                case 2:
                    args.key   = key_;
                    args.value = value_;
                    break;
                case 3:
                    args.key   = key_;
                    args.value = value_;
                    if (typeof override_ == 'boolean') {
                        args.override = override_;
                    }
                    break;
                default:
                    APP.Console.error('APP.Registry._set - not enough arguments');
                    break;
            }
            
            //
            if (typeof key_ != 'string') {
                APP.Console.error('APP.Registry._set - argument[0] is not a string');
                return args.default;
            }
            
            if (typeof _registry[args.key] != 'undefined') {
                if (args.override) {
                    _registry[args.key] = args.value;
                } else {
                    APP.Console.warn('APP.Registry._set - Key: ' + args.key + ' already exists');
                }
            } else {
                _registry[args.key] = args.value;
            }
        }
        
        
        /**
         * ------------------------------------------------------------------------------
         *
         * ------------------------------------------------------------------------------
         */
        return {
            'init': _init,
            'get': _get,
            'set': _set
        };
        
    })();

    /**
     * ----------------------------------------------------------------------------------
     * Vars
     * array (
  't' => '240732566',
)     * ----------------------------------------------------------------------------------
     */
    this.Vars = (function() {

        var _getVars  = {};
        var _postVars = {};
        
        /**
         * ------------------------------------------------------------------------------
         *
         * ------------------------------------------------------------------------------
         */
        function _init() {

            //
            document.location.search.replace(/\??(?:([^=]+)=([^&]*)&?)/g, function () {
                function decode(s) {
                    return decodeURIComponent(s.split("+").join(" "));
                }
                _getVars[decode(arguments[1])] = decode(arguments[2]);
            });
            
            APP.Console.info('APP.Vars:init()');
            //APP.Console.debug(_getVars);
        }

        /**
         * ------------------------------------------------------------------------------
         * _get
         *
         * @param string key_
         *      The GET variables key name.
         * @param mixed default_
         *      Return value is key_ was not found (optional).
         *      Defaults to undefined.    
         * ------------------------------------------------------------------------------
         */
        function _get(key_, default_) {
        
            var args = {
                'key': undefined,
                'default': undefined
            };
            
            switch (arguments.length) {
                case 1:
                    args.key = key_;
                    break;
                case 2:
                    args.key = key_;
                    args.default = default_;
                    break;
                default:
                    APP.Console.error('APP.Vars._get - not enough arguments');
                    break;
            }
        
            //
            if (typeof key_ != 'string') {
                APP.Console.error('APP.Vars._get - argument[0] is not a string');
                return;
            }
            
            //
            if (typeof _getVars[args.key] != 'undefined') {
                return _getVars[args.key];
            } else {
                if (typeof _getVars[args.default] != 'undefined') {
                    return args.default;
                } else {
                    return undefined;
                }
            }
        }

        /**
         * _post
         *
         * @param string key_
         *      The POST variables key name.
         * @param mixed default_
         *      Return value is key_ was not found (optional).
         *      Defaults to undefined.
         */
        function _post(key_, default_) {
        
            var args = {
                'key': undefined,
                'default': undefined
            };
            
            switch (arguments.length) {
                case 1:
                    args.key = key_;
                    break;
                case 2:
                    args.key = key_;
                    args.default = default_;
                    break;
                default:
                    APP.Console.error('APP.Vars._post - not enough arguments');
                    break;
            }
            
            //
            if (typeof key_ != 'string') {
                APP.Console.error('APP.Vars._post - argument[0] is not a string');
                return;
            }

            //
            if (typeof _postVars[args.key] != 'undefined') {
                return _postVars[args.key];
            } else {
                if (typeof _postVars[args.default] != 'undefined') {
                    return args.default;
                } else {
                    return undefined;
                }
            }
        }
        
        /**
         *
         */
        function _setPost(json_) {
            
            _postVars = json_;
        }
        
        /**
         * ------------------------------------------------------------------------------
         *
         * ------------------------------------------------------------------------------
         */
        return {
            'init': _init,
            'get': _get,
            'post': _post,
            'setPost': _setPost
        };
        
    })();

    /**
     * ----------------------------------------------------------------------------------
     * APP.Xhr
     * ----------------------------------------------------------------------------------
     */
    this.Xhr = function(settings_, options_, callback_) {
        
        var _d = false,
            _settingsDefault = {
                'url': window.baseurl,
                'cache': false,
                'type': 'post',
                'dataType': 'json',
                'timeout': 10000,
                'global': false,
                'headers': { 'docready_xhr': true },
                'useAppLoader': false,
                'data': {
                    'token': '0' //prepared for future use
                }
            },
            _settings;
        
        //
        _settings = _settingsDefault;
        
        if (typeof settings_ == 'undefined') {
            APP.Console.error('APP.Xhr argument[0] is missing');
            return _d;
        }
        
        if (typeof options_ !== 'object') {
            APP.Console.error('APP.Xhr argument[1] is not an object');
            return _d;
        }
        
        if (typeof settings_ == 'object') {
            // Handle serialized settings data
            if (typeof settings_[0] != 'undefined') {
                var i, elm = {};
                for (i in settings_) {
                    elm[settings_[i]['name']] = settings_[i]['value'];
                }
                $.extend(true, _settings, elm);
            } else {
                $.extend(true, _settings, settings_);
            }
        }
        
        if (typeof options_ == 'object') {
            // Handle serialized form data
            if (typeof options_[0] != 'undefined') {
                var i, elm = {};
                for (i in options_) {
                    elm[options_[i]['name']] = options_[i]['value'];
                }
                $.extend(true, _settings.data, elm);
            
            } else {
                $.extend(true, _settings.data, options_);
            }
        }
        
        //
        if (_settings.useAppLoader && $('#app-loader').length) {
            APP.Loader.show();
        }
        
        $.ajax(_settings)
            .done(function(res, textStatus, jqXHR) {
                if (typeof res == 'object') {
                    // Object properties: success (bool), msg (string) and data (array) are mandatory
                    if (res.success) {
                        APP.Console.info('APP.Xhr:_load() SUCCESS');
                    } else {
                        var errMsg = res.msg;
                        if (res.msg.length > 0) {
                            APP.Console.warn('APP.Xhr:_load() ERROR: ' + errMsg);
                        }
                    }
                    if (typeof callback_ !== 'undefined') {
                        callback_(res);
                        //return;
                    }

                } else {
                    // Simple return
                    alert('APP.Xhr unexpected return');
                }
                _d = true;
            })
            .fail(function(jqXHR, textStatus, errorThrown) {
                _d = false;
                APP.Console.warn('APP.Xhr:_load() fail');
            })
            .always(function() {
                //
                if (_settings.useAppLoader && $('#app-loader').length) {
                    APP.Loader.hide();
                }
                APP.Console.info('APP.Xhr:_load() always');
                return _d;
            });
    };
    /**
     * ----------------------------------------------------------------------------------
     * APP.Loader
     *
     * #app-loader {
     *     position: fixed;
     *     z-index: 999;
     *     height: 100%;
     *     width: 100%;
     *     top: 0;
     *     left: 0;
     *     background-color: Black;
     *     filter: alpha(opacity=60);
     *     opacity: 0.6;
     *     -moz-opacity: 0.8;
     * }
     *
     * #app-loader .center {
     *     z-index: 1000;
     *     margin: 300px auto;
     *     padding: 10px;
     *     width: 148px;
     *     background-color: #fff;
     *     border-radius: 10px;
     *     filter: alpha(opacity=100);
     *     opacity: 1;
     *     -moz-opacity: 1;
     * }
     *
     * #app-loader .center img
     * {
     *     height: 128px;
     *     width: 128px;
     * }
     * ----------------------------------------------------------------------------------
     */
    this.Loader = (function() {
    
        var _cfg = {
            'shown': false
        }
        
        /**
         * ------------------------------------------------------------------------------
         *      
         * ------------------------------------------------------------------------------
         */
        function _init() {
        
            if (!$('#app-loader').length) {
                
                $('body script:eq(0)').before(function() {
                    var html = ''
                        + '<!-- #app-loader -->'
                        + '<div id="app-loader" style="display:none">'
                            + '<div class="center">'
                                
                            + '</div>'
                        + '</div>'
                        + '<!-- /#app-loader -->';
                
                    return html;
                });
            }
            
            //
            APP.Console.info('APP.Loader:init()');
        }
        
        /**
         * ------------------------------------------------------------------------------
         *      
         * ------------------------------------------------------------------------------
         */
        function _show() {

            if (_cfg.shown === true) {
                return;
            }

            $('#app-loader').show();
            _cfg.shown = true;
        }
        
        /**
         * ------------------------------------------------------------------------------
         *      
         * ------------------------------------------------------------------------------
         */
        function _hide() {

            if (_cfg.shown === false) {
                return;
            }
            
            $('#app-loader').hide();
            _cfg.shown = false;
        }
        
        /**
         * ------------------------------------------------------------------------------
         *
         * ------------------------------------------------------------------------------
         */
        return {
            'init': _init,
            'show': _show,
            'hide': _hide
        };
    
    })();
    /**
     * ----------------------------------------------------------------------------------
     * Scroll
     * ----------------------------------------------------------------------------------
     */
    this.Scroll = {

        /**
         * ------------------------------------------------------------------------------
         * Convenience method used to animate vertical scrolling to page anchor.
         *
         * @public
         * @param string s_
         *      The anchor name to scroll to.
         * @return void
         * ------------------------------------------------------------------------------
         */
        'toAnchor': function(s_) {

            if (typeof s_ !== 'string') {
                return;
            }
            var a = $("a[name='"+ s_ +"']");
            try {
                $('html, body').animate({
                    scrollTop: a.offset().top
                }, 'slow');
            } catch (e) { ; }
        },
        
        /**
         * ------------------------------------------------------------------------------
         * Convenience method used to animate vertical scrolling to page anchor.
         *
         * @public
         * @param object elm_
         *      jQuery element object.
         * @param int t_
         *      Animation time in milliseconds.
         * @return void
         * ------------------------------------------------------------------------------
         */
        'toElement': function(elm_, t_) {

            var position = false;
            try {
                position = elm_.offset().top;
            } catch (err) { ; }

            if (!position) {
                return;
            }

            if (typeof t_ === 'undefined' || !t_) {
                t_ = 1000; // default time
            }

            $('html, body').animate({
                scrollTop : position
            }, t_);
        },
        
        /**
         * ------------------------------------------------------------------------------
         * Convenience method used to animate vertical scrolling.
         *
         * @public
         * @param object elm_
         *      jQuery element object.
         * @param int options_
         *      Options. (maxY, topMargin)
         * @return void
         * ------------------------------------------------------------------------------
         */
        'followTo': function(elm_, options_) {
            var elm = elm_,
                originalY = elm.offset().top,
                topMargin = 20, // Space between element and top of screen (when scrolling)
                maxY = false,
                lastY;
            
            if (typeof options_ === 'object') {
                if (typeof options_.elementMaxY !== 'undefined') {
                    maxY = $('#' + options_.elementMaxY).offset().top;
                }
                if (typeof options_.topMargin !== 'undefined') {
                    topMargin = Number(options_.topMargin);
                }
            }
            
            // Should probably be set in CSS; but here just for emphasis
            elm.css('position', 'relative');
            
            $(window).on('scroll', function(event) {
                var scrollTop = $(window).scrollTop();
                elm.stop(false, false)
                    .animate({
                        'top': (function() {
                            var tp = 0;
                            if (scrollTop < originalY) {
                                //
                            } else {
                                tp =  scrollTop - originalY + topMargin;
                                if (maxY) {
                                    if (tp >= maxY - originalY + topMargin) {
                                        tp = maxY - originalY + topMargin;
                                    }
                                }
                            }
                            return tp;
                        })()
                    }, 300);
            });
        },

        /**
         * ------------------------------------------------------------------------------
         * Scroll back to page top.
         *
         * Convenience method to scroll the current web page to it's top.
         * (Used in Footer)
         *
         * @public
         * @return false
         * ------------------------------------------------------------------------------
         */
        'toTop': function(duration_, callback_) {
        
            var d = (typeof duration_ !== 'undefined') ? duration_ : 'slow';
            var func = (typeof callback_ !== 'undefined') ? callback_ : {};
            
            $('html,body')
                .animate({'scrollTop': 0}, d, func);
            return false;
        },
        
        'init': function() {
            APP.Console.info('APP.Scroll:init()');
        }
    };


	/**
     * ----------------------------------------------------------------------------------
     * APP.Page
     * ----------------------------------------------------------------------------------
     */
    this.Page = {};
    
    /**
     * ----------------------------------------------------------------------------------
     * APP.Page.Global
     * ----------------------------------------------------------------------------------
     */
    this.Global = {};

    /**
     * ----------------------------------------------------------------------------------
     * Init APP
     * ----------------------------------------------------------------------------------
     */
    this.init = function() {

        //
        APP.Console.info('APP:init()');

        try { this.Console.init(); } catch(err) { ; }
try { this.Registry.init(); } catch(err) { ; }
try { this.Vars.init(); } catch(err) { ; }
try { this.Xhr.init(); } catch(err) { ; }
try { this.Loader.init(); } catch(err) { ; }
try { this.Scroll.init(); } catch(err) { ; }

        // 
        if (typeof this.Page.init != 'undefined') {
            this.Page.init();
        } else {
            APP.Console.info('APP.Page:init() - UNUSED');
        }
        
        // 
        if (typeof this.Global.init != 'undefined') {
            this.Global.init();
        } else {
            APP.Console.info('APP.Global:init() - UNUSED');
        }

        //
        //APP.Console.info('Token: ' + APP.Registry.get('token', 'false'));
    };
	
	/**
     * ----------------------------------------------------------------------------------
     *
     * ----------------------------------------------------------------------------------
     */
    return this;

})();

/**
 * --------------------------------------------------------------------------------------
 *
 * --------------------------------------------------------------------------------------
 */
Number.prototype.formatMoney = function(c, d, t) {
    var n = this, 
        c = isNaN(c = Math.abs(c)) ? 2 : c, 
        d = d == undefined ? "." : d, 
        t = t == undefined ? "," : t, 
        s = n < 0 ? "-" : "", 
        i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", 
        j = (j = i.length) > 3 ? j % 3 : 0;
    return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
};
