// class LanguageDaemon
//   a little class for my friend Margarita
//   to help her to type in any language...
// love, Sam

// a single one of these will work as a listener for multiple TextComponents

// n.b. * long matchable sequences should appear before short ones in the array
//      * matchable sequences will work after matchable chars, but not after
//        other matchable sequences - if you really want to have long
//        matchable sequences that start with other matchable sequences,
//        you need to change the start of the longer one to the character
//        that will be substituted for the shorter one...  if that makes
//        any sense!
//      * the system only uses unicode characters as part of sequences;

//        modifiers like ALT cannot be used (yet!).

//        I gave up on the swing version (for now) so I guess that makes the
//        whole effort pretty useless!!

import java.awt.*;
import java.awt.event.*;
//import javax.swing.*;
//import javax.swing.event.*;
//import javax.swing.text.*;

/*class Test extends Frame {
	public static void main(String[] args) {
		new Test().setVisible(true);
	}
	private TextField tf = new TextField();
	private TextArea ta = new TextArea();
	public Test() {
		setLayout(null);
		tf.setBounds(32,32,100,32);
		ta.setBounds(32,96,100,100);
		setBounds(32,32,164,228);
		add(tf); add(ta);
		LanguageDaemon ld = new LanguageDaemon("abc", "bcd", new String[] {"ade", "de"}, "wq");
		tf.addKeyListener(ld);
		ta.addKeyListener(ld);
	}
}*/

class LanguageDaemon implements KeyListener {
	protected char[] inputSequence;
	protected int inputSequenceLength;
	protected int maxSequenceLength;
	protected String matchableChars;
	protected String[] matchableSequences;
	protected String substitutesForChars;
	protected String substitutesForSequences;
	protected Object lastSource;

	public LanguageDaemon(String matchableChars, String substitutesForChars, String[] matchableSequences, String substitutesForSequences) {
		if (
			matchableChars.length() != substitutesForChars.length() ||
		 	matchableSequences.length != substitutesForSequences.length()
		)
			System.err.println("Oh dear, you're misusing the LanguageDaemon - expect null pointer exceptions.");
		else {
			this.matchableChars = matchableChars;
			this.substitutesForChars = substitutesForChars;
			this.matchableSequences = matchableSequences;
			this.substitutesForSequences = substitutesForSequences;
			// maxSequenceLength = 0;
			for (int i=0; i<matchableSequences.length; i++) {
				int len = matchableSequences[i].length();
				if (maxSequenceLength < len) maxSequenceLength = len;
			}
			inputSequence = new char[maxSequenceLength];
			// inputSequenceLength = 0;
		}
	}
	
	public void keyPressed(KeyEvent ev) {}
	
	public void keyReleased(KeyEvent ev) {}
	
	public void keyTyped(KeyEvent ev) {
		Object source = ev.getSource();
		char key = ev.getKeyChar();
		// add the keypress to the input sequence
		if (key == ev.CHAR_UNDEFINED)
			inputSequenceLength = 0;
		else if (source != lastSource) {
			inputSequenceLength = 1;
			inputSequence[0] = key;
		} else if (inputSequenceLength < maxSequenceLength)
			inputSequence[inputSequenceLength++] = key;
		else {
			for (int i=1; i<inputSequenceLength; i++)
				inputSequence[i-1] = inputSequence[i];
			inputSequence[inputSequenceLength-1] = key;
		}
		// check in the list of matchable sequences for a match
		boolean match = false;
		int i, len = 0;
		for (i=0; i<matchableSequences.length; i++) {
			String matchableSequence = matchableSequences[i];
			len = matchableSequence.length();
			if (inputSequenceLength >= len) {
				match = true;
				for (int j=inputSequenceLength-len, k=0; j<inputSequenceLength; j++, k++)
					if (inputSequence[j] != matchableSequence.charAt(k)) {match = false; break;}
				if (match) break;
			}
		}
		if (match) {
			// we have a match!
			inputSequenceLength = 1;
			inputSequence[0] = substitutesForSequences.charAt(i);
			// remove len-1 characters from the TextComponent
			// and insert the one we want!
			if (len>1) {
				if (source instanceof TextComponent) {
					TextComponent tc = (TextComponent)source;
					int caretPos = tc.getCaretPosition();
					String text = tc.getText();
					text = text.substring(0, caretPos-len+1) + text.substring(caretPos);
					tc.setText(text);
					tc.setCaretPosition(caretPos-len+1);
				}/* else if (source instanceof JTextComponent) {
					System.out.println("Hello?");
					// this bit could be optimised for swing...
					JTextComponent tc = (JTextComponent)source;
					int caretPos = tc.getCaretPosition();
					String text = tc.getText();
					text = text.substring(0, caretPos-len+1) + text.substring(caretPos);
					tc.setText(text);
					tc.setCaretPosition(caretPos-len+1);
				}*/ else
					System.err.println("Oh dear, you've made the LanguageDaemon listen to something strange!");
			}
			ev.setKeyChar(inputSequence[0]);
		} else {
			// check in the matchable characters for a match
			i = matchableChars.indexOf(key);
			if (i >= 0) // we have a match!
				ev.setKeyChar(substitutesForChars.charAt(i));
		}
		lastSource = source;
	}
}
