/*
* RapidMiner
*
* Copyright (C) 2001-2014 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 java.util.LinkedList;
import java.util.List;
import com.rapidminer.gui.new_plotter.listener.AggregationWindowingListener;
import com.rapidminer.gui.new_plotter.utility.AggregatedValueRange;
import com.rapidminer.gui.new_plotter.utility.ValueRange;
/**
* This class can be used to create cumulative plots.
*
* Used as a parameter to the grouping creation functions it tells the ValueGrouping
* to include values from a certain amount of groups from the left or from the right
* in a group.
* To include all values left of the current group in the current group, set grabLeft to -1.
* grabLeft works analogously.
*
* If there are less than grabLeft groups on the left of the current group, all left
* groups are taken.
*
* @author Marius Helf
*
*/
public class AggregationWindowing implements Cloneable {
private int grabLeft = 0;
private int grabRight = 0;
private boolean includeIncompleteGroups = true;
private List<AggregationWindowingListener> listeners = new LinkedList<AggregationWindowingListener>();
public AggregationWindowing(int grabLeft, int grabRight, boolean includeIncompleteGroups) {
super();
this.grabLeft = grabLeft;
this.grabRight = grabRight;
this.includeIncompleteGroups = includeIncompleteGroups;
}
public int getGrabLeft() {
return grabLeft;
}
public void setGrabLeft(int grabLeft) {
if(grabLeft!=this.grabLeft) {
this.grabLeft = grabLeft;
fireAggregationWindowingChanged();
}
}
public int getGrabRight() {
return grabRight;
}
public void setGrabRight(int grabRight) {
if(grabRight!=this.grabRight) {
this.grabRight = grabRight;
fireAggregationWindowingChanged();
}
}
/**
* @return the includeIncompleteGroups
*/
public boolean isIncludingIncompleteGroups() {
return includeIncompleteGroups;
}
/**
* @param includeIncompleteGroups the includeIncompleteGroups to set
*/
public void setIncludeIncompleteGroups(boolean includeIncompleteGroups) {
if(includeIncompleteGroups!=this.includeIncompleteGroups) {
this.includeIncompleteGroups = includeIncompleteGroups;
fireAggregationWindowingChanged();
}
}
/**
* Creates a new grouping model (i.e. a list of {@link ValueRange}s)
* with this aggregation windowing applied.
* Does not change the input grouping.
*
* When includeIncompleteGroups is false, the resulting list will contain
* null values for the the incomplete groups.
*/
public List<ValueRange> applyOnGrouping(List<ValueRange> grouping) {
if (grabLeft == 0 && grabRight == 0) {
return grouping;
}
LinkedList<ValueRange> leftGrabbedList = new LinkedList<ValueRange>();
LinkedList<ValueRange> rightGrabbedList = new LinkedList<ValueRange>();
List<ValueRange> cumulatedGrouping = new LinkedList<ValueRange>();
ValueRange currentRange = null;
for (ValueRange range : grouping) {
rightGrabbedList.add(range);
if (currentRange != null) {
leftGrabbedList.add(currentRange);
if (grabLeft > -1 && leftGrabbedList.size() > grabLeft) {
leftGrabbedList.removeFirst();
}
}
if (grabRight > -1 && rightGrabbedList.size() > grabRight) {
currentRange = rightGrabbedList.removeFirst();
}
// check if we want to add the current range
boolean addAggregatedRange = false;
if (currentRange != null) {
if (includeIncompleteGroups) {
addAggregatedRange = true;
} else if (grabLeft == -1) {
addAggregatedRange = true;
} else if (leftGrabbedList.size() >= grabLeft) {
addAggregatedRange = true;
}
}
// add current range
if (addAggregatedRange) {
AggregatedValueRange aggregatedRange = createAggregatedRange(leftGrabbedList, rightGrabbedList, currentRange);
cumulatedGrouping.add(aggregatedRange);
} else if (currentRange != null) {
cumulatedGrouping.add(null);
}
}
if (includeIncompleteGroups || grabRight == -1) {
while (!rightGrabbedList.isEmpty()) {
if (currentRange != null) {
leftGrabbedList.add(currentRange);
}
currentRange = rightGrabbedList.removeFirst();
if (grabLeft > -1 && leftGrabbedList.size() > grabLeft) {
leftGrabbedList.removeFirst();
}
cumulatedGrouping.add(createAggregatedRange(leftGrabbedList, rightGrabbedList, currentRange));
}
} else {
while (cumulatedGrouping.size() < grouping.size()) {
cumulatedGrouping.add(null);
}
}
return cumulatedGrouping;
}
private AggregatedValueRange createAggregatedRange(LinkedList<ValueRange> leftGrabbedList, LinkedList<ValueRange> rightGrabbedList, ValueRange currentRange) {
AggregatedValueRange aggregatedRange = new AggregatedValueRange();
aggregatedRange.addSubRange(currentRange);
for (ValueRange subRange : leftGrabbedList) {
aggregatedRange.addSubRange(subRange);
}
for (ValueRange subRange : rightGrabbedList) {
aggregatedRange.addSubRange(subRange);
}
return aggregatedRange;
}
public void addAggregationWindowingListener(AggregationWindowingListener l) {
listeners.add(l);
}
public void removeAggregationWindowingListener(AggregationWindowingListener l) {
listeners.remove(l);
}
private void fireAggregationWindowingChanged() {
for (AggregationWindowingListener l : listeners) {
l.aggregationWindowingChanged(this);
}
}
@Override
public AggregationWindowing clone() {
AggregationWindowing clone = new AggregationWindowing(grabLeft, grabRight, includeIncompleteGroups);
return clone;
}
}