package edu.isi.karma.controller.command.worksheet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.TreeSet;
import org.json.JSONArray;
import org.json.JSONObject;
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.update.AddColumnUpdate;
import edu.isi.karma.controller.update.ErrorUpdate;
import edu.isi.karma.controller.update.UpdateContainer;
import edu.isi.karma.controller.update.WorksheetUpdateFactory;
import edu.isi.karma.rep.HNode;
import edu.isi.karma.rep.HNode.HNodeType;
import edu.isi.karma.rep.HNodePath;
import edu.isi.karma.rep.HTable;
import edu.isi.karma.rep.Node;
import edu.isi.karma.rep.Node.NodeStatus;
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.util.CommandInputJSONUtil;
import edu.isi.karma.util.JSONUtil;
import edu.isi.karma.util.Util;
import edu.isi.karma.webserver.KarmaException;
public class AddValuesCommand extends WorksheetSelectionCommand{
private final String hNodeId;
//add column to this table
private String hTableId;
//the id of the new column that was created
//needed for undo
private String newHNodeId;
private HNodeType type;
private String newColumnName = "";
private boolean isNewNode;
private static Logger logger = LoggerFactory
.getLogger(AddValuesCommand.class);
public enum JsonKeys {
updateType, hNodeId, worksheetId
}
protected AddValuesCommand(String id,String worksheetId,
String hTableId, String hNodeId, HNodeType type, String selectionId) {
super(id, worksheetId, selectionId);
this.hNodeId = hNodeId;
this.hTableId = hTableId;
isNewNode = false;
this.type = type;
addTag(CommandTag.Transformation);
}
@Override
public String getCommandName() {
return AddValuesCommand.class.getSimpleName();
}
@Override
public String getTitle() {
return "Add Values Command";
}
@Override
public String getDescription() {
return "";
}
@Override
public CommandType getCommandType() {
return CommandType.undoable;
}
@Override
public UpdateContainer doIt(Workspace workspace) throws CommandException {
Worksheet worksheet = workspace.getWorksheet(
worksheetId);
inputColumns.clear();
outputColumns.clear();
Object para = JSONUtil.createJson(this.getInputParameterJson());
String addValues = null;
HNode ndid = null;
try{
if (para instanceof JSONArray) {
//System.out.println("JSONArray:" + para);
addValues = CommandInputJSONUtil.getStringValue("AddValues", (JSONArray)para);
Object t = JSONUtil.createJson(addValues);
if (t instanceof JSONArray) {
JSONArray a = (JSONArray) t;
ndid = addColumn(workspace, worksheet, newColumnName, a);
}
}
WorksheetUpdateFactory.detectSelectionStatusChange(worksheetId, workspace, this);
UpdateContainer c = new UpdateContainer(new AddColumnUpdate(newHNodeId, worksheetId));
c.append(WorksheetUpdateFactory.createRegenerateWorksheetUpdates(worksheetId, getSuperSelection(worksheet)));
if (ndid == null) {
System.err.println("error: ndid");
}
c.append(computeAlignmentAndSemanticTypesAndCreateUpdates(workspace, ndid.getHNodePath(workspace.getFactory())));
return c;
} catch (Exception e) {
logger.error("Error in AddColumnCommand" + e.toString());
Util.logException(logger, e);
e.printStackTrace();
return new UpdateContainer(new ErrorUpdate(e.getMessage()));
}
}
@Override
public UpdateContainer undoIt(Workspace workspace) {
UpdateContainer c = new UpdateContainer();
Worksheet worksheet = workspace.getWorksheet(worksheetId);
HTable currentTable = workspace.getFactory().getHTable(hTableId);
HNode ndid = workspace.getFactory().getHNode(newHNodeId);
ndid.removeNestedTable();
//remove the new column
currentTable.removeHNode(newHNodeId, worksheet);
c.append(WorksheetUpdateFactory.createRegenerateWorksheetUpdates(worksheetId, getSuperSelection(worksheet)));
c.append(computeAlignmentAndSemanticTypesAndCreateUpdates(workspace));
return c;
}
public String getNewHNodeId() {
return newHNodeId;
}
public boolean isNewNode() {
return isNewNode;
}
public void setColumnName(String name) {
this.newColumnName = name;
}
private HNode addColumn(Workspace workspace, Worksheet worksheet, String newColumnName, JSONArray array) throws KarmaException {
if(hTableId==null || hTableId.isEmpty()){
//get table id based on the hNodeId
if(hNodeId==null)
hTableId = worksheet.getHeaders().getId();
else
hTableId = workspace.getFactory().getHNode(hNodeId).getHTableId();
}
HTable hTable = workspace.getFactory().getHTable(hTableId);
if(hTable == null)
{
logger.error("No HTable for id "+ hTableId);
throw new KarmaException("No HTable for id "+ hTableId );
}
//add new column to this table
//add column after the column with hNodeId
HNode ndid = null;
if (newColumnName != null && !newColumnName.trim().isEmpty()) {
if (hTable.getHNodeFromColumnName(newColumnName) != null) {
ndid = hTable.getHNodeFromColumnName(newColumnName);
outputColumns.add(ndid.getId());
}
else {
ndid = hTable.addNewHNodeAfter(hNodeId, type, workspace.getFactory(), newColumnName, worksheet,true);
outputColumns.add(ndid.getId());
isNewNode = true;
}
}
else {
ndid = hTable.addNewHNodeAfter(hNodeId, type, workspace.getFactory(), hTable.getNewColumnName("default"), worksheet,true);
outputColumns.add(ndid.getId());
isNewNode = true;
}
newHNodeId = ndid.getId();
//add as first column in the table if hNodeId is null
//HNode ndid = currentTable.addNewHNodeAfter(null, vWorkspace.getRepFactory(), newColumnName, worksheet,true);
if (array != null) {
populateRowsWithDefaultValues(worksheet, workspace.getFactory(), array, hTable);
}
//save the new hNodeId for undo
return ndid;
}
private void populateRowsWithDefaultValues(Worksheet worksheet, RepFactory factory, JSONArray array, HTable htable) {
SuperSelection selection = getSuperSelection(worksheet);
HNodePath selectedPath = null;
List<HNodePath> columnPaths = worksheet.getHeaders().getAllPaths();
for (HNodePath path : columnPaths) {
if (path.contains(factory.getHNode(newHNodeId))) {
if (path.getLeaf().getId().compareTo(newHNodeId) != 0) {
HNodePath hp = new HNodePath();
HNode hn = path.getFirst();
while (hn.getId().compareTo(newHNodeId) != 0) {
hp.addHNode(hn);
path = path.getRest();
hn = path.getFirst();
}
hp.addHNode(hn);
selectedPath = hp;
}
else
selectedPath = path;
}
}
Collection<Node> nodes = new ArrayList<Node>(Math.max(1000, worksheet.getDataTable().getNumRows()));
worksheet.getDataTable().collectNodes(selectedPath, nodes, selection);
for (Node node : nodes) {
for (int i = 0; i < array.length(); i++) {
if (array.get(i) instanceof JSONObject) {
JSONObject obj = (JSONObject)array.get(i);
if (node.getBelongsToRow().getId().compareTo(obj.getString("rowId")) == 0) {
Object t = obj.get("values");
if (t instanceof String) {
String value = (String)t;
addValues(node, value, factory, null);
}
else if (t instanceof JSONObject) {
addJSONObjectValues((JSONObject)t, worksheet, htable, factory, node.getBelongsToRow(), newHNodeId);
}
else if (t instanceof JSONArray) {
addJSONArrayValues((JSONArray)t, worksheet, htable, factory, node.getBelongsToRow(), newHNodeId);
}
}
}
}
}
}
private boolean addJSONArrayValues(JSONArray array, Worksheet worksheet, HTable htable, RepFactory factory, Row row, String newHNodeId) {
boolean flag = false;
for (int i = 0; i < array.length(); i++) {
JSONObject obj = (JSONObject)array.get(i);
flag |= addJSONObjectValues(obj, worksheet, htable, factory, row, newHNodeId);
}
return flag;
}
@SuppressWarnings("unchecked")
private boolean addJSONObjectValues(JSONObject obj, Worksheet worksheet, HTable htable, RepFactory factory, Row row, String newHNodeId) {
HNode ndid = htable.getHNode(newHNodeId);
HTable nestedHTable = ndid.getNestedTable();
if (nestedHTable == null)
nestedHTable = ndid.addNestedTable("Table for test",
worksheet, factory);
Table nestedTable = row.getNode(newHNodeId).getNestedTable();
Row r = nestedTable.addRow(factory);
boolean flag = false;
for (Object key : new TreeSet<Object>(obj.keySet())) {
Object value = obj.get(key.toString());
HNode h = nestedHTable.getHNodeFromColumnName(key.toString());
if ( h == null) {
h = nestedHTable.addHNode(key.toString(), type, worksheet, factory);
}
outputColumns.add(h.getId());
//
if (value instanceof String)
flag |= addValues(r.getNode(h.getId()), (String)value, factory, nestedTable);
if (value instanceof JSONObject)
flag |= addJSONObjectValues((JSONObject)value, worksheet, nestedHTable, factory, r, h.getId());
if (value instanceof JSONArray)
flag |= addJSONArrayValues((JSONArray) value, worksheet, nestedHTable, factory,r, h.getId());
}
if (!flag)
nestedTable.removeRow(r);
return flag;
}
private boolean addValues(Node node, String value, RepFactory factory, Table table) {
Worksheet worksheet = factory.getWorksheet(worksheetId);
SuperSelection selection = getSuperSelection(worksheet);
boolean flag = true;
if (table != null) {
for (Row r : table.getRows(0, table.getNumRows(), selection)) {
Node n = r.getNeighbor(node.getHNodeId());
if (n.getValue() != null && n.getValue().asString().compareTo(value) == 0) {
flag = false;
break;
}
}
}
if (flag)
node.setValue(value, NodeStatus.original, factory);
return flag;
}
}