import { columeHeader_word, columeHeader_word_index, luckysheetdefaultFont } from '../controllers/constant';
import menuButton from '../controllers/menuButton';
import { isdatatype, isdatatypemulti } from '../global/datecontroll';
import { hasChinaword,isRealNum } from '../global/validate';
import Store from '../store';
import locale from '../locale/locale';
import numeral from 'numeral';
// import method from '../global/method';

/**
 * Common tool methods
 */

/**
 * Determine whether a string is in standard JSON format
 * @param {String} str 
 */
function isJsonString(str) {
    try {
        if (typeof JSON.parse(str) == "object") {
            return true;
        }
    }
    catch (e) { }
    return false;
}


/**
 * extend two objects
 * @param {Object } jsonbject1
 * @param {Object } jsonbject2 
 */
function common_extend(jsonbject1, jsonbject2) {
    let resultJsonObject = {};

    for (let attr in jsonbject1) {
        resultJsonObject[attr] = jsonbject1[attr];
    }

    for (let attr in jsonbject2) {
        // undefined is equivalent to no setting
        if(jsonbject2[attr] == undefined){
            continue;
        }
        resultJsonObject[attr] = jsonbject2[attr];
    }

    return resultJsonObject;
};

// 替换temp中的${xxx}为指定内容 ,temp:字符串，这里指html代码，dataarry：一个对象{"xxx":"替换的内容"}
// 例：luckysheet.replaceHtml("${image}",{"image":"abc","jskdjslf":"abc"})   ==>  abc
function replaceHtml(temp, dataarry) {
    return temp.replace(/\$\{([\w]+)\}/g, function (s1, s2) { let s = dataarry[s2]; if (typeof (s) != "undefined") { return s; } else { return s1; } });
};

//获取数据类型
function getObjType(obj) {
    let toString = Object.prototype.toString;

    let map = {
        '[object Boolean]': 'boolean',
        '[object Number]': 'number',
        '[object String]': 'string',
        '[object Function]': 'function',
        '[object Array]': 'array',
        '[object Date]': 'date',
        '[object RegExp]': 'regExp',
        '[object Undefined]': 'undefined',
        '[object Null]': 'null',
        '[object Object]': 'object'
    }

    // if(obj instanceof Element){
    //     return 'element';
    // }

    return map[toString.call(obj)];
}

//获取当前日期时间
function getNowDateTime(format) {
    let now = new Date();
    let year = now.getFullYear();  //得到年份
    let month = now.getMonth();  //得到月份
    let date = now.getDate();  //得到日期
    let day = now.getDay();  //得到周几
    let hour = now.getHours();  //得到小时
    let minu = now.getMinutes();  //得到分钟
    let sec = now.getSeconds();  //得到秒

    month = month + 1;
    if (month < 10) month = "0" + month;
    if (date < 10) date = "0" + date;
    if (hour < 10) hour = "0" + hour;
    if (minu < 10) minu = "0" + minu;
    if (sec < 10) sec = "0" + sec;

    let time = '';

    //日期
    if(format == 1) {
        time = year + "-" + month + "-" + date;
    }
    //日期时间
    else if(format == 2) {
        time = year + "-" + month + "-" + date+ " " + hour + ":" + minu + ":" + sec;
    }

    return time;
}

//颜色 16进制转rgb
function hexToRgb(hex) {
    let color = [], rgb = [];
    hex = hex.replace(/#/, "");

    if (hex.length == 3) { // 处理 "#abc" 成 "#aabbcc"
        let tmp = [];

        for (let i = 0; i < 3; i++) {
            tmp.push(hex.charAt(i) + hex.charAt(i));
        }

        hex = tmp.join("");
    }

    for (let i = 0; i < 3; i++) {
        color[i] = "0x" + hex.substr(i + 2, 2);
        rgb.push(parseInt(Number(color[i])));
    }

    return 'rgb(' + rgb.join(",") + ')';
};

//颜色 rgb转16进制
function rgbTohex(color) {
    let rgb;

    if (color.indexOf("rgba") > -1) {
        rgb = color.replace("rgba(", "").replace(")", "").split(',');
    }
    else {
        rgb = color.replace("rgb(", "").replace(")", "").split(',');
    }

    let r = parseInt(rgb[0]);
    let g = parseInt(rgb[1]);
    let b = parseInt(rgb[2]);

    let hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);

    return hex;
};

//列下标  字母转数字
function ABCatNum(a) {
    // abc = abc.toUpperCase();

    // let abc_len = abc.length;
    // if (abc_len == 0) {
    //     return NaN;
    // }

    // let abc_array = abc.split("");
    // let wordlen = columeHeader_word.length;
    // let ret = 0;

    // for (let i = abc_len - 1; i >= 0; i--) {
    //     if (i == abc_len - 1) {
    //         ret += columeHeader_word_index[abc_array[i]];
    //     }
    //     else {
    //         ret += Math.pow(wordlen, abc_len - i - 1) * (columeHeader_word_index[abc_array[i]] + 1);
    //     }
    // }

    // return ret;
    if(a==null || a.length==0){
        return NaN;
    }
    var str=a.toLowerCase().split("");
    var num=0;
    var al = str.length;
    var getCharNumber = function(charx){
        return charx.charCodeAt() -96;
    };
    var numout = 0;
    var charnum = 0;
    for(var i = 0; i < al; i++){
        charnum = getCharNumber(str[i]);
        numout += charnum * Math.pow(26, al-i-1);
    };
    // console.log(a, numout-1);
    if(numout==0){
        return NaN;
    }
    return numout-1;
};

//列下标  数字转字母
function chatatABC(n) {
    // let wordlen = columeHeader_word.length;

    // if (index < wordlen) {
    //     return columeHeader_word[index];
    // }
    // else {
    //     let last = 0, pre = 0, ret = "";
    //     let i = 1, n = 0;

    //     while (index >= (wordlen / (wordlen - 1)) * (Math.pow(wordlen, i++) - 1)) {
    //         n = i;
    //     }

    //     let index_ab = index - (wordlen / (wordlen - 1)) * (Math.pow(wordlen, n - 1) - 1);//970
    //     last = index_ab + 1;

    //     for (let x = n; x > 0; x--) {
    //         let last1 = last, x1 = x;//-702=268, 3

    //         if (x == 1) {
    //             last1 = last1 % wordlen;

    //             if (last1 == 0) {
    //                 last1 = 26;
    //             }

    //             return ret + columeHeader_word[last1 - 1];
    //         }

    //         last1 = Math.ceil(last1 / Math.pow(wordlen, x - 1));
    //         //last1 = last1 % wordlen;
    //         ret += columeHeader_word[last1 - 1];

    //         if (x > 1) {
    //             last = last - (last1 - 1) * wordlen;
    //         }
    //     }
    // }

    var orda = 'a'.charCodeAt(0); 
   
    var ordz = 'z'.charCodeAt(0); 
   
    var len = ordz - orda + 1; 
   
    var s = ""; 
   
    while( n >= 0 ) { 
   
        s = String.fromCharCode(n % len + orda) + s; 
   
        n = Math.floor(n / len) - 1; 
   
    } 
   
    return s.toUpperCase(); 
};

function ceateABC(index) {
    let wordlen = columeHeader_word.length;

    if (index < wordlen) {
        return columeHeader_word;
    }
    else {
        let relist = [];
        let i = 2, n = 0;

        while (index < (wordlen / (wordlen - 1)) * (Math.pow(wordlen, i) - 1)) {
            n = i;
            i++;
        }

        for (let x = 0; x < n; x++) {

            if (x == 0) {
                relist = relist.concat(columeHeader_word);
            }
            else {
                relist = relist.concat(createABCdim(x), index);
            }
        }
    }
};

function createABCdim(x, count) {
    let chwl = columeHeader_word.length;

    if (x == 1) {
        let ret = [];
        let c = 0, con = true;

        for (let i = 0; i < chwl; i++) {
            let b = columeHeader_word[i];

            for (let n = 0; n < chwl; n++) {
                let bq = b + columeHeader_word[n];
                ret.push(bq);
                c++;

                if (c > index) {
                    return ret;
                }
            }
        }
    }
    else if (x == 2) {
        let ret = [];
        let c = 0, con = true;

        for (let i = 0; i < chwl; i++) {
            let bb = columeHeader_word[i];

            for (let w = 0; w < chwl; w++) {
                let aa = columeHeader_word[w];

                for (let n = 0; n < chwl; n++) {
                    let bqa = bb + aa + columeHeader_word[n];
                    ret.push(bqa);
                    c++;

                    if (c > index) {
                        return ret;
                    }
                }
            }
        }
    }
};

/**
 * 计算字符串字节长度
 * @param {*} val 字符串
 * @param {*} subLen 要截取的字符串长度
 */
function getByteLen(val,subLen) {
    if(subLen === 0){
        return "";
    }

    if (val == null) {
        return 0;
    }

    let len = 0;
    for (let i = 0; i < val.length; i++) {
        let a = val.charAt(i);

        if (a.match(/[^\x00-\xff]/ig) != null) {
            len += 2;
        }
        else {
            len += 1;
        }

        if(isRealNum(subLen) && len === ~~subLen){
            return val.substring(0,i)
        }

    }

    return len;
};

//数组去重
function ArrayUnique(dataArr) {
    let result = [];
    let obj = {};
    if (dataArr.length > 0) {
        for (let i = 0; i < dataArr.length; i++) {
            let item = dataArr[i];
            if (!obj[item]) {
                result.push(item);
                obj[item] = 1;
            }
        }
    }
    return result
}

//获取字体配置
function luckysheetfontformat(format) {
    let fontarray = locale().fontarray;
    if (getObjType(format) == "object") {
        let font = "";

        //font-style
        if (format.it == "0" || format.it == null) {
            font += "normal ";
        }
        else {
            font += "italic ";
        }

        //font-variant
        font += "normal ";

        //font-weight
        if (format.bl == "0" || format.bl == null) {
            font += "normal ";
        }
        else {
            font += "bold ";
        }

        //font-size/line-height
        if (!format.fs) {
            font += Store.defaultFontSize + "pt ";
        }
        else {
            font += Math.ceil(format.fs) + "pt ";
        }

        if (!format.ff) {
            
            font += fontarray[0] + ', "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Heiti SC", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif';
        }
        else {
            let fontfamily = null;
            let fontjson = locale().fontjson;
            if (isdatatypemulti(format.ff)["num"]) {
                fontfamily = fontarray[parseInt(format.ff)];
            }
            else {

                // fontfamily = fontarray[fontjson[format.ff]];
                fontfamily = format.ff;

                fontfamily = fontfamily.replace(/"/g, "").replace(/'/g, "");

                if(fontfamily.indexOf(" ")>-1){
                    fontfamily = '"' + fontfamily + '"';
                }

                if(fontfamily!=null && document.fonts && !document.fonts.check("12px "+fontfamily)){
                    menuButton.addFontTolist(fontfamily);
                }
            }

            if (fontfamily == null) {
                fontfamily = fontarray[0];
            }

            font += fontfamily + ', "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Heiti SC", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif';
        }

        return font;
    }
    else {
        return luckysheetdefaultFont();
    }
}

//右键菜单
function showrightclickmenu($menu, x, y) {
    let winH = $(window).height(), winW = $(window).width();
    let menuW = $menu.width(), menuH = $menu.height();
    let top = y, left = x;

    if (x + menuW > winW) {
        left = x - menuW;
    }

    if (y + menuH > winH) {
        top = y - menuH;
    }

    if (top < 0) {
        top = 0;
    }

    $menu.css({ "top": top, "left": left }).show();
}

//单元格编辑聚焦
function luckysheetactiveCell() {
    if (!!Store.fullscreenmode) {
        setTimeout(function () {
            // need preventScroll:true,fix Luckysheet has been set top, and clicking the cell will trigger the scrolling problem
            const input = document.getElementById('luckysheet-rich-text-editor');
            input.focus({preventScroll:true});
            $("#luckysheet-rich-text-editor").select();
            // $("#luckysheet-rich-text-editor").focus().select();
        }, 50);
    }
}

//单元格编辑聚焦
function luckysheetContainerFocus() {
    
    // $("#" + Store.container).focus({ 
    //     preventScroll: true 
    // });
    
    // fix jquery error: Uncaught TypeError: ((n.event.special[g.origType] || {}).handle || g.handler).apply is not a function
    // $("#" + Store.container).attr("tabindex", 0).focus();

    // need preventScroll:true,fix Luckysheet has been set top, and clicking the cell will trigger the scrolling problem
    document.getElementById(Store.container).focus({preventScroll:true});
}

//数字格式
function numFormat(num, type) {
    if (num == null || isNaN(parseFloat(num)) || hasChinaword(num) || num == -Infinity || num == Infinity) {
        return null;
    }

    let floatlen = 6, ismustfloat = false;
    if (type == null || type == "auto") {
        if (num < 1) {
            floatlen = 6;
        }
        else {
            floatlen = 1;
        }
    }
    else {
        if (isdatatype(type) == "num") {
            floatlen = parseInt(type);
            ismustfloat = true;
        }
        else {
            floatlen = 6;
        }
    }

    let format = "", value = null;
    for (let i = 0; i < floatlen; i++) {
        format += "0";
    }

    if (!ismustfloat) {
        format = "[" + format + "]";
    }

    if (num >= 1e+21) {
        value = parseFloat(numeral(num).value());
    }
    else {
        value = parseFloat(numeral(num).format("0." + format));
    }

    return value;
}

function numfloatlen(n) {
    if (n != null && !isNaN(parseFloat(n)) && !hasChinaword(n)) {
        let value = numeral(n).value();
        let lens = value.toString().split(".");

        if (lens.length == 1) {
            lens = 0;
        }
        else {
            lens = lens[1].length;
        }

        return lens;
    }
    else {
        return null;
    }
}

//二级菜单显示位置
function mouseclickposition($menu, x, y, p) {
    let winH = $(window).height(), winW = $(window).width();
    let menuW = $menu.width(), menuH = $menu.height();
    let top = y, left = x;

    if (p == null) {
        p = "lefttop";
    }

    if (p == "lefttop") {
        $menu.css({ "top": y, "left": x }).show();
    }
    else if (p == "righttop") {
        $menu.css({ "top": y, "left": x - menuW }).show();
    }
    else if (p == "leftbottom") {
        $menu.css({ "bottom": winH - y - 12, "left": x }).show();
    }
    else if (p == "rightbottom") {
        $menu.css({ "bottom": winH - y - 12, "left": x - menuW }).show();
    }
}

/**
 * 元素选择器
 * @param {String}  selector css选择器
 * @param {String}  context  指定父级DOM
 */
function $$(selector, context) {
    context = context || document
    var elements = context.querySelectorAll(selector)
    return elements.length == 1
        ? Array.prototype.slice.call(elements)[0]
        : Array.prototype.slice.call(elements)
}

/** 
 * 串行加载指定的脚本
 * 串行加载[异步]逐个加载，每个加载完成后加载下一个
 * 全部加载完成后执行回调
 * @param {Array|String}  scripts 指定要加载的脚本
 * @param {Object} options 属性设置
 * @param {Function} callback 成功后回调的函数
 * @return {Array} 所有生成的脚本元素对象数组
 */

function seriesLoadScripts(scripts, options, callback) {
    if (typeof (scripts) !== 'object') {
        var scripts = [scripts];
    }
    var HEAD = document.getElementsByTagName('head')[0] || document.documentElement;
    var s = [];
    var last = scripts.length - 1;
    //递归
    var recursiveLoad = function (i) {
        s[i] = document.createElement('script');
        s[i].setAttribute('type', 'text/javascript');
        // Attach handlers for all browsers
        // 异步
        s[i].onload = s[i].onreadystatechange = function () {
            if (!/*@cc_on!@*/0 || this.readyState === 'loaded' || this.readyState === 'complete') {
                this.onload = this.onreadystatechange = null;
                this.parentNode.removeChild(this);
                if (i !== last) {
                    recursiveLoad(i + 1);
                } else if (typeof (callback) === 'function') {
                    callback()
                };
            }
        }
        // 同步
        s[i].setAttribute('src', scripts[i]);

        // 设置属性
        if (typeof options === 'object') {
            for (var attr in options) {
                s[i].setAttribute(attr, options[attr]);
            }
        }

        HEAD.appendChild(s[i]);
    };
    recursiveLoad(0);
}


/**
 * 并行加载指定的脚本
 * 并行加载[同步]同时加载，不管上个是否加载完成，直接加载全部
 * 全部加载完成后执行回调
 * @param {Array|String}  scripts 指定要加载的脚本
 * @param {Object} options 属性设置
 * @param {Function} callback 成功后回调的函数
 * @return {Array} 所有生成的脚本元素对象数组
 */

function parallelLoadScripts(scripts, options, callback) {
    if (typeof (scripts) !== 'object') {
        var scripts = [scripts];
    }
    var HEAD = document.getElementsByTagName('head')[0] || document.documentElement;
    var s = [];
    var loaded = 0;
    for (var i = 0; i < scripts.length; i++) {
        s[i] = document.createElement('script');
        s[i].setAttribute('type', 'text/javascript');
        // Attach handlers for all browsers
        // 异步
        s[i].onload = s[i].onreadystatechange = function () {
            if (!/*@cc_on!@*/0 || this.readyState === 'loaded' || this.readyState === 'complete') {
                loaded++;
                this.onload = this.onreadystatechange = null;
                this.parentNode.removeChild(this);
                if (loaded === scripts.length && typeof (callback) === 'function') callback();
            }
        };
        // 同步
        s[i].setAttribute('src', scripts[i]);

        // 设置属性
        if (typeof options === 'object') {
            for (var attr in options) {
                s[i].setAttribute(attr, options[attr]);
            }
        }

        HEAD.appendChild(s[i]);
    }
}

/**
* 动态添加css
* @param {String}  url 指定要加载的css地址
*/
function loadLink(url) {
    var doc = document;
    var link = doc.createElement("link");
    link.setAttribute("rel", "stylesheet");
    link.setAttribute("type", "text/css");
    link.setAttribute("href", url);

    var heads = doc.getElementsByTagName("head");
    if (heads.length) {
        heads[0].appendChild(link);
    }
    else {
        doc.documentElement.appendChild(link);
    }
}

/**
* 动态添加一组css
* @param {String}  url 指定要加载的css地址
*/
function loadLinks(urls) {
    if (typeof (urls) !== 'object') {
        urls = [urls];
    }
    if (urls.length) {
        urls.forEach(url => {
            loadLink(url);
        });
    }
}

function transformRangeToAbsolute(txt1){
    if(txt1 ==null ||txt1.length==0){
        return null;
    }

    let txtArray = txt1.split(",");
    let ret = "";
    for(let i=0;i<txtArray.length;i++){
        let txt = txtArray[i];
        let txtSplit = txt.split("!"), sheetName="", rangeTxt="";
        if(txtSplit.length>1){
            sheetName = txtSplit[0];
            rangeTxt = txtSplit[1];
        }
        else{
            rangeTxt = txtSplit[0];
        }

        let rangeTxtArray = rangeTxt.split(":");

        let rangeRet = "";
        for(let a=0;a<rangeTxtArray.length;a++){
            let t = rangeTxtArray[a];

            let row = t.replace(/[^0-9]/g, "");
            let col = t.replace(/[^A-Za-z]/g, "");
            let rangeTT = ""
            if(col!=""){
                rangeTT += "$" + col;
            }

            if(row!=""){
                rangeTT += "$" + row;
            }

            rangeRet+=rangeTT+":";
        }

        rangeRet = rangeRet.substr(0, rangeRet.length-1);

        ret += sheetName + rangeRet + ",";
    }

    return ret.substr(0, ret.length-1); 
}

function openSelfModel(id, isshowMask=true){
    let $t = $("#"+id)
            .find(".luckysheet-modal-dialog-content")
            .css("min-width", 300)
            .end(), 
        myh = $t.outerHeight(), 
        myw = $t.outerWidth();
    let winw = $(window).width(), winh = $(window).height();
    let scrollLeft = $(document).scrollLeft(), scrollTop = $(document).scrollTop();
    $t.css({ 
    "left": (winw + scrollLeft - myw) / 2, 
    "top": (winh + scrollTop - myh) / 3 
    }).show();

    if(isshowMask){
        $("#luckysheet-modal-dialog-mask").show();
    }
}

/**
 * 监控对象变更
 * @param {*} data 
 */
// const createProxy = (data,list=[]) => {
//     if (typeof data === 'object' && data.toString() === '[object Object]') {
//       for (let k in data) {
//         if(list.includes(k)){
//             if (typeof data[k] === 'object') {
//               defineObjectReactive(data, k, data[k])
//             } else {
//               defineBasicReactive(data, k, data[k])
//             }
//         }
//       }
//     }
// }

const createProxy = (data, k, callback) => {
    if(!data.hasOwnProperty(k)){ 
        console.info('No %s in data',k);
        return; 
    };

    if (getObjType(data) === 'object') {
        if (getObjType(data[k]) === 'object' || getObjType(data[k]) === 'array') {
            defineObjectReactive(data, k, data[k], callback)
        } else {
            defineBasicReactive(data, k, data[k], callback)
        }
    }
}
  
function defineObjectReactive(obj, key, value, callback) {
    // 递归
    obj[key] = new Proxy(value, {
      set(target, property, val, receiver) {
        
          setTimeout(() => {
            callback(target, property, val, receiver);
          }, 0);

        return Reflect.set(target, property, val, receiver)
      }
    })
}
  
function defineBasicReactive(obj, key, value, callback) {
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: false,
      get() {
        return value
      },
      set(newValue) {
        if (value === newValue) return
        console.log(`发现 ${key} 属性 ${value} -> ${newValue}`)

        setTimeout(() => {
            callback(value,newValue);
        }, 0);

        value = newValue

      }
    })
}

/**
 * Remove an item in the specified array
 * @param {array} array Target array 
 * @param {string} item What needs to be removed
 */
function arrayRemoveItem(array, item) {
    array.some((curr, index, arr)=>{
        if(curr === item){
            arr.splice(index, 1);
            return curr === item;
        }
    })
}

/**
 * camel 形式的单词转换为 - 形式 如 fillColor -> fill-color
 * @param {string} camel camel 形式
 * @returns
 */
 function camel2split(camel) {
    return camel.replace(/([A-Z])/g, function(all, group) {
        return '-' + group.toLowerCase();
    });
}
  
export {
    isJsonString,
    common_extend,
    replaceHtml,
    getObjType,
    getNowDateTime,
    hexToRgb,
    rgbTohex,
    ABCatNum,
    chatatABC,
    ceateABC,
    createABCdim,
    getByteLen,
    ArrayUnique,
    luckysheetfontformat,
    showrightclickmenu,
    luckysheetactiveCell,
    numFormat,
    numfloatlen,
    mouseclickposition,
    $$,
    seriesLoadScripts,
    parallelLoadScripts,
    loadLinks,
    luckysheetContainerFocus,
    transformRangeToAbsolute,
    openSelfModel,
    createProxy,
    arrayRemoveItem,
    camel2split
}