import ContextMapper from "./ContextMapper";
import Rule from "./Rule";
import URLContextMapper from "./URLContextMapper";
import XPathContextMapper from "./XPathContextMapper";
import ContextLessMapper from "./ContextLessMapper";
import CSSContextMapper from "./CSSContextMapper";

export default class RuleMapper {
    private _cssContext2ContextMapper : Map<string, ContextMapper>;
    private _xpathContext2ContextMapper : Map<string, ContextMapper>;
    private _urlContext2ContextMapper : Map<string, ContextMapper>;
    private _contextLessMapper : ContextMapper;
    private _prefix2Rules : Map<string, Rule[]>;
    private _eventInRules : string[];

    constructor(rules : Rule[]) {
        // console.log('rules:', rules.length);
        this._cssContext2ContextMapper = new Map();
        this._xpathContext2ContextMapper = new Map();
        this._urlContext2ContextMapper = new Map();
        this._contextLessMapper = new ContextLessMapper(undefined);
        this._prefix2Rules = new Map();
        this._eventInRules = [];

        rules.forEach(rule => {
            if (!this._prefix2Rules.has(rule.prefix)) {
                this._prefix2Rules.set(rule.prefix,[]);
            }
            this._prefix2Rules.get(rule.prefix).push(rule);
            if (!this._eventInRules.includes(rule.event)) {
                this._eventInRules.push(rule.event);
            }

            if (rule.contextCSS) {
                // console.log(rule.contextCSS);
                if (!this._cssContext2ContextMapper.has(rule.contextCSS)) {
                    this._cssContext2ContextMapper.set(rule.contextCSS, new CSSContextMapper(rule.contextCSS));
                }
                this._cssContext2ContextMapper.get(rule.contextCSS).add(rule);
            } else if (rule.contextXPath) {
                // console.log(rule.contextXPath);
                if (!this._xpathContext2ContextMapper.has(rule.contextXPath)) {
                    this._xpathContext2ContextMapper.set(rule.contextXPath, new XPathContextMapper(rule.contextXPath));
                }
                this._xpathContext2ContextMapper.get(rule.contextXPath).add(rule);
            } else if (rule.contextURL) {
                if (!this._urlContext2ContextMapper.has(rule.contextURL)) {
                    this._urlContext2ContextMapper.set(rule.contextURL, new URLContextMapper(rule.contextURL));
                }
                this._urlContext2ContextMapper.get(rule.contextURL).add(rule);
            } else {
                this._contextLessMapper.add(rule);
            }
        })

        // console.log('css context:',this._cssContext2ContextMapper.size);
        // console.log('xpath context:',this._xpathContext2ContextMapper.size);
        // console.log('url context:',this._urlContext2ContextMapper.size);
    }

    getRuleListByPrefix(prefix : string) : Rule[] {
        if (this._prefix2Rules.has(prefix)) {
            return this._prefix2Rules.get(prefix);
        } else {
            return [];
        }
    }

    get eventInRules(): string[] {
        return this._eventInRules;
    }

    buildElementToRuleMap(): Map<Element, Rule[]> {
        const result : Map<Element, Rule[]> = new Map();
        for (const mapper of this._urlContext2ContextMapper.values()) {
            for (const [element, rules] of mapper.buildElementToRuleMap()) {
                if (!result.has(element)) {
                    result.set(element,[]);
                }
                result.get(element).push(...rules);
            }
        }
        for (const mapper of this._cssContext2ContextMapper.values()) {
            for (const [element, rules] of mapper.buildElementToRuleMap()) {
                if (!result.has(element)) {
                    result.set(element,[]);
                }
                result.get(element).push(...rules);
            }
        }
        for (const mapper of this._xpathContext2ContextMapper.values()) {
            for (const [element, rules] of mapper.buildElementToRuleMap()) {
                if (!result.has(element)) {
                    result.set(element,[]);
                }
                result.get(element).push(...rules);
            }
        }
        for (const [element, rules] of this._contextLessMapper.buildElementToRuleMap()) {
            if (!result.has(element)) {
                result.set(element,[]);
            }
            result.get(element).push(...rules);
        }
        return result;
    }

}