


package gnu.javax.swing.text.html.parser.support.low;

/**
 * A string buffer that additionally holds line and absolute postion
 * information.
 * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
 */
public class Buffer
{
  public static int INITIAL_SIZE = 2048;

  /**
   * True if the \n symbol has been seen.
   */
  public boolean n_seen;

  /**
   * True if the \r symbol has been seen.
   */
  public boolean r_seen;
  char[] chr = new char[ INITIAL_SIZE ];
  int[] line = new int[ INITIAL_SIZE ];
  int[] position = new int[ INITIAL_SIZE ];

  /**
   * Current line.
   */
  int current_line = 0;

  /**
   * Point to the next free position.
   */
  int length;

  public Buffer()
  {
  }

  public Buffer(String content)
  {
    for (int i = 0; i < content.length(); i++)
      {
        append(content.charAt(i), i);
      }
  }

  /**
   * Get the characters into array.
   * @param srcBegin From, inclusive
   * @param srcEnd To, exclusive.
   * @param dst Into
   * @param dstBegin Offset.
   */
  public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
  {
    System.arraycopy(chr, srcBegin, dst, dstBegin, (srcEnd - srcBegin));
  }

  /**
   * Return the sequence, used to separate lines in the document.
   * @return one of \n, \r or \r\n.
   */
  public String getEndOfLineSequence()
  {
    if (r_seen && n_seen)
      return "\r\n";
    else if (r_seen)
      return "\r";
    else

      // This also is returned for single-line document.
      return "\n";
  }

  /**
   * Truncate.
   * @param n The length to truncate till.
   */
  public void setLength(int n)
  {
    length = n;
  }

  /**
   * Get location information for the given region.
   * @param from Region start, inclusive.
   * @param to Region end, exclusive.
   * @return The location, covering the region.
   */
  public Location getLocation(int from, int to)
  {
    Location l = new Location();
    l.beginLine = line [ from ];
    l.endLine = line [ to - 1 ];

    l.startPosition = position [ from ];
    l.endPosition = position [ to - 1 ] + 1;

    return l;
  }

  /**
   * Add the character.
   * @param c The character.
   * @param pos The character position in the stream (the line number
   * is handled internally in the buffer).
   */
  public void append(char c, int pos)
  {
    if (length >= chr.length)
      expand();
    chr [ length ] = c;
    position [ length ] = pos;

    if (c == '\n')
      {
        if (!r_seen)
          current_line++;
        n_seen = true;
      }
    else if (c == '\r')
      {
        current_line++;
        r_seen = true;
      }

    line [ length ] = current_line;

    length++;
  }

  /**
   * Return char at the given positon.
   */
  public char charAt(int i)
  {
    return chr [ i ];
  }

  /**
   * Delete the range
   * @param from Start position, inclusive.
   * @param to End position, exclusive.
   */
  public void delete(int from, int to)
  {
    int len = to - from;
    if (len < 1)
      throw new AssertionError("Deleting " + from + " till " + to);

    int tail = length - to;

    System.arraycopy(chr, to, chr, from, tail);
    System.arraycopy(position, to, position, from, tail);
    System.arraycopy(line, to, line, from, tail);
    length = length - len;
  }

  /**
   * Double the buffer size.
   */
  public void expand()
  {
    int nSize = 2 * chr.length;

    char[] nchr = new char[ nSize ];
    int[] nposition = new int[ nSize ];
    int[] nline = new int[ nSize ];

    System.arraycopy(chr, 0, nchr, 0, chr.length);
    System.arraycopy(position, 0, nposition, 0, position.length);
    System.arraycopy(line, 0, nline, 0, line.length);

    chr = nchr;
    position = nposition;
    line = nline;
  }

  /**
   * Return length of the occupied part of the buffer.
   */
  public int length()
  {
    return length;
  }

  /**
   * Prepare for parsing the new document.
   */
  public void reset()
  {
    setLength(0);
    r_seen = n_seen = false;
  }

  public String toString()
  {
    return new String(chr, 0, length);
  }
}
