/*
 * $Id: PatentClassifier.java,v 1.8 2006/08/31 19:59:11 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 * 
 * Created on 09.10.2004
 *
 * $Log: PatentClassifier.java,v $
 * Revision 1.8  2006/08/31 19:59:11  marbobo
 * + Refactoring
 *
 * Revision 1.7  2006/03/23 11:47:21  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.6  2005/09/13 09:51:45  jonyp
 * cleaning the code
 *
 * Revision 1.5  2004/12/21 10:29:17  koppy
 * so einiges
 *
 * Revision 1.4  2004/11/29 16:33:04  koppy
 * ID der vorgeschlagenen Kategorie
 *
 * Revision 1.3  2004/11/24 14:17:27  koppy
 * Sortierung der Ergebnisse eingeführt
 *
 * Revision 1.2  2004/11/23 15:02:02  koppy
 * Refactoring: convert(..) --> convertAndSave(..)
 *
 * Revision 1.1  2004/10/09 16:03:01  koppy
 * Initiale Version
 *
 */
package vkc.ws.axis.service.patent;

import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;

import vkc.analyse.Analyser;
import vkc.converter.DocConverter;
import vkc.db.entities.VKCAdditionalDocumentFormat;
import vkc.db.entities.VKCCategory;
import vkc.db.entities.VKCDocument;
import vkc.db.entities.VKCUser;
import vkc.exception.DBException;
import vkc.misc.VKCLogManager;
import vkc.search.ClassifyResultEntry;
import vkc.server.archive.DataStoreException;
import vkc.ws.axis.service.SharkService;

/**
 * This class represents
 * @author Andreas Koop
 */
public abstract class PatentClassifier{
    public static final int HITS_COUNT = 10;
    /**
     * Die Konstante <code>MAX_RESULT_ENTRIES</code>
     * legt die maximale Anzahl von Ergebnissen bei 
     * einer Klassifizierung fest, die in das Ergebnisdokument geschrieben werden.
     */
    public static final int MAX_RESULT_ENTRIES = 20;
    /**
     * Die Konstante <code>MIN_PERCENTAGE</code>
     * gibt den Schwellwert an, ab welchem Ergebnisse
     * in das Ergebnissdokument übernommen werden.
     */
    public static final int MIN_PERCENTAGE = 3; 
    
    public static Comparator resultsComp = new Comparator() {
    	public int compare( Object o1, Object o2 ) {
	        ClassifyResultEntry c1 = (ClassifyResultEntry)o1;
	        ClassifyResultEntry c2 = (ClassifyResultEntry)o2;
	        
	        if (c1.getScore() < c2.getScore()) {
	            return 1;
	        }
	       
	        if (c1.getScore() > c2.getScore()) {
	            return -1;
	        }
	       
	        return 0;
	           
	    }
    };
    
	private String resultCategoryId = "";
	
    /**
     * MEthode dient dazu, den Unterklassen die Möglichkeit zu geben
     * anhand des gegebenen Patentdokumentes, ein Dokument zurück zu geben,
     * das als Basis für die Klassifikation dient.
     * 
     * @param patentDoc
     * @return
     */
    protected VKCDocument getDocumentToBeClassified(VKCDocument patentDoc) throws DBException {
    	if (false) {
    		throw new DBException("");
    	}
    	
        return patentDoc;
    }
    
    /**
     * @param patentsRootCat
     * @param patentDoc
     * @param user
     * @return
     * @throws DataStoreException
     * @throws DBException
     * @throws DBException
     */
    public String classify(VKCCategory patentsRootCat, VKCDocument patentDoc, VKCUser user) throws Exception {
        VKCDocument doc = this.getDocumentToBeClassified(patentDoc);
        
        if (doc == null) {
            return "";
        }
        
        Collection addDocs = doc.getAdditionalDocumentFormats(); 
		
        if (addDocs.size() == 0) {
		    PatentUtils.convertAndSave(doc);
		    addDocs = doc.getAdditionalDocumentFormats();
		}
		
		for (Iterator iter = addDocs.iterator(); iter.hasNext();) {
            VKCAdditionalDocumentFormat f = (VKCAdditionalDocumentFormat) iter.next();
            
            if (!f.getDocTypeId().equals(new Integer(DocConverter.tdf))) {
            	continue;
            }
            
            // TDF Dokument vorhanden
            InputStream tdfStream = f.getInputStream();
            
            DocConverter converter = DocConverter.createConverter(tdfStream, f.getDocTypeId().intValue());
            converter.convert(tdfStream, null);
            
            Analyser analyser = Analyser.createAnalyser(converter.getElements());

    		Collection results = this.classify(analyser, doc, SharkService.CLASSIFY_KEYWORDS_COUNT, user, patentsRootCat);
    		
    		StringBuffer result = new StringBuffer();
    		
    		if (this.getHeader() != null && this.getHeader().trim().length()>0) {
    		    result.append(this.getHeader());
        		result.append("\n\n");
    		}
    		
    		
    		if (results != null && !results.isEmpty()) {
    		    ClassifyResultEntry [] arrResult = (ClassifyResultEntry [])results.toArray(new ClassifyResultEntry[0]);
    		    Arrays.sort(arrResult, PatentClassifier.resultsComp);
    		    this.resultCategoryId = arrResult[0].getCategoryId();
    		    results = Arrays.asList(arrResult);
    		}
    		
    		int writtenResultsCount = 0;
    		
    		if (results != null) {
        		for (Iterator iterator = results.iterator(); iterator.hasNext();) {
                    ClassifyResultEntry resEntry = (ClassifyResultEntry) iterator.next();
                    
                    if (Double.parseDouble(resEntry.getScorePercent().replace(',','.')) < PatentClassifier.MIN_PERCENTAGE ) {
                        continue;
                    }
                    
                    result.append(resEntry.getCategoryAbsPath().getAbsolutePathString());
                    result.append("|");
                    result.append(resEntry.getCategoryId());
                    result.append("|");
                    result.append(resEntry.getScorePercent() + "%");
                    result.append("\n");
                    
                    if (++writtenResultsCount >= PatentClassifier.MAX_RESULT_ENTRIES) {
                        break;
                    }
                }

        		return result.toString();
    		}
        }
		
		VKCLogManager.infoLog(PatentUtils.class, "Kein TDF-Stream für " + doc.getName() + " vorhanden!");
		
		return null;
    }
    
    protected abstract Collection classify(Analyser analyser, VKCDocument doc, int keywordCount, VKCUser user, VKCCategory patentCat) throws Exception;
    
    protected abstract String getResultFilename(String originalPatentFilename);
    
    protected abstract String getResultTitle(String originalPatentFilename);
    
    /**
     * Gibt einen Header-String zurück, der dazu benutzt werden
     * zusätzliche Information auf Anfang eines Ergebnisdokumentes
     * einzufügen. 
     * @return Header
     */
    protected String getHeader() {
        return "";
    }
    
    public String getFinalResultCategoryId() {
        return resultCategoryId;
    }
}