/**
   * Places into Color array the colors at the node, and returns the number of colors. Uses passed
   * stateColors as color key. If null is passed, uses color system of parent data (using maxState
   * of this StsOfCharcter) or, if there is not parent data object, the default colors.
   */
  public int getColorsAtNode(
      int node, ColorDistribution colors, MesquiteColorTable stateColors, boolean showWeights) {
    int numBinBoundaries = 10;
    double[] binBoundaries = stateColors.getPreferredBinBoundaries();
    if (binBoundaries != null) numBinBoundaries = binBoundaries.length;
    for (int i = 0; i < 10; i++) colors.initialize();
    if (getNumItems() == 1) {
      double s = firstItem.getValue(node);
      colors.setWeight(0, 1.0);
      if (!MesquiteDouble.isCombinable(s)) colors.setColor(0, ColorDistribution.unassigned);
      else {
        int place =
            getPlace(s, stateColors); // (int)(((s-minState)/(maxState-minState))*numBinBoundaries);
        colors.setColor(0, stateColors.getColor(numBinBoundaries, place));
      }
    } else {
      for (int i = 0; i < getNumItems(); i++) {
        double s = getState(node, i);
        colors.setWeight(i, 1.0 / getNumItems());
        if (!MesquiteDouble.isCombinable(s)) colors.setColor(0, ColorDistribution.unassigned);
        else {
          int place =
              getPlace(
                  s, stateColors); // (int)(((s-minState)/(maxState-minState))*numBinBoundaries);
          colors.setColor(i, stateColors.getColor(numBinBoundaries, place));
        }
      }
    }

    return getNumItems();
  }
 /*..........................................ContinuousHistory................*/
 public int getLegendStates(
     Color[] cs, String[] stateNames, Point[] tableMappings, MesquiteColorTable stateColors) {
   int colorCount = 0;
   int numBinBoundaries = 10;
   double[] binBoundaries = stateColors.getPreferredBinBoundaries();
   if (binBoundaries != null) numBinBoundaries = binBoundaries.length;
   for (int e = 0; e <= numBinBoundaries; e++) {
     if (binBoundaries == null) {
       double rangeUnit = (maxState - minState) * 1.0 / numBinBoundaries;
       cs[colorCount] = stateColors.getColor(numBinBoundaries, e);
       if (tableMappings != null) tableMappings[colorCount] = new Point(numBinBoundaries, e);
       stateNames[colorCount++] =
           MesquiteDouble.toString(minState + rangeUnit * e)
               + " to "
               + MesquiteDouble.toString(minState + rangeUnit * (e + 1));
     } else {
       double localMin, localMax;
       int localE;
       int localNumBoundaries;
       // here look for closest defined bin boundaries
       localMin = minState;
       localMax = MesquiteDouble.unassigned;
       int localMinK = -1;
       int localMaxK = numBinBoundaries;
       for (int k = 0; k < numBinBoundaries; k++) {
         if (MesquiteDouble.isCombinable(binBoundaries[k])) {
           if (k < e) {
             localMin = binBoundaries[k];
             localMinK = k;
           } else if (!MesquiteDouble.isCombinable(localMax)) {
             localMax = binBoundaries[k];
             localMaxK = k;
           }
         }
       }
       if (!MesquiteDouble.isCombinable(localMax)) localMax = maxState;
       if (localMax < localMin) localMax = localMin;
       localE = e - localMinK - 1;
       localNumBoundaries = localMaxK - localMinK;
       double rangeUnit = (localMax - localMin) * 1.0;
       if (localNumBoundaries != 0) rangeUnit = rangeUnit / localNumBoundaries;
       cs[colorCount] = stateColors.getColor(numBinBoundaries, e);
       if (tableMappings != null) tableMappings[colorCount] = new Point(numBinBoundaries, e);
       stateNames[colorCount++] =
           MesquiteDouble.toString(localMin + rangeUnit * localE)
               + " to "
               + MesquiteDouble.toString(localMin + rangeUnit * (localE + 1));
     }
   }
   return colorCount;
 }
 /*..........................................MContinuousStates................*/
 public boolean allCombinable(int item) {
   for (int ic = 0; ic < getNumChars(); ic++)
     for (int it = 0; it < getNumNodes(); it++) {
       if (!MesquiteDouble.isCombinable(getState(ic, it, item))) return false;
     }
   return true;
 }
 double sumSqFILTERED(double[][] m, double mean) {
   double sumSq = 0;
   for (int i = 0; i < m.length; i++)
     for (int j = 0; j < i; j++) {
       double d = m[i][j];
       if (d >= -0.0000000001 && MesquiteDouble.isCombinable(d)) sumSq += (d - mean) * (d - mean);
     }
   return sumSq;
 }
  /**
   * places into the already instantiated ColorDistribution the colors corresponding to the
   * CharacterState, and returns the number of colors. Uses default colors. Mode is
   * MesquiteColorTable.GRAYSCALE, COLORS, COLORS_NO_BW, or DEFAULT (default depends on subclass)
   */
  public int getColorsOfState(
      CharacterState state, ColorDistribution colors, MesquiteColorTable colorTable) {
    if (colors == null || state == null || !(state instanceof ContinuousState)) return 0;
    int numBinBoundaries = 10;
    double[] binBoundaries = colorTable.getPreferredBinBoundaries();
    if (binBoundaries != null) numBinBoundaries = binBoundaries.length;
    colors.initialize();
    ContinuousState cState = (ContinuousState) state;
    if (cState.getNumItems() == 1) {
      double s = cState.getValue(0);
      colors.setWeight(0, 1.0);
      if (!MesquiteDouble.isCombinable(s)) colors.setColor(0, Color.white);
      else {
        int place =
            getPlace(s, colorTable); // (int)(((s-minState)/(maxState-minState))*numBinBoundaries);
        colors.setColor(
            0,
            colorTable.getColor(
                numBinBoundaries, place)); // bug fixed in 1. 12 that had been introduced in 1. 10
        // colors.setColor(0, colorTable.getColor(s, minState, maxState));  1.10 to 1.11
      }
    } else {
      for (int i = 0; i < cState.getNumItems(); i++) {
        double s = cState.getValue(i);
        colors.setWeight(i, 1.0 / cState.getNumItems());
        if (!MesquiteDouble.isCombinable(s)) colors.setColor(0, Color.white);
        else {
          int place =
              getPlace(
                  s, colorTable); // (int)(((s-minState)/(maxState-minState))*numBinBoundaries);
          colors.setColor(
              i,
              colorTable.getColor(
                  numBinBoundaries, place)); // bug fixed in 1. 12 that had been introduced in 1. 10
          // colors.setColor(i, colorTable.getColor(s, minState, maxState));  1.10 to 1.11
        }
      }
    }

    return cState.getNumItems();
  }
  /*..........................................  ContinuousHistory  ..................................................*/
  public int getPlace(double d, MesquiteColorTable colorTable) {

    int numBinBoundaries = 10;
    double[] binBoundaries = colorTable.getPreferredBinBoundaries();

    if (binBoundaries != null) numBinBoundaries = binBoundaries.length;
    else return (int) (((d - minState) / (maxState - minState)) * numBinBoundaries);

    for (int e = 0; e <= numBinBoundaries; e++) {
      double localMin, localMax;
      int localE;
      int localNumBoundaries;

      // here look for closest defined bin boundaries
      localMin = minState;
      localMax = MesquiteDouble.unassigned;
      int localMinK = -1;
      int localMaxK = numBinBoundaries;
      for (int k = 0; k < numBinBoundaries; k++) {
        if (MesquiteDouble.isCombinable(binBoundaries[k])) {
          if (k < e) {
            localMin = binBoundaries[k];
            localMinK = k;
          } else if (!MesquiteDouble.isCombinable(localMax)) {
            localMax = binBoundaries[k];
            localMaxK = k;
          }
        }
      }
      if (!MesquiteDouble.isCombinable(localMax)) localMax = maxState;
      if (localMax < localMin) localMax = localMin;
      localE = e - localMinK - 1;
      localNumBoundaries = localMaxK - localMinK;
      double rangeUnit = (localMax - localMin) * 1.0;
      if (localNumBoundaries != 0) rangeUnit = rangeUnit / localNumBoundaries;
      if (d <= localMin + rangeUnit * (localE + 1)) // d > localMin + rangeUnit*localE &&
      return e;
    }
    return numBinBoundaries;
  }
  /*..........................................  ContinuousHistory  ..................................................*/
  public double getBinBoundary(int i, MesquiteColorTable colorTable) { // the boundary after bin i

    int numBinBoundaries = 10;
    double[] binBoundaries = colorTable.getPreferredBinBoundaries();
    if (binBoundaries != null) numBinBoundaries = binBoundaries.length;
    else return minState + (i + 1) * (maxState - minState) / numBinBoundaries;

    double localMin, localMax;
    int localE;

    localMin = minState;
    localMax = MesquiteDouble.unassigned;
    int localNumBoundaries;
    int localMinK = -1;
    int localMaxK = numBinBoundaries;
    for (int k = 0;
        k < numBinBoundaries;
        k++) { // what are the defined boundaries on either side of i?
      if (MesquiteDouble.isCombinable(binBoundaries[k])) {
        if (k < i) {
          localMin = binBoundaries[k];
          localMinK = k;
        } else if (!MesquiteDouble.isCombinable(localMax)) {
          localMax = binBoundaries[k];
          localMaxK = k;
        }
      }
    }
    if (!MesquiteDouble.isCombinable(localMax)) localMax = maxState;
    if (localMax < localMin) localMax = localMin;
    localE = i - localMinK - 1;
    localNumBoundaries = localMaxK - localMinK;

    double rangeUnit = (localMax - localMin) * 1.0;
    if (localNumBoundaries > 0) rangeUnit = rangeUnit / localNumBoundaries;

    return localMin + rangeUnit * (localE + 1);
  }
 double meanFILTERED(double[][] m) {
   double sum = 0;
   int n = 0;
   for (int i = 0; i < m.length; i++)
     for (int j = 0; j < i; j++) {
       double d = m[i][j];
       if (d >= -0.0000000001 && MesquiteDouble.isCombinable(d)) {
         sum += d;
         n++;
       }
     }
   if (n == 0) return MesquiteDouble.unassigned;
   return sum / n;
 }
  // by filtered means -ve and uncombinable numbers excluded
  double offDiagonalPMCorrelationFILTERED(double[][] m1, double[][] m2) {
    if (m1 == null || m2 == null) return MesquiteDouble.unassigned;

    double mean1 = meanFILTERED(m1);
    double mean2 = meanFILTERED(m2);
    if (!MesquiteDouble.isCombinable(mean1) || !MesquiteDouble.isCombinable(mean2))
      return MesquiteDouble.unassigned;

    double sumSq1 = sumSqFILTERED(m1, mean1);
    double sumSq2 = sumSqFILTERED(m2, mean2);
    double sumProd = 0;
    for (int i = 0; i < m1.length; i++)
      for (int j = 0; j < i; j++) {
        double d1 = m1[i][j];
        double d2 = m2[i][j];
        if (d1 >= -0.0000000001
            && MesquiteDouble.isCombinable(d1)
            && d2 >= -0.0000000001
            && MesquiteDouble.isCombinable(d2)) sumProd += (d1 - mean1) * (d2 - mean2);
      }
    if (sumSq1 == 0 || sumSq2 == 0) return MesquiteDouble.unassigned;

    return sumProd / Math.sqrt(sumSq1 * sumSq2);
  }
 void reinterpret(MesquiteTree tree, int node) {
   if (tree.nodeIsInternal(node)) {
     if (tree.nodeHasLabel(node)) {
       String label = tree.getNodeLabel(node);
       if (isNumber) {
         double d = MesquiteDouble.fromString(label);
         if (MesquiteDouble.isCombinable(d))
           tree.setAssociatedDouble(nameRef, node, d, appliesToBranch);
       } else {
         tree.setAssociatedObject(nameRef, node, label, appliesToBranch);
       }
       if (deleteAfter) tree.setNodeLabel(null, node);
     }
     for (int daughter = tree.firstDaughterOfNode(node);
         tree.nodeExists(daughter);
         daughter = tree.nextSisterOfNode(daughter)) {
       reinterpret(tree, daughter);
     }
   }
 }
  /*.................................................................................................................*/
  public void calculateNumber(
      Tree tree1, Tree tree2, MesquiteNumber result, MesquiteString resultString) {
    if (result == null) return;
    clearResultAndLastResult(result);
    if (tree1 == null) return;
    if (tree2 == null) return;

    int numTaxa = tree1.getTaxa().getNumTaxa();

    double[][] patristic1 = null;
    patristic1 =
        p1.calculatePatristic(
            tree1,
            numTaxa,
            patristic1); // for this tree calculate patristic distances (number of nodes separating
                         // terminals; no branch lengths)
    double[][] patristic2 = null;
    patristic2 =
        p2.calculatePatristic(
            tree2,
            numTaxa,
            patristic2); // for this tree calculate patristic distances (number of nodes separating
                         // terminals; no branch lengths)

    double correl = offDiagonalPMCorrelationFILTERED(patristic1, patristic2);
    if (isDistance && (MesquiteDouble.isCombinable(correl)))
      correl = -correl + 1.0; // shifting 1 to -1 to be 0 to 2 to act as distance
    result.setValue(correl);
    if (resultString != null) {
      if (isDistance)
        resultString.setValue(
            "Patristic correlation (converted to distance): " + result.toString());
      else resultString.setValue("Patristic correlation: " + result.toString());
    }
    saveLastResult(result);
    saveLastResultString(resultString);
  }
  /*.................................................................................................................*/
  public Object doCommand(String commandName, String arguments, CommandChecker checker) {
    Tree trt = treeDisplay.getTree();
    MesquiteTree t = null;
    if (trt instanceof MesquiteTree) t = (MesquiteTree) trt;
    if (checker.compare(
        this.getClass(),
        "Adjust tool has touched branch",
        "[branch number][x coordinate touched][y coordinate touched][modifiers]",
        commandName,
        "touchedPositionAdjust")) {
      if (t == null) return null;
      MesquiteInteger io = new MesquiteInteger(0);
      int node = MesquiteInteger.fromString(arguments, io);
      int x = MesquiteInteger.fromString(arguments, io);
      int y = MesquiteInteger.fromString(arguments, io);
      String mod = ParseUtil.getRemaining(arguments, io);

      Point newOnLine = treeDisplay.getTreeDrawing().projectionOnLine(node, x, y);
      originalX = newOnLine.x;
      originalY = newOnLine.y;
      // lastX= newOnLine.x;
      // lastY = newOnLine.y;
      Graphics g = null;
      if (GraphicsUtil.useXORMode(null, false)) {
        g = treeDisplay.getGraphics();
        g.setXORMode(Color.white);
        g.setColor(Color.red);
      }
      // double bX = treeDisplay.getTreeDrawing().lineBaseX[node];
      // double bY = treeDisplay.getTreeDrawing().lineBaseY[node];
      // Math.sqrt((originalY-bY)*(originalY-bY) + (originalX-bX)*(originalX-bX));
      lastBL = tree.getBranchLength(node);
      double shortestAbove = MesquiteDouble.unassigned;
      for (int daughter = t.firstDaughterOfNode(node);
          t.nodeExists(daughter);
          daughter = t.nextSisterOfNode(daughter))
        shortestAbove = MesquiteDouble.minimum(shortestAbove, tree.getBranchLength(daughter));
      if (shortestAbove == MesquiteDouble.unassigned) upperLimit = MesquiteDouble.infinite;
      else if (MesquiteDouble.isCombinable(lastBL)) upperLimit = shortestAbove + lastBL;
      else upperLimit = shortestAbove + 1.0;
      int ibX = treeDisplay.getTreeDrawing().lineBaseX[node];
      int ibY = treeDisplay.getTreeDrawing().lineBaseY[node];
      lastX = treeDisplay.getTreeDrawing().lineTipX[node];
      lastY = treeDisplay.getTreeDrawing().lineTipY[node];
      if (GraphicsUtil.useXORMode(null, false)) {
        drawThickLine(g, ibX, ibY, lastX, lastY);
        for (int daughter = t.firstDaughterOfNode(node);
            t.nodeExists(daughter);
            daughter = t.nextSisterOfNode(daughter))
          drawThickLine(
              g,
              treeDisplay.getTreeDrawing().lineTipX[daughter],
              treeDisplay.getTreeDrawing().lineTipY[daughter],
              lastX,
              lastY);
        g.fillOval(
            lastX - ovalRadius,
            lastY - ovalRadius,
            ovalRadius + ovalRadius,
            ovalRadius + ovalRadius);
        try {
          g.drawString(MesquiteDouble.toString(lastBL), lastX + 10, lastY);
        } catch (InternalError e) { // workaround for bug on windows java 1.7.
        } catch (Throwable e) {
        }
        lineOn = true;
        g.dispose();
      }
    } else if (checker.compare(
        this.getClass(),
        "Adjust tool has been dropped",
        "[branch number][x coordinate dropped][y coordinate dropped]",
        commandName,
        "droppedPositionAdjust")) {
      if (t == null) return null;
      if (editorOn) return null;
      MesquiteInteger io = new MesquiteInteger(0);
      int node = MesquiteInteger.fromString(arguments, io);
      int x = MesquiteInteger.fromString(arguments, io);
      int y = MesquiteInteger.fromString(arguments, io);
      if (lineOn) {
        Point newOnLine = treeDisplay.getTreeDrawing().projectionOnLine(node, x, y);
        double bX = treeDisplay.getTreeDrawing().lineBaseX[node];
        double bY = treeDisplay.getTreeDrawing().lineBaseY[node];
        double tX = treeDisplay.getTreeDrawing().lineTipX[node];
        double tY = treeDisplay.getTreeDrawing().lineTipY[node];
        double lengthLine =
            Math.sqrt((originalY - bY) * (originalY - bY) + (originalX - bX) * (originalX - bX));
        double bL;
        if (lengthLine != 0) {
          double extension =
              Math.sqrt(
                      (newOnLine.y - bY) * (newOnLine.y - bY)
                          + (newOnLine.x - bX) * (newOnLine.x - bX))
                  / lengthLine;
          if (t.getBranchLength(node) == 0 || t.branchLengthUnassigned(node)) bL = extension;
          else bL = t.getBranchLength(node) * extension;
        } else bL = 1;

        if (bL > upperLimit) bL = upperLimit;
        else if (bL < lowerLimit) bL = lowerLimit;
        double oldBL = t.getBranchLength(node);
        if (!MesquiteDouble.isCombinable(oldBL)) oldBL = 1.0;
        t.setBranchLength(node, bL, false);
        double difference = oldBL - t.getBranchLength(node);
        for (int daughter = t.firstDaughterOfNode(node);
            t.nodeExists(daughter);
            daughter = t.nextSisterOfNode(daughter))
          if (MesquiteDouble.isCombinable(t.getBranchLength(daughter)))
            t.setBranchLength(daughter, t.getBranchLength(daughter) + difference, false);
        t.notifyListeners(this, new Notification(MesquiteListener.BRANCHLENGTHS_CHANGED));
        Graphics g = treeDisplay.getGraphics();
        g.setPaintMode();
        g.dispose();
        treeDisplay.pleaseUpdate(true);
        lineOn = false;
      }
    } else if (checker.compare(
        this.getClass(),
        "Adjust tool is being dragged",
        "[branch number][x coordinate][y coordinate]",
        commandName,
        "draggedPositionAdjust")) {
      if (t == null) return null;
      if (editorOn) return null;
      MesquiteInteger io = new MesquiteInteger(0);
      int node = MesquiteInteger.fromString(arguments, io);
      int x = MesquiteInteger.fromString(arguments, io);
      int y = MesquiteInteger.fromString(arguments, io);
      if (lineOn) {
        Point newOnLine = treeDisplay.getTreeDrawing().projectionOnLine(node, x, y);
        // WARNING":  This shouldn't result in length increase if simple click and release with no
        // drag; must subtract original X, Y
        Graphics g = null;
        if (GraphicsUtil.useXORMode(null, false)) {
          g = treeDisplay.getGraphics();
          g.setXORMode(Color.white);
          g.setColor(Color.red);
        }
        // g.fillOval(lastX-ovalRadius, lastY-ovalRadius, ovalRadius + ovalRadius, ovalRadius +
        // ovalRadius);
        // g.fillOval(newOnLine.x-ovalRadius, newOnLine.y -ovalRadius, ovalRadius + ovalRadius,
        // ovalRadius + ovalRadius);

        // g.drawLine(originalX, originalY, lastX, lastY);
        // g.drawLine(originalX, originalY, newOnLine.x, newOnLine.y);

        //				if decreasing, & unassigned involved: push unassigned down and assign values to
        // unassigned above; if increasing, push unassigne up
        int ibX = treeDisplay.getTreeDrawing().lineBaseX[node];
        int ibY = treeDisplay.getTreeDrawing().lineBaseY[node];
        int itX = treeDisplay.getTreeDrawing().lineTipX[node];
        int itY = treeDisplay.getTreeDrawing().lineTipY[node];

        double bX = ibX;
        double bY = ibY;
        double tX = itX;
        double tY = itY;
        double lengthLine =
            Math.sqrt((originalY - bY) * (originalY - bY) + (originalX - bX) * (originalX - bX));
        if (lengthLine != 0) {
          if (GraphicsUtil.useXORMode(null, false)) {
            if (MesquiteTrunk.isMacOSX()
                && MesquiteTrunk.getJavaVersionAsDouble() >= 1.5
                && MesquiteTrunk.getJavaVersionAsDouble() < 1.6) // due to a JVM bug
            g.fillRect(lastX, lastY - 20, 100, 20);
            g.drawString(MesquiteDouble.toString(lastBL), lastX + 10, lastY);
            if (MesquiteTrunk.isMacOSX()
                && MesquiteTrunk.getJavaVersionAsDouble() >= 1.5
                && MesquiteTrunk.getJavaVersionAsDouble() < 1.6) // due to a JVM bug
            g.fillRect(lastX, lastY - 20, 100, 20);
          }
          double extension =
              Math.sqrt(
                      (newOnLine.y - bY) * (newOnLine.y - bY)
                          + (newOnLine.x - bX) * (newOnLine.x - bX))
                  / lengthLine;
          double bL;
          if (t.getBranchLength(node) == 0 || t.branchLengthUnassigned(node)) bL = extension;
          else bL = t.getBranchLength(node) * extension;
          if (bL > upperLimit) {
            bL = upperLimit;
            if (t.getBranchLength(node) == 0 || t.branchLengthUnassigned(node))
              extension = upperLimit;
            else extension = upperLimit / t.getBranchLength(node);
          } else if (bL < lowerLimit) {
            bL = lowerLimit;
            if (t.getBranchLength(node) == 0 || t.branchLengthUnassigned(node))
              extension = lowerLimit;
            else extension = lowerLimit / t.getBranchLength(node);
          }
          lastBL = bL;
          if (GraphicsUtil.useXORMode(null, false)) {
            drawThickLine(g, ibX, ibY, lastX, lastY);
            for (int daughter = t.firstDaughterOfNode(node);
                t.nodeExists(daughter);
                daughter = t.nextSisterOfNode(daughter))
              drawThickLine(
                  g,
                  treeDisplay.getTreeDrawing().lineTipX[daughter],
                  treeDisplay.getTreeDrawing().lineTipY[daughter],
                  lastX,
                  lastY);
            g.fillOval(
                lastX - ovalRadius,
                lastY - ovalRadius,
                ovalRadius + ovalRadius,
                ovalRadius + ovalRadius);
          }
          int newX = ibX + (int) (extension * (tX - bX));
          int newY = ibY + (int) (extension * (tY - bY));
          if (GraphicsUtil.useXORMode(null, false)) {
            g.drawString(MesquiteDouble.toString(bL), newX + 10, newY);
            drawThickLine(g, ibX, ibY, newX, newY);
            for (int daughter = t.firstDaughterOfNode(node);
                t.nodeExists(daughter);
                daughter = t.nextSisterOfNode(daughter))
              drawThickLine(
                  g,
                  treeDisplay.getTreeDrawing().lineTipX[daughter],
                  treeDisplay.getTreeDrawing().lineTipY[daughter],
                  newX,
                  newY);
            g.fillOval(
                newX - ovalRadius,
                newY - ovalRadius,
                ovalRadius + ovalRadius,
                ovalRadius + ovalRadius);
          }
          lastX = newX;
          lastY = newY;
        }

        // lastX= newOnLine.x;
        // lastY = newOnLine.y;
      }
    }
    return null;
  }
 /*..........................................    ..................................................*/
 public boolean legalValue(int ic, double states) {
   return !MesquiteDouble.isCombinable(states)
       || ((ic == LATITUDE && states >= -90.0 && states <= 90.0)
           || (ic == LONGITUDE && states >= -180.0 && states <= 180.0));
 }