"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * Cache to store generated match functions
 * @type {Object}
 */
var pMatchFunctionCache = {};
function compare_tagname(tag1, tag2) {
    if (!tag1) {
        return !tag2;
    }
    if (!tag2) {
        return !tag1;
    }
    return tag1.toLowerCase() === tag2.toLowerCase();
}
/**
 * Function cache
 */
var functionCache = {
    f145: function (el, tagName, classes) {
        'use strict';
        tagName = tagName || '';
        classes = classes || [];
        if (el.id !== tagName.substr(1)) {
            return false;
        }
        for (var cls = classes, i = 0; i < cls.length; i++) {
            if (el.classNames.indexOf(cls[i]) === -1) {
                return false;
            }
        }
        return true;
    },
    f45: function (el, tagName, classes) {
        'use strict';
        tagName = tagName || '';
        classes = classes || [];
        for (var cls = classes, i = 0; i < cls.length; i++) {
            if (el.classNames.indexOf(cls[i]) === -1) {
                return false;
            }
        }
        return true;
    },
    f15: function (el, tagName) {
        'use strict';
        tagName = tagName || '';
        if (el.id !== tagName.substr(1)) {
            return false;
        }
        return true;
    },
    f1: function (el, tagName) {
        'use strict';
        tagName = tagName || '';
        if (el.id !== tagName.substr(1)) {
            return false;
        }
    },
    f5: function () {
        'use strict';
        return true;
    },
    f55: function (el, tagName, classes, attr_key) {
        'use strict';
        tagName = tagName || '';
        classes = classes || [];
        attr_key = attr_key || '';
        var attrs = el.attributes;
        return attrs.hasOwnProperty(attr_key);
    },
    f245: function (el, tagName, classes, attr_key, value) {
        'use strict';
        tagName = tagName || '';
        classes = classes || [];
        attr_key = attr_key || '';
        value = value || '';
        var attrs = el.attributes;
        return Object.keys(attrs).some(function (key) {
            var val = attrs[key];
            return key === attr_key && val === value;
        });
        // for (let cls = classes, i = 0; i < cls.length; i++) {if (el.classNames.indexOf(cls[i]) === -1){ return false;}}
        // return true;
    },
    f25: function (el, tagName, classes, attr_key, value) {
        'use strict';
        tagName = tagName || '';
        classes = classes || [];
        attr_key = attr_key || '';
        value = value || '';
        var attrs = el.attributes;
        return Object.keys(attrs).some(function (key) {
            var val = attrs[key];
            return key === attr_key && val === value;
        });
        // return true;
    },
    f2: function (el, tagName, classes, attr_key, value) {
        'use strict';
        tagName = tagName || '';
        classes = classes || [];
        attr_key = attr_key || '';
        value = value || '';
        var attrs = el.attributes;
        return Object.keys(attrs).some(function (key) {
            var val = attrs[key];
            return key === attr_key && val === value;
        });
    },
    f345: function (el, tagName, classes) {
        'use strict';
        tagName = tagName || '';
        classes = classes || [];
        if (!compare_tagname(el.tagName, tagName)) {
            return false;
        }
        for (var cls = classes, i = 0; i < cls.length; i++) {
            if (el.classNames.indexOf(cls[i]) === -1) {
                return false;
            }
        }
        return true;
    },
    f35: function (el, tagName) {
        'use strict';
        tagName = tagName || '';
        return compare_tagname(el.tagName, tagName);
    },
    f3: function (el, tagName) {
        'use strict';
        tagName = tagName || '';
        // if (el.tagName !== tagName) {
        // 	return false;
        // }
        return compare_tagname(el.tagName, tagName);
    }
};
/**
 * Matcher class to make CSS match
 *
 * @class Matcher
 */
var Matcher = /** @class */ (function () {
    /**
     * Creates an instance of Matcher.
     * @param {string} selector
     *
     * @memberof Matcher
     */
    function Matcher(selector) {
        this.nextMatch = 0;
        this.matchers = selector.split(' ').map(function (matcher) {
            if (pMatchFunctionCache[matcher]) {
                return pMatchFunctionCache[matcher];
            }
            var parts = matcher.split('.');
            var tagName = parts[0];
            var classes = parts.slice(1).sort();
            // let source = '"use strict";';
            var function_name = 'f';
            var attr_key = '';
            var value = '';
            if (tagName && tagName !== '*') {
                var reg = void 0;
                if (tagName.startsWith('#')) {
                    // source += 'if (el.id != ' + JSON.stringify(tagName.substr(1)) + ') return false;';// 1
                    function_name += '1';
                }
                else {
                    reg = /^\[\s*(\S+)\s*(=|!=)\s*((((["'])([^\6]*)\6))|(\S*?))\]\s*/.exec(tagName);
                    if (reg) {
                        attr_key = reg[1];
                        var method = reg[2];
                        if (method !== '=' && method !== '!=') {
                            // eslint-disable-next-line no-template-curly-in-string
                            throw new Error('Selector not supported, Expect [key${op}value].op must be =,!=');
                        }
                        if (method === '=') {
                            method = '==';
                        }
                        value = reg[7] || reg[8];
                        // source += `let attrs = el.attributes;for (let key in attrs){const val = attrs[key]; if (key == "${attr_key}" && val == "${value}"){return true;}} return false;`;// 2
                        function_name += '2';
                    }
                    else if ((reg = /^\[(.*?)\]/.exec(tagName))) {
                        attr_key = reg[1];
                        function_name += '5';
                    }
                    else {
                        // source += 'if (el.tagName != ' + JSON.stringify(tagName) + ') return false;';// 3
                        function_name += '3';
                    }
                }
            }
            if (classes.length > 0) {
                // source += 'for (let cls = ' + JSON.stringify(classes) + ', i = 0; i < cls.length; i++) if (el.classNames.indexOf(cls[i]) === -1) return false;';// 4
                function_name += '4';
            }
            // source += 'return true;';// 5
            function_name += '5';
            var obj = {
                func: functionCache[function_name],
                tagName: tagName || '',
                classes: classes || '',
                attr_key: attr_key || '',
                value: value || ''
            };
            // source = source || '';
            return (pMatchFunctionCache[matcher] = obj);
        });
    }
    /**
     * Trying to advance match pointer
     * @param  {HTMLElement} el element to make the match
     * @return {bool}           true when pointer advanced.
     */
    Matcher.prototype.advance = function (el) {
        if (this.nextMatch < this.matchers.length &&
            this.matchers[this.nextMatch].func(el, this.matchers[this.nextMatch].tagName, this.matchers[this.nextMatch].classes, this.matchers[this.nextMatch].attr_key, this.matchers[this.nextMatch].value)) {
            this.nextMatch++;
            return true;
        }
        return false;
    };
    /**
     * Rewind the match pointer
     */
    Matcher.prototype.rewind = function () {
        this.nextMatch--;
    };
    Object.defineProperty(Matcher.prototype, "matched", {
        /**
         * Trying to determine if match made.
         * @return {bool} true when the match is made
         */
        get: function () {
            return this.nextMatch === this.matchers.length;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Rest match pointer.
     * @return {[type]} [description]
     */
    Matcher.prototype.reset = function () {
        this.nextMatch = 0;
    };
    /**
     * flush cache to free memory
     */
    Matcher.prototype.flushCache = function () {
        pMatchFunctionCache = {};
    };
    return Matcher;
}());
exports.default = Matcher;
