/* $Id: GSSearchEngine.java 654 2013-02-08 10:05:15Z ohura $ */
package smart_gs.image_search;

import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import jp.ac.hokudai.meme.core_smart_gs.searcher.FoundRect;
import jp.ac.hokudai.meme.core_smart_gs.searcher.PagedRect;
import jp.ac.hokudai.meme.core_smart_gs.searcher.QueryRect;
import smart_gs.image_search.logical.GSQuery;
import smart_gs.image_search.logical.SearchResult;
import smart_gs.image_search.logical.TextType;
import smart_gs.image_search.normal.swingui.LabelMouseListener;
import smart_gs.logical.Spread;
import smart_gs.logical.SpreadTree;
import sml_editor.logical.LineDirection;

import image_search.ImageSearchAdapter;

public class GSSearchEngine extends ImageSearchAdapter{
	
	private static GSSearchEngine singleton = new GSSearchEngine();
	
	private List<SearchResult> gsResults;
	
	private List<Spread> spreads;
	
	//20090118 North Grid Add
	private boolean useExternalEngine = true;
	
	private ArrayList<ImageSearchFilter> imageSearchFilterList = new ArrayList<ImageSearchFilter>();
	
	public GSSearchEngine() {
		super();
		this.spreads = new ArrayList<Spread>();
		this.gsResults = new ArrayList<SearchResult>();
	}
	public static GSSearchEngine getInstance(){
		return singleton;
	}
	
	
//	public void prepareSearch(){
//		try{
//			SpreadTree.getInstance().loadAllImages();
//			List<File> files = SpreadTree.getInstance().getDSCFiles();
//			this.setDSCFiles(files);
//		}catch(OutOfMemoryError err){
//			JOptionPane.showMessageDialog(null,"couldn't load all images for memory shortage");
//			return;
//		}
//
//		JOptionPane.showMessageDialog(null,"Images Loaded");
//	}
	
	@Override
	public synchronized void execute() {
		if ( singleton.useExternalEngine == false) {
			super.execute();
		} else {
			this.results = new ExternalSearchEngineController().search(this.query, this.spreads);
		}
		this.createResults();
	}
	
	
	//ここのメソッドをコピーすればよい。20080908
	private void createResults(){
		this.gsResults = new ArrayList<SearchResult>();
		/*
		 *  ResultRectsからGSで扱うための結果に変換
		 */
		if(this.results.getSize() < 1){
			return;
		}
		double firstScore = this.results.getFoundRect(1).getscore();
		
		for(int i=1;i<=this.results.getSize();i++){
			FoundRect result = this.results.getFoundRect(i);
			PagedRect[] prects = result.getPRects();
			Rectangle firstRect = null; 
			try{
				firstRect = prects[0].getRect();
			}catch(ArrayIndexOutOfBoundsException e){
				System.out.println("");
				continue;
			}
			Rectangle lastRect = prects[prects.length-1].getRect();
			//20080730 shimizu wrote;
			if(this.query.getLineDirection() == LineDirection.HORIZONTAL){
				//20080714 shimizu wrote;
				int width = lastRect.x - firstRect.x + lastRect.width;
				/*
				 * 行をまたいでいる時の応急処置
				 */
				if(width < 0){
					width = (int)this.query.getRectangle().getWidth();
				}
				Rectangle resRect = new Rectangle(firstRect.x,firstRect.y,width,firstRect.height);
				int pageIndex = prects[0].getPageIndex();
				double score = this.results.getScore(i);
				
				score /= firstScore;
				
				int lineIndex = prects[0].getLineIndex();
				SearchResult searchResult = new SearchResult(this.spreads.get(pageIndex),resRect,score,i,lineIndex);
				// ADD NorthGrid 20090907 フィルターを作成
				boolean isregist =  true;
				for(int j=0;j<imageSearchFilterList.size();j++){
					SearchResult resultFilter = imageSearchFilterList.get(j).filter(searchResult);
					if(resultFilter == null){
						isregist = false;
					}else{
						isregist = true;
						searchResult = resultFilter;
						break;
					}
				}
				if(isregist){
					Spread spread = searchResult.getSpread();
					if (spread.isTransformationIsNecessary()){
						AffineTransform affineTransformFromDscToImage = spread.getAffineTranformFromDscToImg();
						Shape shapeMapped = affineTransformFromDscToImage.createTransformedShape((Rectangle2D)searchResult.getRectangle());
						Rectangle rectangleMapped = shapeMapped.getBounds();	
						searchResult.setRectangle(rectangleMapped);
					}
					this.gsResults.add(searchResult);
				}
			}else{
				int height = lastRect.y - firstRect.y + lastRect.height;
				if(height < 0){
					height = (int)this.query.getRectangle().getHeight();
				}
				Rectangle resRect = new Rectangle(firstRect.x,firstRect.y,firstRect.width,height);
				int pageIndex = prects[0].getPageIndex();
				double score = this.results.getScore(i);
				
				score /= firstScore;
				
				int lineIndex = prects[0].getLineIndex();
				SearchResult searchResult = new SearchResult(this.spreads.get(pageIndex),resRect,score,i,lineIndex);
				// ADD NorthGrid 20090907 フィルターを作成
				boolean isregist =  true;
				for(int j=0;j<imageSearchFilterList.size();j++){
					SearchResult resultFilter = imageSearchFilterList.get(j).filter(searchResult);
					if(resultFilter == null){
						isregist = false;
					}else{
						isregist = true;
						searchResult = resultFilter;
					}
				}
				if(isregist){
					Spread spread = searchResult.getSpread();
					if (spread.isTransformationIsNecessary()){
						AffineTransform affineTransformFromDscToImage = spread.getAffineTranformFromDscToImg();
						Shape shapeMapped = affineTransformFromDscToImage.createTransformedShape((Rectangle2D)searchResult.getRectangle());
						Rectangle rectangleMapped = shapeMapped.getBounds();	
						searchResult.setRectangle(rectangleMapped);
					}
					this.gsResults.add(searchResult);
				}
			}
		}
	}
	
	//20080715 shimizu wrote
	/*
	 * QueryRectが正しく作られたかを確認するためのメソッド
	 */
	public SearchResult testChange(QueryRect QRect){
		SearchResult result;
		/*
		 *  ResultRectsからGSで扱うための結果に変換
		 */
		double firstScore = 1;
		Rectangle firstRect = QRect.getAllRects()[0].getRect();
		Rectangle lastRect = QRect.getAllRects()[QRect.getAllRects().length].getRect();
		//20080714 shimizu wrote;
		//int width = lastRect.x - firstRect.x + lastRect.width;
		/*
		 * 縦書き用に変更（テスト）
		 */
			int height = lastRect.y - firstRect.y + lastRect.height;

		//Rectangle resRect = new Rectangle(firstRect.x,firstRect.y,width,firstRect.height);
		Rectangle resRect = new Rectangle(firstRect.x,firstRect.y,firstRect.width,height);
		//縦書き用の変更ここまで
		int pageIndex = QRect.getFirstPRect().getPageIndex();
		double score = 1;
			
		score /= firstScore;
			
		int lineIndex = QRect.getFirstPRect().getLineIndex();
		result = new SearchResult(this.spreads.get(pageIndex),resRect,score,1,lineIndex);
		return result;
			
		
	}
	public List<SearchResult> getResults(){
		return this.gsResults;
	}
	public void setSearchScope(List<Spread> spreads){
		this.spreads = spreads;
		GSQuery q = (GSQuery)this.query;
		this.spreads.remove(q.getSpread());
		this.spreads.add(0,q.getSpread());
		ArrayList<File> files = new ArrayList<File>();
		for(int i=0;i<spreads.size();i++){
			if(spreads.get(i).hasDscFile()){
				files.add(spreads.get(i).getDscFile());
			}
		}
		this.setSearchScope(files);
	}
	public List<Spread> getSpreads(){
		return this.spreads;
	}
	//20080715 shimizu wrote
	/*
	 * 確認用のSearchResultからラベルを作成
	 */
	protected JLabel createImageLabel(SearchResult result){	
		LineImageCropper cropper = new LineImageCropper(result);
		BufferedImage bufImage = cropper.crop();	
		bufImage = (BufferedImage) cropper.fillRelative(bufImage);
		ImageIcon icon = new ImageIcon(bufImage);	
		JLabel label = new JLabel();
		label.setIcon(icon);
		label.addMouseListener(new LabelMouseListener(label,result.getSpread(),result.getRectangle()));
		return label;
	}

	//20090118 North Grid Add
	public boolean isUseExternalEngine() {
		return useExternalEngine;
	}
	//20090118 North Grid Add
	public void setUseExternalEngine(boolean useExternalEngine) {
		this.useExternalEngine = useExternalEngine;
	}
	
	public void setImageSearchFilterList(ArrayList<ImageSearchFilter> imageSearchFilterList) {
		this.imageSearchFilterList = imageSearchFilterList;
	}
	
}
