// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

const {ccclass, property} = cc._decorator;

@ccclass
export default class Attributes extends cc.Component {
    @property
    id: string = '';

    @property
    class: string = '';

    @property({ type: [cc.String], displayName: '自定义属性', tooltip: "key:value结构，冒号“：”分割" })
    customAttributeStrArr: string[] = [];
    
    attrMap = {};

    // LIFE-CYCLE CALLBACKS:

    // onLoad () {}

    start () {
        this.attrMap = {}
        for (let i = 0 ; i < this.customAttributeStrArr.length; i++) {
            const att = this.customAttributeStrArr[i];
            const [k, v] = att.split(':');
            this.attrMap[k] = v;
        }
    }
    checkNode({selector, type, node, first = true, result = []}) {
        // console.log(node.name);
        const att = node.getComponent('Attributes');
        if (att && att[type] === selector ) {
            if (first) {
                return node;
            } else {
                result.push(node);
                att.walkChildren({selector, type, node, first, result})
            }
        } else if(att && type === 'attr') {
            let [k ,v] = selector.split('=');
            if (k) {
                k = k.trim()
            }
            if (v) {
                v = v.trim()
            }
            if (k && !v) {
                if (first) {
                    if(k in att.attrMap) {
                        return node;
                    } 
                } else {
                    if(k in att.attrMap) {
                        result.push(node);
                    }
                    att.walkChildren({selector, type, node, first, result})
                }
            } else if (k && v){
                if (first) {
                    if(att.attrMap[k]==v) {
                        return node;
                    } 
                } else {
                    if(att.attrMap[k]==v) {
                        result.push(node);
                    }
                    att.walkChildren({selector, type, node, first, result})
                }
            }
        } else {
            if (first) {
                const matchNode = this.walkChildren({selector, type, node, first, result});
                if (matchNode) {
                    return matchNode
                }
            } else {
                this.walkChildren({selector, type, node, first, result});
            }
        }
        
    }
    walkChildren({selector, type, node, first = true, result = []}) {
        for (let i = 0; i < node.children.length; i++) {
            const n = node.children[i];
            // console.log(n.name);
            const r = this.checkNode({selector, type, node: n, first, result});
            if (first && r) {
                return r;
            }
        }
    }
    walk({selector, type, node, first = true, result = []}) {
        const r = this.checkNode({selector, type, node, first, result});
        if (first && r) {
            return r;
        }
        
    }
    getToken(selector) {
        const s = selector[0];
        let type = 'name';
        selector = selector.substr(1);
        if (s === '.') {
            type = 'class';
        } else if (s === '#') {
            type = 'id'
        } else if (s === '[') {
            type = 'attr'
            selector = selector.substring(0, selector.length-1);
            selector = selector.replace(/\s+/g, '').replace(/'/g, '').replace(/"/g, '');
        } else {
            selector = s + selector;
        }
        return {
            type,
            selector
        }
    }
    querySelector(selectorStr) {
        const {selector, type} = this.getToken(selectorStr);
        return this.walk({selector, type, node: this.node});
    }
    querySelectorAll(selectorStr) {
        const {selector, type} = this.getToken(selectorStr);
        const result = [];
        this.walk({selector, type, node: this.node, first: false, result});
        return result;
    }
    // update (dt) {}
}
