/**
 * 目录大纲支持插件
 * @file
 * @since 1.3.0
 */
UE.plugin.register('section', function (){
    /* 目录节点对象 */
    function Section(option){
        this.tag = '';
        this.level = -1,
            this.dom = null;
        this.nextSection = null;
        this.previousSection = null;
        this.parentSection = null;
        this.startAddress = [];
        this.endAddress = [];
        this.children = [];
    }
    function getSection(option) {
        var section = new Section();
        return utils.extend(section, option);
    }
    function getNodeFromAddress(startAddress, root) {
        var current = root;
        for(var i = 0;i < startAddress.length; i++) {
            if(!current.childNodes) return null;
            current = current.childNodes[startAddress[i]];
        }
        return current;
    }

    var me = this;

    return {
        bindMultiEvents:{
            type: 'aftersetcontent afterscencerestore',
            handler: function(){
                me.fireEvent('updateSections');
            }
        },
        bindEvents:{
            /* 初始化、拖拽、粘贴、执行setcontent之后 */
            'ready': function (){
                me.fireEvent('updateSections');
                domUtils.on(me.body, 'drop paste', function(){
                    me.fireEvent('updateSections');
                });
            },
            /* 执行paragraph命令之后 */
            'afterexeccommand': function (type, cmd) {
                if(cmd == 'paragraph') {
                    me.fireEvent('updateSections');
                }
            },
            /* 部分键盘操作，触发updateSections事件 */
            'keyup': function (type, e) {
                var me = this,
                    range = me.selection.getRange();
                if(range.collapsed != true) {
                    me.fireEvent('updateSections');
                } else {
                    var keyCode = e.keyCode || e.which;
                    if(keyCode == 13 || keyCode == 8 || keyCode == 46) {
                        me.fireEvent('updateSections');
                    }
                }
            }
        },
        commands:{
            'getsections': {
                execCommand: function (cmd, levels) {
                    var levelFn = levels || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];

                    for (var i = 0; i < levelFn.length; i++) {
                        if (typeof levelFn[i] == 'string') {
                            levelFn[i] = function(fn){
                                return function(node){
                                    return node.tagName == fn.toUpperCase()
                                };
                            }(levelFn[i]);
                        } else if (typeof levelFn[i] != 'function') {
                            levelFn[i] = function (node) {
                                return null;
                            }
                        }
                    }
                    function getSectionLevel(node) {
                        for (var i = 0; i < levelFn.length; i++) {
                            if (levelFn[i](node)) return i;
                        }
                        return -1;
                    }

                    var me = this,
                        Directory = getSection({'level':-1, 'title':'root'}),
                        previous = Directory;

                    function traversal(node, Directory) {
                        var level,
                            tmpSection = null,
                            parent,
                            child,
                            children = node.childNodes;
                        for (var i = 0, len = children.length; i < len; i++) {
                            child = children[i];
                            level = getSectionLevel(child);
                            if (level >= 0) {
                                var address = me.selection.getRange().selectNode(child).createAddress(true).startAddress,
                                    current = getSection({
                                        'tag': child.tagName,
                                        'title': child.innerText || child.textContent || '',
                                        'level': level,
                                        'dom': child,
                                        'startAddress': utils.clone(address, []),
                                        'endAddress': utils.clone(address, []),
                                        'children': []
                                    });
                                previous.nextSection = current;
                                current.previousSection = previous;
                                parent = previous;
                                while(level <= parent.level){
                                    parent = parent.parentSection;
                                }
                                current.parentSection = parent;
                                parent.children.push(current);
                                tmpSection = previous = current;
                            } else {
                                child.nodeType === 1 && traversal(child, Directory);
                                tmpSection && tmpSection.endAddress[tmpSection.endAddress.length - 1] ++;
                            }
                        }
                    }
                    traversal(me.body, Directory);
                    return Directory;
                },
                notNeedUndo: true
            },
            'movesection': {
                execCommand: function (cmd, sourceSection, targetSection, isAfter) {

                    var me = this,
                        targetAddress,
                        target;

                    if(!sourceSection || !targetSection || targetSection.level == -1) return;

                    targetAddress = isAfter ? targetSection.endAddress:targetSection.startAddress;
                    target = getNodeFromAddress(targetAddress, me.body);

                    /* 判断目标地址是否被源章节包含 */
                    if(!targetAddress || !target || isContainsAddress(sourceSection.startAddress, sourceSection.endAddress, targetAddress)) return;

                    var startNode = getNodeFromAddress(sourceSection.startAddress, me.body),
                        endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
                        current,
                        nextNode;

                    if(isAfter) {
                        current = endNode;
                        while ( current && !(domUtils.getPosition( startNode, current ) & domUtils.POSITION_FOLLOWING) ) {
                            nextNode = current.previousSibling;
                            domUtils.insertAfter(target, current);
                            if(current == startNode) break;
                            current = nextNode;
                        }
                    } else {
                        current = startNode;
                        while ( current && !(domUtils.getPosition( current, endNode ) & domUtils.POSITION_FOLLOWING) ) {
                            nextNode = current.nextSibling;
                            target.parentNode.insertBefore(current, target);
                            if(current == endNode) break;
                            current = nextNode;
                        }
                    }

                    me.fireEvent('updateSections');

                    /* 获取地址的包含关系 */
                    function isContainsAddress(startAddress, endAddress, addressTarget){
                        var isAfterStartAddress = false,
                            isBeforeEndAddress = false;
                        for(var i = 0; i< startAddress.length; i++){
                            if(i >= addressTarget.length) break;
                            if(addressTarget[i] > startAddress[i]) {
                                isAfterStartAddress = true;
                                break;
                            } else if(addressTarget[i] < startAddress[i]) {
                                break;
                            }
                        }
                        for(var i = 0; i< endAddress.length; i++){
                            if(i >= addressTarget.length) break;
                            if(addressTarget[i] < startAddress[i]) {
                                isBeforeEndAddress = true;
                                break;
                            } else if(addressTarget[i] > startAddress[i]) {
                                break;
                            }
                        }
                        return isAfterStartAddress && isBeforeEndAddress;
                    }
                }
            },
            'deletesection': {
                execCommand: function (cmd, section, keepChildren) {
                    var me = this;

                    if(!section) return;

                    function getNodeFromAddress(startAddress) {
                        var current = me.body;
                        for(var i = 0;i < startAddress.length; i++) {
                            if(!current.childNodes) return null;
                            current = current.childNodes[startAddress[i]];
                        }
                        return current;
                    }

                    var startNode = getNodeFromAddress(section.startAddress),
                        endNode = getNodeFromAddress(section.endAddress),
                        current = startNode,
                        nextNode;

                    if(!keepChildren) {
                        while ( current && domUtils.inDoc(endNode, me.document) && !(domUtils.getPosition( current, endNode ) & domUtils.POSITION_FOLLOWING) ) {
                            nextNode = current.nextSibling;
                            domUtils.remove(current);
                            current = nextNode;
                        }
                    } else {
                        domUtils.remove(current);
                    }

                    me.fireEvent('updateSections');
                }
            },
            'selectsection': {
                execCommand: function (cmd, section) {
                    if(!section && !section.dom) return false;
                    var me = this,
                        range = me.selection.getRange(),
                        address = {
                            'startAddress':utils.clone(section.startAddress, []),
                            'endAddress':utils.clone(section.endAddress, [])
                        };
                    address.endAddress[address.endAddress.length - 1]++;
                    range.moveToAddress(address).select().scrollToView();
                    return true;
                },
                notNeedUndo: true
            },
            'scrolltosection': {
                execCommand: function (cmd, section) {
                    if(!section && !section.dom) return false;
                    var me = this,
                        range = me.selection.getRange(),
                        address = {
                            'startAddress':section.startAddress,
                            'endAddress':section.endAddress
                        };
                    address.endAddress[address.endAddress.length - 1]++;
                    range.moveToAddress(address).scrollToView();
                    return true;
                },
                notNeedUndo: true
            }
        }
    }
});