package cn.com.pc.penguin.builder.keyword;

import cn.com.pc.penguin.service.QueryBuilder;
import cn.com.pc.penguin.service.SearchArgs;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.util.Version;

import java.util.Map;


public class KeywordQueryBuilder implements QueryBuilder {
    private Analyzer analyzer ;
    private static KeywordQueryBuilder builder;
    
    private KeywordQueryBuilder(){
    	analyzer = new StandardAnalyzer(Version.LUCENE_30);
    }
    
    public synchronized static KeywordQueryBuilder getInstance(){
    	if(builder != null) {
    		return builder;
    	} else {
    		builder = new KeywordQueryBuilder();
    		return builder;
    	}
    }
    
    public Query buildQuery(SearchArgs searchArgs) throws Exception {
        KeywordSearchArgs keywordSearchArgs = (KeywordSearchArgs)searchArgs;
        BooleanQuery resultQuery = new BooleanQuery();

        this.searchByRecommendation(keywordSearchArgs,resultQuery);
        this.searchBySuggestion(keywordSearchArgs,resultQuery);
        
        if (resultQuery.clauses().size() <= 0) {
            resultQuery.add(new MatchAllDocsQuery(), BooleanClause.Occur.MUST);
        }        
        return resultQuery;
    }
    
	public Query buildFilter(SearchArgs args) throws Exception {
		KeywordSearchArgs keywordSearchArgs = (KeywordSearchArgs)args;
		BooleanQuery resultQuery = new BooleanQuery();
        
		//this.searchBySuggestion(keywordSearchArgs,resultQuery);
		//this.filterById(keywordSearchArgs,resultQuery);
        this.filterByOtherParams(keywordSearchArgs,resultQuery);

        if (resultQuery.clauses().size()>0) {
            return resultQuery;
        }
		return null;
	}
    
	public Sort buildSort(SearchArgs args) throws Exception {
		Sort sort = null;
		if(args.getSortFields() != null) {
			sort = new Sort(args.getSortFields());
		}
		return sort;
	}
    
	private void searchByRecommendation(KeywordSearchArgs keywordSearchArgs,
				BooleanQuery resultQuery) throws Exception {
		if (StringUtils.isNotBlank(keywordSearchArgs.getRecommendion())) {
            String queryString = KeywordSearchFields.Index.KEYWROD + ":" + keywordSearchArgs.getRecommendion();
            QueryParser parser = new QueryParser(Version.LUCENE_30,"", analyzer);
        	Query query = parser.parse(queryString);
			resultQuery.add(query, BooleanClause.Occur.MUST);        	
        }
	}    

    private void searchBySuggestion(KeywordSearchArgs keywordSearchArgs, BooleanQuery booleanQuery) throws Exception {
        if (StringUtils.isNotBlank(keywordSearchArgs.getSuggestion())) { 
        	BooleanQuery bq = new BooleanQuery();
        	Term term = new Term(KeywordSearchFields.Keyword.KEYWROD_UNTOKENIZIED,keywordSearchArgs.getSuggestion());
        	Query suggestQuery = new PrefixQuery(term);
            suggestQuery.setBoost(10f);
            Term pinyinTerm = new Term(KeywordSearchFields.Keyword.KEYWORD_PINYIN,keywordSearchArgs.getSuggestion());
        	Query pinyinQuery = new PrefixQuery(pinyinTerm);
            pinyinQuery.setBoost(5f);

            Term pinyinHeadTerm = new Term(KeywordSearchFields.Keyword.KEYWORD_PINYIN_HEAD,keywordSearchArgs.getSuggestion());
        	Query pinyinHeadQuery = new PrefixQuery(pinyinHeadTerm);
            pinyinHeadQuery.setBoost(2f);

            //有少少性能损耗,可以考虑是否检索这类。
            Term wildCardTerm = new Term(KeywordSearchFields.Keyword.KEYWROD_UNTOKENIZIED,"*" + keywordSearchArgs.getSuggestion() + "*");
            Query wildcardQuery = new WildcardQuery(wildCardTerm);
            
        	bq.add(suggestQuery, BooleanClause.Occur.SHOULD);
        	bq.add(pinyinQuery, BooleanClause.Occur.SHOULD);
        	bq.add(pinyinHeadQuery, BooleanClause.Occur.SHOULD);
        	bq.add(wildcardQuery, BooleanClause.Occur.SHOULD);
        	booleanQuery.add(bq, BooleanClause.Occur.MUST);
        }
    }

    private void filterByOtherParams(KeywordSearchArgs args, BooleanQuery booleanQuery) throws Exception {
        if (args.getOtherParams() != null && args.getOtherParams().size() > 0) {
            for (Map.Entry<String, String> entry : args.getOtherParams().entrySet()) {
            	Query query = new TermQuery(new Term(entry.getKey(),entry.getValue()));
                booleanQuery.add(query, BooleanClause.Occur.MUST);
            }
        }
    }
    
    public Analyzer getAnalyzer() {
        return analyzer;
    }

    public void setAnalyzer(Analyzer analyzer) {
        this.analyzer = analyzer;
    }
}
