import java.util.*;
import java.io.*;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.*;
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 shot boundaries segmentations and some references.
 * It permit 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
 * 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 Hashtable containing the file names of the reference.
     * The key is the video name and value is the file name.
     *     
     */
    private Hashtable referenceFilenames;
    /**
     * The Hashtable containing the reference segmentations.
     * The key is the video name and value is the segmentation.
     * 
     */
    private Hashtable referenceSegmentations = new Hashtable();
    /**
     * The Hashtable containing the system results.
     * The key is the system ID and value is a systemResult instance.
     * 
     */
    private Hashtable systemResults;

    public ComparisonManager(){}
    
    /**
     * Launch the parsing of the file containing the mapping between a video file name 
     * and an Xml segmentation reference file.
     *
     * @param File referenceFileNamesFile name of the file containing this informations
     */   
    public void parseReferenceFileNames(File referenceFileNamesFile){

	//Test the existence of the file
	if (!referenceFileNamesFile.exists()){
	    System.err.println("The Reference Mapping Information (file:video) File \""+referenceFileNamesFile.getAbsolutePath()+"\""+
			       System.getProperty("line.separator")+" does not EXISTS");
	    System.exit(1);	
	}
	System.out.println(System.getProperty("line.separator")+"Parsing Reference Mapping Information..."); 
	// 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");
	    shotResultContentHandler resultHandler = new shotResultContentHandler(out);
	    
            // Parse the input
            SAXParser saxParser = factory.newSAXParser();
            if(referenceFileNamesFile == null || resultHandler == null){
            	System.out.println("NULL");
            	System.exit(0);
            }
            saxParser.parse(referenceFileNamesFile, resultHandler);
            this.referenceFilenames = resultHandler.getReferenceFileNames();
            //System.out.println(this.referenceFilenames);
        } 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();
	   System.exit(1);
        } 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();
	   System.exit(1);
        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();
	    System.exit(1);
        } catch (IOException ioe) {
           // I/O error
           ioe.printStackTrace();
	   System.exit(1);
    	}
    }
    
    /**
     * Launch the parsing of the file containing the Xml reference segmentations.
     *
     */	
    public void parseReference(String referencePath){
	
	// 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");
	    shotResultContentHandler resultHandler = new shotResultContentHandler(out);
	    
            // Parse the input
            SAXParser saxParser = factory.newSAXParser();
            if(resultHandler == null){
            	System.out.println("NULL");
            	System.exit(0);
            }
            
            //For each systemResult in systemResults Hashtable retrieve all videoNames
            //and then find out the reference.xml matching file to parse
            
            Hashtable xmlRefFiles = new Hashtable();//key=.xml, value==video.mpg
            Enumeration e = systemResults.elements();            
            while(e.hasMoreElements()){
		
            	systemResult s = (systemResult) e.nextElement();
            	Enumeration n = s.getSegmentationsVideoNames().elements();
            	while(n.hasMoreElements()){
		    String someVideo = (String) n.nextElement();
		    if (referenceFilenames.containsKey(someVideo))
			xmlRefFiles.put(referenceFilenames.get(someVideo), someVideo);
            	}
            }
            
            //Now we have to parse and then get
            //by getRefSegmentation() from ContentHandler all reference Segmentations
	    
            e = xmlRefFiles.keys();
	    System.out.println(System.getProperty("line.separator")+"Parsing Reference Segmentation..."); 
            while(e.hasMoreElements()){
            	
		String xmlFile = (String) e.nextElement();
		File toParse = new File(referencePath+System.getProperty("file.separator")+xmlFile);
		//Test the existence of the file
		if (!toParse.exists()){
		    System.err.println("The specified file \""+toParse.getAbsolutePath()+"\""+
				       System.getProperty("line.separator")+" does not EXISTS");
		    System.exit(1);
		}
		saxParser.parse(toParse, resultHandler);
		this.referenceSegmentations.put((String) xmlRefFiles.get(xmlFile), resultHandler.getRefSegmentation());	            
            }
            //System.out.println(this.referenceSegmentations);
	    
        } 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();
	   System.exit(1);
        } 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();
	    System.exit(1);
        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();
	    
        } catch (IOException ioe) {
	    // I/O error
	    ioe.printStackTrace();
	    System.exit(1);
    	}
    }
    /**
     * Launch the parsing of the file containing the results per system results.
     *
     * @param systemResultsFile name of the file containing this information.
     */
    public void parseResults(File systemResultsFile){
	
	//Test the existence of the file
	if (!systemResultsFile.exists()){
	    System.err.println("The specified file \""+systemResultsFile.getAbsolutePath()+"\""+
			       System.getProperty("line.separator")+" does not EXISTS");
	    System.exit(1);			
	}
	System.out.println(System.getProperty("line.separator")+"Parsing Submission..."); 
	
        // 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");
	    shotResultContentHandler resultHandler = new shotResultContentHandler(out);
	    
            // Parse the input
            SAXParser saxParser = factory.newSAXParser();
            if(systemResultsFile == null || resultHandler == null){
            	System.out.println("NULL");
            	System.exit(0);
            }
            saxParser.parse(systemResultsFile, resultHandler);
            this.systemResults = resultHandler.getSystemResults();
            //System.out.println(this.systemResults);
	    
        } 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();
	   System.exit(1);
        } 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();
	    System.exit(1);
        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();
	    
        } catch (IOException ioe) {
	    // I/O error
	    ioe.printStackTrace();
	    System.exit(1);
    	}
    }
    /**
     * Process the comparison between the reference segmentations and each system segmentation.
     *     
     */
    public void processComparison() throws Exception{
	
	System.out.println(System.getProperty("line.separator")+"Processing comparison..."); 
	Enumeration e = systemResults.elements();            
	while(e.hasMoreElements()){	    
	    systemResult aSystemResult = (systemResult) e.nextElement();
	    aSystemResult.processComparison(referenceSegmentations);
	    aSystemResult.save();
	}
	System.out.println();
    }
    /**
     * Main entry point to the program.
     *     
     */
    public static void main(String argv[]){

	if ((argv.length < 1) || (argv.length > 5)) {
            System.err.println("Usage: java ComparisonManager [systemSeg_file.xml] [-shortGradual] [-referenceDir]");
	    System.err.println("Example: java ComparisonManager ./mySys.xml -shortGradual5 -referenceDir/home/myAccount/sb/ref/");
            System.exit(1);
        }
        else{
	    String referencePath = ".";
	    for(int i=1; i < argv.length; i++){
        		
		if(argv[i].startsWith("-shortGradual"))
		    Transition.setShortGradualThreshold(Integer.parseInt(argv[i].substring(1+argv[i].lastIndexOf("l"))));        		
		if(argv[i].startsWith("-referenceDir"))
		    referencePath = argv[i].substring(13);      
	    }
	    ComparisonManager c = new ComparisonManager();
	    c.parseResults(new File(argv[0]));
	    
	    c.parseReferenceFileNames(new File(referencePath+System.getProperty("file.separator")+"shotBoundaryReferenceFiles.xml"));
	    c.parseReference(referencePath);			
	    try{
		c.processComparison();
	    }
	    catch(Exception e){ e.printStackTrace(); }
	}
    }
}
