/**
   * Returns a Collection with double values that are corresponding to the class breaks. Note: the
   * smallest number is equal to the minValue of all attributes.
   */
  public Collection filterAttributeValues(SortedSet attributeValues) {
    // -1 because one row in the table is reserved for "all other values". [Bob Boseko]
    // int classCount = getRangeCount() - 1;
    Collection filteredValues = new ArrayList();
    if (attributeValues.size() == 0) {
      return filteredValues;
    }
    // -1 deleted because class range is false
    int classCount = Math.min(getRangeCount(), attributeValues.size());

    // -- [sstein 15.Feb. 2009]
    //   replaced O-Bedels code by own code to be consistent
    //   in case somebody uses Classifier1D methods for classification
    //   and attaches the result as attribute values (i.e. to ensure
    //   that same values are obtained)
    /*
    int featuresCount = stylePanel.getLayer().getFeatureCollectionWrapper().size();
    double avgClassSize = ((double) featuresCount) / ((double) classCount); // type double to avoid round off errors
    SortedMap valuesCount = stylePanel.getAttributeValuesCount();

    Collection filteredValues = getQuantileBreaks(avgClassSize, valuesCount);
    */
    // -- sstein: new code
    double[] data = new double[attributeValues.size()];
    int i = 0;
    boolean isInteger = false;
    for (Iterator iterator = attributeValues.iterator(); iterator.hasNext(); ) {
      Object val = (Object) iterator.next();
      if (val instanceof Integer) {
        data[i] = (Integer) val;
        isInteger = true;
      } else if (val instanceof Double) {
        data[i] = (Double) val;
      } else {
        data[i] = Double.NaN;
      }
      i++;
    }
    double[] breaks = Classifier1D.classifyEqualNumber(data, classCount);
    double minVal = org.math.array.DoubleArray.min(data);
    // add minVal as smallest value
    if (isInteger) {
      filteredValues.add(new Integer((int) minVal));
    } else {
      filteredValues.add(new Double(minVal));
    }
    for (int j = 0; j < breaks.length; j++) {
      if (isInteger) {
        filteredValues.add(new Integer((int) breaks[j]));
      } else {
        filteredValues.add(new Double(breaks[j]));
      }
    }
    // -- sstein: end
    return filteredValues;
  }
  private void setDialogValues(MultiInputDialog dialog, PlugInContext context) {

    dialog.setSideBarDescription(sideBarText);

    dialog.addLayerComboBox(CLAYER, context.getCandidateLayer(0), context.getLayerManager());

    List listNumAttributes =
        FeatureSchemaTools.getFieldsFromLayerWithoutGeometryAndString(context.getCandidateLayer(0));
    Object valAttribute = listNumAttributes.size() > 0 ? listNumAttributes.iterator().next() : null;
    final JComboBox jcb_attribute =
        dialog.addComboBox(this.ATTRIBUTE, valAttribute, listNumAttributes, this.ATTRIBUTE);
    if (listNumAttributes.size() == 0) jcb_attribute.setEnabled(false);

    List listClassifiers = Classifier1D.getAvailableClassificationMethods();
    Object valClassifier =
        listNumAttributes.size() > 0 ? listNumAttributes.iterator().next() : null;
    final JComboBox jcb_classifier =
        dialog.addComboBox(this.CLASSIFIER, valClassifier, listClassifiers, this.CLASSIFIER);

    dialog.addIntegerField(T2, this.ranges, 6, T2);

    dialog.addCheckBox(this.OPTIMIZEWITHKMEANS, false);

    dialog.addCheckBox(this.PROCESSNULLASZERO, false);

    dialog
        .getComboBox(CLAYER)
        .addActionListener(
            new ActionListener() {
              public void actionPerformed(ActionEvent e) {
                List list = getFieldsFromLayerWithoutGeometryAndString();
                if (list.size() == 0) {
                  jcb_attribute.setModel(new DefaultComboBoxModel(new String[0]));
                  jcb_attribute.setEnabled(false);
                } else {
                  jcb_attribute.setModel(new DefaultComboBoxModel(list.toArray(new String[0])));
                  jcb_attribute.setEnabled(true);
                }
              }
            });
  }
  private FeatureDataset classifyAndCreatePlot(TaskMonitor monitor, final PlugInContext context)
      throws Exception {

    monitor.report(this.sCalculateBreaks);
    // =============== get DATA and prepare ==============/
    FeatureSchema fs = this.fc.getFeatureSchema();
    AttributeType type = null;
    if ((fs.getAttributeType(this.selAttribute) == AttributeType.DOUBLE)
        || (fs.getAttributeType(this.selAttribute) == AttributeType.INTEGER)) {
      // -- move on
      type = fs.getAttributeType(this.selAttribute);
    } else {
      // System.out.println("ClassifyAttributesPlugIn: wrong datatype of chosen attribute");
      context.getWorkbenchFrame().warnUser(sWrongDataType);
      return null;
    }

    int size = getFeatureCollectionSize(this.fc, this.selAttribute, this.nullAsZero);
    if (size < 3) {
      return null;
    }
    this.ranges = Math.min(this.ranges, size);

    double[] data = new double[size];
    double[][] plotdata = new double[2][size]; // for drawing 1-D scatter plot
    int[] fID = new int[size];
    int i = 0;
    for (Iterator iter = fc.iterator(); iter.hasNext(); ) {
      Feature f = (Feature) iter.next();
      if (f.getAttribute(this.selAttribute) == null && !nullAsZero) continue;
      fID[i] = f.getID();
      plotdata[1][i] = 1;
      Object val = f.getAttribute(this.selAttribute);
      if (type == AttributeType.DOUBLE) {
        if (val == null) data[i] = 0.0;
        else data[i] = ((Double) val).doubleValue();
      } else if (type == AttributeType.INTEGER) {
        if (val == null) data[i] = 0;
        else data[i] = ((Integer) val).intValue();
      }
      plotdata[0][i] = data[i];
      i++;
    }
    /*
    //-- some testdata
    double[][] plotdata2 = new double[2][8];
    double[] data2 = { -2, 4, 6, 5, 0, 10, 7, 1 };
    double[] axis2 =  {  1, 1, 1, 1, 1, 1, 1, 1 };
    plotdata2[0] = data2;
    plotdata2[1] = axis2;
    */

    if (monitor.isCancelRequested()) {
      return null;
    }

    // =============== find breaks according to chosen method ==============/
    double[] limits = null;

    if (this.useKmeans == false) {
      if (this.selClassifier == Classifier1D.EQUAL_NUMBER) {
        limits = Classifier1D.classifyEqualNumber(data, this.ranges);
      } else if (this.selClassifier == Classifier1D.EQUAL_RANGE) {
        limits = Classifier1D.classifyEqualRange(data, this.ranges);
      } else if (this.selClassifier == Classifier1D.MEAN_STDEV) {
        limits = Classifier1D.classifyMeanStandardDeviation(data, this.ranges);
      } else if (this.selClassifier == Classifier1D.MAX_BREAKS) {
        limits = Classifier1D.classifyMaxBreaks(data, this.ranges);
      } else if (this.selClassifier == Classifier1D.JENKS_BREAKS) {
        limits = Classifier1D.classifyNaturalBreaks(data, this.ranges);
      }
    } else {
      if (this.selClassifier == Classifier1D.EQUAL_NUMBER) {
        limits = Classifier1D.classifyKMeansOnExistingBreaks(data, this.ranges, 3);
      } else if (this.selClassifier == Classifier1D.EQUAL_RANGE) {
        limits = Classifier1D.classifyKMeansOnExistingBreaks(data, this.ranges, 2);
      } else if (this.selClassifier == Classifier1D.MEAN_STDEV) {
        limits = Classifier1D.classifyKMeansOnExistingBreaks(data, this.ranges, 4);
      } else if (this.selClassifier == Classifier1D.MAX_BREAKS) {
        limits = Classifier1D.classifyKMeansOnExistingBreaks(data, this.ranges, 1);
      } else if (this.selClassifier == Classifier1D.JENKS_BREAKS) {
        limits = Classifier1D.classifyKMeansOnExistingBreaks(data, this.ranges, 5);
      }
    }

    if (monitor.isCancelRequested()) {
      return null;
    }

    monitor.report(this.sDisplayBreaks);
    // =============== plot data and class breaks ==============/
    // -- do display here - in case we later want to allow interactive editing of the limits

    // -- reformat limits
    double[][] limits2show = new double[2][limits.length];
    // -- due to bug in jmathplot add limits twice if only three classes = 2breaks are sought
    if (limits.length == 2) {
      limits2show = new double[2][limits.length * 2];
    }
    for (int j = 0; j < limits.length; j++) {
      limits2show[0][j] = limits[j]; // x-axis
      limits2show[1][j] =
          Math.floor(
              i / (4.0 * this.ranges)); // y-axis, estimate height of "bar" from number of items
      // limits2show[1][j]= 1;
      // -- due to bug in jmathplot add limits twice if only three classes are sought
      if (limits.length == 2) {
        limits2show[0][limits.length + j] = limits[j];
        limits2show[1][limits.length + j] = Math.floor(i / (4.0 * this.ranges));
      }
    }

    // =============== plot data and class breaks ==============/
    // -- create plots
    /*final Plot2DPanelOJ*/ plot = new Plot2DPanelOJ();
    plot.addHistogramPlotOJ(
        this.selAttribute, data, this.ranges * 3, context, selLayer, this.selAttribute);
    plot.addScatterPlotOJ(this.sDatapoints, plotdata, fID, context, this.selLayer);
    plot.addBarPlot(this.sClassbreaks, limits2show);
    plot.plotToolBar.setVisible(true);
    plot.setAxisLabel(0, this.selAttribute);
    plot.setAxisLabel(1, this.sCount);
    plot.addLegend("SOUTH");

    // [mmichaud 2012-04-09] Moved in run method after the addLayer method
    // to avoid the problem of the focus change

    // JInternalFrame frame = new JInternalFrame(this.sHistogram);
    // frame.setLayout(new BorderLayout());
    // frame.add(plot, BorderLayout.CENTER);
    // frame.setClosable(true);
    // frame.setResizable(true);
    // frame.setMaximizable(true);
    // frame.setSize(450, 450);
    // frame.setVisible(true);

    // context.getWorkbenchFrame().addInternalFrame(frame);

    // =============== classify data ==============/
    if (monitor.isCancelRequested()) {
      return null;
    }
    monitor.report(this.sClassifying);
    int[] classes = Classifier1D.classifyData(data, limits);
    // double[] classes = org.math.array.StatisticSample.one(data.length);
    // context.getWorkbenchFrame().warnUser("classification not yet implemented");

    // =============== add field ==============/
    if (monitor.isCancelRequested()) {
      return null;
    }
    monitor.report(sAddingField);

    FeatureDataset fd = null;
    ArrayList outData = new ArrayList();
    FeatureSchema targetFSnew = null;
    int count = 0;
    Iterator iterp = fc.iterator();
    String attname = this.selAttribute + "_" + this.selClassifier;
    while (iterp.hasNext()) {
      // count=count+1;
      //	    	if(monitor != null){
      //	    	    monitor.report("item: " + count + " of " + size);
      //	    	}
      Feature p = (Feature) iterp.next();
      Object val = p.getAttribute(this.selAttribute);
      if (val == null && !this.nullAsZero) continue;
      else count++;
      if (count == 1) {
        FeatureSchema targetFs = p.getSchema();
        targetFSnew = FeatureSchemaTools.copyFeatureSchema(targetFs);
        if (targetFSnew.hasAttribute(attname)) {
          // attribute will be overwriten
        } else {
          // add attribute
          targetFSnew.addAttribute(attname, AttributeType.INTEGER);
        }
      }
      // -- evaluate value for every polygon
      Feature fcopy = FeatureSchemaTools.copyFeature(p, targetFSnew);
      // fcopy.setAttribute(this.selClassifier, new Integer(classes[count-1]));
      fcopy.setAttribute(attname, new Integer(classes[count - 1]));
      outData.add(fcopy);
    }
    fd = new FeatureDataset(targetFSnew);
    fd.addAll(outData);
    return fd;
  }