/**
 * 
 * @authors yutent (yutent@doui.cc)
 * @date    2016-09-21 01:36:29
 *
 */

"use strict";


define(['yua', 'lib/drag', 'css!./skin/def'], function(yua){


    var layerDom = {},
        layerObj = {},
        unique = null, //储存当前打开的1/2/3类型的弹窗
        lid = 0,
        defconf = {
            type: 1, // 弹窗类型
            skin: 'def', //默认主题
            icon: 1, //图标类型
            background: '#fff',
            shade: true, //遮罩
            shadeClose: false, //遮罩点击关闭弹窗
            radius: '0px', //弹窗圆角半径
            area: ['auto', 'auto'],
            title: '', //弹窗主标题(在工具栏上的)
            menubar: true, //是否显示菜单栏
            content: '', // 弹窗的内容
            fixed: false, //是否固定不可拖拽
            offset: null, //弹窗出来时的坐标, 为数组,可有4个值,依次是 上右下左
            btns: ['确定', '取消'], //弹窗的2个按钮的文字
            yes: close, //确定按钮对应的回调
            no: close, //取消按钮对应的回调
            success: null //弹窗初始化完成时的回调
        };

    function uuid(){
        return 'layer-' + (++lid)
    }


    function close(id){
        if(typeof id !== 'string' && typeof id !== 'number'){
            return console.error(new Error('要关闭的layer实例不存在'))
        }
        if(/^\$wrap\-/.test(id) || layerObj['$wrap-' + id]){

            try {
                id = (layerObj['$wrap-' + id] ? '$wrap-' : '') + id;
                //未显示过,忽略
                if(!layerObj[id].show){
                    return
                }
                layerObj[id].parentElem.replaceChild(layerObj[id].wrap, layerDom[id][1])
                unique = null
            }catch(err){}
        }else{
            try {
                document.body.removeChild(layerDom[id][1])
                document.body.removeChild(layerDom[id][0])
                unique = null
            }catch(err){}

            delete layerDom[id]
            delete yua.vmodels[id]
        }
        
    }

    function reapeat(str, num){
        var idx = 0,
            result = ''
        while(idx < num){
            result += str
            idx++
        }
        return result
    }

    function fixOffset(val){
        if(!val && val !== 0){
            return 'auto'
        }else{
            return val
        }
    }

    var __constructor = function(conf){
            if(conf){
                this.ready(conf).append().show()
            }
        },
        __layer = {
            alert: function(msg, conf){
                if(typeof conf === 'function'){
                    conf = {yes: conf}
                }else if(typeof conf === 'object'){
                    conf = conf
                }else{
                    conf = {}
                }
                conf.icon = 6
                conf.content = msg
                return __layer.open(conf)
            },
            confirm: function(msg, conf){
                if(typeof conf === 'function'){
                    conf = {yes: conf}
                }else if(typeof conf === 'object'){
                    conf = conf
                }else{
                    conf = {}
                }
                conf.type = 2
                conf.icon = 8
                conf.content = msg
                return __layer.open(conf)
            },
            msg: function(msg, conf){
                if(typeof conf !== 'object'){
                    var tmp = conf
                    conf = {timeout: 2500}
                    if(typeof tmp === 'number'){
                        conf.icon = tmp
                    }
                }

                if(!conf.hasOwnProperty('timeout')){
                    conf.timeout = 2500
                }

                conf.specialMode = true;//特殊模式
                conf.content = '<p class="msg-box">' + msg + '</p>'
                conf.type = 7
                conf.fixed = true
                conf.shade = false
                conf.menubar = false
                conf.radius = '5px'
                return __layer.open(conf)
            },
            loading: function(style, time, cb){
                style = style >>> 0

                if(typeof time === 'function'){
                    cb = time;
                    time = 0
                } else{
                    time = time >>> 0
                    if(typeof cb !== 'function'){
                        cb = yua.noop
                    }
                }
                return __layer.open({type: 6, load: style, yes: cb, timeout: time, menubar: false, background: 'none', fixed: true})
            },
            tips: function(msg, elem, conf){
                if(!(elem instanceof HTMLElement)){
                    return console.error(new Error('tips类型必须指定一个目标容器'))
                }
                if(typeof conf !== 'object'){
                    var tmp = conf
                    conf = {timeout: 2500}
                    if(typeof tmp === 'number'){
                        conf.icon = tmp
                    }
                }
                if(!conf.hasOwnProperty('timeout')){
                    conf.timeout = 2500
                }
                if(!conf.background){
                    conf.background = 'rgba(0,0,0,.5)'
                }
                if(!conf.color){
                    conf.color = '#fff'
                }
                conf.$elem = elem
                conf.content = msg
                conf.type = 5;
                conf.icon = 0;
                conf.fixed = true;
                conf.shade = false;
                conf.menubar = false;
                return __layer.open(conf)
            },
            prompt: function(msg, callback){
                if(typeof callback !== 'function'){
                    return console.error('argument [callback] requires a function, but ' + (typeof callback) + ' given')
                }
                var conf = {
                        type: 3,
                        icon: 7,
                        prompt: '',
                        title: msg,
                        content: '<input class="prompt-value" :duplex="prompt" />',
                        yes: function(id){
                            callback(id, yua.vmodels[id].prompt)
                        }
                    }
                return __layer.open(conf)
            },
            use: function(skin, callback){
                require(['css!./skin/' + skin], callback)
            },
            close: close,
            open: function(conf){
                if(typeof conf === 'string'){
                    conf = '$wrap-' + conf
                    if(!layerObj[conf]){
                        throw new Error('layer实例不存在')
                    }else{
                        //只能显示一个实例
                        if(layerObj[conf].show){
                            return
                        }
                        layerObj[conf].show = true

                        if(!yua.vmodels[conf]){
                            yua.define(layerObj[conf].obj.init)
                        }
                        
                        yua.scan(layerDom[conf][1])
                        layerObj[conf].obj.show()

                        layerObj[conf].parentElem.appendChild(layerDom[conf][1])
                        layerObj[conf].parentElem.replaceChild(layerDom[conf][1], layerObj[conf].wrap)
                    }
                }else{
                    return new __constructor(conf).init.$id
                }
            },
            version: '0.0.1-base'
        };

    /*type: { // 弹窗类型对应的id值
        1: 'alert',
        2: 'confirm',
        3: 'prompt',
        4: 'iframe',
        5: 'tips',
        6: 'loading',
        7: 'msg',
    }*/
    __constructor.prototype = {
        dot: { //loading的子元素数量
            0: 4,
            1: 9,
            2: 2,
            3: 3,
            4: 2,
            5: 5,
            6: 5,
            7: 5
        },
        timeout: null,
        create: function(){
            var layBox = document.createElement('div'),
                coverBox = document.createElement('div');

            coverBox.className = 'do-layer-cover type-' + this.init.type
            // 允许点击遮罩关闭弹层时, 添加控制器
            if(this.init.shadeClose){
                coverBox.setAttribute(':controller', this.cInit.$id)
                coverBox.setAttribute(':click', 'close(\'' + this.init.$id + '\')')
            }
            
            layBox.className = 'do-layer skin-'
                + this.init.skin
                + (this.init.type === 5 && ' active' || '')
                + ' type-'
                + ((!this.init.specialMode && this.init.type === 7) ? 'unspecial' : this.init.type);

            //暂时隐藏,避免修正定位时,能看到闪一下
            layBox.style.visibility = 'hidden'
            layBox.style.borderRadius = this.init.radius
      
            layBox.setAttribute(':controller', this.init.$id)

            //没有菜单栏, 且未禁止拖拽,则加上可拖拽属性
            if(!this.init.menubar && !this.init.fixed){
                layBox.setAttribute(':drag', '')
                layBox.setAttribute('data-limit', 'window')
            }

            //弹窗的宽高
            var boxcss = ''
            if(this.init.area[0] !== 'auto'){
                boxcss += 'width: ' + this.init.area[0] + ';'
            }
            if(this.init.area[1] !== 'auto'){
                boxcss += 'height: ' + this.init.area[1] + ';'
            }

            layBox.innerHTML = this.getMenubar()
                + '<div class="layer-content do-fn-cl '
                    + (this.init.icon === 0 && 'none-icon' || '')
                    + '" style="'
                    + boxcss
                    + '">'
                + this.getCont()
                + '</div>'
                + this.getBtns()
                + (this.init.type === 5 && '<i class="arrow" style="border-top-color: '
                    + this.init.background
                    + '"></i>' || '')
                
            return [this.init.shade ? coverBox : null, layBox]
        },
        getCont: function(){
            if(this.init.type === 6){
                return this.getLoading(this.init.load)
            }else{
                return this.getIcon()
                    + '<div class="detail" :html="content"></div>'
            }
        },
        getLoading: function(style){
            return '<div class="do-ui-load load-style-'
                    + style
                    + '">'
                + '<span class="dot-box">'
                    + reapeat('<i></i>', this.dot[style])
                + '</span>'
                + '</div>'
        },
        //获取窗口导航条
        getMenubar: function(){
            var html = ''
            if(this.init.menubar){
                html += '<div class="layer-title do-fn-noselect" ';
                //可拖拽
                if(!this.init.fixed){
                    html += ':drag="do-layer" data-limit="window" '
                }
                
                html += '>{{title}}'
                    + '<a class="action-close deficon" :click="no(\'' + this.init.$id + '\')"></a>'
                    + '</div>'
            }
            return html
        },
        //获取窗口内容的图标
        getIcon: function(){
            if(this.init.icon === 0){
                return ''
            }
            if(this.init.type < 4 || this.init.type === 5 || this.init.specialMode){
                return '<span class="deficon icon-' + this.init.icon + '"></span>'
            }
            return ''
        },
        // 获取窗口按钮
        getBtns: function(){
            if(this.init.type > 3){
                return ''
            }else{
                var html = '<div class="layer-btns do-fn-noselect">';
                if(this.init.type > 1){
                    html += '<a href="javascript:;" class="action-no" '
                        + ':click="no(\'' + this.init.$id + '\')" '
                        + ':text="btns[1]"></a>'
                    + '<a href="javascript:;" class="action-yes" '
                        + ':click="yes(\'' + this.init.$id + '\')" '
                        + ':text="btns[0]"></a>'
                }else{
                    html += '<a href="javascript:;" class="action-yes" '
                        + ':click="yes(\'' + this.init.$id + '\')" '
                        + ':text="btns[0]"></a>'
                }
                html += '</div>'

                return html
            }
        },
        append: function(){
            //如果有已经打开的弹窗,则关闭
            if(unique){
                __layer.close(unique)
            }
            if(this.init.type < 4){
                unique = this.init.$id
            }
            layerDom[this.init.$id] = this.create()
            if(layerDom[this.init.$id][0]){
                document.body.appendChild(layerDom[this.init.$id][0])
                //仅在允许点击遮罩时,初始化控制器,减少资源消耗
                if(this.init.shadeClose){
                    yua.define(this.cInit)
                    yua.scan(layerDom[this.init.$id][0])
                }
            }

            document.body.appendChild(layerDom[this.init.$id][1])
            yua.define(this.init)
            yua.scan(layerDom[this.init.$id][1])
            return this
        },
        show: function(){
            var _this = this;
            
            setTimeout(function(){
                var style = {visibility: '', background: _this.init.background},
                    css = getComputedStyle(layerDom[_this.init.$id][1]);

                if(_this.init.type === 5){
                    style.color = _this.init.color

                    var $elem = yua(_this.init.$elem),
                        ew = $elem.innerWidth(),
                        ol = $elem.offset().left - document.body.scrollLeft,
                        ot = $elem.offset().top - document.body.scrollTop;

                    style.left = ol + (ew * 0.7)
                    style.top = ot - parseInt(css.height) - 8

                }else{
                    if(_this.init.offset){
                        style.top = fixOffset(_this.init.offset[0])
                        style.right = fixOffset(_this.init.offset[1])
                        style.bottom = fixOffset(_this.init.offset[2])
                        style.left = fixOffset(_this.init.offset[3])
                    }else{
                        style = yua.mix(style, {
                            marginLeft: -parseInt(css.width) / 2,
                            marginTop: -parseInt(css.height) / 2,
                        })
                    }
                }
                
                yua(layerDom[_this.init.$id][1]).css(style)

            }, 4)
  

            if(this.init.success && typeof this.init.success === 'function'){
                //弹窗成功的回调
                this.init.success(this.init.$id)
            }
            // loading类型,回调需要自动触发
            if(this.init.type > 3) {
                //大于0自动触发超时关闭
                if(this.init.timeout > 0){
                    clearTimeout(this.timeout)
                    this.timeout = setTimeout(function(){

                        clearTimeout(_this.timeout)
                        __layer.close(_this.init.$id)

                        // 为loading类型时,自动关闭同时触发回调
                        if(_this.init.type === 6){
                            _this.init.yes(_this.init.$id)
                        }

                    }, this.init.timeout)

                } else if(this.init.type === 6) {
                    // loading类型, 非自动关闭时, 主动触发回调
                    this.init.yes(this.init.$id)
                }
                
            }

        },
        ready: function(conf){
            this.init = yua.mix({}, defconf, conf)
            if(!this.init.$id){
                this.init.$id = uuid();
            }
            if(this.init.icon > 17){
                this.icon.icon = 17
            }
            //base版没有iframe类型
            if(this.init.type === 4){
                this.icon.type = 7
            }
            this.cInit = {
                $id: this.init.$id + '-c',
                close: this.init.shadeClose ? close : yua.noop
            };
            return this
        }
    }


    yua.directive('layer', {
        priority: 1400,
        init: function(binding){
            if(!binding.param){
                binding.element.style.display = 'none'
            }
        },
        update: function(val){
            if(!val){
                return console.error(new Error(':layer指令格式不正确或无效属性. [' + this.name + '="' + this.expr) + '"]')
            }

            var _this = this,
                init = Object.assign({}, this.element.dataset);

            if(!this.param){
                init.type = 7;
                init.$id = '$wrap-' + val;
                if(!init.hasOwnProperty('menubar')){
                    init.menubar = false;
                }

                var tmp = new __constructor().ready(init);

                tmp.init.content = this.element.cloneNode(true);

                layerObj[tmp.init.$id] = {obj: tmp, parentElem: this.element.parentNode, wrap: this.element, show: false};
                layerDom[tmp.init.$id] = tmp.create();
            }else if(this.param === 'tips'){
                var $elem = yua(this.element),
                    ew = $elem.innerWidth(),
                    ol = $elem.offset().left - document.body.scrollLeft,
                    ot = $elem.offset().top - document.body.scrollTop,
                    tipsBox = document.createElement('div'),
                    tipsArrow = document.createElement('i'),
                    tipsCont = document.createElement('div');


                tipsBox.className = 'do-layer skin-def type-5'
                tipsBox.style.left = ol + (ew * 0.7) + 'px'
                if(init.background){
                    tipsBox.style.background = init.background
                    tipsArrow.style.borderTopColor = init.background
                }
                if(init.color){
                    tipsBox.style.color = init.color
                }
                tipsCont.className = 'layer-content'
                tipsCont.textContent = val
                tipsArrow.className = 'arrow'
                tipsBox.appendChild(tipsCont)
                tipsBox.appendChild(tipsArrow)



                yua(document).bind('scroll', function(){
                    ol = $elem.offset().left - document.body.scrollLeft;
                    ot = $elem.offset().top - document.body.scrollTop;

                    tipsBox.style.left = ol + (ew * 0.7) + 'px'
                    tipsBox.style.top = (ot - tipsBox.offsetHeight - 8) + 'px'
                })

                $elem.bind('mouseenter', function(ev){
                    _this.element.parentNode.appendChild(tipsBox)
                    clearTimeout(_this.showTime)
                    clearTimeout(_this.hideTime)
                    _this.showTime = setTimeout(function(){
                        tipsBox.style.top = (ot - tipsBox.offsetHeight - 8) + 'px'
                        tipsBox.classList.add('active')
                        
                    }, 4)
                    
                })
                $elem.bind('mouseleave', function(){
                    _this.hideTime = setTimeout(function(){
                        clearTimeout(_this.hideTime)
                        try{
                            _this.element.parentNode.removeChild(tipsBox)
                        }catch(err){}
                    }, 150)
                })
            }
        }
    })



    if(!window.layer)
        window.layer = __layer


    return __layer

})