
/**
 * apply経由でスコープを保持して関数を呼び出す
 */
function  b(obj, func){
    return function(){
//		return func.apply(obj, arguments);
		try {
			return func.apply(obj, arguments);
		}
		catch(e){
			//log(obj.name + "::" +e);
			return null;
		}
    };
}


/**
 * clone object
 * @param {Object} obj
 */
function clone(obj){
	var f = function(){	};
	f.prototype = obj;
	return new f();
}


var RerankJp = {
	
	//logを出力するか
	debug : false,
	
	//tagcloudを再構築するか
	reconstructCloud : true,
	//const
	/**
	 * 検索結果取得の間隔
	 */
	searchInterval : 50,
	
	/**
	 * ボタンが消えるまでの時間
	 */
	floatTimeout : 5000,	

  /*
   * 言語
   */
  lang : "en",
	
	enableUndo : true,
	
	/**
	 * "元に戻す"操作の最大記録
	 */
	maxUndo : 3,


        //format
    header : "<div class=\"left\" id=\"header_left\"><span id=\"operation\"><strong>Web search results</strong></span></div><div class=\"info\" id=\"info\"></div><div class=\"right\"><strong>$start$</strong> - <strong>$numbers$</strong> of About <strong>$totalResultsAvaiable$</strong> results for <strong>$query$</strong> </div>",
    searching: "Searching for <strong>$query$</strong> ...",
    info : "<span id=\"operation\"> <strong>$operation$</strong> <strong>$term$</strong></span> <span id=\"undo\" class=\"enable\">Undo</span>",
    notfound : '<span class="404">We did not find any results for <strong>$query$</strong> </span>',


	query : null,
	queryList : [],
	queryRegList : [],
	num : 200,
	items: [],
	completeFlags : [],
	lastBlock : -1,
	floatTimer : null,
	highlights : [],
	maxTotalResult : 0,
	floatOffsetY : 15,
	floatOffsetX : -15,
	prevOperations: [],	//"元に戻す"
	
	
	
	/**
	 * 初期化
	 */
	initialize : function(){
		//formイベントのバインド
		$E.initialize();

		if(!this.checkQuery()){	//クエリを受け取ってない場合は何もしない
			this.getTrend();
			return false;
		}
		
		//検索結果取得の開始
		this.startSearch();
		
	},
	
	clear : function(){
		$('#main_result').get(0).innerHTML = '<ol id="result"></ol><div id="loading"></div>';
		$('#result_header').get(0).innerHTML = "";
		$("#query_suggest").get(0).innerHTML ="";
	},
	
	checkQuery : function(){
		if(this.getParamFromURL('p',null)){
			var params = this.getSearchParams();
			if(params.query == "検索語句を入力！"){
				return false;
			}
			$("#textQuery").val($.trim(params.query));
			$("#num").val(this.getParamFromURL('num',"200"));
      if(params.lang == "en"){
        $("#langen").attr("checked","checked");
      }
			return true;
		}
		else{	
			return false;
		}
	},

	/**
	 * ここを起点に
	 */
	startSearch : function(){
		var params = this.getSearchParams();
		this.params = params;
		this.query = this.params.query;
		var queryList = this.query.replace(/"/g,"").split(/[\s　]/g);
		//var queryList = this.query.split(/[\s　]/g);
		var list = [];
		for(var i = 0, n = queryList.length; i < n; i++){
			q = queryList[i].replace(/["']/g,"");
			q = queryList[i];
			if(q.length > 1){
				list.push(q);
			}
		}
		this.queryList = list;
		this.queryRegList = [];
		for(i = 0, n = this.queryList.length; i < n; i++){
			var reg = new RegExp(this.escapeRegExp(this.queryList[i]),"ig");
			this.queryRegList.push(reg);
		}
		this.num = this.params.num;
    this.lang = this.params.lang;
		
		
	
		//ここから実際に検索開始
		this.clear();
		$('#result_header').get(0).innerHTML = this.searching.replace('$query$',this.escapeHTML(this.query));
		this.startIndicator();
		//logging
		$L.search(this.query,this.num);
    var search = new YahooSearch();
    var p = {
      'query' : this.query,
      'num' : this.num,
      'lang' : this.lang
    }
    search.doSearch(p,this.searchInterval * i,b(this,this.recieveResultBlock));
		
		//クエリサジェストの取得
		this.getSuggest();
	},
	

	/**
	 * 今のところqueryとnumとlangだけ
	 */
	getSearchParams : function(){
		var query = $.trim(s_query.replace(/[+]/g,' '));
		query = query.replace(/[\s 　]/g," ");
		query = query.replace(/[ ]+/," ");
		var num = s_num;
    var lang = s_lang;
		var params = {
			'query': query,
			'num' : Number(num),
      'lang' : lang
		};
		return params;
	},

  getParamFromURL : function(key,def){
    if(key == "p"){
      return s_query;
    }
    else if(key == "num"){
      return s_num;
    }
    else if(key == "lang"){
      return s_lang;
    }
    return def
                    },
	
	
	/**
	 * 検索結果を取得し終えたrequestごとに呼ばれる
	 * @param {Array} items
	 * @param {String} query
	 * @param {Number} totalResults
	 * @param {Number} totalReturnedItems
	 */
	recieveResultBlock : function(items,query,totalResults,totalReturnedItems){
		var maxResult = Math.max(this.maxTotalResult,totalResults);
		this.maxTotalResult = maxResult;

		var source = this.makeHtml(items);
    if(items && items.length >= 1){
      $('#result').get(0).appendChild(source); //問答無用で先頭に
      this.items = items;
    }
	  
		var resultNum = 0;
		if(this.items){
			resultNum = this.items.length;
		}
		else{
			resultNum = 0;
		}
		var header = this.makeSearchHeader(query,maxResult,resultNum);
		$('#result_header').get(0).innerHTML = header;	//html()は遅いので使用しない		
    this.stopIndicator();
    $("#result_header").addClass('finish');
    if(!this.items || this.items.length < 1){	//結果が0件
      $("#result_header").get(0).innerHTML = "<div class=\"left\" id=\"header_left\"><strong>Web Search Results</strong></div>";
      $("#result").get(0).innerHTML = this.notfound.replace("$query$",this.escapeHTML(this.query));
      return;
    }
    $E.bindItems();
    $T.createTagCloud();
	},

	makeSearchHeader : function(query,totalResult,num){
		return $R.header.replace("$start$",1).replace("$numbers$",num).replace("$totalResultsAvaiable$",this.number_format(totalResult)).replace("$query$",query);
	},
	
		
	/**
	 * 検索結果要素をresultに挿入する
	 * @param {Array} items
	 */
	makeHtml : function(items){
		//innerHTML ? documentFragment ?
		var df = document.createDocumentFragment();
		for(var i = 0, n = items.length; i < n; i++){
			df.appendChild(items[i].toHtml());
		}
		return df;
	},
	
	/**
	 * termを選択した際に，選択した語を含む検索結果の背景色を変更する
	 * @param {String} term
	 * @param {String} type
	 * @param {Number} currentRank
	 * @param {Object} element
	 */
	highlightItems : function(term,type,currentRank,element){
		//IEはli要素のbackgroundColorの変更がやけに重いので除外
		if($.browser.msie){
			return;
		}
		var targets = []; //highlightするitem集合
		if (!element) {
			return;
		}
		var from = Math.max(0,currentRank - 5);
		var to_num =  Math.min(this.items.length,currentRank + 5);
		
		for(var i = from; i <= to_num; i++){
			var item = this.items[i];
			var elm = item.elm;
			if(item.isContain(term,type)){
				$(elm).css("backgroundColor","#ddffdd");
				targets.push(elm);
			}
		}
		this.highlights = targets; 
	},
	
	clearHighlight : function(){
		for(var i = 0, n = this.highlights.length; i < n; i++){
			$(this.highlights[i]).css("backgroundColor","#ffffff");
		}
		this.highlights = [];
	},
	
	/** rerank **/
	
	prepareRerank : function(){
		this.hideFloat();
		if(this.rerankTimer){
			clearTimeout(this.rerankTimer);
			this.rerankTimer = null;
		}
		var sel = this.escapeRegExp($E.selectString);
		var termReg; var replaceReg;
		try {
			termReg = new RegExp();
			replaceReg = new RegExp();
			termReg.compile(sel.replace(" ","[ ]?"),"i");
			replaceReg.compile('(<span class="(em|del)">)*' + sel.replace(" ","[ ]?") + '(</span>)*',"i");
		}
		catch(e){
			log(e);
			return false;
		}
		this.selectString = $E.selectString;
		this.termReg = termReg;
		this.replaceReg = replaceReg;	
		
		if (this.enableUndo) {
			if (this.prevOperations.length >= this.maxUndo) {
				this.prevOperations.shift();
			}
			if (this.prevOperations.length < this.maxUndo) {
				var operation = [];
				operation.push($('#result').get(0).innerHTML);
				var master = this.items;
				var slave = clone(master);
				this.items = slave;
				operation.push(master);
				operation.push($('#operation').get(0).innerHTML);
				this.prevOperations.push(operation);
			}
		}
		
		//tagcloudを消去
		if (this.reconstructCloud) {
			$T.initialize();
		}
		return true;	
	},
	
	undo : function(){
		if(this.prevOperations && this.prevOperations.length >= 1){
			var operation = this.prevOperations.pop();
			$('#result').get(0).innerHTML = operation[0];
			this.items = operation[1];
			var elms = $("#result").get(0).childNodes;
			for(var i = 0, n = this.items.length; i < n; i++){
				this.items[i].makeElementFromSource(elms[i]);
			}
			$('#operation').get(0).innerHTML = operation[2];	
		}
		if (this.prevOperations.length == 0) {
			$('#undo').get(0).setAttribute('class', 'disable');
		}
	},
	
	termEmphasis : function(){
		//logging
		$L.rerank("emphasis",$E.lastActiveType,$E.selectString,$E.lastBaseNode);		
		var resultNum  = this.items.length;
		var df = document.createDocumentFragment();
		var upList = [];
		var downList = [];
		log('TermEmphasis::' + this.selectString + "++" + $E.lastActiveType + ';;' + resultNum);
		var selectString = this.selectString;
		var type = $E.lastActiveType;
		var termReg = this.termReg;
		var replaceReg = this.replaceReg;
		for(var i = 0; i < resultNum; i++){
			var item = this.items[i];
			var elm = item.elm;
			if(item.isContain(termReg,type)){
				item.termEmphasis(this.escapeHTML(selectString),termReg,replaceReg);
				df.appendChild(item.elm);
				upList.push(item);
			}
			else{
				downList.push(item);
			}
		}
		$("#result").prepend(df);
		this.items = upList.concat(downList);
		try {
			document.getElementById('result_header').scrollIntoView();
			//document.getElementById('formarea').scrollIntoView();
		}catch(e){
			
		}	
		

		this.lastOperation = "<span class=\"emphasis\">Promote</span>";

		this.afterRerank();
		
	 
	},
	
	termDeletion : function(){
		//logging
		$L.rerank("deletion",$E.lastActiveType,$E.selectString,$E.lastBaseNode);	
		var upList = [];
		var downList = [];
		var df = document.createDocumentFragment();
		var selectString = this.selectString;
		var type = $E.lastActiveType;
		var termReg = this.termReg;
		var replaceReg = this.replaceReg;
		for(var i = 0, n = this.items.length; i < n; i++){
			var item = this.items[i];
			var elm = item.elm;
			if(item.isContain(termReg,type)){
				item.termDeletion(this.escapeHTML(selectString),termReg,replaceReg);
				df.appendChild(item.elm);
				downList.push(item);
			}
			else{
				upList.push(item);
			}
		}
		$("#result").get(0).appendChild(df);
		
		this.items = upList.concat(downList);

		this.lastOperation = "<span class=\"deletion\">Demote</span>";		
		this.afterRerank();

	},
	
	afterRerank : function(){
		var term = $E.selectString;
		if(term.length > 12){
			term = term.substring(0,10) + "...";
		}
		$('#header_left').get(0).innerHTML = this.info.replace('$term$',this.escapeHTML(term)).replace('$operation$',this.lastOperation);
		if(!this.enableUndo){
			$('#undo').get(0).innerHTML = "";
		}
		else {
				$('#undo').bind('click', b($R, $R.undo));

		}
		//tagcloudを再構築するかどうか
		if (this.reconstructCloud) {
			$T.createTagCloud();		
		}
	},
	
	/** indicator **/
	
	 startIndicator : function(){
		$("#loading").get(0).innerHTML = '<div id="indicator"><img src="' + $C.indicator + '" /></div>';
	},
	
	stopIndicator : function(){
		$("#loading").get(0).innerHTML = '';
	},
	
	/* float button */
	
	
	startFloat : function(x,y){
		var emCss = {
			"position" : "absolute",
			"top" : (y - 40) + "px",
			"left" : (x - 20) + "px",
		}
		var delCss = {
			"position" : "absolute",
			"top" : (y + 10) + "px",
			"left" : (x - 21) + "px",
		}
		$("#buttonEmphasis").css(emCss);
		$("#buttonDeletion").css(delCss);
		$("#buttonEmphasis").show();
		$("#buttonDeletion").show();
		this.floatTimer = setTimeout(b(this,this.hideFloat),this.floatTimeout);
	},
	
	hideFloat : function(){
		
		if(this.floatTimer){
			clearTimeout(this.floatTimer);
			this.floatTimer = null;
		}
		
		if(this.activeElement){
			$(this.activeElement).removeClass('active');
			this.activeElement = null;
		}
		
		this.clearHighlight();
		$("#buttonEmphasis").hide();
		$("#buttonDeletion").hide();
	},
	
	getSuggest : function(){
		var base = "./php/suggest.php?";
		var url = base + "p=" + encodeURIComponent(this.query);
		$.get(url,b(this,this.receiveSuggest));
	},
	
	
	receiveSuggest : function(data){
		var thisurl = "./index.php?";
		var suggests = eval("(" + data +")");
		var items = suggests.items;
		var limit = Math.min(5,items.length);
		var basenode = document.createElement("div");
		if (limit >= 1) {
			var t = document.createElement("span");
			t.textContent ="Related Searches:";
			basenode.appendChild(t);
			for (var i = 0; i < limit; i++) {
				var url = "/image/" + encodeURIComponent(items[i]);
				var s = document.createElement("span");
				s.setAttribute("class","suggest");
				var a = document.createElement("a");
				a.setAttribute("href",url);
				a.textContent = items[i];
				s.appendChild(a);
				basenode.appendChild(s);
			}
		}
		else{
			basenode.textContent = "";
			$("#query_suggest").hide();
			$("#google_link").show()
		}
		$("#query_suggest").append(basenode);
	},

	getTrend : function(){
		var base = "./php/trend.php";
		$.get(base,b(this,this.receiveTrend));
	},
	
	
	receiveTrend : function(data){
		var thisurl = "./index.php?";
		var suggests = eval("(" + data +")");
		var items = suggests.items;
		var limit = Math.min(5,items.length);
		var basenode = document.createElement("div");
		if (limit >= 1) {
			var t = document.createElement("span");
			t.textContent ="Example Queries:";
			basenode.appendChild(t);
			var num = $("#num").val();
			for (var i = 0; i < limit; i++) {
				var url = "/image/" + encodeURIComponent(items[i]);
				var s = document.createElement("span");
				s.setAttribute("class","suggest");
				var a = document.createElement("a");
				a.setAttribute("href",url);
				a.textContent = items[i];
				s.appendChild(a);
				basenode.appendChild(s);
			}
		}
		else{
			basenode.textContent = "";
		}
		$("#query_suggest").append(basenode);
	},

	
	number_format : function(val){
		return val.toString().replace( /([0-9]+?)(?=(?:[0-9]{3})+$)/g , '$1,' );
	},
	
	
	/*util*/
	
	
	a_reg : /&/g,
	a_str : "&amp;",
	b_reg : /"/g,
	b_str : "&quot;",
	c_reg : />/g,
	c_str : "&gt;",
	d_reg : /</g,
	d_str : "&lt;",
	escapeHTML : function(str){
		return str.replace(this.a_reg,this.a_str).replace(this.b_reg,this.b_str).replace(this.c_reg,this.c_str).replace(this.d_reg,this.d_str);
	},
	
	eh : this.escapeHTML,
	
	e_a : /\./ig,
	s_a : "\\.",
	e_b : /\)/ig,
	s_b : "\\)",
	e_c : /\(/ig,
	s_c : "\\(",
	e_d : /\?/ig,
	s_d : "\\?",
	e_e : /\+/ig,
//	s_e : "\\+",
	e_f : /\{\}/ig,
	s_f : "\\{",
	e_g : /\}/ig,
	s_g : "\\}",
	e_h : /\*/ig,
	s_h : "\\*",		
	escapeRegExp : function(str){
		return str.replace(this.e_a,this.s_a).replace(this.e_b,this.s_b).replace(this.e_c,this.s_c).replace(this.e_d,this.s_d).
					replace(this.e_e,this.s_e).replace(this.e_f,this.s_f).replace(this.e_g,this.s_g).replace(this.e_h,this.s_h);
	}
};

function log(str){
	if ($R && $R.debug) {
    $("#log").prepend(str + "<br>");
		//$("#log").get(0).innerHTML += str + "<br>\r\n";
	}
}

$R = RerankJp;

$('document').ready( function(){
	$R.initialize();
	comp = new AutoComplete("textQuery");
});

