/**
 * 入口
 * @author zhouwf 2018-9-20
 */
;(function (global, undefined) {
    "use strict";

    /**
     * 配置文件地址
     */
    var HORIZON_CONFIG_PATH = './assets/config',
        HORIZON_CONFIG_URL = '/config.json';
    
    /**
     * 应用根路径, 由地址栏中获取
     */
    var APP_ROOT_PATH = (function() {
        var path = (self.location + '').split('/');
        return path[3] && path[3] !== '#' ? ('/' + path[3]) : '';
    })();

    /**
     * 当前脚本DOM对象
     */
    var CURRENT_SCRIPT = (function() {
        var script = document.currentScript;
        if (!script) {
            var scripts = document.scripts;
            for (var i = scripts.length - 1; i >= 0; i--) {
                if (scripts[i].src.indexOf('horizon.js')) {
                    script = scripts[i];
                    break;
                }
            }
        }
        var configPath = script.getAttribute('data-config-path');
        if (configPath) {
            HORIZON_CONFIG_PATH = configPath;
        }
        return script;
    })();
    
    // 重置配置文件地址
    HORIZON_CONFIG_URL = HORIZON_CONFIG_PATH + HORIZON_CONFIG_URL;

    /**
     * 当前脚本指定的应用入口脚本路径
     */
    var MAIN_SCRIPT_URL = CURRENT_SCRIPT.getAttribute('data-main');

    var isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]';

    /**
     * JSON polyfill
     */
    if ( !global.JSON ) {
        global.JSON = {
            parse: function(data) {
                var _json = data;
                if(/^\{.*\}$/.test(data)) {
                    eval('(0 ? 0 : _json = ' + data + ')');
                }
                return _json;
            },
            stringify: function(data) {
                var _str = data;
                if(typeof data !== 'string') {
                    eval('(0 ? 0 : _str = "' + data + '")');
                }
                return _str;
            }
        };
    }
    
    /**
     * 配置
     */
    var Config = {
        /**
         * ------------------------- 产品配置信息 ----------------------------
         * 默认数据来源为读取配置文件: HORIZON_CONFIG_URL
         * 配置中可使用的变量列表:
         * {root} 会替换成地址栏中获取到的应用名, 如果项目没有应用名则不使用此变量
         * {app} 会替换成应用根路径
         * {workflow} 会替换成流程引擎根路径
         * {designer} 会替换成表单引擎根路径
         * {assets} 会替换成资源文件根路径
         * {env} 会根据当前环境配置替换成对应产品出厂默认路径
         * @example 
         * {
         *     // 当前环境, 0: 流程引擎, 1: 表单引擎, 2: 流程&表单引擎集成环境
         *     "environment": 1,
         *     // 版本
         *     "version": "8.0",
         *     // 登录页面地址, 可用变量 {root}, {app}, {workflow}, {designer}
         *     "loginUrl": "",
         *     // 退出请求地址, 可用变量 {root}, {app}, {workflow}, {designer}
         *     "logoutUrl": "",
         *     // 帮助页面地址, 可用变量 {root}, {app}, {workflow}, {designer}
         *     "helpUrl": "./help/index.html",
         *     // 隐私页面地址, 可用变量 {root}, {app}, {workflow}, {designer}
         *     "privacyUrl": "",
         *     // 条款页面地址, 可用变量 {root}, {app}, {workflow}, {designer}
         *     "clauseUrl": "",
         *  
         *     // 路径配置
         *     "path": {
         *         // 应用根路径, 可用变量 {root}
         *         "app": "{root}",
         *         // 流程引擎根路径, 可用变量 {root}, {app}
         *         "workflow": "{app}/workflow",
         *         // 表单引擎根路径, 可用变量 {root}, {app}
         *         "designer": "{app}/designer",
         *         // 资源文件根路径, 可用变量 {root}, {app}, {workflow}, {designer}, {env}
         *         "assets": "{env}/assets",
         *         // 第三方插件根路径, 可用变量 {root}, {app}, {workflow}, {designer}, {assets}, {env}
         *         "plugins": "{env}/plugins",
         *         // 服务端请求路径, 可用变量 {root}, {app}
         *         "server": "{app}",
         *         // 服务端请求前缀, 可用变量 {env}
         *         "serverUrlPrefix": "/horizon/{env}",
         *         // 服务端请求后缀
         *         "serverUrlSuffix": ".wf"
         *     }
         * }
         */
        data: {},
        /**
         * 获取
         */
        ready: function(callback) {
            if (HORIZON_CONFIG_URL) {
                var _this = this,
                    xmlhttp = new XMLHttpRequest();
                xmlhttp.onreadystatechange = function() {
                    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                        _this.data = JSON.parse(xmlhttp.responseText);
                        if (typeof(_this.data) == 'string') {
                            _this.data = eval("("+xmlhttp.responseText+")")
                        }
                        _this.format();
                        _this.setGlobalPaths(_this.data.path);
                        callback(_this.data);
                    }
                };
                xmlhttp.open('GET', HORIZON_CONFIG_URL, true);
                xmlhttp.send();
            } else {
                this.setGlobalPaths(this.data.path);
                callback(this.data);
            }
        },
        /**
         * 路径中可用变量
         */
        pathVars: (function() {
            var env = ['env'],
                root = ['root'],
                app = root.concat(['app']),
                product = app.concat(['workflow', 'designer']),
                all = product.concat(['assets', 'plugins']);
            return {
                env: env,
                root: root,
                app: app,
                product: product,
                all: all
            };
        })(),
        /**
         * 环境变量
         */
        envVars: function() {
            var config = this.data,
                def = {
                    assets: config.path.workflow,
                    plugins: config.path.workflow,
                    serverUrlPrefix: 'workflow'
                };
            if (config.environment === 1) {
                def.assets = config.path.designer;
                def.plugins = config.path.designer + '/assets';
                def.serverUrlPrefix = 'designer';
            }
            return def;
        },
        /**
         * 替换变量
         * */
        replaceVars: function(data, vars, envVal) {
            var config = this.data;
            for (var i = 0, iLen = vars.length; i < iLen; i++) {
                var reg = new RegExp('\{' + vars[i] + '\}');
                if (reg.test(data)) {
                    var path;
                    if (vars[i] === 'root') {
                        path = APP_ROOT_PATH;
                    } else if (vars[i] === 'env') {
                        path = envVal || '';
                    } else {
                        path = config['path'][vars[i]];
                    }
                    data = data.replace(reg, path);
                }
            }
            return data;
        },
        /**
         * 格式化
         */
        format: function() {
            var _this = this,
                config = this.data;
            if (config.path) {
                // 变量
                var path = {
                    app: _this.pathVars.root,
                    workflow: _this.pathVars.app,
                    designer: _this.pathVars.app,
                    assets: _this.pathVars.product.concat(_this.pathVars.env),
                    plugins: _this.pathVars.product.concat(['assets'], _this.pathVars.env),
                    server: _this.pathVars.app,
                    serverUrlPrefix: _this.pathVars.env
                };
                // 处理path变量
                for (var key in path) {
                    var envVars = this.envVars();
                    config['path'][key] = _this.replaceVars(config['path'][key], path[key], envVars[key]);
                }
                // 处理其它变量
                for (var key in config) {
                    if (key === 'path') return;
                    config[key] = _this.replaceVars(config[key], _this.pathVars.product);
                }
            }
            return config;
        },
        /**
         * 设置全局路径配置变量 PS: 为了兼容旧版本而存在
         */
        setGlobalPaths: function(path) {
            if (!global['horizonConfigPaths']) {
                global['horizonConfigPaths'] = {
                    // 工程上下文路径
                    apppath: path.app,
                    // 后台服务根路径
                    serverpath: path.server,
                    // 引擎文件根路径
                    syspath: path.workflow,
                    // 第三方插件根路径
                    pluginpath: path.plugins,
                    // 资源文件根路径
                    assetspath: path.assets,
                    // 公用页面路径
                    commonpath: path.workflow + '/common',
                    // 服务器请求前缀
                    urlprefix: path.server + path.serverUrlPrefix,
                    // 服务器请求后缀
                    urlsuffix: path.serverUrlSuffix,
                    // 流程框架路径
                    flowpath: path.workflow + '/module/workflow/index.html'
                }
            }
        }
    };

    var Util = {
        /**
         * 获取节点的style属性值
         * */
        getStyle: function(node, name) {
            var style = node.currentStyle || window.getComputedStyle(node, null);
            return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](name);
        },
        /**
         * 载入CSS
         * */
        link: function(end, href, fn, cssname, attr) {
            var _this = this;
            if (typeof end === 'string') {
                attr = cssname;
                cssname = fn;
                fn = href;
                href =  end;
                end = false;
            }
            if (typeof fn === 'string') {
                attr = cssname;
                cssname = fn;
            } else if (typeof fn === 'object') {
                attr = fn;
            }
            if (typeof cssname === 'object') {
                attr = cssname;
            }
            var app = (cssname || href).replace(/\.|\//g, '');
            var id = 'horizon-css-' + app, timeout = 0;

            if (!document.getElementById(id)) {
                var head = document.getElementsByTagName('head')[0],
                    link = document.createElement('link');
                if (/\{*\}/g.test(href)) {
                    href = Config.replaceVars(href, Config.pathVars.all);
                }
                if (!(/\.css$/.test(href))) {
                    href += '.css';
                }
                if (Config.data.version) {
                    href += '?v=' + Config.data.version;
                }
                link.rel = 'stylesheet';
                link.href = href;
                link.id = id;
                if (typeof attr === 'object') {    
                    for (var key in attr) {
                        link.setAttribute(key, attr[key]);
                    }    
                }
                var main = document.querySelector('.main-stylesheet');
                main = main.length ? main[0] : main;
                if (!end && main) {
                    head.insertBefore(link, main);
                } else {
                    head.appendChild(link);
                }

                if (global.respond && document.all && !document.addEventListener) {
                    link.attachEvent('onload', function() {
                        global.respond.update();
                    });
                }
            }

            if (typeof fn !== 'function') return;
                
            // 轮询css是否加载完毕
            (function poll() {
                if (++timeout > 8 * 1000 / 100) {
                    return global.console && console.error('horizon.css: Invalid');
                }
                parseInt(_this.getStyle(document.getElementById(id), 'width')) === 1989 ? fn() : setTimeout(poll, 100);
            }());
        },
        /**
         * 载入JS
         * */
        script: function(src, fn, jsname, attr) {
            if (typeof fn === 'string') {
                if (typeof jsname === 'object') {
                    attr = jsname;
                }
                jsname = fn;
            } else if (typeof fn === 'object') {
                attr = fn;
            }
            if (typeof jsname === 'object') {
                attr = jsname;
            }
            var app = (jsname || src).replace(/\.|\//g, ''),
                id = 'horizon-js-' + app;      
            
            if (!document.getElementById(id)) {
                var head = document.getElementsByTagName('head')[0],
                    node = document.createElement('script');
                
                if (/\{*\}/g.test(src)) {
                    src = Config.replaceVars(src, Config.pathVars.all);
                }
                if (!(/\.js$/.test(src))) {
                    src += '.js';
                }
                if (Config.data.version) {
                    src += '?v=' + Config.data.version;
                }
                node.charset = 'utf-8';
                node.src = src;
                node.id = id;
                if (typeof attr === 'object') {    
                    for (var key in attr) {
                        node.setAttribute(key, attr[key]);
                    }    
                }
                head.appendChild(node);
            
                if (typeof fn !== 'function') return;

                if (node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && !isOpera) {
                    node.attachEvent('onreadystatechange', function() {
                        (node.readyState === 'complete' || node.readyState === 'loaded') && fn();
                    });
                } else {
                    node.addEventListener('load', function() { fn() }, false);
                }
            } else if (typeof fn === 'function') fn();
        },
        /**
         * jQuery Ajax Setup
         */
        jQueryAjaxSetup: function(jquery) {
            jquery = jquery || global.jQuery || global.$;
            jquery && jquery.ajaxSetup({
                headers: {
                    'access_token': (function () {
                        var token = global.localStorage.getItem('horizon_token');
                        if (token) {
                            token = JSON.parse(token).token;
                        }
                        return token;
                    })()
                },
                xhrFields: {
                    withCredentials: true
                },
                dataFilter:function (data, type){
                    if(type == 'json' && typeof data == 'string') {
                        try {
                            var responseText = JSON.parse(data);
                            if (responseText.status === 'error' && responseText.code === 401) {
                                location.href = Config.data.loginUrl;
                                return ;
                            }
                            if ((responseText.status === 'error' && responseText.code === 403) || (responseText.msg === 403 && responseText.restype === "err")) {
                                if(Config.data['403Url']  !== undefined){
                                    location.href = Config.data['403Url'];
                                    return ;
                                }
                            }
                        }catch (e){
                            if (data == 'licensetimeout') {
                                location.href = Config.data.path[Config.data.environment === 1 ? 'designer' : 'app'] + '/init/config/index.html';
                            }
                            if (data == 'toHome') {
                                location.href = Config.data.path[Config.data.environment === 1 ? 'designer' : 'app'] + '/welcome.html';
                            }
                        }

                    }
                    return data;
                },
                complete: function (XMLHttpRequest, textStatus) {
                    var responseText = XMLHttpRequest.responseText;
                    try {
                        if (responseText){
                            responseText = JSON.parse(responseText);
                            if (responseText.status === 'error' && responseText.code === 401) {
                                location.href = Config.data.loginUrl;
                                return;
                            }
                            if ((responseText.status === 'error' && responseText.code === 403) || (responseText.msg === 403 && responseText.restype === "err")) {
                                if(Config.data['403Url']  !== undefined){
                                    location.href = Config.data['403Url'];
                                    return;
                                }
                            }
                        }
                    } catch (e) {
                        if (responseText.toLowerCase() === 'licensetimeout') {
                            location.href = Config.data.path[Config.data.environment === 1 ? 'designer' : 'app'] + '/init/config/index.html';
                        }
                        if (responseText.toLowerCase() === 'tohome') {
                            location.href = Config.data.path[Config.data.environment === 1 ? 'designer' : 'app'] + '/welcome.html';
                        }
                    }
                }
            });
        },
        formSubmitCallback:function (responseText) {
            if (typeof responseText == "object"){
                if (responseText.status === 'error' && responseText.code === 401) {
                    location.href = Config.data.loginUrl;
                }
            }
            if (typeof responseText == "string"){
                if (responseText.toLowerCase() === 'licensetimeout') {
                    location.href = Config.data.path[Config.data.environment === 1 ? 'designer' : 'app'] + '/init/config/index.html';
                }
                if (responseText.toLowerCase() === 'tohome') {
                    location.href = Config.data.path[Config.data.environment === 1 ? 'designer' : 'app'] + '/welcome.html';
                }
            }
        }
    };

    /**
     * 准备
     */
    var Ready = {
        go: function(callback) {
            Config.ready(function() {
                Ready.setHorizon();
                if (MAIN_SCRIPT_URL) {
                    // 引入基础脚本
                    Util.script('{assets}/common/js/horizon.base', function() {
                        if (/\{*\}/g.test(MAIN_SCRIPT_URL)) {
                            MAIN_SCRIPT_URL = Config.replaceVars(MAIN_SCRIPT_URL, Config.pathVars.all);
                        }
                        if (typeof global['horizonAfterReady'] === 'function') {
                            global['horizonAfterReady']();
                        }
                        // 引入 requireJS 和 main script
                        Util.script('{plugins}/require/require', 'requireJS', {
                            async: true,
                            defer: true,
                            'data-main': MAIN_SCRIPT_URL
                        });
                    }, 'base');
                } else if (typeof callback === 'function') callback();
            });
        },
        /**
         * 设置horizon对象
         */
        setHorizon: function() {
            global.horizon = {
                /**
                 * Util
                 */
                util: Util,
                /**
                 * 配置信息
                 */
                config: Config.data
            }
        }
    };

    // 如果指定应用主脚本[data-main]则默认执行ready事件并不在对外提供
    // 将使用 requireJS 加载应用主脚本
    if (MAIN_SCRIPT_URL) {
        Ready.go();
    } else {
        global.horizon = {
            ready: Ready.go
        }
    }

})(window);