/*******************************************************************************
* Copyright (C) 2010 Robert Munteanu <robert.munteanu@gmail.com>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.itsolut.mantis.core;
import java.util.*;
import org.eclipse.core.runtime.Assert;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.osgi.util.NLS;
import com.itsolut.mantis.core.MantisAttributeMapper.Attribute;
import com.itsolut.mantis.core.TaskRelationshipChange.Direction;
import com.itsolut.mantis.core.model.MantisRelationship;
import com.itsolut.mantis.core.util.MantisUtils;
/**
*
* @author Robert Munteanu
*/
public class TaskRelationshipChangeFinder {
private final MantisTaskDataHandler _mantisTaskDataHandler;
public TaskRelationshipChangeFinder(MantisTaskDataHandler mantisTaskDataHandler) {
_mantisTaskDataHandler = mantisTaskDataHandler;
}
/**
* Returns a sorted list of detected changes, possibly empty
*
* <p>The list will contain all the found deletions and then all the found additions. This will
* insure that the change list can be processed as-is, without additional sorting.</p>
*
* @param taskData
* @param changedAttributes
* @return a sorted list of detected changes, possibly empty
*/
public List<TaskRelationshipChange> findChanges(TaskData taskData, Set<TaskAttribute> changedAttributes) {
Assert.isNotNull(taskData);
Assert.isNotNull(changedAttributes);
if ( changedAttributes.size() > 0 && taskData.isNew() )
throw new RuntimeException(NLS.bind("Task data is new but changedAttributes.size is {0}.", changedAttributes.size()));
List<TaskRelationshipChange> changes = new ArrayList<TaskRelationshipChange>();
for (Attribute relationAttribute : MantisAttributeMapper.taskRelationAttributes()) {
TaskAttribute parentAttribute = taskData.getRoot().getAttribute(relationAttribute.getKey());
TaskAttribute oldAttribute = null;
for (TaskAttribute attribute : changedAttributes) {
if (attribute.getId().equals(relationAttribute.getKey())) {
oldAttribute = attribute;
break;
}
}
if (oldAttribute == null && !taskData.isNew())
continue;
List<String> newValues = parentAttribute != null ? unwrapValues(parentAttribute.getValues()) : Collections.<String> emptyList();
Map<String,String> oldIdToValues = taskData.isNew() ? Collections.<String, String> emptyMap() : findOldValues(oldAttribute);
changes.addAll(findRemovedValues(relationAttribute, newValues, oldIdToValues));
changes.addAll(findAddedValues(relationAttribute, newValues, new ArrayList<String>(oldIdToValues.values())));
}
// place deletions first, as this is the natural processing order
Collections.sort(changes, new Comparator<TaskRelationshipChange>() {
public int compare(TaskRelationshipChange o1, TaskRelationshipChange o2) {
if ( o1.getDirection() == o2.getDirection() )
return 0;
if ( o1.getDirection() == Direction.Added )
return 1;
return -1;
}
});
return changes;
}
/**
* This method works around the fact that we sometimes receive values a CSV strings,
* and sometimes as lists of strings
*/
private List<String> unwrapValues(List<String> values) {
List<String> results = new ArrayList<String>();
for (String value : values)
if (value.indexOf(',') == -1)
results.add(value);
else
results.addAll(fromCsvString(value));
return results;
}
private List<String> fromCsvString(String value) {
if ( MantisUtils.isEmpty(value) )
return Collections.emptyList();
String[] raw = value.split("\\,");
List<String> values = new ArrayList<String>(raw.length);
for (String rawValue : raw)
values.add(rawValue.trim());
return values;
}
private Map<String,String> findOldValues(TaskAttribute oldAttribute) {
List<String> oldValues = oldAttribute.getValues();
List<String> oldIds = fromCsvString(oldAttribute.getMetaData().getValue(MantisAttributeMapper.TASK_ATTRIBUTE_RELATIONSHIP_IDS));
Assert.isTrue(oldValues.size() == oldIds.size(), NLS.bind("Inconsistency when reading old attribute values for {0}. oldValues: {1}, oldIds: {2}.", new Object[] { oldAttribute.getId(), oldValues, oldIds }));
Map<String,String> oldValuesById = new HashMap<String, String>();
for ( int i = 0; i < oldValues.size(); i++ )
oldValuesById.put(oldIds.get(i), oldValues.get(i));
return oldValuesById;
}
private List<TaskRelationshipChange> findRemovedValues(Attribute relationAttribute, List<String> newValues,
Map<String, String> oldIdToValues) {
List<TaskRelationshipChange> changed = new ArrayList<TaskRelationshipChange>();
for (Map.Entry<String,String> oldValueEntry : oldIdToValues.entrySet()) {
if (!(newValues.contains(oldValueEntry.getValue())))
changed.add(new TaskRelationshipChange(Direction.Removed, createRelationship(relationAttribute, Integer.parseInt(oldValueEntry.getKey()),
oldValueEntry.getValue())));
}
return changed;
}
private MantisRelationship createRelationship(Attribute relationAttribute, int relationshipId, String targetId) {
MantisRelationship relationship = new MantisRelationship();
relationship.setId(relationshipId);
relationship.setTargetId(Integer.parseInt(targetId));
relationship.setType(_mantisTaskDataHandler.getRelationTypeForAttribute(relationAttribute));
return relationship;
}
private List<TaskRelationshipChange> findAddedValues(Attribute relationAttribute, List<String> newValues,
List<String> oldValues) {
List<TaskRelationshipChange> changed = new ArrayList<TaskRelationshipChange>();
for (String fromValue : newValues) {
if (MantisUtils.isEmpty(fromValue))
continue;
if (!(oldValues.contains(fromValue)))
changed.add(new TaskRelationshipChange(Direction.Added, createRelationship(relationAttribute, 0,
fromValue)));
}
return changed;
}
}