package genesom;

import java.util.StringTokenizer;

public class GridPosition {

  protected final static double hx1 = 0., hy1 = 0.,
                                hx2 = 1., hy2 = 1.,
                                hx3 = .5, hy3 = .86602540;  // sqrt(1-.5^2)

  public Node n1;  // from  (predecessor)
  public Node n2;  // to 1  (descendent)
  public Node n3;  // to 2  (descendent)
  public double lambda12;     // (100-lambda)% of n1, lambda% of n2
  public double lambda13;     // (100-lambda)% of n1, lambda% of n3


  public GridPosition() {}

  public GridPosition(GridPosition gp) {
    n1 = gp.n1;
    n2 = gp.n2;
    n3 = gp.n3;
    lambda12 = gp.lambda12;
    lambda13 = gp.lambda13;
  }

  public GridPosition(String persistent_representation) {

    persistent_representation = persistent_representation.replace('[', ' ').
                                                          replace(']', ' ').
                                                          replace('|', ' ').
                                                          replace(';', ' ').
                                                          trim();

    StringTokenizer st = new StringTokenizer(persistent_representation);

    int c = 0;

    double[] result = new double[5];

    while(st.hasMoreTokens() && c < 5)
       result[c++] = new Double(st.nextToken()).doubleValue();

    if(c < 5)
      throw new RuntimeException("GridPosition instantiation error from persistent representation " + persistent_representation);

    n1 = new Node().setInitID((int)result[0]);
    n2 = new Node().setInitID((int)result[1]);
    n3 = new Node().setInitID((int)result[2]);

    if((lambda12 = result[3]) > 1.) lambda12 = 1.;
    else if(lambda12 < 0.) lambda12 = 0.;

    if((lambda13 = result[4]) > 1.) lambda13 = 1.;
    else if(lambda13 < 0.) lambda13 = 0.;
  }

  public int match(GridPosition o) {

    if(n1 == o.n1) {
        if(n2 == o.n2 && n3 == o.n3) return 1;
        if(n2 == o.n3 && n3 == o.n2) return 2;
    } else if(n1 == o.n2) {
        if(n2 == o.n1 && n3 == o.n3) return 3;
        if(n2 == o.n3 && n3 == o.n1) return 4;
    } else if(n1 == o.n3) {
        if(n2 == o.n1 && n3 == o.n2) return 5;
        if(n2 == o.n2 && n3 == o.n1) return 6;
    }

    return 0;
  }


  public boolean equals(GridPosition o) {                     // lambdiff == 0.

    int match = match(o);

    switch(match) {

      case 0: return false;

      case 1:
        if(lambda12 == o.lambda12 && lambda13 == o.lambda13) return true;
        break;
      case 2:
        if(lambda12 == o.lambda13 && lambda13 == o.lambda12) return true;
        break;
      case 3:
        if(lambda12 == 1. - o.lambda12 - o.lambda13 && lambda13 == o.lambda13) return true;
        break;
      case 4:
        if(lambda12 == o.lambda13 && lambda13 == 1. - o.lambda12 - o.lambda13) return true;
        break;
      case 5:
        if(lambda12 == 1. - o.lambda12 - o.lambda13 && lambda13 == o.lambda12) return true;
        break;
      default:        // case 6:
        if(lambda12 == o.lambda12 && lambda13 == 1. - o.lambda12 - o.lambda13) return true;
        break;
    }

    return false;
  }


  public boolean equals(Node n) {

    if(n1 == n && n2 == n && n3 == n) return true;
    if(n3 == n && lambda13 == 1.) return true;
    if(n2 == n && lambda12 == 1.) return true;
    if(n1 == n && (lambda13 == 0. || lambda12 == 0.)) return true;

    return false;
  }


// never used
  public double lambdiff(GridPosition o) {

    double tmp;

    int match = match(o);

    switch(match) {

      case 0: return -1.;

      case 1:
        return (tmp = (lambda12 - o.lambda12)) * tmp + (tmp = (lambda13 - o.lambda13)) * tmp;
      case 2:
        return (tmp = (lambda12 - o.lambda13)) * tmp + (tmp = (lambda13 - o.lambda12)) * tmp;
      case 3:
        return (tmp = (lambda12 - 1. + o.lambda12 + o.lambda13)) * tmp + (tmp = (lambda13 - o.lambda13)) * tmp;
      case 4:
        return (tmp = (lambda12 - o.lambda13)) * tmp + (tmp = (lambda13 - 1. + o.lambda12 + o.lambda13)) * tmp;
      case 5:
        return (tmp = (lambda12 - 1. + o.lambda12 + o.lambda13)) * tmp + (tmp = (lambda13 - o.lambda12)) * tmp;
      default:        // case 6:
        return (tmp = (lambda12 - o.lambda12)) * tmp + (tmp = (lambda13 - 1. + o.lambda12 + o.lambda13)) * tmp;
    }
  }


/*
  public String toString() {  // return linear combination of weights

    StringBuffer sb = new StringBuffer();

    double[] w1 = n1.getWeights(),
             w2 = n2.getWeights(),
             w3 = n3.getWeights();

    sb.append("[").append(n1.id).append(" ").append(n2.id).append(" ").append(n3.id).append("|").append(lambda12).append(";").append(lambda13).append("] ");

    for(int i = 0, k = w1.length; i < k; i++) {
      sb.append((1. - lambda12 - lambda13) * w1[i] +
                                 lambda12  * w2[i] +
                                 lambda13  * w3[i]);
      if(i < k-1) sb.append(" ");
    }

    return sb.toString();
  }
*/

  public String toString() {  // return weights affiliation

    StringBuffer sb = new StringBuffer();

    double[] w1 = n1.getWeights(),
             w2 = n2.getWeights(),
             w3 = n3.getWeights();

    sb.append("[").append(n1.id).append(" ").append(n2.id).append(" ").append(n3.id).append("|").append(lambda12).append(";").append(lambda13).append("] ");

    double t,
           l12_2 = lambda12 * lambda12,
           l13_2 = lambda13 * lambda13,
           h1 = 1.-Math.sqrt(l12_2 + l13_2 + lambda12 * lambda13),
           h2 = 1.-Math.sqrt((t = (1. - lambda12)) * t + l13_2 - t * lambda13),
           h3 = 1.-Math.sqrt((t = (1. - lambda13)) * t + l12_2 - t * lambda12);

    t = 1. / (h1 + h2 + h3);

    for(int i = 0, k = w1.length; i < k; i++) {
      sb.append((h1 * w1[i] + h2 * w2[i] + h3 * w3[i]) * t);

      if(i < k-1) sb.append(" ");
    }

    return sb.toString();
  }

  public String toPersistentRepresentation() { return toString(); }
}
