/*
 * Alignment.java
 *
 * ...
 * ...
 * ...
 */

package aksis.alignment;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.nio.charset.*;

/**
 * Program startup class for alignment project.
 * @author Johan Utne Poppe
 */

public class Alignment {

	public static final String VERSION = "2006-10-05";   // 2006-10-05
	public static final int NUM_FILES = 2;
	public static final int MIN_NUM_TRY = 0;
	public static final int MAX_NUM_TRY = 2;
	public static final int MAX_DIFF_TRY = 1;
	public static final int MAX_TOTAL_TRY = 3;
	public static final String DEFAULT__SETTINGS_FILENAME = ".\\tca2.cfg";   // 2006-09-21
	public static final String DEFAULT__RELEVANT_ELEMENT_NAMES = "s head";
	public static final String DEFAULT__RELEVANT_ANCESTOR_ELEMENT_NAMES = "p div";
	public static final String DEFAULT__SPECIAL_CHARACTERS = ".,;:?!&^(){}[]'" + '"';
	public static final String DEFAULT__SCORING_CHARACTERS = "?!%";   // characters that add to the score if they occur in both tetxt
	public static final float DEFAULT__LENGTH_RATIO = 1.1f;   // ###
	public static final float MIN__LENGTH_RATIO = 0.5f;   // least allowable value of the above
	public static final float MAX__LENGTH_RATIO = 2.f;   // greatest allowable value of the above
	public static final float STEP__LENGTH_RATIO = 0.01f;   // step in the spinner component of the above

	public static final int DEFAULT__DICE_MIN_WORD_LENGTH = 5;   // default. user settable. words with length below this value will not be compared
	public static final int MIN__DICE_MIN_WORD_LENGTH = 1;   // least possible value of the above

	public static final float DEFAULT__DICE_MIN_COUNTING_SCORE = 0.7f;   // word pairs with raw dice score below this value will not get a score
	public static final float MIN__DICE_MIN_COUNTING_SCORE = 0.5f;   // least allowable value of the above
	public static final float MAX__DICE_MIN_COUNTING_SCORE = 0.9f;   // greatest allowable value of the above
	public static final float STEP__DICE_MIN_COUNTING_SCORE = 0.01f;   // step in the spinner component of the above
	public static final int MIN__LARGE_CLUSTER_SCORE_PERCENTAGE = 0;
	public static final int MAX__LARGE_CLUSTER_SCORE_PERCENTAGE = 100;
	public static final int DEFAULT__LARGE_CLUSTER_SCORE_PERCENTAGE = 25;
	public static final int STEP__LARGE_CLUSTER_SCORE_PERCENTAGE = 5;
	
	public static final int DEFAULT__MAX_PATH_LENGTH = 10;
	public static final int MAX__MAX_PATH_LENGTH = 20;

	public static final float MIN__ANCHORWORD_MATCH_WEIGHT       = 0.5f;
	public static final float MIN__ANCHORPHRASE_MATCH_WEIGHT     = 0.5f;
	public static final float MIN__PROPERNAME_MATCH_WEIGHT       = 0.5f;
	public static final float MIN__DICE_MATCH_WEIGHT             = 0.5f;
	public static final float MIN__DICEPHRASE_MATCH_WEIGHT       = 0.5f;
	public static final float MIN__NUMBER_MATCH_WEIGHT           = 0.5f;
	public static final float MIN__SCORINGCHARACTER_MATCH_WEIGHT = 0.5f;
	public static final float MAX__ANCHORWORD_MATCH_WEIGHT       = 3.0f;
	public static final float MAX__ANCHORPHRASE_MATCH_WEIGHT     = 3.0f;
	public static final float MAX__PROPERNAME_MATCH_WEIGHT       = 3.0f;
	public static final float MAX__DICE_MATCH_WEIGHT             = 3.0f;
	public static final float MAX__DICEPHRASE_MATCH_WEIGHT       = 3.0f;
	public static final float MAX__NUMBER_MATCH_WEIGHT           = 3.0f;
	public static final float MAX__SCORINGCHARACTER_MATCH_WEIGHT = 3.0f;
	public static final float STEP__MATCH_WEIGHT = 0.1f;
	public static final float DEFAULT__ANCHORWORD_MATCH_WEIGHT       = 1.0f;
	public static final float DEFAULT__ANCHORPHRASE_MATCH_WEIGHT     = 1.6f;
	public static final float DEFAULT__PROPERNAME_MATCH_WEIGHT       = 1.3f;
	public static final float DEFAULT__DICE_MATCH_WEIGHT             = 1.3f;
	public static final float DEFAULT__DICEPHRASE_MATCH_WEIGHT       = 1.6f;
	public static final float DEFAULT__NUMBER_MATCH_WEIGHT           = 1.3f;
	public static final float DEFAULT__SCORINGCHARACTER_MATCH_WEIGHT = 1.3f;

	public static final int MODE_ONE = 1;
	public static final int MODE_SKIP11 = 2;
	public static final int MODE_AUTO = 3;


	/*
	 * ¤¤¤In many circumstances, you need a chance to do some clean-up when the user shuts down your application...
	 * <http://www.onjava.com/pub/a/onjava/2003/03/26/shutdownhook.html#listing1>
	 */
	public void start(AlignmentModel model) {
		ShutdownHook shutdownHook = new ShutdownHook(model);
		Runtime.getRuntime().addShutdownHook(shutdownHook);
	}
	
	
	public void startGui(AlignmentModel model) {
		AlignGui gui = new AlignGui(model);
		JFrame frame = new JFrame("TCA2");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(gui);
		frame.setJMenuBar(gui.menuBar);
		// get the size of the default screen (¤¤¤in principle there can be more than one screen)
		Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
		frame.setSize(screenDim);
		frame.setVisible(true);
		frame.setLocationRelativeTo(null);   // relative to screen
		gui.compareInfoGraphics = gui.compareInfoPanel.getGraphics();
	}
	
	public static void main(String[] args) throws Exception {
		AlignmentModel model = new AlignmentModel();
		
		// <http://www.onjava.com/pub/a/onjava/2003/03/26/shutdownhook.html#listing1>
		// model must exist before start() is run, because the latter needs it
		Alignment alignment = new Alignment();
		alignment.start(model);
		
		
		/*
		 * Parse options. Start the gui in the traditional way
		 * or start a cli version, which is given three options
		 */
		Options opt = new Options(args, 0);
		opt.addSet("nullset", 0);
		opt.addSet("cliset", 2).addOption("a", Options.Separator.BLANK);
		OptionSet set = opt.getMatchingSet();
		if (set == null) {
  // Print usage hints
			System.exit(1);
		}
		if (set.getSetName().equals("nullset")) {
			alignment.startGui(model);
		}
		if (set.getSetName().equals("cliset")) {
			int t = 0;
			for (String filename : set.getData()) {
				System.out.println(filename);
				File file = new File(filename);
				model.inputFilepath[t] = file.getCanonicalPath();
				System.out.println("getParent " + file.getCanonicalPath());
				model.loadTobeAlignedFile(file, t);
				t++;
			}
			
			OptionData d = set.getOption("a");
			System.out.println(d.getResultValue(0));
			File anchorFile = new File(d.getResultValue(0));
			model.anchorWordList.loadFromFile(anchorFile);
			
// 			model.saveFilesAutomatically();
			// We have the files loaded, start aligning
			model.suggest2();
		}
	}
	
} // end class Alignment

// <http://www.onjava.com/pub/a/onjava/2003/03/26/shutdownhook.html#listing1>
class ShutdownHook extends Thread {

	AlignmentModel model;
	
	ShutdownHook(AlignmentModel model) {
		super();
		//System.out.println("ShutdownHook konstruktor kjører");
		this.model = model;
	}

	public void run() {
		if (model.logFileOut != null) {   // 2006-08-11
			try {
				String text = "\n\n>>> Program closed. Stop logging <<<\n\n";
				model.logFileOut.write(text, 0, text.length());
			} catch (Exception ex) {
				ErrorMessage.error("Exception when writing to " + model.getLogFilename() + ":\n" + ex.toString());   // 2006-08-10
			}
			try {
				model.logFileOut.close();
			} catch (Exception e) {
				ErrorMessage.error("Exception when trying to close log file:\n" + e.toString());
			}
		}
    	}
}
