import java.util.*;
import java.io.*;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import org.xml.sax.*;

/**
 * This class is the main in processing the comparison of a system's item "segmentations" and some references.
 * It permits to launch the parsing of Xml files without worrying about parsing errors
 * and also to process the comparison of system's parsed segmentations with reference segmentations.
 *
 * @author NIST-ITL-IAD-Retrieval Group
 * This software was produced by NIST, an agency of the
 * U.S. government, and by statute is not subject to copyright in the
 * United States.  Recipients of this software assume all
 * responsibilities associated with its operation, modification and
 * maintenance.
 *
 */

public class ComparisonManager {

	/**
     * The reference direcotry.
     *
     */
	public static String refDirName = null;
	/**
     * The number of maximum allowed items.
     *
     */
	public static int maxAllowedItems = 100;

	/**
     * Gets the full path to the reference directory.
     *
     */
	static protected String getFullRefDirName() {
		return System.getProperty("user.dir") +System.getProperty("file.separator") + refDirName;
	}

    /**
     * Overrule refDir, only if directory exists
     *
     */
	static protected void setRefDirName(String theRefDirName) {
		refDirName = theRefDirName;
		File theRefDir = new File(refDirName);
    	if (!theRefDir.exists()) 
			theRefDir = new File(getFullRefDirName());
		if (!theRefDir.exists()) {
			System.err.println("Error: Cannot open directory " + refDirName);
			usage();
			System.exit(1);
		}
	}

	/**
     * The comparator instance for overlapping, used with its default parameter values.
     *     
     */
	private OverlapComparator overlap = OverlapComparator.getInstance();
	/**
     * The Hashtable containing the reference segmentations.
     * The key is the topic number and value is the segmentation.
     * 
     */
	private Hashtable referenceSegmentations = new Hashtable();
	/**
     * The system ID of the results.
     * The key is the system ID + topic number and value is a segmentation.
     * 
     */
	private Hashtable systemResults;
	/**
     * Simple constructor.
     *
     */
	public ComparisonManager(){	}	
	/**
     * Launch the parsing of the file containing the Xml reference, known as topic description files.
	 *
     */	
	public void parseReference(){
		
		// Use the validating parser
        SAXParserFactory factory = SAXParserFactory.newInstance();
        //factory.setValidating(true);
        try {
			Writer out = new OutputStreamWriter(System.out, "UTF8");
            // Set up output stream
            out = new OutputStreamWriter(System.out, "UTF8");
			xmlContentHandler resultHandler = new xmlContentHandler(out, maxAllowedItems);
            SAXParser saxParser = factory.newSAXParser();
            if(resultHandler == null){
            	System.out.println("NULL");
            	System.exit(0);
            }

			String[] children = null;
			String refDir = refDirName;
			File dirToCheck = new File(refDir);
			children = dirToCheck.list();

			if(children != null){
				System.out.println(System.getProperty("line.separator")+"Parsing Reference Files..."); 
				for(int i = 0; i < children.length; i++){
					if(children[i].endsWith(".xml")){
						File toParse = new File(refDir, children[i]);
			            saxParser.parse(toParse, resultHandler);
			            Segmentation s = resultHandler.getRefSegmentation();
			            this.referenceSegmentations.put(s.getTopicNumber(), s);
		      		}
		      	}
		    }

        } catch (SAXParseException spe) {
           // Error generated by the parser
           System.out.println("\n** Parsing error"
              + ", line " + spe.getLineNumber()
              + ", uri " + spe.getSystemId());
           System.out.println("   " + spe.getMessage() );

           // Use the contained exception, if any
           Exception  x = spe;
           if (spe.getException() != null)
               x = spe.getException();
           x.printStackTrace();

        } catch (SAXException sxe) {
           // Error generated by this application
           // (or a parser-initialization error)
           Exception  x = sxe;
           if (sxe.getException() != null)
               x = sxe.getException();
           x.printStackTrace();

        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();

        } catch (IOException ioe) {
           // I/O error
           ioe.printStackTrace();
    	}
	}

	/**
     * Launch the parsing of the file containing the results per system results.
	 *
     * @param comparedSetFile name of the file containing this information.
     */	
	public void parseResults(File comparedSetFile){
		
		//Test the existence of the file
		if (!comparedSetFile.exists()){
           	System.err.println("The specified file \""+comparedSetFile.getAbsolutePath()+"\""+
           	System.getProperty("line.separator")+" does not EXISTS or should be in a sub-directory called \"System\"");
           	System.exit(1);			
		}
		System.out.println(System.getProperty("line.separator")+"Parsing System file..."); 
		
        // Use the validating parser
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setValidating(true);
        try {
			Writer out = new OutputStreamWriter(System.out, "UTF8");
            // Set up output stream
            out = new OutputStreamWriter(System.out, "UTF8");
			xmlContentHandler resultHandler = new xmlContentHandler(out, maxAllowedItems);

            // Parse the input
            SAXParser saxParser = factory.newSAXParser();
            if(comparedSetFile == null || resultHandler == null){
            	System.out.println("NULL");
            	System.exit(0);
            }
            saxParser.parse(comparedSetFile, resultHandler);
            this.systemResults = resultHandler.getSystemResults();
        } catch (SAXParseException spe) {
           // Error generated by the parser
           System.out.println("\n** Parsing error"
              + ", line " + spe.getLineNumber()
              + ", uri " + spe.getSystemId());
           System.out.println("   " + spe.getMessage() );

           // Use the contained exception, if any
           Exception  x = spe;
           if (spe.getException() != null)
               x = spe.getException();
           x.printStackTrace();

        } catch (SAXException sxe) {
           // Error generated by this application
           // (or a parser-initialization error)
           Exception  x = sxe;
           if (sxe.getException() != null)
               x = sxe.getException();
           x.printStackTrace();

        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();

        } catch (IOException ioe) {
           // I/O error
           ioe.printStackTrace();
    	}
	}
	/**
     * Process the comparison between the reference segmentation and each system segmentation.
     *     
     */
	public void processComparison() throws Exception{

		//For each segmentation
		System.out.println(System.getProperty("line.separator")+"Processing comparison..."); 
		Enumeration e = systemResults.elements();
		while(e.hasMoreElements()){
        
       		SysSegmentation aSystemSeg = (SysSegmentation) e.nextElement();
       		if(aSystemSeg.getDroppedOut() != 0){
       			System.out.println(aSystemSeg.getDroppedOut()+" double items out from topic#"+aSystemSeg.getTopicNumber()+
       			" " + aSystemSeg.getSysId());
       		}
       		RefSegmentation aRefSeg = (RefSegmentation) referenceSegmentations.get(aSystemSeg.getTopicNumber());
       		//We compare the two segmentations
       		//Creation of a comparisonResult
			if(aRefSeg == null){
				System.out.println("ref Seg == null, abnormal exiting-"+aSystemSeg.getTopicNumber());
				System.exit(0);
			}
			else if(aSystemSeg == null){
				System.out.println("sys Seg == null, abnormal exiting");
				System.exit(0);
			}
			else{
				aRefSeg.processComparison(aSystemSeg, maxAllowedItems);
			}
    	}
	}

	/**
	 * Print usage message
	 */
	public static void usage() {
            System.err.println("Usage: java ComparisonManager [systemKI_file.xml] [-pRefXXX] [-pSysXXX] [-maxAllowedItemsXXX] [-refDir dir]");
            System.err.println("Examples:");
            System.err.println("  java ComparisonManager Sys_MY_SYSTEM_KI.xml -pRef0.6666 -pSys0.3333 -maxAllowedItems100");
            System.err.println("  # This will set pRef parameter to 0.6666, and pSys to 0.3333");
            System.err.println("  # pRef = Minimum pourcentage of the common portion within a known-item");
            System.err.println("  # pSys = Minimum pourcentage of the common portion within a system item");      
            System.err.println("  # Default values are 0.6666 for pRef,0.3333 for pSys and 100 for maxAllowedItems");
	}

	/**
     * Main entry point to the program.
     *     
     */
	public static void main(String argv[]){

		if ((argv.length < 1) || (argv.length > 5)) {
		  usage();
		  System.exit(1);
        }
        else{
        	for(int i=1; i < argv.length; i++){
        		
	       		if(argv[i].startsWith("-pRef"))
        			OverlapComparator.setPRef(Double.parseDouble(argv[i].substring(1+argv[i].lastIndexOf("f"))));
        		if(argv[i].startsWith("-pSys"))
        			OverlapComparator.setPSys(Double.parseDouble(argv[i].substring(1+argv[i].lastIndexOf("s"))));
				if (argv[i].equals("-refDir")) {
			  		if (++i>argv.length) {
			    		usage();
			    		System.exit(1);
			  		}
			  		setRefDirName( argv[i] );
				}
				if (argv[i].equals("-maxAllowedItems"))
					maxAllowedItems = Integer.parseInt(argv[i].substring(1+argv[i].lastIndexOf("s")));
			}
			if (refDirName == null) setRefDirName( "Reference");

			ComparisonManager c = new ComparisonManager();
			c.parseResults(new File(System.getProperty("user.dir")+
									System.getProperty("file.separator")+
									"System"+
									System.getProperty("file.separator")+
									argv[0]));
			c.parseReference();
			try{
				c.processComparison();
			}
			catch(Exception e){ e.printStackTrace(); }
		}
	}
}