'use strict';

function TextualRule (prop,map,exact) {
	this.prop    = prop;
	this.map     = map;
	this.exact   = exact;
}
TextualRule.prototype.parse = function (words) {
	var keywords = [];
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		var keyword = this.parseWord(word);
		if (!keyword) continue;
		keywords.push(keyword);
		words.splice(i,1);
		i--;
	}
	var prop = this.prop;
	var exact = this.exact;
	return function filter (info) {
		if (!keywords.length) return true;
		return keywords.some(function (keyword) {
			if (info[prop] && typeof info[prop] !== 'string') info[prop] = true;
			var value = ('' + info[prop]).toLowerCase();
			if (exact) {
				return value === keyword;
			} else {
				return value.indexOf(keyword) !== -1;
			}
		});
	};
};
TextualRule.prototype.parseWord = function (word) {
	for (var keyword in this.map) {
		var matchWords = this.map[keyword];
		if (matchWords.some(function (matchWord) {
			return word === Localize.traditionalize(matchWord);
		},this)) {
			return keyword;
		}
	}
	return null;
};
///////////////////////////////////////////////////////////////
//
//  枚举型规则,包括:
//    ColorRule,TypeRule,RarityRule,RiseRule,TrapRule,AcceRule
//  匹配例子:
//    "白 LRIG SR 红"
//    "白色 精灵 lr red rise"
//
///////////////////////////////////////////////////////////////
var ColorRule = new TextualRule('color',{
	'colorless': ['colorless','无','无色','無','incolore','무','무색'],
	'white': ['white','白','白色','白','белая','bianco','백','백색'],
	'black': ['black','黑','黑色','黒','чёрная','nero','흑','흑색'],
	'red': ['red','红','红色','赤','красная','rosso','적','적색'],
	'blue': ['blue','蓝','蓝色','青','синяя','blu','청','청색'],
	'green': ['green','绿','绿色','緑','зелёная','verde','녹','녹색']
},false);
var TypeRule = new TextualRule('cardType',{
	'lrig': ['l','lrig','分身','ルリグ','идел','루리그'],
	'signi': ['s','signi','精灵','シグニ','запись','시그니'],
	'spell': ['spell','魔法','スペル','магия','스펠'],
	'arts': ['arts','必杀','技艺','アーツ','умение','아츠'],
	'resona': ['resona','共鸣','レゾナ','отголосок','레조나']
},true);
var RarityRule = new TextualRule('rarity',{
	'c': ['c'],
	'r': ['r'],
	'lc': ['lc'],
	'sr': ['sr'],
	'lr': ['lr'],
	'st': ['st'],
	'pr': ['pr'],
	'sp': ['sp']
},true);
var RiseRule = new TextualRule('rise',{
	'true': ['rise','升阶','ライズ'],
},true);
var TrapRule = new TextualRule('trap',{
	'true': ['trap','陷阱','陷阱标记','トラップ'],
},true);
var AcceRule = new TextualRule('acce',{
	'true': ['acce','accessory','附属','アクセ'],
},true);

///////////////////////////////////////////////////////////////
//
//  效果(能力)型规则:
//    SkillRule
//  匹配例子:
//    "常","常时","常时效果","常时能力"
//    "※","爆发","爆发效果","迸发","迸发效果"
//
///////////////////////////////////////////////////////////////
var SkillRule = {};
SkillRule.parse = function (words) {
	var effectProps = [];
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		var effectProp = this.parseWord(word);
		if (!effectProp) continue;
		effectProps.push(effectProp);
		words.splice(i,1);
		i--;
	}
	return function filter (info) {
		if (!effectProps.length) return true;
		info = CardInfo[info.cid];
		return effectProps.some(function (effectProp) {
			var effectTexts = info[effectProp];
			return effectTexts && effectTexts.length;
		});
	};
};
SkillRule.parseWord = TextualRule.prototype.parseWord;
SkillRule.map = {
	'constEffectTexts': [
		'【常】','常','常时','常时效果','常時能力',
		'【常】','常','常時','常時效果','常時能力',
		'[constant]','const','constant',
		'[постоянно]','постоянно',
		'상시','[상시]'
	],
	'startUpEffectTexts': [
		'【出】','出','出场','出场效果','出场能力',
		'【出】','出','出現','出現效果','出現能力',
		'[on-play]','[onplay]','on-play','onplay',
		'[при вводе]','при вводе',
		'출현','[출현]'
	],
	'actionEffectTexts': [
		'【起】','起','起动','起动效果','起动能力',
		'【起】','起','起動','起動效果','起動能力',
		'[action]','action',
		'[действие]','действие',
		'기동','[기동]',
	],
	'burstEffectTexts': [
		'【※】','※','爆发','迸发','爆发效果','迸发效果','生命爆发','生命迸发','生命爆发效果','生命迸发效果',
		'ライフバースト','バースト',
		'burst','lifeburst','lb',
		'вспышка','жизненная вспышка',
		'라이프 버스트','라이프버스트','버스트'
	]
};

///////////////////////////////////////////////////////////////
//
//  无迸发规则:
//    NoBurstRule
//  匹配例子:
//    "无爆发","noburst"
//
///////////////////////////////////////////////////////////////
var NoBurstRule = {};
NoBurstRule.parse = function (words) {
	var matched = false;
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		if (!this.parseWord(word)) continue;
		matched = true;
		words.splice(i,1);
		i--;
	}
	return function filter (info) {
		if (!matched) return true;
		info = CardInfo[info.cid];
		return (info.cardType === 'SIGNI' || info.cardType === 'SPELL') &&
		       (!info.burstEffectTexts || !info.burstEffectTexts.length);
	};
};
NoBurstRule.parseWord = TextualRule.prototype.parseWord;
NoBurstRule.map = {
	'burstEffectTexts': [
		'无爆发','无迸发','无爆发效果','无迸发效果','无生命爆发','无生命迸发','无生命爆发效果','无生命迸发效果',
		'noburst',
		'ライフバースト-','バースト-',
		'迸发-','爆发-',
		'burst-','lifeburst-','lb-',
		'вспышка-','жизненная вспышка-',
		'버스트-','라이프버스트-'
	]
};

///////////////////////////////////////////////////////////////
//
//  CROSS规则:
//    CrossRule
//  匹配例子:
//    "cross","交错","クロス"等
//
///////////////////////////////////////////////////////////////
var CrossRule = {};
CrossRule.parse = function (words) {
	var matched = false;
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		if (!this.parseWord(word)) continue;
		matched = true;
		words.splice(i,1);
		i--;
	}
	return function filter (info) {
		if (!matched) return true;
		info = CardInfo[info.cid];
		return (info.cardType === 'SIGNI') &&
		       (info.crossLeft || info.crossRight);
	};
};
CrossRule.parseWord = TextualRule.prototype.parseWord;
CrossRule.map = {
	'cross': [
		'cross','交错','クロス','связь','크로스',
		'[cross]','>cross<','【cross】','【交错】','【クロス】','[связь]','>크로스<'
	]
};

///////////////////////////////////////////////////////////////
//
//  时点规则:
//    TimmingRule
//  匹配例子:
//    "【主要阶段】","主要阶段"
//    "【魔法切入】","魔法切入"
//
///////////////////////////////////////////////////////////////
var TimmingRule = {};
TimmingRule.parse = function (words) {
	var timmings = [];
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		var timming = this.parseWord(word);
		if (!timming) continue;
		timmings.push(timming);
		words.splice(i,1);
		i--;
	}
	return function filter (info) {
		if (!timmings.length) return true;
		return timmings.some(function (timming) {
			if (!info.timmings) return false;
			return inArr(timming,info.timmings);
		});
	};
};
TimmingRule.parseWord = TextualRule.prototype.parseWord;
TimmingRule.map = {
	'mainPhase': [
		'主要阶段','【主要阶段】','主要',
		'メインフェイズ','【メインフェイズ】',
		'[mainphase]','mainphase','main',
		'[основнаяфаза]','основнаяфаза','основная',
		'메인','메인페이즈','[메인페이즈]'
	],
	'attackPhase': [
		'攻击阶段','【攻击阶段】','攻击',
		'アタックフェイズ','【アタックフェイズ】',
		'[attackphase]','attackphase','attack',
		'[фазаатаки]','фазаатаки','атака',
		'어택','어택페이즈','[어택페이즈]'
	],
	'spellCutIn': [
		'魔法切入','【魔法切入】','切入',
		'スペルカットイン','【スペルカットイン】',
		'[spellcut-in]','[cut-in]','[spellcutin]','[cutin]','spellcutin','cutin','cut',
		'[ответнамагию]','[ответ]','ответнамагию','ответ',
		'컷인','컷인','[스펠컷인]','스펠컷인'
	]
};

///////////////////////////////////////////////////////////////
//
//  限定规则:
//    LimitingRule
//  匹配例子:
//    "小玉"
//    "小玉+"
//
///////////////////////////////////////////////////////////////
var LimitingRule = {};
LimitingRule.parse = function (words) {
	var matchedClasses = [];
	var flagNoLimiting = false;
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		var classes = [
			'タマ','花代','ユヅキ','ピルルク','エルドラ','ミルルン','緑子',
			'アン','ウリス','イオナ','ウムル','リメンバ','タウィル','サシェ',
			'ミュウ','アイヤイ','アルフォウ','ハナレ','リル','メル',
			'あや','ナナシ','ドーナ','ママ'
		];
		for (var j = 0; j < classes.length; j++) {
			var cls = classes[j];
			var matched = false;
			var localizedClass = Localize('class',cls).toLowerCase();
			if (word === localizedClass) {
				matched = true;
			} else if (word === localizedClass+'+') {
				matched = true;
				flagNoLimiting = true;
			}
			if (matched) {
				matchedClasses.push(cls);
				words.splice(i,1);
				i--;
				break;
			}
		}
	}
	return function filter (info) {
		if (!matchedClasses.length) return true;
		if (info.cardType === 'LRIG') {
			return matchedClasses.some(function (cls) {
				if (!info.classes) return false;
				return inArr(cls,info.classes);
			},this);
		}
		if (!info.limiting) return flagNoLimiting;
		var limitings = info.limiting.split('/');
		return limitings.some(function (limiting) {
			return inArr(limiting,matchedClasses);
		});
	};
};

///////////////////////////////////////////////////////////////
//
//  类别规则:
//    ClassRule
//  匹配例子:
//    "精武"
//    "武装"
//
///////////////////////////////////////////////////////////////
var ClassRule = {};
ClassRule.parse = function (words) {
	var matchedClasses = [];
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		var classes = [
			'精像','天使','悪魔','美巧','精武','アーム','ウェポン','遊具',
			'毒牙','精羅','鉱石','宝石','植物','原子','宇宙','精械','電機',
			'古代兵器','迷宮','精生','水獣','空獣','地獣','龍獣','凶蟲','精元',
			'武勇','調理','トリック','英知','微菌','怪異',
		];
		for (var j = 0; j < classes.length; j++) {
			var cls = classes[j];
			if (word === Localize('class',cls).toLowerCase().replace(' ','')) {
				matchedClasses.push(cls);
				words.splice(i,1);
				i--;
				break;
			}
		}
	}
	return function filter (info) {
		if (!matchedClasses.length) return true;
		return matchedClasses.some(function (cls) {
			if (!info.classes) return false;
			return inArr(cls,info.classes);
		},this);
	};
};

///////////////////////////////////////////////////////////////
//
//  数值型规则,包括:
//    PowerRule,LevelRule,LimitRule
//  匹配格式:
//    相等: "关键字:=数值"
//    大于: "关键字:>=数值" 或 "关键字:数值+"
//    小于: "关键字:<=数值" 或 "关键字:数值-"
//    范围: "关键字:min~max" 或 "关键字:min-max"
//    (注: 上述的":"和"="可省略.)
//  匹配例子(每行等价):
//    "力量>100","Power>100","Power:100+","Power100+"
//    "等级=4","level=4","level4","lv4","lv.4"
//    "界限>7 界限<9","limit7+ 界限9-","界限:7-9","界限7~9"
//
///////////////////////////////////////////////////////////////
function NumericRule (prop,keywords) {
	this.prop = prop;
	this.keywords = keywords;
}
NumericRule.prototype.parseExpression = function (str) {
	var match;
	// 相等
	match = str.match(/^=*(\d+)$/);
	if (match) {
		var num = parseInt(match[1]);
		return [num,num];
	}
	// 大于
	match = str.match(/^>=*(\d+)\+?$/);
	if (!match) match = str.match(/^(\d+)\+$/);
	if (match) {
		var num = parseInt(match[1]);
		return [num,Infinity];
	}
	// 小于
	match = str.match(/^<=*(\d+)\-?$/);
	if (!match) match = str.match(/^(\d+)\-$/);
	if (match) {
		var num = parseInt(match[1]);
		return [-Infinity,num];
	}
	// 范围
	match = str.match(/^(\d+)[\-\~](\d+)$/);
	if (match) {
		var a = parseInt(match[1]);
		var b = parseInt(match[2]);
		return [a,b];
	}
	return null
};
NumericRule.prototype.parseWord = function (word) {
	for (var i = 0; i < this.keywords.length; i++) {
		var keyword = Localize.traditionalize(this.keywords[i]);
		if (word.indexOf(keyword) === 0) {
			word = word.slice(keyword.length).replace(/^:/,'');
			return this.parseExpression(word);
		}
	}
	return null;
};
NumericRule.prototype.parse = function (words) {
	var ranges = [];
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		var range = this.parseWord(word);
		if (!range) continue;
		ranges.push(range);
		words.splice(i,1);
		i--;
	}
	var prop = this.prop;
	return function filter (info) {
		if (!ranges.length) return true;
		if ((info.cardType === 'SPELL') || (info.cardType === 'ARTS')) {
			return false;
		}
		return ranges.every(function (range) {
			var value = info[prop];
			var min = range[0];
			var max = range[1];
			return (value >= min) && (value <= max);
		});
	};
};
var PowerRule = new NumericRule('power',['力量','パワー','power','сила','파워']);
var LevelRule = new NumericRule('level',['等级','レベル','level','lv.','lv','уровень','livello','레벨']);
var LimitRule = new NumericRule('limit',['界限','リミット','limite','limit','ограничение','리미트']);

///////////////////////////////////////////////////////////////
//
//  数字规则: NumberRule.
//  匹配说明:
//    力量和等级的关键字可以省略,此时用NumberRule匹配.
//    数字小于10,则匹配为等级,否则匹配为力量.
//  匹配例子:
//    "1000+ 3-"      // 等价于"power>1000 level<3"
//    ">3 2000~3000"  // 等价于"level>3 power:2000~3000"
//
///////////////////////////////////////////////////////////////
var NumberRule = new NumericRule('',['']);
NumberRule.parse = function (words) {
	var ranges = [];
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		var range = this.parseWord(word);
		if (!range) continue;
		ranges.push(range);
		words.splice(i,1);
		i--;
	}
	return function filter (info) {
		return ranges.every(function (range) {
			if ((info.cardType === 'SPELL') || (info.cardType === 'ARTS')) return false;
			function matchLevel (num) {
				return !isFinite(num) || (num < 10);
			}
			var value = range.every(matchLevel)? info.level : info.power;
			var min = range[0];
			var max = range[1];
			return (value >= min) && (value <= max);
		});
	};
};

///////////////////////////////////////////////////////////////
//
//  画师规则: IllustRule.
//  匹配例子:
//    "画师:pop"
//    "Illust:藤真拓哉"
//
///////////////////////////////////////////////////////////////
var IllustRule = {};
IllustRule.parseWord = function (word) {
	var match = word.match(/illust:?(.+)/);
	if (!match) match = word.match(/画师:?(.+)/);
	if (!match) match = word.match(/畫師:?(.+)/);
	if (!match) return null;
	return match[1];
}
IllustRule.parse = function (words) {
	var illusts = [];
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		var illust = this.parseWord(word);
		if (!illust) continue;
		illusts.push(illust);
		words.splice(i,1);
		i--;
	}
	return function filter (info) {
		if (!illusts.length) return true;
		return illusts.some(function (illust) {
			var cardIllust = info.illust.toLowerCase();
			return cardIllust.indexOf(illust) !== -1;
		});
	};
};

///////////////////////////////////////////////////////////////
//
//  ID规则: WxidRule.
//  匹配例子:
//    "WD01-001","wd01-001","wD01001"  // 仅匹配"WD01-001"
//    "wx02-01","WX0201"  // 匹配"WX02-010"至"WX02-019"
//    "wd03-","WD03"      // 匹配"WD03"的所有卡
//    "wx12-re01","WX12CB" // 匹配re,CB卡
//
///////////////////////////////////////////////////////////////
var WxidRule = {};
WxidRule.parseWord = function (word) {
	var match = word.match(/^(wx\d{2}|wd\d{2}|pr|sp\d{2})-?(re\d{0,2}|cb\d{0,2}|\d{0,3}[a|b]?)$/);
	if (!match) return null;
	return match[1] + '-' + match[2];
}
WxidRule.parse = function (words) {
	var idLimits = [];
	for (var i = 0; i < words.length; i++) {
		var word = words[i];
		var limit = this.parseWord(word);
		if (!limit) continue;
		idLimits.push(limit);
		words.splice(i,1);
		i--;
	}
	return function filter (info) {
		if (!idLimits.length) return true;
		return idLimits.some(function (limit) {
			return info.wxid.toLowerCase().indexOf(limit) === 0;
		});
	};
};

///////////////////////////////////////////////////////////////
//
//  卡名规则: NameRule.
//  匹配例子:
//    "喷流 知识"       // 卡名同时包含"喷流"和"知识".
//    "喷流|知识"       // 卡名包含"喷流"或"知识".
//    "喷流||知识"      // 卡名包含"喷流"或"知识".
//    "喷流||的||知识"  // 卡名包含"喷流"或"知识"或"的".
//
///////////////////////////////////////////////////////////////
var NameRule = {};
NameRule.dotRegex =
	/[\u00B7\u0387\u05BC\u2022\u2027\u2219\u22C5\u30FB\uFF0E\uFF65⁑:*†]/g;
NameRule.fullWidth =
	'0123456789=@#' +
	'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
	'abcdefghijklmnopqrstuvwxyz';
NameRule.halfWidth =
	'0123456789=@#' +
	'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
	'abcdefghijklmnopqrstuvwxyz';
NameRule.normalizeString = function (str) {
	var chars = str.replace(this.dotRegex,'').split('');
	chars.forEach(function (char,idx) {
		var i = this.fullWidth.indexOf(char);
		chars[idx] = this.halfWidth[i] || char;
	},this);
	return chars.join('').toLowerCase();
};
NameRule.parse = function (words) {
	var wordSets = [];
	words.forEach(function (word) {
		wordSets.push(word.split(/\|+/));
	},this);
	words.length = 0;
	var that = this;
	return function filter (info) {
		return wordSets.every(function (wordSet) {
			if (!wordSet.length) return true;
			return wordSet.some(function (word) {
				var name = that.normalizeString(Localize.cardName(info));
				var w = that.normalizeString(word);
				return (name.indexOf(w) !== -1);
			},this);
		},this);
	};
};