// 検索データの部分表示閾値（文字数）
var PartialDisplayStrNum = 150;
// 部分表示のときの検索文字列の前後表示文字数
var BeforeAndAfterNum = 32;
// 最初にヒットしたもののみ表示
var OnlyFirstSearch = false;
// ヒット文字強調エレメント
var HitStringDecorationStart = '<font color="#FF0000"><b>';
var HitStringDecorationEnd = '</b></font>';
// 複数検索ワード区切り文字
var MatchWordDlm = '`';

function SearchTextSet(stext){

	var result = new String;
	var result_detail = new String;
	var resCnt = 0;
	var any_result = new Boolean (false);

	result += '<h1>キーワード検索の結果</h1>';
	
	//add sanitize
	stext = sanitizeHTML(stext);
	
	//全角英数字を半角に
	var search_moji = z2h_ascii(stext);

	var synonymList;
	if (typeof(gSynonymList) == 'undefined') {
		synonymList = [];
	} else {
		synonymList = gSynonymList;
	}

	var patterns = getMatchPatterns(search_moji, synonymList);

	for (var s = 0; s < gContents.length; s++){

		var search_string = gContents[s];
		var matchstrings = '';
		var partialDisplay = (search_string.length > PartialDisplayStrNum);
		var matchwords = [];

		for (var ix = 0; ix < patterns.length; ix++) {
			var pattern = patterns[ix];

			var matchStringLine = getMatchSring(search_string, pattern, partialDisplay, matchwords);

			if (matchStringLine.length > 0) {
				matchstrings += matchStringLine;
			}
		}

		if (matchstrings) {
			resCnt = resCnt + 1;
			any_result = true;

			var urlstr = getLinkTitle(gPlace[s], gFilename[s], gTitle[s], matchwords);
			result_detail += urlstr + matchstrings;
		}
	}

	result += '<p align="right"><b>検索結果：ResultCount件</b></p>'.replace('ResultCount',resCnt);
	result += result_detail;

	if (any_result == false){
		result += '<br><div>「SearchKeyword」はありませんでした。</div>'.replace('SearchKeyword',stext);
	}

	return result;
 }

// Enterキーでも検索できるように
function SearchEnter(pmoji,event){

	if (event.keyCode == 13){
		if (pmoji != "") {
			var resultStr = SearchTextSet(pmoji);
			if (resultStr) {
				$(".content").html(resultStr);
			}
		}
	}
}

function SearchText(pmoji) {
	if (pmoji != "") {
		var resultStr = SearchTextSet(pmoji);
		if (resultStr) {
			$(".content").html(resultStr);
		}
	}
}

// 全角英数字を半角に変換
function z2h_ascii(src) {
	var str = new String;
	var len = src.length;
	for (var i = 0; i < len; i++) {
		var c = src.charCodeAt(i);
		if (c >= 65281 && c <= 65374 && c != 65340) {
			str += String.fromCharCode(c - 65248);
		} else if (c == 8217) {
			str += String.fromCharCode(39);
		} else if (c == 8221) {
			str += String.fromCharCode(34);
		} else if (c == 12288) {
			str += String.fromCharCode(32);
		} else if (c == 65507) {
			str += String.fromCharCode(126);
		} else if (c == 65509) {
			str += String.fromCharCode(92);
		} else {
			str += src.charAt(i);
		} 
	}
	return str;
}

function getMatchSring(src, pattern, partialDisplay, matchwords) {
	var matchstring = '';

	var rgexptn = pattern.base;
	rgexptn.lastIndex = 0;
	if (pattern.andp) {
		pattern.andp.lastIndex = 0;
	}

	if (partialDisplay) {
		// ヒットした文字列の前後数文字表示
		var result;
		var resultAnd;
		var andMatch = false;
		var andMatchList = [];

		while (result = rgexptn.exec(src)) {
			if (result[0].length == 0) {
				break;
			}

			matchwords[result[0]] = result.index;

			if (pattern.andp && !andMatch) {
				while (resultAnd = pattern.andp.exec(src)) {
					if (resultAnd[0].length == 0) {
						break;
					}
					var andMatchString = getDispLine(src, pattern.andp, resultAnd[0]);
					andMatchList.push(andMatchString);
					andMatch = true;

					matchwords[resultAnd[0]] = resultAnd.index;
				}

				if (!andMatch) {
					break;
				}

				matchstring += getDispLine(src, rgexptn, result[0]);

				for (var i = 0; i < andMatchList.length; i++) {
					matchstring += andMatchList[i];
				}

			} else {
				matchstring += getDispLine(src, rgexptn, result[0]);
			}

			if (OnlyFirstSearch) {
				break;
			}
		}

	} else {
		var mresult = src.match(rgexptn);
		if (mresult) {
			if (pattern.andp) {
				var resultAnd = pattern.andp.exec(src);
				if (!resultAnd) {
					return matchstring;
				}
			}

			var repstring = '<p align="left">' + HitStringDecorationStart + '$1' + HitStringDecorationEnd + '</p>\n';
			matchstring = src.replace(rgexptn,repstring);

			if (pattern.andp) {
				matchstring += src.replace(pattern.andp,repstring);
			}
		}
	}

	return matchstring;
}

function getLinkTitle(place, filename, title, matchwords) {

	var url = filename;
	var keyword = "";

	for(var key in matchwords) {
		keyword += MatchWordDlm + key;
	}

	if (keyword.length > 0) {
		url += "?search=" + encodeURIComponent(keyword.substring(1));
	}

	var urlstr =' <h2 align="left"><a href="' + url + '" rel="parent" onclick="$.fn.appendFontSizeClass(this); $.fn.appendToggleIndex(this);"> ' + title + "</a></h2>\n";

	//タブ文字の削除
	urlstr = urlstr.replace(/\t/g,"");

	return urlstr;
}

function getMatchDispLine(search_string, pattern, pos, wordlen) {
	var result_detail = "";

	//検索文字の位置から前の文字列を指定
	var place00 = pos - BeforeAndAfterNum;

	if(place00 <= 0 ){
		place00 = 1;
	}

	//検索結果の表示文字数を指定
	var place01 = PartialDisplayStrNum;

	if (search_string.length < place00 + place01 ){
		place01 = search_string.length - place00 - 1;
	}

	var txt = search_string.substr(place00,place01);
	var place = txt.search(pattern);
	var len = wordlen;

	//検索結果を生成
	result_detail += '<p align="left">～' + txt.substr(1,place - 1)
				   + HitStringDecorationStart + txt.substr(place,len) + HitStringDecorationEnd
				   + txt.substr(place + len) + '～</p>\n';
	return result_detail;
}

function getDispLine(src, rgexptn, matchStr) {
	var beforeString = getBeforeString(src, rgexptn, matchStr);
	var afterString = getAfterString(src, rgexptn);

	return '<p align="left">' + beforeString + HitStringDecorationStart + matchStr + HitStringDecorationEnd + afterString + '</p>\n';
}

function getBeforeString(src, rgexptn, mstr) {
	var ellipsis = '';
	var stix = rgexptn.lastIndex - mstr.length - BeforeAndAfterNum;

	if (stix < 0) {
		stix = 0;
	} else {
		ellipsis = '～';
	}

	var edix = rgexptn.lastIndex - mstr.length;
	return ellipsis + src.substring(stix, edix);
}

function getAfterString(src, rgexptn) {
	var ellipsis = '';
	var stix = rgexptn.lastIndex;
	var edix = rgexptn.lastIndex + BeforeAndAfterNum;

	if (edix >= src.length) {
		edix = src.length - 1;
	} else {
		ellipsis = '～'
	}

	return src.substring(stix , edix) + ellipsis;
}

function getMatchPatterns(searchText, synonymList) {
	var synonymWords = null;

	if (synonymList) {
		synonymWords = getSynonyms(searchText, synonymList); 
	}

	// 類義語が設定されていなければ、指定検索文字のみ
	if (!synonymWords) {
		synonymWords = [];
		synonymWords.push(searchText);
	}

	// マッチパターンの事前作成
	var patterns = [];

	for (var wix = 0; wix < synonymWords.length; wix++) {
		var word = synonymWords[wix].trim();

		//特殊文字をエスケープ
		var sanitizer_RE = new RegExp("(\\\\|\\*|\\+|\\.|\\?|\\{|\\}|\\(|\\)|\\[|\\]|\\^|\\$|\\-|\\||\\/)","g");
		word = word.replace(sanitizer_RE, "\\$1");

		var searchText = '(' + word + ')';
		var pattern = searchText;
		var rgexptn = new RegExp(pattern,'ig');
		var rptn = {};
		rptn.base = rgexptn;
		rptn.andp = null;
		rptn.wordlen = word.length;
		patterns.push(rptn);
	}

	return patterns;
}

function getSynonyms(pWord, pSynonymList) {

	for (var i = 0; i < pSynonymList.length; i++) {
		var dataLines = pSynonymList[i];
		for (var j = 0; j < dataLines.length; j++) {
			if (dataLines[j] == pWord) {
				return dataLines;
			}
		}
	}
	return null;
}

//sanitize
function sanitizeHTML(unsafe) {
    return unsafe
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;");
}