feature[ats_ATS144393]: Add Copy Set Functionality for Dispo tool

Change-Id: I4dc13219899c2ad35bd6284a0901567f2640cb3c
diff --git a/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/CopySetParamOption.java b/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/CopySetParamOption.java
new file mode 100644
index 0000000..cb77175
--- /dev/null
+++ b/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/CopySetParamOption.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Boeing.
+ * 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
+ *
+ * Contributors:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osee.disposition.model;
+
+/**
+ * @author Angel Avila
+ */
+public enum CopySetParamOption {
+   NONE(0),
+   OVERRIDE(1),
+   OVERRIDE_EMPTY(2),
+   MERGE(3);
+
+   private final int value;
+
+   CopySetParamOption(int value) {
+      this.value = value;
+   }
+
+   public final int getValue() {
+      return value;
+   }
+
+   public boolean isOverride() {
+      return this == CopySetParamOption.OVERRIDE;
+   }
+
+   public boolean isEmptyOverride() {
+      return this == CopySetParamOption.OVERRIDE_EMPTY;
+   }
+
+   public boolean isMerge() {
+      return this == CopySetParamOption.MERGE;
+   }
+
+   public boolean isNone() {
+      return this == CopySetParamOption.NONE;
+   }
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/CopySetParams.java b/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/CopySetParams.java
new file mode 100644
index 0000000..06167a0
--- /dev/null
+++ b/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/CopySetParams.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Boeing.
+ * 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
+ *
+ * Contributors:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osee.disposition.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @author Angel Avila
+ */
+@XmlRootElement(name = "CopySetParams")
+public class CopySetParams {
+
+   private CopySetParamOption annotationParam;
+   private CopySetParamOption categoryParam;
+   private CopySetParamOption noteParam;
+   private CopySetParamOption assigneeParam;
+
+   public CopySetParamOption getAnnotationParam() {
+      return annotationParam;
+   }
+
+   public CopySetParamOption getCategoryParam() {
+      return categoryParam;
+   }
+
+   public CopySetParamOption getNoteParam() {
+      return noteParam;
+   }
+
+   public CopySetParamOption getAssigneeParam() {
+      return assigneeParam;
+   }
+
+   public void setAnnotationParam(CopySetParamOption annotationParam) {
+      this.annotationParam = annotationParam;
+   }
+
+   public void setCategoryParam(CopySetParamOption categoryParam) {
+      this.categoryParam = categoryParam;
+   }
+
+   public void setNoteParam(CopySetParamOption noteParam) {
+      this.noteParam = noteParam;
+   }
+
+   public void setAssigneeParam(CopySetParamOption assigneeParam) {
+      this.assigneeParam = assigneeParam;
+   }
+
+}
diff --git a/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/DispoItemData.java b/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/DispoItemData.java
index bc3958b..0c9ab9a 100644
--- a/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/DispoItemData.java
+++ b/plugins/org.eclipse.osee.disposition.rest.model/src/org/eclipse/osee/disposition/model/DispoItemData.java
@@ -39,7 +39,6 @@
    private String elapsedTime;
    private Boolean aborted;
    private String itemNotes;
-   private Boolean needsReview;
 
    public DispoItemData() {
 
@@ -189,10 +188,6 @@
       this.itemNotes = itemNotes;
    }
 
-   public void setNeedsReview(Boolean needsReview) {
-      this.needsReview = needsReview;
-   }
-
    @Override
    public boolean matches(Identity<?>... identities) {
       for (Identity<?> identity : identities) {
diff --git a/plugins/org.eclipse.osee.disposition.rest.test/src/org/eclipse/osee/disposition/rest/importer/AnnotationCopierTest.java b/plugins/org.eclipse.osee.disposition.rest.test/src/org/eclipse/osee/disposition/rest/importer/AnnotationCopierTest.java
index 7ff360a..7d2f014 100644
--- a/plugins/org.eclipse.osee.disposition.rest.test/src/org/eclipse/osee/disposition/rest/importer/AnnotationCopierTest.java
+++ b/plugins/org.eclipse.osee.disposition.rest.test/src/org/eclipse/osee/disposition/rest/importer/AnnotationCopierTest.java
@@ -18,7 +18,7 @@
 import org.eclipse.osee.disposition.model.DispoItemData;
 import org.eclipse.osee.disposition.model.DispoStrings;
 import org.eclipse.osee.disposition.rest.internal.DispoConnector;
-import org.eclipse.osee.disposition.rest.internal.importer.AnnotationCopier;
+import org.eclipse.osee.disposition.rest.internal.importer.DispoSetCopier;
 import org.eclipse.osee.disposition.rest.internal.report.OperationReport;
 import org.eclipse.osee.disposition.rest.util.DispoUtil;
 import org.json.JSONArray;
@@ -158,10 +158,10 @@
       destItem.setDiscrepanciesList(destDiscrepancies);
       OperationReport report = new OperationReport();
 
-      AnnotationCopier copier = new AnnotationCopier(connector);
+      DispoSetCopier copier = new DispoSetCopier(connector);
       List<DispoItem> toModify =
-         copier.copyEntireSet(Collections.singletonList(destItem), Collections.singletonList((DispoItem) sourceItem),
-            true, report);
+         copier.copyAllDispositions(Collections.singletonMap(destItem.getName(), destItem),
+            Collections.singletonList((DispoItem) sourceItem), true, report);
 
       DispoItem modifiedItem = toModify.get(0);
       JSONArray modifiedItemAnnotations = modifiedItem.getAnnotationsList();
@@ -212,10 +212,10 @@
       destItem.setDiscrepanciesList(destDiscrepancies);
 
       OperationReport report = new OperationReport();
-      AnnotationCopier copier = new AnnotationCopier(connector);
+      DispoSetCopier copier = new DispoSetCopier(connector);
       List<DispoItem> toModify =
-         copier.copyEntireSet(Collections.singletonList(destItem), Collections.singletonList((DispoItem) sourceItem),
-            true, report);
+         copier.copyAllDispositions(Collections.singletonMap(destItem.getName(), destItem),
+            Collections.singletonList((DispoItem) sourceItem), true, report);
 
       DispoItem modifiedItem = toModify.get(0);
       JSONArray modifiedItemAnnotations = modifiedItem.getAnnotationsList();
diff --git a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/DispoApi.java b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/DispoApi.java
index 0aa3f02..e99a022 100644
--- a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/DispoApi.java
+++ b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/DispoApi.java
@@ -12,6 +12,7 @@
 
 import java.util.Collection;
 import java.util.List;
+import org.eclipse.osee.disposition.model.CopySetParams;
 import org.eclipse.osee.disposition.model.DispoAnnotationData;
 import org.eclipse.osee.disposition.model.DispoItem;
 import org.eclipse.osee.disposition.model.DispoItemData;
@@ -55,7 +56,7 @@
 
    boolean editDispoAnnotation(DispoProgram program, String itemId, String annotationId, DispoAnnotationData newAnnotation, String userName);
 
-   String copyDispoSet(DispoProgram program, DispoSet destination, DispoSet source);
+   String copyDispoSet(DispoProgram program, DispoSet destination, DispoSet source, CopySetParams params);
 
    // Deletes
 
diff --git a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/DispoApiImpl.java b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/DispoApiImpl.java
index fb98aac..7448ef2 100644
--- a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/DispoApiImpl.java
+++ b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/DispoApiImpl.java
@@ -19,6 +19,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import org.eclipse.osee.disposition.model.CopySetParams;
 import org.eclipse.osee.disposition.model.DispoAnnotationData;
 import org.eclipse.osee.disposition.model.DispoItem;
 import org.eclipse.osee.disposition.model.DispoItemData;
@@ -30,9 +31,9 @@
 import org.eclipse.osee.disposition.model.Note;
 import org.eclipse.osee.disposition.rest.DispoApi;
 import org.eclipse.osee.disposition.rest.DispoImporterApi;
-import org.eclipse.osee.disposition.rest.internal.importer.AnnotationCopier;
 import org.eclipse.osee.disposition.rest.internal.importer.DispoImporterFactory;
 import org.eclipse.osee.disposition.rest.internal.importer.DispoImporterFactory.ImportFormat;
+import org.eclipse.osee.disposition.rest.internal.importer.DispoSetCopier;
 import org.eclipse.osee.disposition.rest.internal.report.OperationReport;
 import org.eclipse.osee.disposition.rest.util.DispoFactory;
 import org.eclipse.osee.disposition.rest.util.DispoUtil;
@@ -190,7 +191,7 @@
       return wasUpdated;
    }
 
-   private boolean editDispoItems(DispoProgram program, List<DispoItem> dispoItems, boolean resetRerunFlag) {
+   private boolean editDispoItems(DispoProgram program, Collection<DispoItem> dispoItems, boolean resetRerunFlag) {
       boolean wasUpdated = false;
 
       ArtifactReadable author = getQuery().findUser();
@@ -478,24 +479,33 @@
    }
 
    @Override
-   public String copyDispoSet(DispoProgram program, DispoSet destination, DispoSet source) {
-      AnnotationCopier copier = new AnnotationCopier(dispoConnector);
-      List<DispoItemData> destinationItems = new ArrayList<DispoItemData>();
+   public String copyDispoSet(DispoProgram program, DispoSet destination, DispoSet source, CopySetParams params) {
+      List<DispoItem> sourceItems = getDispoItems(program, source.getGuid());
+      Map<String, DispoItemData> namesToDestItems = new HashMap<String, DispoItemData>();
       for (DispoItem itemArt : getDispoItems(program, destination.getGuid())) {
          DispoItemData itemData = DispoUtil.itemArtToItemData(itemArt, true, true);
-         destinationItems.add(itemData);
+         namesToDestItems.put(itemData.getName(), itemData);
       }
-      List<DispoItem> toEdit = Collections.emptyList();
+      Map<String, DispoItem> namesToToEditItems = new HashMap<String, DispoItem>();
       OperationReport report = new OperationReport();
-      try {
-         toEdit = copier.copyEntireSet(destinationItems, getDispoItems(program, source.getGuid()), true, report);
-      } catch (JSONException ex) {
-         report.addOtherMessage(ex.getMessage());
+
+      DispoSetCopier copier = new DispoSetCopier(dispoConnector);
+      if (!params.getAnnotationParam().isNone()) {
+         List<DispoItem> copyResults = copier.copyAllDispositions(namesToDestItems, sourceItems, true, report);
+         for (DispoItem item : copyResults) {
+            namesToToEditItems.put(item.getName(), item);
+         }
       }
-      if (!toEdit.isEmpty()) {
-         editDispoItems(program, toEdit, false);
+
+      copier.copyCategories(namesToDestItems, sourceItems, namesToToEditItems, params.getCategoryParam());
+      copier.copyAssignee(namesToDestItems, sourceItems, namesToToEditItems, params.getAssigneeParam());
+      copier.copyNotes(namesToDestItems, sourceItems, namesToToEditItems, params.getNoteParam());
+
+      if (!namesToToEditItems.isEmpty()) {
+         editDispoItems(program, namesToToEditItems.values(), false);
       }
 
       return generateReportArt(program, getQuery().findUser(), report, "Copy Dispositions");
    }
+
 }
diff --git a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/DispoWriter.java b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/DispoWriter.java
index 66a1afa..6966f9d 100644
--- a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/DispoWriter.java
+++ b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/DispoWriter.java
@@ -10,6 +10,7 @@
  *******************************************************************************/
 package org.eclipse.osee.disposition.rest.internal;
 
+import java.util.Collection;
 import java.util.List;
 import org.eclipse.osee.disposition.model.DispoItem;
 import org.eclipse.osee.disposition.model.DispoProgram;
@@ -34,7 +35,7 @@
 
    void updateDispoItem(ArtifactReadable author, DispoProgram program, String dispoItemId, DispoItem data);
 
-   void updateDispoItems(ArtifactReadable author, DispoProgram program, List<DispoItem> data, boolean resetRerunFlag);
+   void updateDispoItems(ArtifactReadable author, DispoProgram program, Collection<DispoItem> data, boolean resetRerunFlag);
 
    String createDispoReport(DispoProgram program, ArtifactReadable author, String contens, String operationTitle);
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/OrcsStorageImpl.java b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/OrcsStorageImpl.java
index 780d745..155b1e7 100644
--- a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/OrcsStorageImpl.java
+++ b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/OrcsStorageImpl.java
@@ -374,8 +374,8 @@
    }
 
    @Override
-   public void updateDispoItems(ArtifactReadable author, DispoProgram program, List<DispoItem> data, boolean resetRerunFlag) {
-      TransactionBuilder tx = getTxFactory().createTransaction(program.getUuid(), author, "Edit Multiple Dispo Items");
+   public void updateDispoItems(ArtifactReadable author, DispoProgram program, Collection<DispoItem> data, boolean resetRerunFlag) {
+      TransactionBuilder tx = getTxFactory().createTransaction(program.getUuid(), author, "Copy Categories");
 
       for (DispoItem newItem : data) {
          ArtifactReadable dispoItemArt = findDispoArtifact(program, newItem.getGuid(), DispoConstants.DispoItem);
diff --git a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/AnnotationCopier.java b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/AnnotationCopier.java
deleted file mode 100644
index 7756e5d..0000000
--- a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/AnnotationCopier.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 Boeing.
- * 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
- *
- * Contributors:
- *     Boeing - initial API and implementation
- *******************************************************************************/
-package org.eclipse.osee.disposition.rest.internal.importer;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.eclipse.osee.disposition.model.Discrepancy;
-import org.eclipse.osee.disposition.model.DispoAnnotationData;
-import org.eclipse.osee.disposition.model.DispoItem;
-import org.eclipse.osee.disposition.model.DispoItemData;
-import org.eclipse.osee.disposition.model.DispoStrings;
-import org.eclipse.osee.disposition.rest.internal.DispoConnector;
-import org.eclipse.osee.disposition.rest.internal.report.OperationReport;
-import org.eclipse.osee.disposition.rest.util.DispoUtil;
-import org.eclipse.osee.framework.jdk.core.util.Strings;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * @author Angel Avila
- */
-public class AnnotationCopier {
-
-   private final DispoConnector connector;
-
-   public AnnotationCopier(DispoConnector connector) {
-      this.connector = connector;
-   }
-
-   public List<DispoItem> copyEntireSet(List<DispoItemData> destinationItems, Collection<DispoItem> sourceItems, boolean isCopySet, OperationReport report) throws JSONException {
-      List<DispoItem> modifiedItems = new ArrayList<DispoItem>();
-
-      HashMap<String, DispoItemData> nameToDestItems = createNameToItemList(destinationItems);
-      for (DispoItem sourceItem : sourceItems) {
-         DispoItemData destItem = nameToDestItems.get(sourceItem.getName());
-
-         if (destItem != null) {
-            JSONArray annotationsList = destItem.getAnnotationsList();
-            /**
-             * If item is PASS don't bother copying over Annotations from Source Item, all annotations are Default
-             * Annotations and already created in the Import
-             */
-            if (!destItem.getStatus().equals(DispoStrings.Item_Pass)) {
-               DispoItemData newItem = createNewItemWithCopiedAnnotations(destItem, sourceItem, isCopySet, report);
-               if (newItem != null) {
-                  if (!Strings.isValid(destItem.getGuid())) {
-                     newItem.setGuid(sourceItem.getGuid());
-                  } else {
-                     newItem.setGuid(destItem.getGuid());
-                  }
-                  modifiedItems.add(newItem);
-
-                  report.addMessageForItem(destItem.getName(), "$$$$Had %s Dispositions$$$$\n",
-                     annotationsList.length());
-                  report.addMessageForItem(destItem.getName(), "$$$$Now has %s Dispositions$$$$",
-                     newItem.getAnnotationsList().length());
-               }
-            } else if (!Strings.isValid(destItem.getGuid()) && !sourceItem.getStatus().equals(DispoStrings.Item_Pass)) {
-               destItem.setGuid(sourceItem.getGuid());
-               modifiedItems.add(destItem);
-            }
-
-         }
-      }
-      return modifiedItems;
-   }
-
-   private DispoItemData createNewItemWithCopiedAnnotations(DispoItemData destItem, DispoItem sourceItem, boolean isCopySet, OperationReport report) throws JSONException {
-      DispoItemData toReturn;
-      boolean isSameDiscrepancies = matchAllDiscrepancies(destItem, sourceItem);
-      if (isSameDiscrepancies) {
-         toReturn = buildNewItem(destItem, sourceItem, isCopySet, report);
-      } else {
-         toReturn = null;
-         report.addMessageForItem(destItem.getName(),
-            "Tried to copy from item id: [%s] but discrepancies were not the same", sourceItem.getGuid());
-      }
-
-      return toReturn;
-   }
-
-   private DispoItemData buildNewItem(DispoItemData destItem, DispoItem sourceItem, boolean isSkipDestDefaultAnnotations, OperationReport report) throws JSONException {
-      boolean isChangesMade = false;
-      DispoItemData newItem = new DispoItemData();
-      newItem.setDiscrepanciesList(destItem.getDiscrepanciesList());
-      JSONArray newList = new JSONArray(destItem.getAnnotationsList().toString());
-      newItem.setAnnotationsList(newList);
-
-      JSONArray newAnnotations = newItem.getAnnotationsList();
-      JSONArray sourceAnnotations = sourceItem.getAnnotationsList();
-
-      Set<String> destDefaultAnntationLocations = getDefaultAnnotations(newItem);
-
-      for (int i = 0; i < sourceAnnotations.length(); i++) {
-         JSONObject annotationJson = sourceAnnotations.getJSONObject(i);
-         DispoAnnotationData sourceAnnotation = DispoUtil.jsonObjToDispoAnnotationData(annotationJson);
-
-         String sourceLocation = sourceAnnotation.getLocationRefs();
-
-         if (DispoUtil.isDefaultAnntoation(sourceAnnotation)) {
-            /**
-             * This means the source has an annotation that's TEST_UNIT or Exception_Handling, so don't copy it over, we
-             * might leave an uncovered discrepancy which is intended and need to log
-             */
-            if (!destDefaultAnntationLocations.contains(sourceLocation)) {
-               report.addMessageForItem(destItem.getName(),
-                  "Did not copy annotations for location(s) [%s] because they are default annotations",
-                  sourceAnnotation.getLocationRefs());
-            }
-         } else if (isSkipDestDefaultAnnotations && destDefaultAnntationLocations.contains(sourceLocation)) {
-            /**
-             * isSkipDestDefault is true when annotation copier is called by a copy set, this means we do not want to
-             * copy over source annotations that have the same location as a Dest annotation that's already covered by a
-             * Default Annotation This means the destination has an annotation that's TEST_UNIT or Exception_Handling,
-             * so don't copy over a manual Disposition
-             */
-            report.addMessageForItem(
-               destItem.getName(),
-               "Did not copy annotations for location(s) [%s] because the destination item already has a default annotations at these locations",
-               sourceAnnotation.getLocationRefs());
-         } else if (newAnnotations.toString().contains(sourceAnnotation.getGuid())) {
-            report.addMessageForItem(
-               destItem.getName(),
-               "Did not copy annotations for location(s) [%s] because the destination item already has the same annotations at these locations [%s]",
-               sourceAnnotation.getLocationRefs());
-         } else {
-            DispoAnnotationData newAnnotation = sourceAnnotation;
-
-            if (destDefaultAnntationLocations.contains(sourceLocation)) {
-               /**
-                * The discrepancy of this manual disposition is now covered by a Default Annotation so this Manual
-                * Annotation is invalid, mark as such by making the location Ref negative, don't bother connecting the
-                * annotation
-                */
-               // Make location ref negative to indicate this 
-               String locationRefs = sourceAnnotation.getLocationRefs();
-               Integer locationRefAsInt = Integer.valueOf(locationRefs);
-               if (locationRefAsInt > 0) {
-                  newAnnotation.setLocationRefs(String.valueOf(locationRefAsInt * -1));
-               }
-               report.addMessageForItem(destItem.getName(),
-                  "The annotation was copied over but is no longer needed: [%s]", locationRefs);
-            }
-            connector.connectAnnotation(newAnnotation, newItem.getDiscrepanciesList());
-            isChangesMade = true;
-            // Both the source and destination are dispositionable so copy the annotation
-            int nextIndex = newAnnotations.length();
-            newAnnotation.setIndex(nextIndex);
-            newAnnotations.put(nextIndex, DispoUtil.annotationToJsonObj(newAnnotation));
-         }
-      }
-
-      if (isChangesMade) {
-         newItem.setAnnotationsList(newAnnotations);
-         String newStatus = connector.getItemStatus(newItem);
-         newItem.setStatus(newStatus);
-      } else {
-         newItem = null;
-      }
-      return newItem;
-   }
-
-   private Set<String> getDefaultAnnotations(DispoItemData item) throws JSONException {
-      Set<String> defaultAnnotationLocations = new HashSet<String>();
-      JSONArray annotations = item.getAnnotationsList();
-      if (annotations == null) {
-         annotations = new JSONArray();
-      }
-      for (int i = 0; i < annotations.length(); i++) {
-         JSONObject annotationJson = annotations.getJSONObject(i);
-         DispoAnnotationData annotation = DispoUtil.jsonObjToDispoAnnotationData(annotationJson);
-         if (DispoUtil.isDefaultAnntoation(annotation)) {
-            defaultAnnotationLocations.add(annotation.getLocationRefs());
-         }
-      }
-
-      return defaultAnnotationLocations;
-   }
-
-   private HashMap<String, DispoItemData> createNameToItemList(List<DispoItemData> destinationItems) {
-      HashMap<String, DispoItemData> nameToItem = new HashMap<String, DispoItemData>();
-      for (DispoItemData item : destinationItems) {
-         nameToItem.put(item.getName(), item);
-      }
-      return nameToItem;
-   }
-
-   private boolean matchAllDiscrepancies(DispoItemData destItem, DispoItem sourceItem) throws JSONException {
-      Map<Integer, String> destLocationToText = generateLocationToTextMap(destItem);
-      boolean toReturn = true;
-
-      JSONObject sourceDiscrepancies = sourceItem.getDiscrepanciesList();
-      @SuppressWarnings("unchecked")
-      Iterator<String> iterator = sourceDiscrepancies.keys();
-      while (iterator.hasNext()) {
-         String key = iterator.next();
-         JSONObject discrepancyAsJson = sourceDiscrepancies.getJSONObject(key);
-         Discrepancy sourceDiscrepancy = DispoUtil.jsonObjToDiscrepancy(discrepancyAsJson);
-
-         int sourceLocation = sourceDiscrepancy.getLocation();
-         String destDicrepancyText = destLocationToText.get(sourceLocation);
-         if (destDicrepancyText == null) {
-            // No Discrepancy with that location in the destination item, return false
-            toReturn = false;
-            break;
-         } else if (sourceDiscrepancy.getText().equals(destDicrepancyText)) {
-            continue;
-         } else {
-            toReturn = false;
-            break;
-         }
-
-      }
-      return toReturn;
-   }
-
-   private Map<Integer, String> generateLocationToTextMap(DispoItem item) throws JSONException {
-      Map<Integer, String> locationToText = new HashMap<Integer, String>();
-      JSONObject discrepancies = item.getDiscrepanciesList();
-      @SuppressWarnings("unchecked")
-      Iterator<String> iterator = discrepancies.keys();
-      while (iterator.hasNext()) {
-         String key = iterator.next();
-         JSONObject discrepancyAsJson = discrepancies.getJSONObject(key);
-         Discrepancy discrepancy = DispoUtil.jsonObjToDiscrepancy(discrepancyAsJson);
-         locationToText.put(discrepancy.getLocation(), discrepancy.getText());
-      }
-
-      return locationToText;
-   }
-}
diff --git a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/DispoSetCopier.java b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/DispoSetCopier.java
new file mode 100644
index 0000000..7a78d05
--- /dev/null
+++ b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/DispoSetCopier.java
@@ -0,0 +1,390 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Boeing.
+ * 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
+ *
+ * Contributors:
+ *     Boeing - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.osee.disposition.rest.internal.importer;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.osee.disposition.model.CopySetParamOption;
+import org.eclipse.osee.disposition.model.Discrepancy;
+import org.eclipse.osee.disposition.model.DispoAnnotationData;
+import org.eclipse.osee.disposition.model.DispoItem;
+import org.eclipse.osee.disposition.model.DispoItemData;
+import org.eclipse.osee.disposition.model.DispoStrings;
+import org.eclipse.osee.disposition.rest.internal.DispoConnector;
+import org.eclipse.osee.disposition.rest.internal.report.OperationReport;
+import org.eclipse.osee.disposition.rest.util.DispoUtil;
+import org.eclipse.osee.framework.jdk.core.util.Strings;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * @author Angel Avila
+ */
+public class DispoSetCopier {
+
+   private final DispoConnector connector;
+
+   public DispoSetCopier(DispoConnector connector) {
+      this.connector = connector;
+   }
+
+   public List<DispoItem> copyAllDispositions(Map<String, DispoItemData> nameToDestItems, Collection<DispoItem> sourceItems, boolean isCoverageCopy, OperationReport report) {
+      List<DispoItem> modifiedItems = new ArrayList<DispoItem>();
+
+      // Iterate through every source item since we want to try to find a match for every item in the source
+      for (DispoItem sourceItem : sourceItems) {
+         DispoItemData destItem = nameToDestItems.get(sourceItem.getName());
+
+         if (destItem != null) {
+            // Only try to copy over annotations if matching dest item is NOT PASS
+            if (!destItem.getStatus().equals(DispoStrings.Item_Pass)) {
+               DispoItemData newItem = createNewItemWithCopiedAnnotations(destItem, sourceItem, isCoverageCopy, report);
+               if (newItem != null) {
+                  modifiedItems.add(newItem);
+
+                  JSONArray destAnnotationsList = destItem.getAnnotationsList();
+                  report.addMessageForItem(destItem.getName(), "$$$$Had %s Dispositions$$$$\n",
+                     destAnnotationsList.length());
+                  report.addMessageForItem(destItem.getName(), "$$$$Now has %s Dispositions$$$$",
+                     newItem.getAnnotationsList().length());
+               }
+            } else if (!Strings.isValid(destItem.getGuid()) && !sourceItem.getStatus().equals(DispoStrings.Item_Pass)) {
+               /**
+                * In the case of Coverage, the destination Item is the item created by a new import so we assign it the
+                * id of the source so that it will overwrite the source date with the new import data
+                */
+               destItem.setGuid(sourceItem.getGuid());
+               modifiedItems.add(destItem);
+            }
+
+         } else {
+            report.addMessageForItem(sourceItem.getName(), "No matching item found in the Destination Set");
+         }
+      }
+      return modifiedItems;
+   }
+
+   private DispoItemData createNewItemWithCopiedAnnotations(DispoItemData destItem, DispoItem sourceItem, boolean isCoverageCopy, OperationReport report) {
+      DispoItemData toReturn = null;
+
+      try {
+         boolean isSameDiscrepancies = matchAllDiscrepancies(destItem, sourceItem);
+         if (isSameDiscrepancies) {
+            toReturn = buildNewItem(destItem, sourceItem, isCoverageCopy, report);
+         } else {
+            report.addMessageForItem(destItem.getName(),
+               "Tried to copy from item id: [%s] but discrepancies were not the same", sourceItem.getGuid());
+         }
+      } catch (JSONException ex) {
+         report.addOtherMessage("Item[%s] has bad JSON. Exception Message:[%s]", sourceItem.getName(), ex.getMessage());
+      }
+
+      return toReturn;
+   }
+
+   private DispoItemData buildNewItem(DispoItemData destItem, DispoItem sourceItem, boolean isCoverageCopy, OperationReport report) throws JSONException {
+      boolean isChangesMade = false;
+      DispoItemData newItem = initNewItem(destItem, sourceItem);
+      JSONArray newAnnotations = newItem.getAnnotationsList();
+      JSONArray sourceAnnotations = sourceItem.getAnnotationsList();
+      Set<String> destDefaultAnntationLocations = getDefaultAnnotations(newItem);
+
+      for (int i = 0; i < sourceAnnotations.length(); i++) {
+         JSONObject annotationJson = sourceAnnotations.getJSONObject(i);
+         DispoAnnotationData sourceAnnotation = DispoUtil.jsonObjToDispoAnnotationData(annotationJson);
+
+         String sourceLocation = sourceAnnotation.getLocationRefs();
+
+         // Check for ignore cases
+         if (DispoUtil.isDefaultAnntoation(sourceAnnotation)) {
+            /**
+             * This means this annotation is TEST_UNIT or Exception_Handling, so don't copy it over, only log if the
+             * destination item doesn't have this annotation as a Default i.e means something changed user should be
+             * aware.Currently only for Coverage
+             */
+            if (!destDefaultAnntationLocations.contains(sourceLocation)) {
+               report.addMessageForItem(destItem.getName(),
+                  "Did not copy annotations for location(s) [%s] because they are default annotations",
+                  sourceAnnotation.getLocationRefs());
+            }
+         } else if (isCoverageCopy && destDefaultAnntationLocations.contains(sourceLocation)) {
+            /**
+             * isCoverageCopy is true when annotation copier is called by a coverage import, this means we need to also
+             * check that the matching dest annotation isn't a DEFAULT resolution before copying over.
+             */
+            report.addMessageForItem(
+               destItem.getName(),
+               "Did not copy annotations for location(s) [%s] because the destination item already has a default annotations at these locations",
+               sourceAnnotation.getLocationRefs());
+         } else if (newAnnotations.toString().contains(sourceAnnotation.getGuid())) {
+            report.addMessageForItem(
+               destItem.getName(),
+               "Did not copy annotations for location(s) [%s] because the destination item already has this Annotation [%s]",
+               sourceAnnotation.getLocationRefs(), sourceAnnotation.getGuid());
+         } else {
+            DispoAnnotationData newAnnotation = sourceAnnotation;
+
+            if (destDefaultAnntationLocations.contains(sourceLocation)) {
+               /**
+                * The discrepancy of this manual disposition is now covered by a Default Annotation so this Manual
+                * Annotation is invalid, mark as such by making the location Ref negative, don't bother connecting the
+                * annotation
+                */
+               // Make location ref negative to indicate this 
+               String locationRefs = sourceAnnotation.getLocationRefs();
+               Integer locationRefAsInt = Integer.valueOf(locationRefs);
+               if (locationRefAsInt > 0) {
+                  newAnnotation.setLocationRefs(String.valueOf(locationRefAsInt * -1));
+               }
+               report.addMessageForItem(destItem.getName(),
+                  "The annotation was copied over but is no longer needed: [%s]", locationRefs);
+            }
+            connector.connectAnnotation(newAnnotation, newItem.getDiscrepanciesList());
+            isChangesMade = true;
+            // Both the source and destination are dispositionable so copy the annotation
+            int nextIndex = newAnnotations.length();
+            newAnnotation.setIndex(nextIndex);
+            newAnnotations.put(nextIndex, DispoUtil.annotationToJsonObj(newAnnotation));
+         }
+      }
+
+      if (isChangesMade) {
+         newItem.setAnnotationsList(newAnnotations);
+         String newStatus = connector.getItemStatus(newItem);
+         newItem.setStatus(newStatus);
+      } else {
+         report.addMessageForItem(destItem.getName(), "Nothing to copy");
+         newItem = null;
+      }
+      return newItem;
+   }
+
+   private DispoItemData initNewItem(DispoItemData destItem, DispoItem sourceItem) throws JSONException {
+      DispoItemData newItem = new DispoItemData();
+      newItem.setDiscrepanciesList(destItem.getDiscrepanciesList());
+      JSONArray newList = new JSONArray(destItem.getAnnotationsList().toString());
+      newItem.setAnnotationsList(newList);
+      if (Strings.isValid(destItem.getGuid())) {
+         newItem.setGuid(destItem.getGuid());
+      } else {
+         newItem.setGuid(sourceItem.getGuid());
+      }
+      newItem.setName(destItem.getName());
+      return newItem;
+   }
+
+   private Set<String> getDefaultAnnotations(DispoItemData item) throws JSONException {
+      Set<String> defaultAnnotationLocations = new HashSet<String>();
+      JSONArray annotations = item.getAnnotationsList();
+      if (annotations == null) {
+         annotations = new JSONArray();
+      }
+      for (int i = 0; i < annotations.length(); i++) {
+         JSONObject annotationJson = annotations.getJSONObject(i);
+         DispoAnnotationData annotation = DispoUtil.jsonObjToDispoAnnotationData(annotationJson);
+         if (DispoUtil.isDefaultAnntoation(annotation)) {
+            defaultAnnotationLocations.add(annotation.getLocationRefs());
+         }
+      }
+
+      return defaultAnnotationLocations;
+   }
+
+   private boolean matchAllDiscrepancies(DispoItemData destItem, DispoItem sourceItem) throws JSONException {
+      Map<Integer, String> destLocationToText = generateLocationToTextMap(destItem);
+      boolean toReturn = true;
+
+      JSONObject sourceDiscrepancies = sourceItem.getDiscrepanciesList();
+      @SuppressWarnings("unchecked")
+      Iterator<String> iterator = sourceDiscrepancies.keys();
+      while (iterator.hasNext()) {
+         String key = iterator.next();
+         JSONObject discrepancyAsJson = sourceDiscrepancies.getJSONObject(key);
+         Discrepancy sourceDiscrepancy = DispoUtil.jsonObjToDiscrepancy(discrepancyAsJson);
+
+         int sourceLocation = sourceDiscrepancy.getLocation();
+         String destDicrepancyText = destLocationToText.get(sourceLocation);
+         if (destDicrepancyText == null) {
+            // No Discrepancy with that location in the destination item, return false
+            toReturn = false;
+            break;
+         } else if (sourceDiscrepancy.getText().equals(destDicrepancyText)) {
+            continue;
+         } else {
+            toReturn = false;
+            break;
+         }
+
+      }
+      return toReturn;
+   }
+
+   private Map<Integer, String> generateLocationToTextMap(DispoItem item) throws JSONException {
+      Map<Integer, String> locationToText = new HashMap<Integer, String>();
+      JSONObject discrepancies = item.getDiscrepanciesList();
+      @SuppressWarnings("unchecked")
+      Iterator<String> iterator = discrepancies.keys();
+      while (iterator.hasNext()) {
+         String key = iterator.next();
+         JSONObject discrepancyAsJson = discrepancies.getJSONObject(key);
+         Discrepancy discrepancy = DispoUtil.jsonObjToDiscrepancy(discrepancyAsJson);
+         locationToText.put(discrepancy.getLocation(), discrepancy.getText());
+      }
+
+      return locationToText;
+   }
+
+   public void copyCategories(Map<String, DispoItemData> destinationItems, Collection<DispoItem> sourceItems, Map<String, DispoItem> toEdit, CopySetParamOption option) {
+      for (DispoItem sourceItem : sourceItems) {
+         DispoItem destItem = destinationItems.get(sourceItem.getName());
+
+         if (destItem != null) {
+            String currentCategory = destItem.getCategory();
+            String sourceCategory = sourceItem.getCategory();
+            String newCategory;
+
+            switch (option) {
+               case OVERRIDE:
+                  newCategory = sourceCategory;
+                  break;
+               case OVERRIDE_EMPTY:
+                  if (!Strings.isValid(currentCategory)) {
+                     newCategory = sourceCategory;
+                  } else {
+                     newCategory = currentCategory;
+                  }
+                  break;
+               case MERGE:
+                  if (!Strings.isValid(currentCategory)) {
+                     newCategory = sourceCategory;
+                  } else {
+                     newCategory = currentCategory + "::" + sourceCategory;
+                  }
+                  break;
+               case NONE:
+               default:
+                  newCategory = currentCategory;
+                  break;
+            }
+
+            // Check to see if this item is already set to be edited
+            DispoItem matchingToEdit = toEdit.get(sourceItem.getName());
+            if (matchingToEdit != null) {
+               ((DispoItemData) matchingToEdit).setCategory(newCategory);
+            } else {
+               DispoItemData newToEdit = new DispoItemData();
+               newToEdit.setGuid(destItem.getGuid());
+               newToEdit.setName(destItem.getName());
+               newToEdit.setCategory(newCategory);
+               toEdit.put(newToEdit.getName(), newToEdit);
+            }
+         }
+      }
+   }
+
+   public void copyAssignee(Map<String, DispoItemData> destinationItems, Collection<DispoItem> sourceItems, Map<String, DispoItem> toEdit, CopySetParamOption option) {
+      for (DispoItem sourceItem : sourceItems) {
+         DispoItem destItem = destinationItems.get(sourceItem.getName());
+
+         if (destItem != null) {
+            String currentAssignee = destItem.getAssignee();
+            String sourceAssignee = sourceItem.getAssignee();
+            String newAssignee;
+
+            switch (option) {
+               case OVERRIDE:
+                  newAssignee = sourceAssignee;
+                  break;
+               case OVERRIDE_EMPTY:
+                  if (currentAssignee.equalsIgnoreCase("UNASSIGNED")) {
+                     newAssignee = sourceAssignee;
+                  } else {
+                     newAssignee = currentAssignee;
+                  }
+                  break;
+               case MERGE:
+                  // Should not get here
+               case NONE:
+               default:
+                  newAssignee = currentAssignee;
+                  break;
+            }
+
+            // Check to see if this item is already set to be edited
+            DispoItem matchingToEdit = toEdit.get(sourceItem.getName());
+            if (matchingToEdit != null) {
+               ((DispoItemData) matchingToEdit).setAssignee(newAssignee);
+            } else {
+               DispoItemData newToEdit = new DispoItemData();
+               newToEdit.setGuid(destItem.getGuid());
+               newToEdit.setName(destItem.getName());
+               newToEdit.setAssignee(newAssignee);
+               toEdit.put(newToEdit.getName(), newToEdit);
+            }
+         }
+      }
+   }
+
+   public void copyNotes(Map<String, DispoItemData> destinationItems, Collection<DispoItem> sourceItems, Map<String, DispoItem> toEdit, CopySetParamOption option) {
+      for (DispoItem sourceItem : sourceItems) {
+         DispoItem destItem = destinationItems.get(sourceItem.getName());
+
+         if (destItem != null) {
+            String currentItemNotes = destItem.getItemNotes();
+            String sourceItemNotes = sourceItem.getItemNotes();
+            String newItemNotes;
+
+            switch (option) {
+               case OVERRIDE:
+                  newItemNotes = sourceItemNotes;
+                  break;
+               case OVERRIDE_EMPTY:
+                  if (!Strings.isValid(currentItemNotes)) {
+                     newItemNotes = sourceItemNotes;
+                  } else {
+                     newItemNotes = currentItemNotes;
+                  }
+                  break;
+               case MERGE:
+                  if (!Strings.isValid(currentItemNotes)) {
+                     newItemNotes = sourceItemNotes;
+                  } else {
+                     newItemNotes = currentItemNotes + "::" + sourceItemNotes;
+                  }
+                  break;
+               case NONE:
+               default:
+                  newItemNotes = currentItemNotes;
+                  break;
+            }
+
+            // Check to see if this item is already set to be edited
+            DispoItem matchingToEdit = toEdit.get(sourceItem.getName());
+            if (matchingToEdit != null) {
+               ((DispoItemData) matchingToEdit).setItemNotes(newItemNotes);
+            } else {
+               DispoItemData newToEdit = new DispoItemData();
+               newToEdit.setGuid(destItem.getGuid());
+               newToEdit.setName(destItem.getName());
+               newToEdit.setItemNotes(newItemNotes);
+               toEdit.put(newToEdit.getName(), newToEdit);
+            }
+         }
+      }
+   }
+}
diff --git a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/coverage/LisFileParser.java b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/coverage/LisFileParser.java
index bb36176..c1b6309 100644
--- a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/coverage/LisFileParser.java
+++ b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/internal/importer/coverage/LisFileParser.java
@@ -33,7 +33,7 @@
 import org.eclipse.osee.disposition.rest.DispoImporterApi;
 import org.eclipse.osee.disposition.rest.internal.DispoConnector;
 import org.eclipse.osee.disposition.rest.internal.DispoDataFactory;
-import org.eclipse.osee.disposition.rest.internal.importer.AnnotationCopier;
+import org.eclipse.osee.disposition.rest.internal.importer.DispoSetCopier;
 import org.eclipse.osee.disposition.rest.internal.report.OperationReport;
 import org.eclipse.osee.disposition.rest.util.DispoUtil;
 import org.eclipse.osee.framework.core.util.Result;
@@ -113,15 +113,16 @@
 
       // This is a reimport so we'll need to copy all the annotations
       if (!exisitingItems.isEmpty()) {
-         AnnotationCopier copier = new AnnotationCopier(dispoConnector);
-         try {
-            List<DispoItemData> itemsFromImport = new ArrayList<DispoItemData>();
-            itemsFromImport.addAll(values);
+         DispoSetCopier copier = new DispoSetCopier(dispoConnector);
+         List<DispoItemData> itemsFromImport = new ArrayList<DispoItemData>();
+         itemsFromImport.addAll(values);
 
-            toReturn = copier.copyEntireSet(itemsFromImport, exisitingItems.values(), false, report);
-         } catch (JSONException ex) {
-            //
+         Map<String, DispoItemData> nameToItem = new HashMap<String, DispoItemData>();
+         for (DispoItemData item : itemsFromImport) {
+            nameToItem.put(item.getName(), item);
          }
+
+         toReturn = copier.copyAllDispositions(nameToItem, exisitingItems.values(), false, report);
       } else {
          toReturn = new ArrayList<DispoItem>();
          toReturn.addAll(values);
diff --git a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/resources/DispoAdminResource.java b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/resources/DispoAdminResource.java
index ed3c9bc..93a9359 100644
--- a/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/resources/DispoAdminResource.java
+++ b/plugins/org.eclipse.osee.disposition.rest/src/org/eclipse/osee/disposition/rest/resources/DispoAdminResource.java
@@ -10,12 +10,13 @@
  *******************************************************************************/
 package org.eclipse.osee.disposition.rest.resources;
 
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Date;
+import javax.ws.rs.Consumes;
 import javax.ws.rs.Encoded;
 import javax.ws.rs.GET;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
@@ -24,6 +25,7 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.StreamingOutput;
+import org.eclipse.osee.disposition.model.CopySetParams;
 import org.eclipse.osee.disposition.model.DispoProgram;
 import org.eclipse.osee.disposition.model.DispoSet;
 import org.eclipse.osee.disposition.model.DispoSetData;
@@ -71,7 +73,7 @@
    @Path("/export")
    @GET
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
-   public Response postDispoSetExport(@Encoded @QueryParam("primarySet") String primarySet, @QueryParam("option") String option) throws FileNotFoundException {
+   public Response postDispoSetExport(@Encoded @QueryParam("primarySet") String primarySet, @QueryParam("option") String option) {
       final DispoSet dispoSet = dispoApi.getDispoSetById(program, primarySet);
       final ExportSet writer = new ExportSet(dispoApi);
       final String options = option;
@@ -91,14 +93,15 @@
    }
 
    @Path("/copy")
-   @GET
+   @POST
+   @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
-   public Response getDispoSetCopy(@Encoded @QueryParam("destinationSet") String destinationSet, @Encoded @QueryParam("sourceSet") String sourceSet) {
+   public Response getDispoSetCopy(@Encoded @QueryParam("destinationSet") String destinationSet, @Encoded @QueryParam("sourceSet") String sourceSet, CopySetParams params) {
       Response.Status status;
       final DispoSet destination = dispoApi.getDispoSetById(program, destinationSet);
       final DispoSet source = dispoApi.getDispoSetById(program, sourceSet);
 
-      String reportUrl = dispoApi.copyDispoSet(program, destination, source);
+      String reportUrl = dispoApi.copyDispoSet(program, destination, source, params);
       DispoSetData responseSet = new DispoSetData();
       responseSet.setOperationStatus(reportUrl);
 
diff --git a/plugins/org.eclipse.osee.disposition.rest/web/admin.html b/plugins/org.eclipse.osee.disposition.rest/web/admin.html
index 6632e36..64f91a2 100644
--- a/plugins/org.eclipse.osee.disposition.rest/web/admin.html
+++ b/plugins/org.eclipse.osee.disposition.rest/web/admin.html
@@ -17,7 +17,7 @@
                 <select class="form-control" ng-model="programSelection" ng-change="updateProgram()" ng-options="obj.value as obj.text for obj in programs"></select>
             </div>
             <div class="row" id=reportRow>
-                <div class="span3 offset1" id=reportContainer>
+                <div ng-show="sets.length > 0" class="span3 offset1" id=reportContainer>
                     <h3>STRS Report</h3>
                     <h5>Select Primary Set (Demo Set)</h5>
                     <select class="form-control" ng-model="primarySet" ng-options="obj.guid as obj.name for obj in sets"></select>
@@ -29,7 +29,7 @@
             
             <div class="row" id=setCopyRow>
                 <div class="span3 offset1" id=setCopyContainer>
-                    <button ng-click="openCopySetModal()" ng-hide="true" class="btn btn-primary active" id=generateReportBtn>Merge Annotations</button>
+                    <button ng-click="openCopySetModal()" ng-show="sets.length > 0" class="btn btn-primary active" id=generateReportBtn>Merge Annotations</button>
                 </div>
             </div>
             
@@ -71,17 +71,29 @@
         <div class="modal-header">
             <h3 class="modal-title">Copy Annotations</h3>
         </div>
-        <div class="modal-body" style="height: 300px; overflow: auto;">
+        <div class="modal-body" overflow: auto;">
             <div class="form-group">
 					 Select Destination Set
-                <select ng-model="destinationSet" ng-options="obj.guid as obj.name for obj in setsLocal">
+                <select class="form-control" ng-model="destinationSet" ng-options="obj.guid as obj.name for obj in setsLocal">
 					 </select>
             </div>
             <div class="form-group">
 					 Select Source Set
-                <select ng-model="sourceSet" ng-options="obj.guid as obj.name for obj in setsLocal">
+                <select class="form-control" ng-model="sourceSet" ng-options="obj.guid as obj.name for obj in setsLocal">
 					 </select>
             </div>
+
+			<div class="form-inline">
+				    <h5>Copy Dispositions</h5>
+                <select class="form-control" ng-model="annotationParam" ng-options="obj.value as obj.text for obj in annotationOptions"></select>
+				    <h5>Copy Categories</h5>
+                <select class="form-control" ng-model="categoryParam" ng-options="obj.value as obj.text for obj in categoryOptions"></select>
+				    <h5>Copy Assignees</h5>
+                <select class="form-control" ng-model="assigneeParam" ng-options="obj.value as obj.text for obj in assigneeOptions"></select>
+				    <h5>Copy Item Notes</h5>
+                <select class="form-control" ng-model="noteParam" ng-options="obj.value as obj.text for obj in noteOptions"></select>
+			</div>
+
         </div>
         <div class="modal-footer">
             <button class="btn btn-primary" ng-click="ok()">OK</button>
diff --git a/plugins/org.eclipse.osee.disposition.rest/web/js/adminController.js b/plugins/org.eclipse.osee.disposition.rest/web/js/adminController.js
index 90d0085..d45ad15 100644
--- a/plugins/org.eclipse.osee.disposition.rest/web/js/adminController.js
+++ b/plugins/org.eclipse.osee.disposition.rest/web/js/adminController.js
@@ -210,11 +210,17 @@
 		            }
 		        };
 		        
-		        $scope.copySet = function(destination, source)	 {
-		            CopySet.get({
+		        $scope.copySet = function(inputs)	 {
+		        	var copySetOp = new CopySet;
+		        	copySetOp.annotationParam = inputs.annotationParam;
+		        	copySetOp.categoryParam = inputs.categoryParam;
+		        	copySetOp.assigneeParam = inputs.assigneeParam;
+		        	copySetOp.noteParam = inputs.noteParam;
+		        	
+		        	copySetOp.$save({
 		                programId: $scope.programSelection,
-		                destinationSet: destination,
-		                sourceSet: source,
+		                destinationSet: inputs.destinationSet,
+		                sourceSet: inputs.sourceSet,
 		            }, function(data) {
 		            	var reportUrl = data.operationStatus;
 			            window.open(reportUrl);
@@ -267,18 +273,32 @@
 		            });
 
 		            modalInstance.result.then(function(inputs) {
-		                $scope.copySet(inputs.destinationSet, inputs.sourceSet);
+		                $scope.copySet(inputs);
 		            });
 		        }
 		        
 		        
 		        var CopySetModalCtrl = function($scope, $modalInstance, sets) {
 		            $scope.setsLocal = angular.copy(sets);
+		            $scope.annotationOptions = [{ value: 0, text: 'NONE'}, { value: 1, text: 'OVERRIDE'}];
+		            $scope.categoryOptions = [{ value: 0, text: 'NONE'}, { value: 1, text: 'OVERRIDE'}, { value: 2, text: 'ONLY COPY IF DEST IS EMPTY'}, { value: 3, text: 'MERGE DEST AND SOURCE'}];
+		            $scope.assigneeOptions = [{ value: 0, text: 'NONE'}, { value: 1, text: 'OVERRIDE'}, { value: 2, text: 'ONLY COPY IF DEST IS UNASSIGNED'}];
+		            $scope.noteOptions = [{ value: 0, text: 'NONE'}, { value: 1, text: 'OVERRIDE'}, { value: 2, text: 'ONLY COPY IF DEST IS EMPTY'}, { value: 3, text: 'MERGE DEST AND SOURCE'}];
+		            
+		            $scope.annotationParam = 0;
+		            $scope.categoryParam = 0;
+		            $scope.assigneeParam = 0;
+		            $scope.noteParam = 0;
 
 		            $scope.ok = function() {
 		                var inputs = {};
 		                inputs.destinationSet = this.destinationSet;
 		                inputs.sourceSet = this.sourceSet;
+		                inputs.annotationParam = this.annotationParam;
+		                inputs.categoryParam = this.categoryParam;
+		                inputs.noteParam = this.noteParam;
+		                inputs.assigneeParam = this.assigneeParam;
+		                
 		                $modalInstance.close(inputs);
 		            };
 
diff --git a/plugins/org.eclipse.osee.disposition.rest/web/js/dispoApp.js b/plugins/org.eclipse.osee.disposition.rest/web/js/dispoApp.js
index 11cde89..be4c67e 100644
--- a/plugins/org.eclipse.osee.disposition.rest/web/js/dispoApp.js
+++ b/plugins/org.eclipse.osee.disposition.rest/web/js/dispoApp.js
@@ -74,8 +74,8 @@
 app.provider('ExportSet', function() {
 	    this.$get = ['$resource',
 	        function($resource) {
-	            var CopySet = $resource('/dispo/program/:programId/admin/export', {}, {});
-	            return CopySet;
+	            var ExportSet = $resource('/dispo/program/:programId/admin/export', {}, {});
+	            return ExportSet;
 	        }
 	    ];
 	});