package jxl.biff.formula;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import jxl.biff.WorkbookMethods;

class Yylex {
  private final int YY_BUFFER_SIZE = 512;
  
  private final int YY_F = -1;
  
  private final int YY_NO_STATE = -1;
  
  private final int YY_NOT_ACCEPT = 0;
  
  private final int YY_START = 1;
  
  private final int YY_END = 2;
  
  private final int YY_NO_ANCHOR = 4;
  
  private final int YY_BOL = 65536;
  
  private final int YY_EOF = 65537;
  
  private boolean emptyString;
  
  private ExternalSheet externalSheet;
  
  private WorkbookMethods nameTable;
  
  private BufferedReader yy_reader;
  
  private int yy_buffer_index;
  
  private int yy_buffer_read;
  
  private int yy_buffer_start;
  
  private int yy_buffer_end;
  
  private char[] yy_buffer;
  
  private int yychar;
  
  private int yyline;
  
  private boolean yy_at_bol;
  
  private int yy_lexical_state;
  
  private boolean yy_eof_done;
  
  private final int YYSTRING = 1;
  
  private final int YYINITIAL = 0;
  
  private final int[] yy_state_dtrans;
  
  private boolean yy_last_was_cr;
  
  private final int YY_E_INTERNAL = 0;
  
  private final int YY_E_MATCH = 1;
  
  private String[] yy_error_string;
  
  private int[] yy_acpt;
  
  private int[] yy_cmap;
  
  private int[] yy_rmap;
  
  private int[][] yy_nxt;
  
  int getPos() {
    return this.yychar;
  }
  
  void setExternalSheet(ExternalSheet es) {
    this.externalSheet = es;
  }
  
  void setNameTable(WorkbookMethods nt) {
    this.nameTable = nt;
  }
  
  Yylex(Reader reader) {
    this();
    if (null == reader)
      throw new Error("Error: Bad input stream initializer."); 
    this.yy_reader = new BufferedReader(reader);
  }
  
  Yylex(InputStream instream) {
    this();
    if (null == instream)
      throw new Error("Error: Bad input stream initializer."); 
    this.yy_reader = new BufferedReader(new InputStreamReader(instream));
  }
  
  private Yylex() {
    this.yy_eof_done = false;
    this.YYSTRING = 1;
    this.YYINITIAL = 0;
    this.yy_state_dtrans = new int[] { 0, 30 };
    this.yy_last_was_cr = false;
    this.YY_E_INTERNAL = 0;
    this.YY_E_MATCH = 1;
    this.yy_error_string = new String[] { "Error: Internal error.\n", "Error: Unmatched input.\n" };
    this.yy_acpt = new int[] { 
        0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
        4, 4, 0, 4, 4, 4, 4, 4, 4, 4, 
        0, 4, 4, 0, 4, 4, 0, 4, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
        0, 0, 4, 0, 4, 0, 0, 4, 0 };
    this.yy_cmap = unpackFromString(1, 65538, "29:8,14:3,29:21,14,16,28,15,11,15:2,13,26,27,3,1,8,2,10,4,9:10,17,15,7,6,5,15:2,23,12:3,21,22,12:5,24,12:5,19,25,18,20,12:5,15:5,29,12:26,29,15,29,15,29:65409,0:2")[0];
    this.yy_rmap = unpackFromString(1, 89, "0,1,2,1,2:2,3,2,4,2,5,2:2,1:3,2:3,6,7,1,8,9,10,11,12,13,11,14,15,1,16,17,11,2,18,19,20,21,22,23,2,24,25,1,26,27,8,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,13,50,51,52,53,54,55,56,14,57,20,58,59,60,2,61,62,63")[0];
    this.yy_nxt = unpackFromString(64, 30, "1,2,3,4,5,6,7,8,9,10,32,40,32,43,11,85:2,12,83,32:3,88,32:3,13,14,15,-1:32,85,-1,85:10,46,85:2,86,85:9,-1:5,85,-1,85:3,16,85:6,46,85:2,86,85:9,-1:5,85,-1,85:2,17,18,85:6,46,85:2,86,85:9,-1:5,85,-1,85:6,10,48,85:2,46,85:2,86,85:9,-1:5,85,-1,85:6,19,85:3,46,85:2,86,55,85:8,-1:5,85,-1,85:6,33,34,49,34,46,85:2,86,50,34:8,21,-1:4,85,-1,85:6,22,85:3,46,85:2,86,85:9,-1:5,85,-1,85:7,35,85,35,46,85:2,86,85,35:8,-1:5,85,-1,85:6,24,85:3,46,85:2,86,68,85:8,-1:5,85,-1,85:6,44,34,85,34,46,85:2,86,85,34:8,21,-1:4,85,-1,85:7,42,85,42,46,85:2,86,85,42:8,-1:5,85,-1,85:6,27,85:3,46,85:2,86,85:9,-1:5,85,-1,85:6,29,85:3,46,85:2,86,85:9,-1:4,1,39:27,31,39,-1,85,-1,85:6,19,20,49,20,46,85:2,86,50,20:8,21,-1:4,85,-1,85:6,33,44,85,44,46,85:2,86,55,44:8,-1:13,36,-1:7,72,-1:22,45,-1,45,-1:5,45:8,-1:13,38,-1:21,39:27,-1,39,-1,85,-1,85:7,51,85,51,46,85:2,86,85,51:8,-1:5,85,-1,85:6,44,34,85,34,46,85:2,86,85,34:3,25,34:4,21,-1:4,85,-1,85:10,-1,85:12,-1:5,85,-1,85:6,44:2,85,44,46,85:2,86,85,44:8,-1:20,52,-1:14,85,-1,85:6,44,34,85,34,46,85:2,86,85,34:3,28,34:4,21,-1:4,85,-1,85:6,19,85:3,46,85:2,86,85:9,-1:5,85,-1,85:7,23,56,23,46,85:2,86,85,23:8,-1:5,85,-1,85:6,19,57,49,57,46,85:2,86,50,57:8,-1:14,58,59,58,-1:5,58:8,-1:5,85,-1,85:6,24,60,61,60,46,85:2,86,62,60:8,-1:5,85,-1,85:7,53,85,53,46,85:2,86,85,53:8,-1:5,85,-1,85:7,63,64,63,46,85:2,86,85,63:8,-1:5,85,-1,85:7,23,85,23,46,85:2,86,85,23:8,-1:5,85,-1,85:6,19,85,49,85,46,85:2,86,50,85:8,-1:13,36,65,66,65,-1:4,67,65:8,-1:14,58,-1,58,-1:5,58:8,-1:5,85,-1,85:6,24,85,61,85,46,85:2,86,62,85:8,-1:5,85,-1,85:6,24,85:3,46,85:2,86,85:9,-1:5,85,-1,85:7,26,69,26,46,85:2,86,85,26:8,-1:5,85,-1,85:6,27,70,71,70,46,85:2,86,85,70:8,-1:5,85,-1,85:7,63,85,63,46,85:2,86,85,63:8,-1:13,36,-1,66,-1:5,67,-1:21,36,-1:30,37,73,37,-1:5,37:8,-1:5,85,-1,85:7,74,75,74,46,85:2,86,85,74:8,-1:5,85,-1,85:7,26,85,26,46,85:2,86,85,26:8,-1:5,85,-1,85:6,27,85,71,85,46,85:2,86,85:9,-1:14,76,77,76,-1:5,76:8,-1:14,37,-1,37,-1:5,37:8,-1:5,85,-1,85:6,29,78,79,78,46,85:2,86,85,78:8,-1:5,85,-1,85:7,74,85,74,46,85:2,86,85,74:8,-1:13,38,80,81,80,-1:5,80:8,-1:14,76,-1,76,-1:5,76:8,-1:5,85,-1,85:6,29,85,79,85,46,85:2,86,85:9,-1:13,38,-1,81,-1:19,85,-1,85:6,33,34,49,34,46,85:2,86,50,34:2,41,34:5,21,-1:4,85,-1,85:6,19,20,49,20,46,85:2,86,50,20,82,20:6,21,-1:4,85,-1,85:6,44,34,85,34,46,85:2,86,85,34:7,47,21,-1:4,85,-1,85:7,53,54,53,46,85:2,86,85,53:8,-1:5,85,-1,85:6,33,34,49,34,46,85:2,86,50,34:6,84,34,21,-1:4,85,-1,85:6,19,20,49,20,46,85:2,86,50,20:5,87,20:2,21,-1:3");
    this.yy_buffer = new char[512];
    this.yy_buffer_read = 0;
    this.yy_buffer_index = 0;
    this.yy_buffer_start = 0;
    this.yy_buffer_end = 0;
    this.yychar = 0;
    this.yyline = 0;
    this.yy_at_bol = true;
    this.yy_lexical_state = 0;
  }
  
  private void yybegin(int state) {
    this.yy_lexical_state = state;
  }
  
  private int yy_advance() throws IOException {
    if (this.yy_buffer_index < this.yy_buffer_read)
      return this.yy_buffer[this.yy_buffer_index++]; 
    if (0 != this.yy_buffer_start) {
      int i = this.yy_buffer_start;
      int j = 0;
      while (i < this.yy_buffer_read) {
        this.yy_buffer[j] = this.yy_buffer[i];
        i++;
        j++;
      } 
      this.yy_buffer_end -= this.yy_buffer_start;
      this.yy_buffer_start = 0;
      this.yy_buffer_read = j;
      this.yy_buffer_index = j;
      int next_read = this.yy_reader.read(this.yy_buffer, this.yy_buffer_read, this.yy_buffer.length - this.yy_buffer_read);
      if (-1 == next_read)
        return 65537; 
      this.yy_buffer_read += next_read;
    } 
    while (this.yy_buffer_index >= this.yy_buffer_read) {
      if (this.yy_buffer_index >= this.yy_buffer.length)
        this.yy_buffer = yy_double(this.yy_buffer); 
      int next_read = this.yy_reader.read(this.yy_buffer, this.yy_buffer_read, this.yy_buffer.length - this.yy_buffer_read);
      if (-1 == next_read)
        return 65537; 
      this.yy_buffer_read += next_read;
    } 
    return this.yy_buffer[this.yy_buffer_index++];
  }
  
  private void yy_move_end() {
    if (this.yy_buffer_end > this.yy_buffer_start && '\n' == this.yy_buffer[this.yy_buffer_end - 1])
      this.yy_buffer_end--; 
    if (this.yy_buffer_end > this.yy_buffer_start && '\r' == this.yy_buffer[this.yy_buffer_end - 1])
      this.yy_buffer_end--; 
  }
  
  private void yy_mark_start() {
    for (int i = this.yy_buffer_start; i < this.yy_buffer_index; i++) {
      if ('\n' == this.yy_buffer[i] && !this.yy_last_was_cr)
        this.yyline++; 
      if ('\r' == this.yy_buffer[i]) {
        this.yyline++;
        this.yy_last_was_cr = true;
      } else {
        this.yy_last_was_cr = false;
      } 
    } 
    this.yychar = this.yychar + this.yy_buffer_index - this.yy_buffer_start;
    this.yy_buffer_start = this.yy_buffer_index;
  }
  
  private void yy_mark_end() {
    this.yy_buffer_end = this.yy_buffer_index;
  }
  
  private void yy_to_mark() {
    this.yy_buffer_index = this.yy_buffer_end;
    this.yy_at_bol = (this.yy_buffer_end > this.yy_buffer_start && ('\r' == this.yy_buffer[this.yy_buffer_end - 1] || '\n' == this.yy_buffer[this.yy_buffer_end - 1] || '߬' == this.yy_buffer[this.yy_buffer_end - 1] || '߭' == this.yy_buffer[this.yy_buffer_end - 1]));
  }
  
  private String yytext() {
    return new String(this.yy_buffer, this.yy_buffer_start, this.yy_buffer_end - this.yy_buffer_start);
  }
  
  private int yylength() {
    return this.yy_buffer_end - this.yy_buffer_start;
  }
  
  private char[] yy_double(char[] buf) {
    char[] newbuf = new char[2 * buf.length];
    for (int i = 0; i < buf.length; i++)
      newbuf[i] = buf[i]; 
    return newbuf;
  }
  
  private void yy_error(int code, boolean fatal) {
    System.out.print(this.yy_error_string[code]);
    System.out.flush();
    if (fatal)
      throw new Error("Fatal Error.\n"); 
  }
  
  private int[][] unpackFromString(int size1, int size2, String st) {
    int colonIndex = -1;
    int sequenceLength = 0;
    int sequenceInteger = 0;
    int[][] res = new int[size1][size2];
    for (int i = 0; i < size1; i++) {
      for (int j = 0; j < size2; j++) {
        if (sequenceLength != 0) {
          res[i][j] = sequenceInteger;
          sequenceLength--;
        } else {
          int commaIndex = st.indexOf(',');
          String workString = (commaIndex == -1) ? st : st.substring(0, commaIndex);
          st = st.substring(commaIndex + 1);
          colonIndex = workString.indexOf(':');
          if (colonIndex == -1) {
            res[i][j] = Integer.parseInt(workString);
          } else {
            String lengthString = workString.substring(colonIndex + 1);
            sequenceLength = Integer.parseInt(lengthString);
            workString = workString.substring(0, colonIndex);
            sequenceInteger = Integer.parseInt(workString);
            res[i][j] = sequenceInteger;
            sequenceLength--;
          } 
        } 
      } 
    } 
    return res;
  }
  
  public ParseItem yylex() throws IOException, FormulaException {
    int yy_anchor = 4;
    int yy_state = this.yy_state_dtrans[this.yy_lexical_state];
    int yy_next_state = -1;
    int yy_last_accept_state = -1;
    boolean yy_initial = true;
    yy_mark_start();
    int yy_this_accept = this.yy_acpt[yy_state];
    if (0 != yy_this_accept) {
      yy_last_accept_state = yy_state;
      yy_mark_end();
    } 
    while (true) {
      int yy_lookahead;
      if (yy_initial && this.yy_at_bol) {
        yy_lookahead = 65536;
      } else {
        yy_lookahead = yy_advance();
      } 
      yy_next_state = -1;
      yy_next_state = this.yy_nxt[this.yy_rmap[yy_state]][this.yy_cmap[yy_lookahead]];
      if (65537 == yy_lookahead && true == yy_initial)
        return null; 
      if (-1 != yy_next_state) {
        yy_state = yy_next_state;
        yy_initial = false;
        yy_this_accept = this.yy_acpt[yy_state];
        if (0 != yy_this_accept) {
          yy_last_accept_state = yy_state;
          yy_mark_end();
        } 
        continue;
      } 
      if (-1 == yy_last_accept_state)
        throw new Error("Lexical Error: Unmatched Input."); 
      yy_anchor = this.yy_acpt[yy_last_accept_state];
      if (0 != (0x2 & yy_anchor))
        yy_move_end(); 
      yy_to_mark();
      switch (yy_last_accept_state) {
        case -2:
        case 1:
          break;
        case 2:
          return new Plus();
        case -3:
          break;
        case 3:
          return new Minus();
        case -4:
          break;
        case 4:
          return new Multiply();
        case -5:
          break;
        case 5:
          return new Divide();
        case -6:
          break;
        case 6:
          return new GreaterThan();
        case -7:
          break;
        case 7:
          return new Equal();
        case -8:
          break;
        case 8:
          return new LessThan();
        case -9:
          break;
        case 9:
          return new ArgumentSeparator();
        case -10:
          break;
        case 10:
          return new IntegerValue(yytext());
        case -11:
        case -12:
        case 11:
          break;
        case 12:
          return new RangeSeparator();
        case -13:
          break;
        case 13:
          return new OpenParentheses();
        case -14:
          break;
        case 14:
          return new CloseParentheses();
        case -15:
          break;
        case 15:
          this.emptyString = true;
          yybegin(1);
          break;
        case -16:
          break;
        case 16:
          return new GreaterEqual();
        case -17:
          break;
        case 17:
          return new NotEqual();
        case -18:
          break;
        case 18:
          return new LessEqual();
        case -19:
          break;
        case 19:
          return new CellReference(yytext());
        case -20:
          break;
        case 20:
          return new NameRange(yytext(), this.nameTable);
        case -21:
          break;
        case 21:
          return new StringFunction(yytext());
        case -22:
          break;
        case 22:
          return new DoubleValue(yytext());
        case -23:
          break;
        case 23:
          return new ColumnRange(yytext());
        case -24:
          break;
        case 24:
          return new CellReference3d(yytext(), this.externalSheet);
        case -25:
          break;
        case 25:
          return new BooleanValue(yytext());
        case -26:
          break;
        case 26:
          return new ColumnRange3d(yytext(), this.externalSheet);
        case -27:
          break;
        case 27:
          return new Area(yytext());
        case -28:
          break;
        case 28:
          return new BooleanValue(yytext());
        case -29:
          break;
        case 29:
          return new Area3d(yytext(), this.externalSheet);
        case -30:
          break;
        case 30:
          this.emptyString = false;
          return new StringValue(yytext());
        case -31:
          break;
        case 31:
          yybegin(0);
          if (this.emptyString)
            return new StringValue(""); 
          break;
        case -32:
          break;
        case 33:
          return new CellReference(yytext());
        case -33:
          break;
        case 34:
          return new NameRange(yytext(), this.nameTable);
        case -34:
          break;
        case 35:
          return new ColumnRange(yytext());
        case -35:
          break;
        case 36:
          return new CellReference3d(yytext(), this.externalSheet);
        case -36:
          break;
        case 37:
          return new ColumnRange3d(yytext(), this.externalSheet);
        case -37:
          break;
        case 38:
          return new Area3d(yytext(), this.externalSheet);
        case -38:
          break;
        case 39:
          this.emptyString = false;
          return new StringValue(yytext());
        case -39:
          break;
        case 41:
          return new NameRange(yytext(), this.nameTable);
        case -40:
          break;
        case 42:
          return new ColumnRange3d(yytext(), this.externalSheet);
        case -41:
          break;
        case 44:
          return new NameRange(yytext(), this.nameTable);
        case -42:
          break;
        case 45:
          return new ColumnRange3d(yytext(), this.externalSheet);
        case -43:
          break;
        case 47:
          return new NameRange(yytext(), this.nameTable);
        case -44:
          break;
        case 82:
          return new NameRange(yytext(), this.nameTable);
        case -45:
          break;
        case 84:
          return new NameRange(yytext(), this.nameTable);
        case -46:
          break;
        case 87:
          return new NameRange(yytext(), this.nameTable);
        case -47:
          break;
        default:
          yy_error(0, false);
          break;
        case -1:
          break;
      } 
      yy_initial = true;
      yy_state = this.yy_state_dtrans[this.yy_lexical_state];
      yy_next_state = -1;
      yy_last_accept_state = -1;
      yy_mark_start();
      yy_this_accept = this.yy_acpt[yy_state];
      if (0 != yy_this_accept) {
        yy_last_accept_state = yy_state;
        yy_mark_end();
      } 
    } 
  }
}
