/*
 *	Modulname:	ETextArea
 *	Autor:		Eyer Leander
 *	Datum:		04.03.2005
 *
 *	(c) Copyright 2005 by
 *		Eyer IT Services, Naters
 *	All rights reserved
 */
package survey.gui;

import javax.swing.*;
import javax.swing.text.Document;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Vector;

/**
 * A customized version of the JTextArea.
 * The primary advantage is the ability to install a "ChangeListener", who will
 * be called when the content of the TextField changes (quite similar to the change
 * event with JavaScript). Additionally, it automatically preselects the whole content
 * when activated (to simplify changing). Unlike the ETextField, the ETextArea does not
 * capture "ENTER" events as they are already used for line breaks.
 *
 * The TextArea will be preconfigured with 3 pixel insets and enabled word wrapping at word boundaries.
 */
public class ETextArea extends JTextArea implements FocusListener {

	/** Content Cache (so that we actually know when something was changed) */
	private String cache = "";
	/** Event listeners */
	private Vector listeners = new Vector();

	/** Default Constructor */
	public ETextArea() {
		super();
		init();
	}

	/** Constructor with fixed number of columns and rows */
	public ETextArea(int rows, int columns) {
		super(rows, columns);
		init();
	}

	/** Constructor with preset text */
	public ETextArea(String text) {
		super(text);
		cache = text;
		init();
	}

	/** Constructor with preset text and fixed number of columns and rows */
	public ETextArea(String text, int rows, int columns) {
		super(text, rows, columns);
		cache = text;
		init();
	}

	/** Constructor with custom document, preset text and fixed number of columns and rows */
	public ETextArea(Document doc, String text, int rows, int columns) {
		super(doc, text, rows, columns);
		cache = text;
		init();
	}

	/** This method is called by all constructors */
	private void init() {
		//config GUI
		setMargin(new Insets(3, 2, 3, 2));
		setLineWrap(true);
        setWrapStyleWord(true);

		//register listeners
		addFocusListener(this);
	}

	/** Update the internal cache if the text was changed through this api call (instead of changed by the user) */
	public void setText(String newText) {
		super.setText(newText);
		cache = newText;
		if (cache == null) {
			cache = "";
		}
	}

	/**
	 * Add a TextChangeListener to the notify list. The listener will be informed
	 * about changes of the text field
	 * @param listener		Listener to be added
	 */
	public void addChangeListener(TextChangeListener listener) {
		listeners.add(listener);
	}

	/**
	 * Remove a TextChangeListener from the notify list. The listener will no longer be informed
	 * about changes in the text field
	 * @param listener		Listener to be removed
	 */
	public void removeChangeListener(TextChangeListener listener) {
		listeners.remove(listener);
	}

	/**
	 * Notify all listeners about a change in the text field
	 * @param evt	Event describing the change
	 */
	private void fireTextChangeEvent(TextChangeEvent evt) {
		for (int i = 0; i < listeners.size(); i++) {
			((TextChangeListener) listeners.get(i)).textChanged(evt);
		}
	}

	/**
	 * Invoked when a component gains the keyboard focus.
	 */
	public void focusGained(FocusEvent e) {
		selectAll();
	}

	/**
	 * Invoked when a component loses the keyboard focus.
	 */
	public void focusLost(FocusEvent e) {
		fireEventIfRequired(TextChangeEvent.Trigger.FOCUS_LOST);
	}

	/**
	 * Compare the current text with the cached one and fire an event if a change occured
	 * @param trigger		Trigger who initialized the examination
	 */
	private void fireEventIfRequired(TextChangeEvent.Trigger trigger) {
		String newText = getText();
		if (newText.equals(cache) == false) {
			TextChangeEvent evt = new TextChangeEvent(this, cache, newText, trigger);
			fireTextChangeEvent(evt);
			cache = newText;
		}
	}



}

