package com.simolecule.centres;

import java.util.ArrayList;
import java.util.List;

public final class Node<A, B> {

  /**
   * Flag indicates whether the node has been expanded.
   */
  public static final int EXPANDED = 0x1;

  /**
   * Flag indicates whether the node was duplicated
   * at a ring closure.
   */
  public static final int RING_DUPLICATE = 0x2;

  /**
   * Flag indicates whether the node was duplicated
   * at a bond with order > 1.
   */
  public static final int BOND_DUPLICATE = 0x4;

  /**
   * Mask to check if a node is duplicated.
   */
  public static final int DUPLICATE = 0x6;

  /**
   * Node was created for an implicit hydrogen,
   * the 'atom' value will be null.
   */
  public static final int IMPL_HYDROGEN = 0x8;


  private final Digraph<A, B> g;
  private final A             atom;
  private final int           dist;
  private       Descriptor    aux;
  private int flags = 0;


  final         short[]          visit;
  private final List<Edge<A, B>> edges;

  public Node(Digraph<A, B> g,
              short[] visit,
              A atom,
              int dist,
              int flags)
  {
    this.g = g;
    this.visit = visit;
    this.atom = atom;
    this.dist = dist;
    this.flags = flags;
    this.edges = (flags & DUPLICATE) != 0
            ? new ArrayList<Edge<A, B>>()
            : new ArrayList<Edge<A, B>>(4);
    if (visit == null || (flags & DUPLICATE) != 0)
      this.flags |= EXPANDED;
  }

  Node<A, B> newChild(int idx, A atom)
  {
    final short[] visit = this.visit.clone();
    visit[idx] = (short) (dist + 1);
    return new Node<>(g, visit, atom, dist + 1, 0);
  }

  Node<A, B> newTerminalChild(int idx, A atom, int flags)
  {
    short dist = (short) ((flags & DUPLICATE) != 0
            ? visit[idx]
            : this.dist + 1);
    return new Node<>(g, null, atom, dist, flags);
  }

  void add(Edge<A, B> e)
  {
    this.edges.add(e);
  }

  public int getDistance()
  {
    return dist;
  }

  public A getAtom()
  {
    return atom;
  }

  public Descriptor getAux()
  {
    return aux;
  }

  public void setAux(Descriptor desc)
  {
    this.aux = desc;
  }

  public List<Edge<A, B>> getEdges()
  {
    if ((flags & EXPANDED) == 0) {
      flags |= EXPANDED;
      g.expand(this);
    }
    return edges;
  }

  public boolean isSet(int mask) {
    return (mask & flags) != 0;
  }

  public boolean isDuplicate()
  {
    return (flags & DUPLICATE) != 0;
  }

  public boolean isTerminal()
  {
    return visit == null || ((flags & EXPANDED) != 0 && edges.size() == 1);
  }

  String getSymbol(int elem)
  {
    switch (elem) {
      case 6:
        return "C";
      case 7:
        return "N";
      case 8:
        return "O";
      default:
        return "#" + elem;
    }
  }

  @Override
  public String toString()
  {
    StringBuilder sb = new StringBuilder();
    if (isDuplicate())
      sb.append('(');
    if (g != null && atom != null) {
      sb.append(getSymbol(g.getMol().getAtomicNum(atom)) + ":" + (1+g.getMol().getAtomIdx(atom)));
    } else if (atom == null) {
      sb.append("H");
    }
    if (isDuplicate())
      sb.append(')');
    return sb.toString();
  }
}

@@ -931,23 +931,23 @@
         
-short
+char
 %5B%5D
+ 
         
@@ -1041,21 +1041,20 @@
         
-short
+char
 %5B%5D visit
@@ -1505,21 +1505,20 @@
   final 
-short
+char
 %5B%5D visit
@@ -1558,21 +1558,20 @@
 idx%5D = (
-short
+char
 ) (dist 
@@ -1699,20 +1699,18 @@
   %7B%0A    
-shor
+in
 t dist =
@@ -1715,15 +1715,15 @@
  = (
-short
+char
 ) 
+(
 ((fl
@@ -1789,32 +1789,33 @@
 : this.dist + 1)
+)
 ;%0A    return new
@@ -2319,16 +2319,18 @@
 nt mask)
+%0A 
  %7B%0A    r
@@ -2555,16 +2555,106 @@
 %0A  %7D%0A%0A  
+public boolean isExpanded()%0A  %7B%0A    return (flags & EXPANDED) != 0;%0A  %7D%0A%0A  private static 
 String g
@@ -2655,16 +2655,23 @@
 ring get
+Element
 Symbol(i
@@ -2699,24 +2699,58 @@
 ch (elem) %7B%0A
+      case 1:%0A        return %22H%22;%0A
       case 6
@@ -2839,16 +2839,122 @@
 rn %22O%22;%0A
+      case 17:%0A        return %22Cl%22;%0A      case 35:%0A        return %22Br%22;%0A      case 9:%0A        return %22F%22;%0A
       de
@@ -3173,26 +3173,27 @@
 %7B%0A      
-sb
+// 
 .append(
 getSymbo
@@ -3188,18 +3188,24 @@
 end(
-getSymbol(
+%22:%22).append(1 + 
 g.ge
@@ -3222,32 +3222,51 @@
 Atom
-icNum
+Idx
 (atom)
-) + %22:%22 + (1+
+%0A      sb.append(getElementSymbol(
 g.ge
@@ -3275,27 +3275,29 @@
 ol().getAtom
-Idx
+icNum
 (atom)));%0A  

Use char (unsigned) for distance.