/* global OpenDocument */

OpenDocument.StyleMatcher = function () {
    this.singletonMap = new Map();
    this.groupByClassMap = new Map();
    
};

OpenDocument.StyleMatcher.prototype.putStyle = function (styleName, cssToken) {
    if ((!cssToken) || (!cssToken.startsWith('.')) || (cssToken.length < 2)) {
        return;
    }
    var cssClassArray = (cssToken.substring(1)).split(".");
    if (cssClassArray.length === 1) {
        this.singletonMap.set(cssClassArray[0], styleName);
    } else {
        let group = new OpenDocument.StyleMatcher.Group(cssClassArray, styleName);
        for(let cssClass of cssClassArray) {
            let groupByClass = this.groupByClassMap.get(cssClass);
            if (!groupByClass) {
                groupByClass = new OpenDocument.StyleMatcher.GroupByClass();
                this.groupByClassMap.set(cssClass, groupByClass);
            }
            groupByClass.addGroup(group);
        }
    }
};

OpenDocument.StyleMatcher.prototype.getMatchingStyle = function (element) {
    var groupByClassMap = this.groupByClassMap;
    var length = element.classList.length;
    if (length === 0) {
        return "";
    }
    if (length === 1) {
        let matchingStyle = this.singletonMap.get(element.classList.item(0));
        if (matchingStyle) {
            return matchingStyle;
        } else {
            return "";
        }
    }
    var singletonCandidate = "";
    var cssClassSet = new Set();
    for(let cssClass of element.classList) {
        let matchingStyle = this.singletonMap.get(cssClass);
        if ((matchingStyle) && (!singletonCandidate)) {
            singletonCandidate = matchingStyle;
        }
        cssClassSet.add(cssClass);
    }
    var bestGroup =  _getBestGroup();
    if ( bestGroup) {
        return  bestGroup.styleName;
    }
    return singletonCandidate;
    
    function _getBestGroup() {
        if (groupByClassMap.size === 0) {
            return null;
        }
        let bestCandidate = null;
        for(let cssClass of element.classList) {
            let groupByClass = groupByClassMap.get(cssClass);
            if (groupByClass) {
                let candidate = groupByClass.getBestMatching(cssClassSet);
                if (candidate) {
                    if (bestCandidate) {
                        if (candidate.compare(bestCandidate) > 0) {
                            bestCandidate = candidate;
                        }
                    } else {
                        bestCandidate = candidate;
                    }
                }
            }
        }
        return bestCandidate;
    }
};


OpenDocument.StyleMatcher.GroupByClass = function () {
    this.groupArray = [];
};

OpenDocument.StyleMatcher.GroupByClass.prototype.addGroup = function (group) {
    var length = this.groupArray.length;
    var done = false;
    for(let i = 0; i < length; i++) {
        let currentGroup = this.groupArray[i];
        if (group.compare(currentGroup) >= 0) {
            this.groupArray.splice(i, 0, group);
            done = true;
            break;
        }
    }
    if (!done) {
        this.groupArray.push(group);
    }
};

OpenDocument.StyleMatcher.GroupByClass.prototype.getBestMatching = function (cssClassSet) {
    for(let group of this.groupArray) {
        if (group.match(cssClassSet)) {
            return group;
        }
    }
    return null;
};

OpenDocument.StyleMatcher.Group = function (cssClassArray, styleName) {
    this.cssClassArray = cssClassArray;
    this.styleName = styleName;
    this.level = cssClassArray.length;
};

OpenDocument.StyleMatcher.Group.prototype.compare = function (otherGroup) {
    if (this.level > otherGroup.level) {
        return 1;
    }
    if (this.level < otherGroup.level) {
        return -1;
    }
    return 0;
};

OpenDocument.StyleMatcher.Group.prototype.match = function (cssClassSet) {
    for(let cssClass of this.cssClassArray) {
        if (!cssClassSet.has(cssClass)) {
            return false;
        }
    }
    return true;
};

