/* (C) 2012 Pragmatic Software
   This Source Code Form is subject to the terms of the Mozilla Public
   License, v. 2.0. If a copy of the MPL was not distributed with this
   file, You can obtain one at http://mozilla.org/MPL/2.0/
   */

package com.googlecode.networklog;

import java.lang.RuntimeException;

// Inspired by Hugh Perkins's jfastparser
// https://github.com/hughperkins/jfastparser/blob/1434212efac5ed422724d75dbb3359b72dd7c614/src/jfastparser/Parser.java

public class FastParser {
  char[] line;
  int len;
  int pos;
  char delimiter;

  public FastParser() {
    this(null, 0, ' ');
  }

  public FastParser(char delimiter) {
    this(null, 0, delimiter);
  }

  public FastParser(char[] line, int len) {
    this(line, len, ' ');
  }

  public FastParser(char[] line, int len, char delimiter) {
    this.line = line;
    this.len = len;
    this.delimiter = delimiter;
  }

  public void setLine(char[] line, int len) {
    if(MyLog.enabled) {
      MyLog.d("setLine line: [" + new String(line, 0, len) + "] len: " + len);
    }
    this.line = line;
    this.len = len;
    pos = 0;
  }

  public void setPos(int newpos) {
    if(newpos < 0 || newpos >= len) {
      throw new IndexOutOfBoundsException("Attempt to set new pos " + newpos + " is out of range 0 - " + len);
    }

    pos = newpos;
  }

  public void setDelimiter(char delimiter) {
    this.delimiter = delimiter;
  }

  public long getLong() {
    return getLong(delimiter);
  }

  public long getLong(char delimiter) {
    int newpos = pos;
    long value = 0;
    boolean neg = false;

    if(pos >= len) {
      throw new RuntimeException("pos at end of string");
    }

    if(line[pos] == '-') {
      neg = true;
      newpos++;
    }

    if(line[pos] == '+') {
      pos++;
      newpos++;
    }

    char thischar = 0;

    while(newpos < len && (thischar = line[newpos]) != delimiter && thischar >= '0' && thischar <= '9') {
      value = value * 10 + (line[newpos] - '0');
      newpos++;
    }

    if(pos == newpos) {
      throw new RuntimeException("expected long but found [" + line[pos] + "] in [" + new String(line, pos, len - pos) + "]");
    }

    pos = newpos;
    eatDelimiter();
    return neg ? -value : value;
  }

  public int getInt() {
    return getInt(delimiter);
  }

  public int getInt(char delimiter) {
    int newpos = pos;
    int value = 0;
    boolean neg = false;

    if(pos >= len) {
      throw new RuntimeException("pos at end of string");
    }

    if(line[pos] == '-') {
      neg = true;
      newpos++;
    }

    if(line[pos] == '+') {
      pos++;
      newpos++;
    }

    char thischar = 0;

    while(newpos < len && (thischar = line[newpos]) != delimiter && thischar >= '0' && thischar <= '9') {
      value = value * 10 + (line[newpos] - '0');
      newpos++;
    }

    if(pos == newpos) {
      throw new RuntimeException("expected int but found [" + line[pos] + "] in [" + new String(line, pos, len - pos) + "]");
    }

    pos = newpos;
    eatDelimiter();
    return neg ? -value : value;
  }

  public double getDouble() {
    int newpos = pos;
    double value = 0;
    boolean negative = false;
    boolean afterpoint = false;
    double divider = 1;
    char thischar = 0;

    while(newpos < len && (thischar = line[newpos]) != ' ' && thischar != 'e' && thischar != '\t') {
      if(thischar == '-') {
        negative = true;
      } else if(thischar == '.') {
        afterpoint = true;
      } else {
        int thisdigit = thischar - '0';
        value = value * 10 + thisdigit;
        if(afterpoint) {
          divider *= 10;
        }
      }

      newpos++;
    }

    if(thischar == 'e') {
      newpos++;
      boolean exponentnegative = false;
      int exponent = 0;

      while(newpos < len && (thischar = line[newpos]) != delimiter) {
        if(thischar == '-') {
          exponentnegative = true;
        } else if(thischar != '+') {
          exponent = exponent * 10 + (thischar - '0');
        }

        newpos++;
      }

      if(exponentnegative) {
        exponent = -exponent;
      }

      value *= Math.pow(10, exponent);
    }

    if(negative) {
      value = -value;
    }

    value /= divider;

    if(pos == newpos) {
      throw new RuntimeException("expected double but found [" + line[pos] + "] in [" + new String(line, pos, len - pos) + "]");
    }

    pos = newpos;
    eatDelimiter();
    return value;
  }

  public String getString() {
    return getString(delimiter);
  }

  public String getString(char delimiter) {
    int newpos = pos;
    String value;

    while(newpos < len && line[newpos] != delimiter) {
      newpos++;
    }

    if(pos == newpos) {
      value = null;
    } else {
      value = StringPool.get(line, pos, newpos - pos);
    }

    pos = newpos;
    eatDelimiter();
    return value;
  }

  public void eatDelimiter() {
    eatChar(delimiter);
  }

  public void eatChar(char target) {
    if(pos < len && line[pos] != target) {
      throw new RuntimeException("expected [" + target + "] but got " + line[pos] + " in [" + new String(line, pos, len - pos) + "]");
    }
    pos++;
  }

  public boolean more() {
    return pos < len;
  }
}

@@ -4673,20 +4673,18 @@
 value = 
-null
+%22%22
 ;%0A    %7D 

Return "" instead of null when not reading any characters in getString()