/**
 * 复数变化规则
 * 
 * 
 */
export class PluralizeRule{

    /**
     * 不规则
     *  
     * @protected
     * @type {string[]}
     * @memberof PluralizeRule
     */
    protected irregular: Map<string, string> = new Map();

    /**
     * 不可数
     *  
     * @protected
     * @type {string[]}
     * @memberof PluralizeRule
     */
     protected uncountable: string[] = [
        "equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "people", "men",
        "children", "sexes", "moves", "stadiums", "oxen", "octopi", "viri", "aliases", "quizzes",
    ];

    /**
     * 初始化pluralizeRule对象
     * 
     * @param opts 额外参数
     * @memberof PluralizeRule
     */
    public constructor(opts: any = {}) {
        this.initIrregular();
    }

    /**
     * 初始化不规则变化
     * 
     * @param opts 额外参数
     * @memberof PluralizeRule
     */
    protected initIrregular(){
        this.irregular.set("person", "people");
        this.irregular.set("man", "men");
        this.irregular.set("child", "children");
        this.irregular.set("sex", "sexes");
        this.irregular.set("move", "moves");
        this.irregular.set("stadium", "stadiums");
    }

    /**
     * 是否为不可数
     * 
     * @param word 单词
     * @returns 返回判断
     * @memberof PluralizeRule
     */
    public isUncountable(word: string){
        const index: number = this.uncountable.findIndex((wordStr: string) =>{
            return Object.is(word, wordStr);
        })
        if (index == -1) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 不规则变化
     * 
     * @param word 单词
     * @returns 返回变化值
     * @memberof PluralizeRule
     */
    public irregularChange(word: string){
        for(let item of this.irregular.entries()){
            if(word && word.endsWith(item[0])){
                return word.replace(new RegExp(item[0],'g'),item[1]);
            }
        }
        return this.irregular.get(word);
    }

    /**
     * 规则变化
     * 
     * @param word 单词
     * @returns 返回变化值
     * @memberof PluralizeRule
     */
    public ruleChange(word: string){
        if(/(ax|test)is$/.test(word)) return word.replace(/is$/,"es");
        if(/(octop|vir)us$/.test(word)) return word.replace(/us$/,"i");
        if(/(octop|vir)i$/.test(word)) return word;
        if(/(alias|status)$/.test(word)) return word+"es";
        if(/(bu)s$/.test(word)) return word.replace(/s$/,"ses");
        if(/(buffal|tomat)o$/.test(word)) return word.replace(/o$/,"oes");
        if(/([ti])um$/.test(word)) return word.replace(/um$/,"a");
        if(/([ti])a$/.test(word)) return word;
        if(/sis$/.test(word)) return word.replace(/sis$/,"ses");
        if(/(?:([^f])fe|([lr])f)$/.test(word)) return word.substring(0, word.length - 1)+"ves";
        if(/(hive)$/.test(word)) return word+"s";
        if(/([^aeiouy]|qu)y$/.test(word)) return word.replace(/y$/,"ies");
        if(/(x|ch|ss|sh)$/.test(word)) return word+"es";
        if(/(matr|vert|ind)ix|ex$/.test(word)) return word.replace(/ix|ex$/,"ices");
        if(/([m|l])ouse$/.test(word)) return word.replace(/ouse$/,"ice");
        if(/([m|l])ice$/.test(word)) return word;
        if(/^(ox)$$/.test(word)) return word+"en";
        if(/(quiz)$/.test(word)) return word+"zes";
        if(/s$/.test(word)) return word.replace(/s$/,"s");
        return word+"s";
    }
}