gt: 		Vector<GroupingType> valueVector = new Vector<GroupingType>();
context: /**
   * Copyright (C) 2001-2016 by RapidMiner and the contributors
   *
   * Complete list of developers available at our web site:
   *
   * http://rapidminer.com
   *
   * This program is free software: you can redistribute it and/or modify it under the terms of the
   * GNU Affero General Public License as published by the Free Software Foundation, either version 3
   * of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
   * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Affero General Public License for more details.
   *
   * You should have received a copy of the GNU Affero General Public License along with this program.
   * If not, see http://www.gnu.org/licenses/.
   */
  package com.rapidminer.gui.new_plotter.configuration;
  
  import com.rapidminer.datatable.DataTable;
  import com.rapidminer.gui.new_plotter.ChartConfigurationException;
  import com.rapidminer.gui.new_plotter.PlotConfigurationError;
  import com.rapidminer.gui.new_plotter.configuration.DataTableColumn.ValueType;
  import com.rapidminer.gui.new_plotter.configuration.ValueGrouping.GroupingType;
  import com.rapidminer.gui.new_plotter.configuration.ValueGrouping.ValueGroupingFactory;
  import com.rapidminer.gui.new_plotter.configuration.event.AxisParallelLinesConfigurationChangeEvent;
  import com.rapidminer.gui.new_plotter.listener.DimensionConfigListener;
  import com.rapidminer.gui.new_plotter.listener.events.DimensionConfigChangeEvent;
  import com.rapidminer.gui.new_plotter.listener.events.DimensionConfigChangeEvent.DimensionConfigChangeType;
  import com.rapidminer.gui.new_plotter.utility.NumericalValueRange;
  import com.rapidminer.gui.new_plotter.utility.ValueRange;
  
  import java.text.DateFormat;
  import java.util.HashSet;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Set;
  import java.util.Vector;
  
  
  /**
   * A class which manages the domain groupings of all {@link ValueSource}s in a
   * {@link PlotConfiguration}. This manager is necessary, because switching between grouping types is
   * not possible all the time because of some constraints. The DimensionConfigManager enforces these
   * constraints.
   * 
   * @author Marius Helf, Nils Woehler
   * 
   */
  public class DomainConfigManager extends AbstractDimensionConfig implements DimensionConfigListener, Cloneable,
  		AxisParallelLinesConfigurationListener {
  
  	public static enum Sorting {
  		NONE, ASCENDING
  	}
  
  	public enum GroupingState {
  		GROUPED, UNGROUPED, PARTIALLY_GROUPED
  	}
  
  	private static final Sorting DEFAULT_SORTING_MODE = Sorting.ASCENDING;
  
  	private DefaultDimensionConfig ungroupedMasterDimensionConfig, groupedMasterDimensionConfig;
  	private PlotConfiguration plotConfiguration;
  	private Sorting sortingMode = DEFAULT_SORTING_MODE;
  	private AxisParallelLinesConfiguration crosshairLines = new AxisParallelLinesConfiguration();
  	private final int id;
  
  	public DomainConfigManager(PlotConfiguration plotConfiguration, DataTableColumn domainColumn) {
  		super(PlotDimension.DOMAIN);
  
  		if (plotConfiguration == null) {
  			throw new IllegalArgumentException("null plotConfiguration not allowed.");
  		}
  
  		this.id = plotConfiguration.getNextId();
  		this.plotConfiguration = plotConfiguration;
  		ungroupedMasterDimensionConfig = new DefaultDimensionConfig(plotConfiguration, domainColumn, getDimension());
  
  		groupedMasterDimensionConfig = new DefaultDimensionConfig(plotConfiguration, domainColumn, getDimension());
  		try {
  			groupedMasterDimensionConfig.setGrouping(new EquidistantFixedBinCountBinning(5, Double.NaN, Double.NaN,
  					domainColumn, domainColumn.isNominal(), getDateFormat()));
  		} catch (ChartConfigurationException e) {
  			groupedMasterDimensionConfig.setGrouping(new DistinctValueGrouping(domainColumn, domainColumn.isNominal(),
  					getDateFormat()));
  		}
  		groupedMasterDimensionConfig.addDimensionConfigListener(this);
  		crosshairLines.addAxisParallelLinesConfigurationListener(this);
  	}
  
  	/**
  	 * Private ctor, used only by the clone method.
  	 */
  	private DomainConfigManager(int id) {
  		super(PlotDimension.DOMAIN);
  		ungroupedMasterDimensionConfig = null;
  		groupedMasterDimensionConfig = null;
  		plotConfiguration = null;
  		crosshairLines.addAxisParallelLinesConfigurationListener(this);
  		this.id = id;
  	}
  
  	public DefaultDimensionConfig getDomainConfig(boolean grouped) {
  		if (grouped) {
  			return groupedMasterDimensionConfig;
  		} else {
  			return ungroupedMasterDimensionConfig;
  		}
  	}
  
  	public boolean isLogarithmicDomainAxis() {
  		return groupedMasterDimensionConfig.isLogarithmic();
  	}
  
  	@Override
  	public ValueRange getUserDefinedRangeClone(DataTable dataTable) {
  		return groupedMasterDimensionConfig.getUserDefinedRangeClone(dataTable);
  	}
  
  	public DataTableColumn getDomainColumn() {
  		return ungroupedMasterDimensionConfig.getDataTableColumn();
  	}
  
  	@Override
  	public PlotDimension getDimension() {
  		return PlotDimension.DOMAIN;
  	}
  
  	@Override
  	public DataTableColumn getDataTableColumn() {
  		return groupedMasterDimensionConfig.getDataTableColumn();
  	}
  
  	@Override
  	public ValueGrouping getGrouping() {
  		return groupedMasterDimensionConfig.getGrouping();
  	}
  
  	@Override
  	public String getLabel() {
  		return groupedMasterDimensionConfig.getLabel();
  	}
  
  	@Override
  	public boolean isAutoRangeRequired() {
  		return groupedMasterDimensionConfig.isAutoRangeRequired();
  	}
  
  	@Override
  	public boolean isLogarithmic() {
  		return groupedMasterDimensionConfig.isLogarithmic();
  	}
  
  	@Override
  	public boolean isAutoNaming() {
  		return groupedMasterDimensionConfig.isAutoNaming();
  	}
  
  	@Override
  	public void setDataTableColumn(DataTableColumn column) {
  
  		if (column == null) {
  			throw new IllegalArgumentException("Null Domain columns are not allowed");
  		}
  
  		if (column.isNominal()
  				&& groupedMasterDimensionConfig.getGrouping().getGroupingType() != GroupingType.DISTINCT_VALUES) {
  			setFireEvents(false);
  			try {
  				setGrouping(ValueGroupingFactory.getValueGrouping(GroupingType.DISTINCT_VALUES, getDataTableColumn(), true,
  						getDateFormat()));
  			} catch (ChartConfigurationException e) {
  				throw new RuntimeException("Could not create grouping. This should not happen");
  			}
  			setFireEvents(true);
  		}
  
  		ungroupedMasterDimensionConfig.setDataTableColumn(column);
  		groupedMasterDimensionConfig.setDataTableColumn(column);
  	}
  
  	public Sorting getSortingMode() {
  		return sortingMode;
  	}
  
  	public void setSortingMode(Sorting sortingMode) {
  		if (sortingMode != this.sortingMode) {
  			this.sortingMode = sortingMode;
  			fireDimensionConfigChanged(new DimensionConfigChangeEvent(this, PlotDimension.DOMAIN, sortingMode));
  		}
  	}
  
  	@Override
  	public void setUserDefinedRange(NumericalValueRange range) {
  		ungroupedMasterDimensionConfig.setUserDefinedRange(range);
  		groupedMasterDimensionConfig.setUserDefinedRange(range);
  	}
  
  	@Override
  	public void setLogarithmic(boolean logarithmic) {
  		ungroupedMasterDimensionConfig.setLogarithmic(logarithmic);
  		groupedMasterDimensionConfig.setLogarithmic(logarithmic);
  	}
  
  	@Override
  	public void setAutoNaming(boolean autoNaming) {
  		groupedMasterDimensionConfig.setAutoNaming(autoNaming);
  	}
  
  	@Override
  	public void setLabel(String label) {
  		groupedMasterDimensionConfig.setLabel(label);
  	}
  
  	@Override
  	public List<PlotConfigurationError> getErrors() {
  		// TODO check all preconditions
  		// TODO additional checks if valueType is NOMINAL (compatible categories etc.)
  		LinkedList<PlotConfigurationError> errors = new LinkedList<PlotConfigurationError>();
  
  		DataTableColumn dataTableColumn = getDataTableColumn();
  		if (dataTableColumn.getName() == null || dataTableColumn.getName().isEmpty()) {
  			PlotConfigurationError error = new PlotConfigurationError("undefined_dimension", PlotDimension.DOMAIN.getName());
  			errors.add(error);
  			return errors;
  		}
  
  		// This is now check within each RangeAxis separately
  		// if (getValueType() == ValueType.INVALID) {
  		// PlotConfigurationError error = new PlotConfigurationError("illegal_domain_type",
  		// getValueType(), ValueType.INVALID);
  		// errors.add(error);
  		// return errors;
  		// }
  
  		errors.addAll(groupedMasterDimensionConfig.getErrors());
  		if (errors.size() > 0) {
  			return errors;
  		}
  		errors.addAll(ungroupedMasterDimensionConfig.getErrors());
  
  		return errors;
  	}
  
  	@Override
  	public List<PlotConfigurationError> getWarnings() {
  		LinkedList<PlotConfigurationError> warnings = new LinkedList<PlotConfigurationError>();
  
  		warnings.addAll(groupedMasterDimensionConfig.getWarnings());
  		if (warnings.size() > 0) {
  			return warnings;
  		}
  		warnings.addAll(ungroupedMasterDimensionConfig.getWarnings());
  
  		return warnings;
  	}
  
  	@Override
  	public boolean isValid() {
  		return getErrors().isEmpty();
  	}
  
  	@Override
  	public ValueType getValueType() {
  		ValueType valueType = ValueType.INVALID;
  		List<ValueSource> allValueSources = plotConfiguration.getAllValueSources();
  		if (allValueSources.isEmpty()) {
  			if (isGrouping() && getDataTableColumn().getName().length() == 0) {
  				return getGrouping().getDomainType();
  			} else {
  				return ValueType.UNKNOWN;
  			}
  		}
  
  		for (ValueSource valueSource : allValueSources) {
  			ValueType currentValueType = valueSource.getDomainConfig().getValueType();
  			if (currentValueType != valueType) {
  				if (valueType == ValueType.INVALID) {
  					valueType = currentValueType;
  				} else {
  					// This implies that some valueSources have a different type on
  					// the domain axis than others.
  					// That results in an unplottable domain axis.
  					return ValueType.INVALID;
  				}
  			}
  		}
  		return valueType;
  	}
  
  	@Override
  	public boolean isNominal() {
  		return getValueType() == ValueType.NOMINAL;
  	}
  
  	@Override
  	public boolean isNumerical() {
  		return getValueType() == ValueType.NUMERICAL;
  	}
  
  	@Override
  	public boolean isDate() {
  		return getValueType() == ValueType.DATE_TIME;
  	}
  
  	@Override
  	public void setGrouping(ValueGrouping grouping) {
  		groupedMasterDimensionConfig.setGrouping(grouping);
  	}
  
  	@Override
  	public void setUpperBound(Double upperBound) {
  		ungroupedMasterDimensionConfig.setUpperBound(upperBound);
  		groupedMasterDimensionConfig.setUpperBound(upperBound);
  	}
  
  	@Override
  	public void setLowerBound(Double lowerBound) {
  		ungroupedMasterDimensionConfig.setLowerBound(lowerBound);
  		groupedMasterDimensionConfig.setLowerBound(lowerBound);
  	}
  
  	@Override
  	public Double getUserDefinedUpperBound() {
  		return groupedMasterDimensionConfig.getUserDefinedUpperBound();
  	}
  
  	@Override
  	public Double getUserDefinedLowerBound() {
  		return groupedMasterDimensionConfig.getUserDefinedLowerBound();
  	}
  
  	/**
  	 * Returns true if at least one ValueSource in the PlotConfiguration uses the domain axis
  	 * grouping provided by this DomainConfigManager.
  	 * 
  	 * @see com.rapidminer.gui.new_plotter.configuration.DimensionConfig#isGrouping()
  	 */
  	@Override
  	public boolean isGrouping() {
  		for (ValueSource valueSource : plotConfiguration.getAllValueSources()) {
  			if (valueSource.isUsingDomainGrouping()) {
  				return true;
  			}
  		}
  		return false;
  	}
  
  	public GroupingState getGroupingState() {
  		int groupingCounter = 0;
  		for (ValueSource valueSource : plotConfiguration.getAllValueSources()) {
  			if (valueSource.isUsingDomainGrouping()) {
  				++groupingCounter;
  			}
  		}
  		if (groupingCounter == plotConfiguration.getAllValueSources().size()) {
  			return GroupingState.GROUPED;
  		}
  		if (groupingCounter > 0) {
  			return GroupingState.PARTIALLY_GROUPED;
  		}
  
  		return GroupingState.UNGROUPED;
  	}
  
  	@Override
  	public void dimensionConfigChanged(DimensionConfigChangeEvent change) {
  		DimensionConfigChangeEvent domainManagerEvent;
  		DimensionConfigChangeType type = change.getType();
  		switch (type) {
  			case ABOUT_TO_CHANGE_GROUPING:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), type);
  				break;
  			case AUTO_NAMING:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), change.getAutoNaming(),
  						type);
  				break;
  			case COLOR_PROVIDER:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), change.getColorProvider());
  				break;
  			case COLOR_SCHEME:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), type);
  				break;
  			case COLUMN:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), change.getDataTableColumn());
  				break;
  			case CROSSHAIR_LINES_CHANGED:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(),
  						change.getCrosshairLinesChange());
  				break;
  			case DATE_FORMAT_CHANGED:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDateFormat());
  				break;
  			case GROUPING_CHANGED:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(),
  						change.getGroupingChangeEvent());
  				break;
  			case LABEL:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), change.getLabel());
  				break;
  			case RANGE:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(),
  						change.getValueRangeChangedEvent());
  				break;
  			case RESET:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), type);
  				break;
  			case SCALING:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), change.getLogarithmic(),
  						type);
  				break;
  			case SHAPE_PROVIDER:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), change.getShapeProvider());
  				break;
  			case SIZE_PROVIDER:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), change.getSizeProvider());
  				break;
  			case SORTING:
  				domainManagerEvent = new DimensionConfigChangeEvent(this, change.getDimension(), change.getSortingMode());
  				break;
  			default:
  				throw new IllegalArgumentException("Should not happen. Unknown event typ " + type);
  		}
  
  		fireDimensionConfigChanged(domainManagerEvent);
  	}
  
  	@Override
  	public Vector<GroupingType> getValidGroupingTypes() {
  		GroupingType[] values = ValueGrouping.GroupingType.values();
  