package gov.nasa.jpl.mbee.mdk.mms.sync.delta;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.nomagic.magicdraw.core.Project;
import com.nomagic.magicdraw.core.ProjectUtilities;
import com.nomagic.magicdraw.esi.EsiUtils;
import com.nomagic.magicdraw.openapi.uml.ModelElementsManager;
import com.nomagic.magicdraw.openapi.uml.ReadOnlyElementException;
import com.nomagic.magicdraw.teamwork2.locks.ILockProjectService;
import com.nomagic.uml2.ext.jmi.helpers.ModelHelper;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Element;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.NamedElement;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Package;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.PackageableElement;
import gov.nasa.jpl.mbee.mdk.api.incubating.MDKConstants;
import gov.nasa.jpl.mbee.mdk.api.incubating.convert.Converters;
import gov.nasa.jpl.mbee.mdk.json.JacksonUtils;
import gov.nasa.jpl.mbee.mdk.util.Changelog;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* Created by igomes on 7/25/16.
*/
//@donbot update json simple to jackson
public class SyncElements {
private static final String CLEAR_SUFFIX = "_clear";
private static final DateFormat NAME_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH.mm.ss.SSSZ");
private static String getSyncPackageID(Project project) {
return Converters.getIProjectToIdConverter().apply(project.getPrimaryProject()) + MDKConstants.SYNC_SYSML_ID_SUFFIX;
}
public static Package getSyncPackage(Project project) {
String folderId = getSyncPackageID(project);
Element folder = Converters.getIdToElementConverter().apply(folderId, project);
return folder instanceof Package ? (Package) folder : null;
}
public static Collection<SyncElement> getAllOfType(Project project, SyncElement.Type type) {
Package syncPackage = getSyncPackage(project);
if (syncPackage == null) {
return Collections.emptySet();
}
Collection<PackageableElement> packagedElements = syncPackage.getPackagedElement();
Map<String, SyncElement> syncElements = new HashMap<>(packagedElements.size());
List<NamedElement> clearElements = new ArrayList<>(packagedElements.size());
for (Element element : packagedElements) {
if (!(element instanceof NamedElement)) {
continue;
}
String name = ((NamedElement) element).getName();
if (!name.startsWith(type.getPrefix())) {
continue;
}
if (name.endsWith(CLEAR_SUFFIX)) {
clearElements.add((NamedElement) element);
continue;
}
syncElements.put(name, new SyncElement((NamedElement) element, type));
}
for (NamedElement clearElement : clearElements) {
String name = clearElement.getName();
syncElements.remove(name.substring(0, name.length() - CLEAR_SUFFIX.length()));
}
return syncElements.values();
}
public static SyncElement setByType(Project project, SyncElement.Type type, String comment) {
Package syncPackage = getSyncPackage(project);
if (syncPackage == null) {
project.getCounter().setCanResetIDForObject(true);
syncPackage = project.getElementsFactory().createPackageInstance();
syncPackage.setOwner(project.getModel());
syncPackage.setName("__MMSSync__");
syncPackage.setID(getSyncPackageID(project));
}
Collection<PackageableElement> packagedElements = syncPackage.getPackagedElement();
Map<String, SyncElement> syncElements = new HashMap<>(packagedElements.size());
List<NamedElement> clearElements = new ArrayList<>(packagedElements.size());
for (Element element : packagedElements) {
if (!(element instanceof NamedElement)) {
continue;
}
String name = ((NamedElement) element).getName();
if (!name.startsWith(type.getPrefix())) {
continue;
}
if (name.endsWith(CLEAR_SUFFIX)) {
clearElements.add((NamedElement) element);
continue;
}
syncElements.put(name, new SyncElement((NamedElement) element, type));
}
// DELETE ALREADY CLEARED BLOCKS AND THEIR CLEAR BLOCKS (AND DANGLING CLEAR BLOCKS)
for (NamedElement clearElement : clearElements) {
if (!clearElement.isEditable()) {
continue;
}
String name = clearElement.getName();
String clearedElementName = name.substring(0, name.length() - CLEAR_SUFFIX.length());
SyncElement clearedSyncElement = syncElements.get(clearedElementName);
if (clearedSyncElement == null) {
// delete dangling clear blocks
try {
ModelElementsManager.getInstance().removeElement(clearElement);
} catch (ReadOnlyElementException e) {
e.printStackTrace();
}
continue;
}
syncElements.remove(clearedElementName);
if (!clearedSyncElement.getElement().isEditable()) {
continue;
}
try {
ModelElementsManager.getInstance().removeElement(clearedSyncElement.getElement());
ModelElementsManager.getInstance().removeElement(clearElement);
} catch (ReadOnlyElementException e) {
e.printStackTrace();
}
}
// PERSIST CONTENT
boolean isReusing = false;
NamedElement newSyncElementElement = null;
for (SyncElement syncElement : syncElements.values()) {
if (syncElement.getElement().isEditable()) {
newSyncElementElement = syncElement.getElement();
isReusing = true;
break;
}
}
if (newSyncElementElement == null) {
newSyncElementElement = project.getElementsFactory().createClassInstance();
newSyncElementElement.setOwner(syncPackage);
}
newSyncElementElement.setName(type.getPrefix() + "_" + NAME_DATE_FORMAT.format(new Date()));
ModelHelper.setComment(newSyncElementElement, comment);
// DELETE/CLEAR ALL OLD SYNC ELEMENTS OF SAME TYPE AND DANGLING CLEAR BLOCKS
for (SyncElement syncElement : syncElements.values()) {
// so it doesn't delete the one that we just updated
if (isReusing && syncElement.getElement() == newSyncElementElement) {
continue;
}
if (syncElement.getElement().isEditable()) {
try {
ModelElementsManager.getInstance().removeElement(syncElement.getElement());
continue;
} catch (ReadOnlyElementException e) {
e.printStackTrace();
}
}
NamedElement newClearElement = project.getElementsFactory().createClassInstance();
newClearElement.setName(syncElement.getElement().getName() + CLEAR_SUFFIX);
newClearElement.setOwner(syncPackage);
}
return new SyncElement(newSyncElementElement, type);
}
@SuppressWarnings("unchecked")
public static ObjectNode buildJson(Changelog<String, ?> changelog) {
ObjectNode objectNode = JacksonUtils.getObjectMapper().createObjectNode();
for (Changelog.ChangeType changeType : Changelog.ChangeType.values()) {
ArrayNode arrayNode = JacksonUtils.getObjectMapper().createArrayNode();
changelog.get(changeType).keySet().forEach(arrayNode::add);
objectNode.set(changeType.name().toLowerCase(), arrayNode);
}
return objectNode;
}
public static Changelog<String, Void> buildChangelog(SyncElement syncElement) {
String comment = ModelHelper.getComment(syncElement.getElement());
try {
JsonNode jsonNode = JacksonUtils.getObjectMapper().readTree(comment);
if (jsonNode != null && jsonNode.isObject()) {
return buildChangelog((ObjectNode) jsonNode);
}
} catch (IOException e) {
e.printStackTrace();
}
return new Changelog<>();
}
public static Changelog<String, Void> buildChangelog(ObjectNode objectNode) {
Changelog<String, Void> changelog = new Changelog<>();
for (Changelog.ChangeType changeType : Changelog.ChangeType.values()) {
JsonNode jsonNode = objectNode.get(changeType.name().toLowerCase());
if (jsonNode == null || !jsonNode.isArray()) {
continue;
}
for (JsonNode jsonNode1 : jsonNode) {
if (jsonNode1 == null || !jsonNode1.isTextual()) {
continue;
}
changelog.addChange(jsonNode1.asText(), null, changeType);
}
}
return changelog;
}
public static List<Element> lockSyncFolder(Project project) {
if (!ProjectUtilities.isFromEsiServer(project.getPrimaryProject())) {
return Collections.emptyList();
}
String folderId = Converters.getIProjectToIdConverter().apply(project.getPrimaryProject()) + MDKConstants.SYNC_SYSML_ID_SUFFIX;
Element folder = Converters.getIdToElementConverter().apply(folderId, project);
if (folder == null) {
return Collections.emptyList();
}
ILockProjectService lockService = EsiUtils.getLockService(project);
if (lockService == null) {
return Collections.emptyList();
}
Collection<Element> ownedElements = folder.getOwnedElement();
List<Element> lockedElements = new ArrayList<>(ownedElements.size());
for (Element element : folder.getOwnedElement()) {
if (element instanceof com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Class && !lockService.isLocked(element) && lockService.canBeLocked(element)) {
lockedElements.add(element);
}
}
if (!lockService.lockElements(lockedElements, false, null)) {
return Collections.emptyList();
}
return lockedElements;
}
}