/**
* Copyright (C) 2001-2017 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.operator.nio;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import com.rapidminer.operator.nio.model.ColumnMetaData;
import com.rapidminer.operator.nio.model.ParsingError;
/**
* Validates the MetaData set by the user in the MetaDataDeclarationWizardStep which is a part of
* importing e.g. an Excel file.
*
* @author Dominik Halfkann
*/
public class MetaDataValidator extends Observable {
private List<ParsingError> errorList = new ArrayList<ParsingError>();
Map<ColumnMetaData, Integer> metaDataToColNumMap = new HashMap<ColumnMetaData, Integer>();
Map<String, List<Integer>> columnRoles = new HashMap<String, List<Integer>>();
Map<String, List<Integer>> columnNames = new HashMap<String, List<Integer>>();
List<Integer> oldDuplicateNameColumn = new ArrayList<Integer>();
List<Integer> duplicateNameColumn = new ArrayList<Integer>();
List<Integer> oldDuplicateRoleColumn = new ArrayList<Integer>();
List<Integer> duplicateRoleColumn = new ArrayList<Integer>();
private void updateColumnMaps(ColumnMetaData cmd) {
int updatedColumnNum = metaDataToColNumMap.get(cmd);
deleteColumnNumFromMaps(updatedColumnNum);
if (cmd.isSelected()) {
// name
List<Integer> columnsForName = columnNames.get(cmd.getUserDefinedAttributeName());
if (columnsForName == null) {
// if there isn't a list for that name, create one
List<Integer> columns = new ArrayList<Integer>();
columns.add(updatedColumnNum);
columnNames.put(cmd.getUserDefinedAttributeName(), columns);
} else {
// if there is already a list for that name, add column
columnsForName.add(updatedColumnNum);
}
// role
List<Integer> columnsForRole = columnRoles.get(cmd.getRole());
if (columnsForRole == null) {
// if there isn't a list for that role, create one
List<Integer> columns = new ArrayList<Integer>();
columns.add(updatedColumnNum);
columnRoles.put(cmd.getRole(), columns);
} else {
// if there is already a list for that role, add column
columnsForRole.add(updatedColumnNum);
}
}
}
private void validate(ColumnMetaData cmd) {
updateColumnMaps(cmd);
checkForDuplicates();
}
public void checkForDuplicates() {
oldDuplicateNameColumn.clear();
oldDuplicateNameColumn.addAll(duplicateNameColumn);
duplicateNameColumn.clear();
oldDuplicateRoleColumn.clear();
oldDuplicateRoleColumn.addAll(duplicateRoleColumn);
duplicateRoleColumn.clear();
errorList = new ArrayList<ParsingError>();
for (Entry<String, List<Integer>> roleEntry : columnRoles.entrySet()) {
if (roleEntry.getValue().size() > 1 && !roleEntry.getKey().equals("attribute")) {
errorList.add(new ParsingError(roleEntry.getValue(), ParsingError.ErrorCode.SAME_ROLE_FOR_MULTIPLE_COLUMNS,
roleEntry.getKey()));
duplicateRoleColumn.addAll(roleEntry.getValue());
}
}
for (Entry<String, List<Integer>> nameEntry : columnNames.entrySet()) {
if (nameEntry.getValue().size() > 1) {
errorList.add(new ParsingError(nameEntry.getValue(), ParsingError.ErrorCode.SAME_NAME_FOR_MULTIPLE_COLUMNS,
nameEntry.getKey()));
duplicateNameColumn.addAll(nameEntry.getValue());
}
}
checkIfUpdate();
}
private void checkIfUpdate() {
if (!oldDuplicateNameColumn.equals(duplicateNameColumn) || !oldDuplicateRoleColumn.equals(duplicateRoleColumn)) {
// if one of the duplicates lists aren't equal, fire update
Set<Integer> columnsUpdate = new HashSet<Integer>();
columnsUpdate.addAll(oldDuplicateNameColumn);
columnsUpdate.addAll(duplicateNameColumn);
columnsUpdate.addAll(oldDuplicateRoleColumn);
columnsUpdate.addAll(duplicateRoleColumn);
this.setChanged();
this.notifyObservers(columnsUpdate);
}
}
public List<ParsingError> getErrors() {
return errorList;
}
public void addColumnMetaData(ColumnMetaData cmd, int column) {
metaDataToColNumMap.put(cmd, column);
cmd.addObserver(new Observer() {
@Override
public void update(Observable o, Object arg) {
if (o instanceof ColumnMetaData) {
ColumnMetaData cmd = (ColumnMetaData) o;
validate(cmd);
}
}
});
updateColumnMaps(cmd);
}
private void deleteColumnNumFromMaps(int columnNumber) {
for (Entry<String, List<Integer>> nameEntry : columnNames.entrySet()) {
if (nameEntry.getValue() != null) {
nameEntry.getValue().remove((Integer) columnNumber);
}
}
for (Entry<String, List<Integer>> roleEntry : columnRoles.entrySet()) {
if (roleEntry.getValue() != null) {
roleEntry.getValue().remove((Integer) columnNumber);
}
}
}
public boolean isDuplicateNameColumn(int column) {
return duplicateNameColumn.contains(column);
}
public boolean isDuplicateRoleColumn(int column) {
return duplicateRoleColumn.contains(column);
}
}