/**
 * @ignore
 * abstraction of tree node ,root and other node will extend it
 * @author yiminghe@gmail.com
 */
KISSY.add("tree/node", function (S, Node, Container, TreeNodeRender) {
    var $ = Node.all,
        KeyCode = Node.KeyCode;

    /**
     * Tree Node. xclass: 'tree-node'.
     * @class KISSY.Tree.Node
     * @extends KISSY.Component.Container
     */
   return Container.extend({
        bindUI: function () {
            this.on('afterAddChild', onAddChild);
            this.on('afterRemoveChild', onRemoveChild);
            this.on('afterAddChild afterRemoveChild', syncAriaSetSize);
        },

        syncUI: function () {
            // 集中设置样式
            refreshCss(this);
            syncAriaSetSize.call(this, {
                target: this
            });
        },

        handleKeyDownInternal: function (e) {
            var self = this,
                processed = true,
                tree = self.get("tree"),
                expanded = self.get("expanded"),
                nodeToBeSelected,
                isLeaf = self.get("isLeaf"),
                children = self.get("children"),
                keyCode = e.keyCode;

            // 顺序统统为前序遍历顺序
            switch (keyCode) {
                case KeyCode.ENTER:
                    return self.handleClickInternal(e);
                    break;

                // home
                // 移到树的顶层节点
                case KeyCode.HOME:
                    nodeToBeSelected = tree;
                    break;

                // end
                // 移到最后一个可视节点
                case KeyCode.END:
                    nodeToBeSelected = getLastVisibleDescendant(tree);
                    break;

                // 上
                // 当前节点的上一个兄弟节点的最后一个可显示节点
                case KeyCode.UP:
                    nodeToBeSelected = getPreviousVisibleNode(self);
                    break;

                // 下
                // 当前节点的下一个可显示节点
                case KeyCode.DOWN:
                    nodeToBeSelected = getNextVisibleNode(self);
                    break;

                // 左
                // 选择父节点或 collapse 当前节点
                case KeyCode.LEFT:
                    if (expanded && (children.length || isLeaf === false)) {
                        self.set("expanded", false);
                    } else {
                        nodeToBeSelected = self.get('parent');
                    }
                    break;

                // 右
                // expand 当前节点
                case KeyCode.RIGHT:
                    if (children.length || isLeaf === false) {
                        if (!expanded) {
                            self.set("expanded", true);
                        } else {
                            nodeToBeSelected = children[0];
                        }
                    }
                    break;

                default:
                    processed = false;
                    break;
            }

            if (nodeToBeSelected) {
                nodeToBeSelected.select();
            }

            return processed;
        },

        next: function () {
            var self = this,
                parent = self.get('parent'),
                siblings,
                index;
            if (!parent) {
                return null;
            }
            siblings = parent.get('children');
            index = S.indexOf(self, siblings);
            if (index == siblings.length - 1) {
                return null;
            }
            return siblings[index + 1];
        },

        prev: function () {
            var self = this,
                parent = self.get('parent'),
                siblings,
                index;
            if (!parent) {
                return null;
            }
            siblings = parent.get('children');
            index = S.indexOf(self, siblings);
            if (index === 0) {
                return null;
            }
            return siblings[index - 1];
        },

        /**
         * Select current tree node.
         */
        select: function () {
            this.set('selected', true);
        },

        handleClickInternal: function (e) {
            var self = this,
                target = $(e.target),
                expanded = self.get("expanded"),
                tree = self.get("tree");
            tree.focus();
            if (target.equals(self.get("expandIconEl"))) {
                self.set("expanded", !expanded);
            } else {
                self.select();
                self.fire("click");
            }
            return true;
        },

        /**
         * override root 's renderChildren to apply depth and css recursively
         */
        createChildren: function () {
            var self = this;
           self.renderChildren.apply(self, arguments);
            // only sync child sub tree at root node
            if (self === self.get('tree')) {
                updateSubTreeStatus(self, self, -1, 0);
            }
        },

        _onSetExpanded: function (v) {
            var self = this;
            refreshCss(self);
            self.fire(v ? "expand" : "collapse");
        },

        _onSetSelected: function (v, e) {
            var tree = this.get("tree");
            if (e && e.byPassSetTreeSelectedItem) {
            } else {
                tree.set('selectedItem', v ? this : null);
            }
        },

        /**
         * Expand all descend nodes of current node
         */
        expandAll: function () {
            var self = this;
            self.set("expanded", true);
            S.each(self.get("children"), function (c) {
                c.expandAll();
            });
        },

        /**
         * Collapse all descend nodes of current node
         */
        collapseAll: function () {
            var self = this;
            self.set("expanded", false);
            S.each(self.get("children"), function (c) {
                c.collapseAll();
            });
        }
    }, {
        ATTRS: {
            xrender: {
                value: TreeNodeRender
            },

            checkable: {
                value: false,
                view: 1
            },

            // 事件代理
            handleMouseEvents: {
                value: false
            },

            /**
             * Only For Config.
             * Whether to force current tree node as a leaf.                 *
             * It will change as children are added.
             *
             * @type {Boolean}
             */
            isLeaf: {
                view: 1
            },

            /**
             * Element for expand icon.
             * @type {KISSY.NodeList}
             */
            expandIconEl: {
            },

            /**
             * Element for icon.
             * @type {KISSY.NodeList}
             */
            iconEl: {
            },

            /**
             * Whether current tree node is selected.
             * @type {Boolean}
             */
            selected: {
                view: 1
            },

            /**
             * Whether current tree node is expanded.
             * @type {Boolean}
             * Defaults to: false.
             */
            expanded: {
                sync: 0,
                value: false,
                view: 1
            },

            /**
             * html title for current tree node.
             * @type {String}
             */
            tooltip: {
                view: 1
            },

            /**
             * Tree instance current tree node belongs to.
             * @type {KISSY.Tree}
             */
            tree: {
                getter: function () {
                    var from = this;
                    while (from && !from.isTree) {
                        from = from.get('parent');
                    }
                    return from;
                }
            },

            /**
             * depth of node.
             * @type {Number}
             */
            depth: {
                view: 1
            },

            focusable: {
                value: false
            },

            defaultChildCfg: {
                value: {
                    xclass: 'tree-node'
                }
            }
        },
        xclass: 'tree-node'
    });

    // # ------------------- private start

    function onAddChild(e) {
        var self = this;
        if (e.target == self) {
            updateSubTreeStatus(self, e.component, self.get('depth'), e.index);
        }
    }

    function onRemoveChild(e) {
        var self = this;
        if (e.target == self) {
            recursiveSetDepth(self.get('tree'), e.component);
            refreshCssForSelfAndChildren(self, e.index);
        }
    }

    function syncAriaSetSize(e) {
        var self = this;
        if (e.target === self) {
            self.el.setAttribute('aria-setsize',
                self.get('children').length);
        }
    }

    function isNodeSingleOrLast(self) {
        var parent = self.get('parent'),
            children = parent && parent.get("children"),
            lastChild = children && children[children.length - 1];
        // 根节点
        // or
        // 父亲的最后一个子节点
        return !lastChild || lastChild == self;
    }

    function isNodeLeaf(self) {
        var isLeaf = self.get("isLeaf");
        // 强制指定了 isLeaf,否则根据儿子节点集合自动判断
        return !(isLeaf === false || (isLeaf === undefined && self.get("children").length));
    }

    function getLastVisibleDescendant(self) {
        var children = self.get("children");
        // 没有展开或者根本没有儿子节点,可视的只有自己
        if (!self.get("expanded") || !children.length) {
            return self;
        }
        // 可视的最后一个子孙
        return getLastVisibleDescendant(children[children.length - 1]);
    }

    // not same with _4e_previousSourceNode in editor !
    function getPreviousVisibleNode(self) {
        var prev = self.prev();
        if (!prev) {
            prev = self.get('parent');
        } else {
            prev = getLastVisibleDescendant(prev);
        }
        return prev;
    }

    // similar to _4e_nextSourceNode in editor
    function getNextVisibleNode(self) {
        var children = self.get("children"),
            n,
            parent;
        if (self.get("expanded") && children.length) {
            return children[0];
        }
        // 没有展开或者根本没有儿子节点
        // 深度遍历的下一个
        n = self.next();
        parent = self;
        while (!n && (parent = parent.get('parent'))) {
            n = parent.next();
        }
        return n;
    }

    /*
     每次添加/删除节点,都检查自己以及自己子孙 class
     每次 expand/collapse,都检查
     */
    function refreshCss(self) {
        if (self.get && self.view) {
            self.view.refreshCss(isNodeSingleOrLast(self), isNodeLeaf(self));
        }
    }

    function updateSubTreeStatus(self, c, depth, index) {
        var tree = self.get("tree");
        if (tree) {
            recursiveSetDepth(tree, c, depth + 1);
            refreshCssForSelfAndChildren(self, index);
        }
    }

    function recursiveSetDepth(tree, c, setDepth) {
        if (setDepth !== undefined) {
            c.set("depth", setDepth);
        }
        S.each(c.get("children"), function (child) {
            if (typeof setDepth == 'number') {
                recursiveSetDepth(tree, child, setDepth + 1);
            } else {
                recursiveSetDepth(tree, child);
            }
        });
    }

    function refreshCssForSelfAndChildren(self, index) {
        refreshCss(self);
        index = Math.max(0, index - 1);
        var children = self.get('children'),
            c,
            len = children.length;
        for (; index < len; index++) {
            c = children[index];
            refreshCss(c);
            c.el.setAttribute("aria-posinset", index + 1);
        }
    }

    // # ------------------- private end
}, {
    requires: ['node', 'component/container', './node-render']
});

/**
 * @ignore
 * 2012-09-25
 *  - 去除 dblclick 支持,该交互会重复触发 click 事件,可能会重复执行逻辑
 */