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

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

   void init() {
      reco = new Recognizer[4];
      for (int i = 0 ; i < 4 ; i++)
         reco[i] = new Recognizer();

      for (int dir = 0 ; dir < 6 ; dir++) {
         double theta = Math.PI * (5 - dir) / 3;
         double cos = 10 * Math.cos(theta), sin = 10 * Math.sin(theta);
   
         for (int j = 0 ; j < pattern.length ; j++) {
   	    double p[] = pattern[j];
   	    if (p.length > 0) {
               int n = 2, xy[] = {0,0, 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]);
   	       }
	       add(xy, n, dir, j);
            }
         }
      }
   }

   void add(int xy[], int n, int dir, int j) {
      int ch = map(dir, j);
      reco[sortByLength[j]].add(xy, n, "" + (char)ch);
   }

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

   public int shift(int c) {
      int m;
      if (c >= 'a' && c <= 'z')
         c += 'A' - 'a';
      else
         for (int k = 0 ; k < _abc.length ; k++)
            if ( (m = _abc[k].indexOf(c)) >= 0)
               return _ABC[k].charAt(m);
      return c;
   }

   public double[] getPattern(Object obj) { return getPattern(obj, 1); }
   public double[] getPattern(Object obj, int j) {
      return reco[j].getPattern(obj);
   }

   public int recognize(int xy[], int n, int j, boolean shifted) {
      int c = ((String)reco[j].recognize(xy, n)).charAt(0), m;
      if (shifted)
         c = shift(c);
      String s = "" + (char)c;
      if (s == null)
         return 0;
      return (int)s.charAt(0);
   }

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

   public int map(int i, int j) {
      return remap((int)_abc[i].charAt(j));
   }

   public static final int ALT   = 2001;
   public static final int CNTRL = 2002;
   public static final int DELWD = 2003;
   public static final int END   = 2004;
   public static final int SEND  = 2005;
   public static final int SHIFT = 2006;

   private int remap(int c) {
      switch (c) {
      case 'A': c = ALT  ; break; // ALT KEY
      case 'B': c = '\b' ; break; // BACKSPACE
      case 'C': c = SHIFT; break; // SHIFT KEY
      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 KEY
      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 'W': c = DELWD; break; // DELETE WORD
      }
      return c;
   }

   private Recognizer reco[];

//    !"#$%&'()*+,-./0123456789:;<=>?
//   @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
//   `abcdefghijklmnopqrstuvwxyz{|}~

   String _abc[] = { "?4yab d5*",
                     "`6cefjh7!",
                     "'8gilkn9=",
                     ".0mopqsA-",
                     "%KrtuNw1,",
                     "&2vBxCz3;", };

   String _ABC[] = { "?>--- -[-",
                     "^]-----{|",
                     "\"}-----(+",
                     ".)-----A_",
                     "#K---N-\\,",
                     "$/-B--C<:", };

   double Y = .5 * Math.sqrt(3);
   double pattern[][] = {
      {-0.25, .5*Y,   -1.0,  0.0,                        }, // [  1
      {-1.00, .5*Y,   -1.0,  0.0,                        }, // 2  1
      {-1.00, .5*Y,   -2.0,  0.0,                        }, // v  3
      {-1.00,    0,                                      }, // B  1
      {-1.00,-.5*Y,   -2.0,  0.0,                        }, // x  3
      {-1.50,-   Y,    0.0,  0.0,                        }, // z  0
      {-1.50,-   Y,                                      }, // W  2
      {-1.00,-.5*Y,   -1.0,  0.0,                        }, // 3  1
      {-0.25,-.5*Y,   -1.0,  0.0,                        }, // (  1
   };
   int sortByLength[] = {1, 1, 3, 1, 3, 0, 2, 1, 1};
}

