// A "pen-based typing" alphabet recognizer - Ken Perlin

public class AlphaDraw {
   public AlphaDraw() {
      init();
   }

   void init() {
      abcReco = new Recognizer();
      numReco = new Recognizer();

      for (int i = 0 ; i < 8 ; i++) {
         double theta = Math.PI * (1 - i) / 4;
         double cos = 10 * Math.cos(theta), sin = 10 * Math.sin(theta);
   
         for (int j = -1 ; j <= 1 ; j++)
         for (int k = 0 ; k < 3 ; k++) {
   	    int p[] = pattern[k][j+1];
   	    if (p.length > 0) {
               int n = 2, xy[] = {0,0, 0,0, 0,0, 0,0};
   	       for (int m = 0 ; m < p.length ; m += 2) {
   	          xy[n++] = (int)( cos * p[m] + sin * p[m+1]);
   	          xy[n++] = (int)(-sin * p[m] + cos * p[m+1]);
   	       }
	       isNumeric = true ; add(numReco, xy, n, map(i,j,k));
	       isNumeric = false; add(abcReco, xy, n, map(i,j,k));
            }
         }
      }
   }

   void add(Recognizer reco, int xy[], int n, int ch) {
      if (ch != '?')
	 reco.add(xy, n, "" + (char)ch);
   }

   boolean isNonums = false;
   public void toggleHasNumbers() {
      isNonums = ! isNonums;
      init();
   }

   public int shift(int c) {
      return c <  ' ' || c > 127 ? c :
             c >= '@' ? (c&32)==0 ? c+32 : c-32 :
                        (c&16)==0 ? c+16 : c-16 ;
   }

   public double[] getPattern(Object obj) { return reco().getPattern(obj); }

   public int recognize(int xy[], int n) {
      String s = (String)reco().recognize(xy, n);
      if (s == null)
         return 0;
      return (int)s.charAt(0);
   }

   Recognizer reco() { return isNumeric ? numReco : abcReco; }

   public void toggleNumeric() {
      isNumeric = ! isNumeric;
   }
   private boolean isNumeric = false;

   public int map(int i, int j, int k) {
      String _m[] = isNumeric ? _num : isNonums ? _abc_nonums : _abc;
      return remap((int)_m[k].charAt(4*i + j+1));
   }

   public static final int END = 2001;
   public static final int SEND = 2002;
   public static final int SHIFT = 2003;
   public static final int CNTRL = 2004;

   private int remap(int c) {
      switch (c) {
      case 'A': c = SHIFT; break; // UPPER CASE
      case 'B': c = '\b' ; break; // BACKSPACE
      case 'C': c='C'-'@'; break; // CONTROL C
      case 'D': c = 1005 ; break; // UP ARROW
      case 'E': c =   27 ; break; // ESC
      case 'F': c = ' '  ; break; // SPACE
      case 'I': c = END  ; break; // END
      case 'K': c = CNTRL; break; // CONTROL
      case 'L': c = 1006 ; break; // LEFT ARROW
      case 'N': c = '\n' ; break; // NEW LINE
      case 'O': c = SEND ; break; // SEND
      case 'R': c = 1007 ; break; // RIGHT ARROW
      case 'S': c = '\\' ; break; // BACKSLASH
      case 'T': c = '\t' ; break; // TAB
      case 'U': c = 1004 ; break; // DOWN ARROW
      case 'V': c='V'-'@'; break; // CONTROL V
      case 'X': c='X'-'@'; break; // CONTROL X
      }
      return c;
   }

   private Recognizer abcReco, numReco;

   String _abc[] = { "zab def hij lFm nop qNr stu wBx",
                     "3c4 5g6 7k8 9,0 @.; ~A- Tv* 1y2",
                     "[ S L R / ] U D ? E R L K ? D U", };

   String _abc_nonums[] = { "zab def hij lFm nop qNr stu wBx",
                            "?c? ?g? ?k? ?,? @.; ~A- Tv* ?y?",
                            "[ S L R / ] U D ? E R L ? ? D U", };

   String _num[] = { "3O4 5U6 7I8 9R0 ?#? ?D? ?*? 1L2",
                     "??? ?C? ??? ??? ?V? ??? ?X? ???",
                     "? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?", };
   
   int pattern[][][] = {{{0,-1,-1,-1    }, {0,-1    }, {0,-1,1,-1    }},
                        {{0,-1,-1, 0    }, {0,-1,0,0}, {0,-1,1, 0    }},
                        {{0,-2,-1,-1,0,0}, {        }, {0,-2,1,-1,0,0}},};
}

