package de.visone.nlpext.gui;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import org.apache.log4j.Logger;

import de.visone.base.Mediator;
import de.visone.gui.tabs.NetworkCreationCard;
import de.visone.gui.tabs.option.BooleanOptionItem;
import de.visone.gui.tabs.option.InputFileOptionItem;
import de.visone.gui.tabs.option.IntegerOptionItem;
import de.visone.nlpext.network.TextNetwork;

/**
 * The common ancestor for {@link CRACard} and {@link WNACard}.
 * 
 * @author unknown
 * @author matthias
 */
public abstract class NLPPanel extends NetworkCreationCard {
	private static final Logger logger = Logger.getLogger(NLPPanel.class);

	protected static final String STOP_WORDS_FILTER = "/de/visone/nlpext/resource/stop_words.txt";
	protected static final String CANNOT_LOAD_STOPWORDS = "could not read stopword filter file."
			+ " will use default filter.";

	private static final String MIN_LENGTH_LABEL = "minimal word length";
	private static final String STOPWORD_FILE_LABEL = "stopword file";
	private static final String DEFAULT_STOPWORDS_LABEL = "use default stopwords";
	private static final String TEXT_FILE_LABEL = "text file";
	private static final String QUICK_LAYOUT_LABEL = "quick layout";

	private BooleanOptionItem quickLayout;
	private InputFileOptionItem text;
	protected InputFileOptionItem stopwords;
	private BooleanOptionItem defaultStopWords;
	private IntegerOptionItem minLength;

	/**
	 * @param mediator
	 *            the {@link Mediator}
	 * @param cardname
	 *            name shown in the combo box
	 */
	protected NLPPanel(final Mediator mediator, final String cardname) {
		super(cardname, mediator);
	}

	protected void addBasicOptions() {
		addHeading("options");
		quickLayout = new BooleanOptionItem();
		quickLayout.setValue(true);
		addOptionItem(quickLayout, QUICK_LAYOUT_LABEL);

		addHeading("natural language text");
		text = new InputFileOptionItem("text file", ".txt");
		addOptionItem(text, TEXT_FILE_LABEL);

		addHeading("stopword filter");
		defaultStopWords = new BooleanOptionItem();
		defaultStopWords.setValue(true);
		addOptionItem(defaultStopWords, DEFAULT_STOPWORDS_LABEL);
		affectsOthers(defaultStopWords);
		stopwords = new InputFileOptionItem("stopword file", ".txt");
		addOptionItem(stopwords, STOPWORD_FILE_LABEL);
		minLength = new IntegerOptionItem(3, 1, 5);
		addOptionItem(minLength, MIN_LENGTH_LABEL);
	}

	@Override
	protected void toggleOptionItemsEnabled() {
		if (stopwords != null)
			stopwords.setEnabled(!defaultStopWords.getValue());
	}

	@Override
	protected final boolean doRunAlgorithm() {
		new Thread("nlp main") {
			@Override
			public void run() {
				runAlgorithm();
			};
		}.start();
		// started successfully. if it fails, it fails asynchronously
		return true;
	}

	protected abstract void runAlgorithm();

	// ------------ get methods ------------

	/** returns true if default stop words shall be used. */
	public boolean useDefaultStopWords() {
		return defaultStopWords.getValue();
	}

	public int getMinWordLength() {
		return minLength.getValue();
	}

	/** returns true if quick layout was asked for by the user. */
	public boolean getLayoutMode() {
		return quickLayout.getValue();
	}

	/**
	 * returns the file selected by the user if it exists and can be read,
	 * otherwise null is returned.
	 */
	public File getTextFile() {
		return text.getValue();
	}

	// ------------ other methods ------------

	/** Pops up an error dialog with the specified message. */
	protected void error(final String msg) {
		JOptionPane.showMessageDialog(mediator.getWindow(), msg, "error",
				JOptionPane.ERROR_MESSAGE);
	}

	/**
	 * this method can be used to extract user input from a file. Leading and
	 * trailing whitespace will be omitted. Blank lines and and everything
	 * behind a # is ignored, too.
	 * 
	 * @param handlerEntry
	 *            the label identifying the file in the handler
	 * @param defaultResource
	 *            the file that should be used otherwise
	 * @param errorField
	 *            code of error message
	 * @return a string array of all non-comment trimmed lines
	 */
	protected String[] extractLinesFromFile(final File file,
			final String defaultResource, final String errorField,
			final boolean useDefault) {
		try {
			final ArrayList<String> lineList = new ArrayList<String>();

			BufferedReader br = null;
			Throwable t = null;

			try {
				if (!useDefault) {
					logger.debug("reading from file: " + file);
					br = new BufferedReader(new FileReader(file));
				}
			} catch (final Exception e) {
				error(errorField);
				t = e;
				logger.error("problem while opening file: " + e.getMessage(), e);
			}

			if (useDefault || t != null || br == null) {
				logger.debug("using default file: " + defaultResource);
				logger.debug("resource: "
						+ NLPPanel.class.getResource(defaultResource));
				final InputStream in = NLPPanel.class
						.getResourceAsStream(defaultResource);
				if (br != null)
					br.close();
				br = new BufferedReader(new InputStreamReader(in));
			}

			String line;
			while ((line = br.readLine()) != null) {
				if (line.indexOf("#") != -1)
					line = line.substring(0, line.indexOf("#"));

				line = line.trim();

				if (line.equals(""))
					continue;

				lineList.add(line);
			}
			br.close();

			final String[] lineArray = new String[lineList.size()];
			for (int i = 0; i < lineArray.length; i++)
				lineArray[i] = lineList.get(i);
			return lineArray;
		} catch (final Exception e) {
			logger.error("exception while reading file: " + e.getMessage(), e);
			return null;
		}
	}

	public abstract TextNetwork getTextNetwork();

	@Override
	public abstract String getApplyText();
}
