/* $Id: DocumentSearcher.java 125 2011-03-09 09:49:51Z ohura $ */
/*
 * Created on 2006/08/23
 */
package jp.ac.hokudai.meme.core_smart_gs.searcher;

import java.awt.Rectangle;
import java.io.*;
import java.util.*;

import jp.ac.hokudai.meme.core_smart_gs.*;
import jp.ac.hokudai.meme.core_smart_gs.io.*;

/**
 * @author hajime
 * 
 * <p>IDocumentSearcher を実装したAbstract Class。</p>
 * 
 */

/**
 * @author hajime
 */
public abstract class DocumentSearcher implements IDocumentSearcher{
    
	protected List fileList_ = null;
    protected IDSCFileLoader loader_ = null;
    protected DSCData dscData_ = null;
    protected int searcherType_ = -1;
    private static DocumentSearcher searcher_ = null;
    protected int maxFound_ = 10; //default
    
    
    protected DocumentSearcher(){
        fileList_ = new ArrayList();
        dscData_ = new DSCData();
//        TODO swiching loader code
//        loader_ = new DSCFileLoader();
        loader_ = new DSCFileLoader5002();
    }
    
    /**
     * <p>DocumentSearcherのインスタンスを取得します。
     * IDocumentSearcher.TYPE_---を引数に渡します。
     * 現在TYPE_NORMALのみ。</p>
     * <p>Singleton実装はマルチスレッド非対応です。</p>
     * @param type IDocumentSearcher.TYPE_NORMAL
     * @return
     */
    public static IDocumentSearcher getInstance(int type){
        if(searcher_ == null){
            switch (type) {
            case IDocumentSearcher.TYPE_NORMAL:
                searcher_ = new DocumentSearcherTerasawa();
                break;
                
            case IDocumentSearcher.TYPE_DTW_1:
                searcher_ = new DocumentSearcherDTW(type);
                break;
                
            case IDocumentSearcher.TYPE_DTW_2:
                searcher_ = new DocumentSearcherDTW(type);
                break;
            
            default:
                break;
            }
        }
        
        searcher_.searcherType_ = type;
        return (IDocumentSearcher)searcher_;
    }
    
    /**
     * 
     * <p>addFileList に指定したファイルをファイルリストに追加します。</p>
     * <p>このメソッドを用いてDSCファイルを指定することで、searchメソッドが使用可能になります。</p>
     * @param addFileList 追加するDSCファイルのリスト
     * @return 読み込み済みの全てのファイルリスト
     * @throws IOException
     */
    public File[] addDscFile(File[] addFileList) throws IOException, InvalidDataFormatException {
        for (int i = 0; i < addFileList.length; i++) {
            loader_.loadDscFile(dscData_, addFileList[i]);
            fileList_.add(addFileList[i]);
        }
        return (File[]) fileList_.toArray(new File[0]);
    }
    
    /**
     * 
     * <p>現在読み込まれているファイルリストを初期化します。</p>
     * <p></p>
     * @return retStatus
     */
    public boolean clearFileList() {
        fileList_ = new ArrayList();
        dscData_ = new DSCData();
        return true;
    }
    
    /**
     * <p>DSCデータを読み込んでいるかを返します。</p>
     * 
     * @return flag
     */
    public boolean hasDscData() {
        return dscData_.hasDscData();
    }
    
    /**
     * <p>使用する検索アルゴリズムを変更します。</p>
     * @param type アルゴリズムのType現在はTYPE_NORMALのみ。
     * @return アルゴリズムを変更した結果のSearcherをIDocumentSearcher形式で返します。
     */
    public IDocumentSearcher switchSeacher(int type) {
        DocumentSearcher src = this;
        if (src.searcherType_ == type) {
            return src;
        }
        DocumentSearcher dest = (DocumentSearcher) DocumentSearcher.getInstance(type);
        dest.dscData_ = src.dscData_;
        dest.fileList_ = src.fileList_;
        dest.loader_ = src.loader_;
        return dest;
    }
    
    /**
     * <p>queryに指定された領域をクエリとして検索を実行します。</p>
     * <p>queryに指定された領域をクエリとして検索を実行し、検索結果の順位付きリストをResultRect形式で返します。</p>
     * @param query
     * @return ResultRect形式で結果を返します。
     */
    public ResultRects search(QueryRect query) {
        ResultIndex resultindex = searchStart(dscData_.getDscData(), convertRectToIndex(query.getFirstPRect()));
        return convertIndexToRect(resultindex);
    }
    
//    public ResultRects searchWithLineNo(QueryRect query) {
//        
//    }
    
    /* (非 Javadoc)
     * @see jp.ac.hokudai.meme.core_smart_gs.searcher.IDocumentSearcher#getSearcherType()
     */
    public int getSearcherType() {
        return searcherType_;
    }
    
    public QueryRect rectConfirm(QueryRect queryRect) {
        int[] rectIndexes = convertRectToIndex(queryRect.getFirstPRect());
        PagedRect[] pRects = dscData_.convertPieceIndexToRect(rectIndexes);
        QueryRect retQRects = new QueryRect();
        for (int i = 0; i < pRects.length; i++) {
            retQRects.addQueryPRect(pRects[i]);
        }
        return retQRects;
    }
    
    protected int[] convertRectToIndex(PagedRect prect) {
    	int page=prect.getPageIndex();
    	Rectangle bigrect=prect.getRect();
    	ArrayList intary = new ArrayList();
        int cumslitnumprevpage;
        if(page==0){
        	cumslitnumprevpage=0;
        }else{
        	cumslitnumprevpage=dscData_.getCumSlitInPage(page-1);
        }
        Rectangle[] rectary=dscData_.getPageRectangle(page);
        Rectangle rect;
        for(int i=0;i<dscData_.getSlitInPage(page);++i){
            rect=rectary[i];
            if(rect.intersects(bigrect)){
                intary.add(new Integer(cumslitnumprevpage + i));
            }
    	}
        int[] converted = new int[intary.size()];
        for (int i = 0; i < converted.length; i++) {
			converted[i] = ((Integer)intary.get(i)).intValue();
			
		}
        return converted;
    }

//    private boolean isIntersected(Rectangle rectA, Rectangle rectB) {
//    	//rectAとrectBが交わるかどうかを判定します。交わるとは共通部分を持つということです。
//    	int x0=rectA.x;
//    	int y0=rectA.y;
//    	int x1=x0+rectA.width;
//    	int y1=y0+rectA.height;
//    	
//    	boolean flag;
//        if(rectB.contains(x0,y0)) flag=true;
//        else if(rectB.contains(x1,y0)) flag=true;
//        else if(rectB.contains(x0,y1)) flag=true;
//        else if(rectB.contains(x1,y1)) flag=true;
//        else flag=false;
//    	return flag;
//	}

	protected ResultRects convertIndexToRect(ResultIndex ridx) {
    	int i;
    	ResultRects rrect = new ResultRects();
    	for(i=0;i<ridx.size();++i){
    		rrect.addResult(convertFoundIndexToRect(ridx.get(i)));
    	}
        return rrect;
    }
    
    protected FoundRect convertFoundIndexToRect(FoundIndex fidx) {
//        FoundRect frect = new FoundRect(dscData_.convertPieceIndexToRect(fidx.indexList_), fidx.score_);
        FoundRect frect = new FoundRect(dscData_.convertPieceIndexToRect(fidx.indexList_), fidx.score_);
        return frect;
    }
    
    public void setMaxFound(int maxFound) {
        maxFound_ = maxFound;
	}
    
    abstract protected ResultIndex searchStart(double[][] dscData, int[] index);

}
