/* Generated by JTB 1.5.1 */
package grammars.y;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import grammars.y.syntaxtree.INode;
import grammars.y.visitor.IRetVisitor;
import grammars.y.visitor.IRetArguVisitor;
import grammars.y.visitor.IVoidVisitor;
import grammars.y.visitor.IVoidArguVisitor;

@SuppressWarnings("javadoc")
public class Token  implements INode, java.io.Serializable {

  /* JavaCC members declarations */

  private static final long serialVersionUID = 1L;

  public int kind;

  public int beginLine;

  public int beginColumn;

  public int endLine;

  public int endColumn;

  public String image;

  public Token next;

  public Token specialToken;

  public Object getValue() {
    return null;
  }

  public Token() {
    /* empty */
  }

  public Token(final int ki) {
    this(ki, null);
  }

  public Token(final int ki, final String im) {
    kind = ki;
    image = im;
  }

  public static Token newToken(int ofKind, String image) {
    switch(ofKind) {
      default:
        return new Token(ofKind, image);
    }
  }

  public static Token newToken(int ofKind) {
    return newToken(ofKind, null);
  }

  @Override
  public String toString() {
    return image;
  }

  /* JTB members declarations */

  public List<Token> specialTokens;

  public Token getSpecialAt(final int i) {
    if (specialTokens == null)
      throw new NoSuchElementException("No specialTokens in token"); //$NON-NLS-1$
    return specialTokens.get(i);
  }

  public int numSpecials() {
    if (specialTokens == null)
      return 0;
    return specialTokens.size();
  }

  public void addSpecial(final Token s) {
    if (specialTokens == null)
     specialTokens = new ArrayList<>();
    specialTokens.add(s);
  }

  public void trimSpecials() {
    if (specialTokens == null)
      return;
    ((ArrayList<Token>) specialTokens).trimToSize();
  }

  public String getSpecials(final String spc) {
    if (specialTokens == null)
      return ""; //$NON-NLS-1$
    int stLastLine = -1;
    final StringBuilder buf = new StringBuilder(64);
    boolean hasEol = false;
    for (final Iterator<Token> e = specialTokens.iterator(); e.hasNext();) {
      final Token st = e.next();
      final char c = st.image.charAt(st.image.length() - 1);
      hasEol = c == '\n' || c == '\r';
      if (stLastLine != -1)
        // not first line 
        if (stLastLine != st.beginLine) {
          // if not on the same line as the previous
          for (int i = stLastLine + 1; i < st.beginLine; i++)
            // keep blank lines
          buf.append(LS);
          buf.append(spc);
        } else
          // on the same line as the previous
          buf.append(' ');
      buf.append(st.image);
      if (!hasEol && e.hasNext())
        // not a single line comment and not the last one
        buf.append(LS);
      stLastLine = st.endLine;
    }
    // keep the same number of blank lines before the current non special
    for (int i = stLastLine + (hasEol ? 1 : 0); i < beginLine; i++) {
      buf.append(LS);
      if (i != beginLine - 1)
      buf.append(spc);
    }
    // indent if the current non special is not on the same line
    if (stLastLine != beginLine)
      buf.append(spc);
    return buf.toString();
  }

  public String withSpecials(final String spc) {
    return withSpecials(spc, null);
  }

  public String withSpecials(final String spc, final String var) {
    final String specials = getSpecials(spc);
    int len = specials.length() + 1;
    if (len == 1)
      return (var == null ? image : var + image);
    if (var != null)
      len += var.length();
    StringBuilder buf = new StringBuilder(len + image.length());
    buf.append(specials);
    // see if needed to add a space
    int stLastLine = -1;
    if (specialTokens != null)
    for (Token e : specialTokens) {
      stLastLine = e.endLine;
    }
    if (stLastLine == beginLine)
      buf.append(' ');
    if (var != null)
      buf.append(var);
    buf.append(image);
    return buf.toString();
  }

  /*
   * Visitors accept methods (no -novis option, visitors specification : Void,void,None;VoidArgu,void,A;Ret,R,None;RetArgu,R,A)
   */

  @Override
  public <R> R accept(final IRetVisitor<R> vis) {
    return vis.visit(this);
  }

  @Override
  public <R, A> R accept(final IRetArguVisitor<R, A> vis, final A argu) {
    return vis.visit(this, argu);
  }

  @Override
  public void accept(final IVoidVisitor vis) {
    vis.visit(this);
  }

  @Override
  public <A> void accept(final IVoidArguVisitor<A> vis, final A argu) {
    vis.visit(this, argu);
  }

}
