/**
   * 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 MesquiteColorTable getColorTable(MesquiteColorTable colorTable) {

    if (colorTable == null) colorTable = new MesquiteColorTable();

    if (colorTable.getMode() == MesquiteColorTable.COLORS)
      colorTable.setMode(MesquiteColorTable.COLORS_NO_BW);

    return colorTable;
  }
 /*..........................................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;
 }
  /**
   * 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);
  }