package edu.isi.karma.controller.command.worksheet; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import edu.isi.karma.controller.command.CommandException; import edu.isi.karma.controller.command.CommandType; import edu.isi.karma.controller.command.WorksheetSelectionCommand; import edu.isi.karma.controller.command.selection.SuperSelection; import edu.isi.karma.controller.command.selection.SuperSelectionManager; import edu.isi.karma.controller.update.ErrorUpdate; import edu.isi.karma.controller.update.UpdateContainer; import edu.isi.karma.controller.update.WorksheetDeleteUpdate; import edu.isi.karma.controller.update.WorksheetListUpdate; import edu.isi.karma.controller.update.WorksheetUpdateFactory; import edu.isi.karma.er.helper.CloneTableUtils; import edu.isi.karma.modeling.alignment.Alignment; import edu.isi.karma.modeling.alignment.AlignmentManager; import edu.isi.karma.rep.HNode; import edu.isi.karma.rep.HNode.HNodeType; import edu.isi.karma.rep.HTable; import edu.isi.karma.rep.HashValueManager; import edu.isi.karma.rep.Node; import edu.isi.karma.rep.RepFactory; import edu.isi.karma.rep.Row; import edu.isi.karma.rep.Table; import edu.isi.karma.rep.Worksheet; import edu.isi.karma.rep.Workspace; import edu.isi.karma.rep.metadata.WorksheetProperties.Property; import edu.isi.karma.util.Util; public class UnfoldCommand extends WorksheetSelectionCommand { //add column to this table //the id of the new column that was created //needed for undo private String newWorksheetId; private String newHNodeId; private String keyHNodeId; private String valueHNodeId; private String keyName; private String valueName; private boolean notOtherColumn; private static Logger logger = LoggerFactory .getLogger(FoldCommand.class); public enum JsonKeys { updateType, hNodeId, worksheetId } protected UnfoldCommand(String id, String model, String worksheetId, String keyHNodeid, String valueHNodeid, boolean notOtherColumn, String selectionId) { super(id, model, worksheetId, selectionId); newWorksheetId = null; newHNodeId = null; this.keyHNodeId = keyHNodeid; this.valueHNodeId = valueHNodeid; this.notOtherColumn = notOtherColumn; addTag(CommandTag.Transformation); } @Override public String getCommandName() { return this.getClass().getSimpleName(); } @Override public String getTitle() { return "Unfold"; } @Override public String getDescription() { return keyName + " <b>with</b> " + valueName; } @Override public CommandType getCommandType() { return CommandType.undoable; } @Override public UpdateContainer doIt(Workspace workspace) throws CommandException { RepFactory factory = workspace.getFactory(); inputColumns.clear(); outputColumns.clear(); Worksheet oldws = workspace.getWorksheet( worksheetId); Worksheet newws = null; HTable ht = factory.getHTable(factory.getHNode(keyHNodeId).getHTableId()); if (ht == oldws.getHeaders()) { newws = unfoldTopLevel(oldws, keyHNodeId, valueHNodeId, workspace, factory); this.newWorksheetId = newws.getId(); } else { try { inputColumns.add(keyHNodeId); inputColumns.add(valueHNodeId); unfoldNestedLevel(oldws, ht, keyHNodeId, valueHNodeId, factory); }catch(Exception e) { e.printStackTrace(); } } try{ UpdateContainer c = new UpdateContainer(); c.add(new WorksheetListUpdate()); if (newws == null) c.append(WorksheetUpdateFactory.createRegenerateWorksheetUpdates(oldws.getId(), getSuperSelection(oldws), workspace.getContextId())); if (newws != null) { c.append(WorksheetUpdateFactory.createRegenerateWorksheetUpdates(newws.getId(), SuperSelectionManager.DEFAULT_SELECTION, workspace.getContextId())); c.append(WorksheetUpdateFactory.createSemanticTypesAndSVGAlignmentUpdates(newws.getId(), workspace)); } c.append(computeAlignmentAndSemanticTypesAndCreateUpdates(workspace)); return c; } catch (Exception e) { WorksheetUpdateFactory.detectSelectionStatusChange(worksheetId, workspace, this); logger.error("Error in UnfoldCommand" + e.toString()); Util.logException(logger, e); return new UpdateContainer(new ErrorUpdate(e.getMessage())); } } @Override public UpdateContainer undoIt(Workspace workspace) { UpdateContainer c = new UpdateContainer(); if (this.newWorksheetId != null) { workspace.removeWorksheet(newWorksheetId); workspace.getFactory().removeWorksheet(newWorksheetId, workspace.getCommandHistory()); c.add(new WorksheetListUpdate()); c.add(new WorksheetDeleteUpdate(newWorksheetId)); } if (this.newHNodeId != null) { Worksheet worksheet = workspace.getWorksheet(worksheetId); HNode ndid = workspace.getFactory().getHNode(newHNodeId); HTable currentTable = workspace.getFactory().getHTable(ndid.getHTableId()); ndid.removeNestedTable(); //remove the new column currentTable.removeHNode(newHNodeId, worksheet); c.append(WorksheetUpdateFactory.createRegenerateWorksheetUpdates(worksheetId, getSuperSelection(worksheet), workspace.getContextId())); c.append(computeAlignmentAndSemanticTypesAndCreateUpdates(workspace)); } return c; } public void setValueName(String valueName) { this.valueName = valueName; } public void setKeyName(String keyName) { this.keyName = keyName; } private void unfoldNestedLevel(Worksheet oldws, HTable ht, String keyHNodeid, String valueHNodeid, RepFactory factory) { ArrayList<HNode> topHNodes = new ArrayList<>(ht.getHNodes()); SuperSelection selection = getSuperSelection(oldws); HTable parentHT = ht.getParentHNode().getHTable(factory); List<Table> parentTables = new ArrayList<>(); CloneTableUtils.getDatatable(oldws.getDataTable(), parentHT,parentTables, selection); ArrayList<Row> parentRows = new ArrayList<>(); for (Table tmp : parentTables) { for (Row row : tmp.getRows(0, tmp.getNumRows(), selection)) { parentRows.add(row); } } //ArrayList<Row> parentRows = parentTable.getRows(0, parentTable.getNumRows()); HNode newNode = parentHT.addHNode("Unfold: " + ht.getHNode(keyHNodeid).getColumnName(), HNodeType.Transformation, oldws, factory); outputColumns.add(newNode.getId()); this.newHNodeId = newNode.getId(); HTable newHT = newNode.addNestedTable("Unfold: " + ht.getHNode(keyHNodeid).getColumnName(), oldws, factory); HNode key = ht.getHNode(keyHNodeid); HNode value = ht.getHNode(valueHNodeid); List<HNode> hnodes = new ArrayList<>(); List<String> hnodeIds = new ArrayList<>(); if (!notOtherColumn) { for (HNode h : topHNodes) { if (h.getId().compareTo(value.getId()) != 0 && h.getId().compareTo(key.getId()) != 0) { hnodes.add(h); hnodeIds.add(h.getId()); } } } for (Entry<String, String> entry : CloneTableUtils.cloneHTable(newHT, oldws, factory, hnodes, false).entrySet()) { outputColumns.add(entry.getValue()); } List<Row> resultRows = new ArrayList<>(); for (Row parentRow: parentRows) { Table t = null; for (Node node : parentRow.getNodes()) { if (node.hasNestedTable() && node.getNestedTable().getHTableId().compareTo(ht.getId()) == 0) { t = node.getNestedTable(); break; } } Map<String, String> keyMapping = new HashMap<>(); Map<String, String> HNodeidMapping = new HashMap<>(); ArrayList<Row> rows = t.getRows(0, t.getNumRows(), selection); for (Row row : rows) { Node n = row.getNode(key.getId()); keyMapping.put(HashValueManager.getHashValue(oldws, n.getId(), factory), n.getValue().asString()); } for (Entry<String, String> stringStringEntry : keyMapping.entrySet()) { HNode hn = newHT.getHNodeFromColumnName(stringStringEntry.getValue().toLowerCase().replace('/', '_')); if (hn == null) { HNode n = newHT.addHNode(stringStringEntry.getValue().toLowerCase().replace('/', '_'), HNodeType.Transformation, oldws, factory); outputColumns.add(n.getId()); HTable htt = n.addNestedTable("values", oldws, factory); outputColumns.add(htt.addHNode("Values", HNodeType.Transformation, oldws, factory).getId()); HNodeidMapping.put(stringStringEntry.getValue(), n.getId()); } else HNodeidMapping.put(stringStringEntry.getValue(), hn.getId()); } Map<String, ArrayList<String>> hash = new HashMap<>(); for (Row row : rows) { String hashValue = HashValueManager.getHashValue(row, hnodeIds); ArrayList<String> ids = hash.get(hashValue); if (ids == null) ids = new ArrayList<>(); ids.add(row.getId()); hash.put(hashValue, ids); //System.out.println("Hash: " + HashValueManager.getHashValue(row, hnodeIDs)); } for (Entry<String, ArrayList<String>> stringArrayListEntry : hash.entrySet()) { ArrayList<String> r = stringArrayListEntry.getValue(); Node node = parentRow.getNeighbor(newNode.getId()); Row lastRow = CloneTableUtils.cloneDataTable(factory.getRow(r.get(0)), node.getNestedTable(), newHT, hnodes, factory, selection); for (String rowid : r) { Row cur = factory.getRow(rowid); String newId = HNodeidMapping.get(cur.getNode(key.getId()).getValue().asString()); Node newnode = lastRow.getNode(newId); Node oldnode = cur.getNode(value.getId()); Row tmprow = newnode.getNestedTable().addRow(factory); tmprow.getNeighborByColumnName("Values", factory).setValue(oldnode.getValue().asString(), oldnode.getStatus(), factory); //newnode.setValue(oldnode.getValue().asString(), oldnode.getStatus(), factory); } resultRows.add(lastRow); } } for (Row tmpRow : resultRows) { for (Node node : tmpRow.getNodes()) { if (node.hasNestedTable()) { Table tmpTable = node.getNestedTable(); if (tmpTable.getNumRows() == 0) { tmpTable.addRow(factory); } } } } } private Worksheet unfoldTopLevel(Worksheet oldws, String keyHNodeid, String valueHNodeid, Workspace workspace, RepFactory factory) { Worksheet newws = factory.createWorksheet("Unfold: " + oldws.getTitle(), workspace, oldws.getEncoding()); SuperSelection selection = getSuperSelection(oldws); newws.getMetadataContainer().getWorksheetProperties().setPropertyValue(Property.sourceType, oldws.getMetadataContainer().getWorksheetProperties().getPropertyValue(Property.sourceType)); ArrayList<HNode> topHNodes = new ArrayList<>(oldws.getHeaders().getHNodes()); ArrayList<Row> rows = oldws.getDataTable().getRows(0, oldws.getDataTable().getNumRows(), selection); HNode key = oldws.getHeaders().getHNode(keyHNodeid); HNode value = oldws.getHeaders().getHNode(valueHNodeid); List<HNode> hnodes = new ArrayList<>(); List<String> hnodeIds = new ArrayList<>(); if (!notOtherColumn) { for (HNode h : topHNodes) { if (h.getId().compareTo(value.getId()) != 0 && h.getId().compareTo(key.getId()) != 0) { hnodes.add(h); hnodeIds.add(h.getId()); } } } CloneTableUtils.cloneHTable(newws.getHeaders(), newws, factory, hnodes, false); Map<String, String> keyMapping = new HashMap<>(); Map<String, String> HNodeidMapping = new HashMap<>(); for (Row row : rows) { Node n = row.getNode(key.getId()); keyMapping.put(HashValueManager.getHashValue(oldws, n.getId(), factory), n.getValue().asString()); } for (Entry<String, String> stringStringEntry : keyMapping.entrySet()) { HNode n = newws.getHeaders().addHNode(stringStringEntry.getValue(), HNodeType.Transformation, newws, factory); HTable ht = n.addNestedTable("values", newws, factory); ht.addHNode("Values", HNodeType.Transformation, newws, factory); HNodeidMapping.put(stringStringEntry.getValue(), n.getId()); } Map<String, ArrayList<String>> hash = new TreeMap<>(); for (Row row : rows) { String hashValue = HashValueManager.getHashValue(row, hnodeIds); ArrayList<String> ids = hash.get(hashValue); if (ids == null) ids = new ArrayList<>(); ids.add(row.getId()); hash.put(hashValue, ids); } List<Row> resultRows = new ArrayList<>(); for (Entry<String, ArrayList<String>> stringArrayListEntry : hash.entrySet()) { ArrayList<String> r = stringArrayListEntry.getValue(); Row lastRow = CloneTableUtils.cloneDataTable(factory.getRow(r.get(0)), newws.getDataTable(), newws.getHeaders(), hnodes, factory, selection); for (String rowid : r) { Row cur = factory.getRow(rowid); String newId = HNodeidMapping.get(cur.getNode(key.getId()).getValue().asString()); Node newnode = lastRow.getNode(newId); Node oldnode = cur.getNode(value.getId()); Row tmprow = newnode.getNestedTable().addRow(factory); tmprow.getNeighborByColumnName("Values", factory).setValue(oldnode.getValue().asString(), oldnode.getStatus(), factory); //newnode.setValue(oldnode.getValue().asString(), oldnode.getStatus(), factory); } resultRows.add(lastRow); } for (Row tmpRow : resultRows) { for (Node node : tmpRow.getNodes()) { if (node.hasNestedTable()) { Table tmpTable = node.getNestedTable(); if (tmpTable.getNumRows() == 0) { tmpTable.addRow(factory); } } } } return newws; } }