package edu.isi.karma.controller.command.worksheet; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import au.com.bytecode.opencsv.CSVReader; import edu.isi.karma.rep.CellValue; import edu.isi.karma.rep.HNode; 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; public class SplitColumnByDelimiter { private final String hNodeId; private final Worksheet worksheet; private final String delimiter; private final Workspace workspace; private String splitValueHNodeID; private final Logger logger = LoggerFactory.getLogger(this.getClass()); public SplitColumnByDelimiter(String hNodeId, Worksheet worksheet, String delimiter, Workspace workspace) { super(); this.hNodeId = hNodeId; this.worksheet = worksheet; this.delimiter = delimiter; this.workspace = workspace; } public String getSplitValueHNodeID() { return splitValueHNodeID; } public void split(HashMap<Node, CellValue> oldNodeValueMap, HashMap<Node, NodeStatus> oldNodeStatusMap) { RepFactory factory = workspace.getFactory(); HNode hNode = factory.getHNode(hNodeId); // The column should not have a nested table but check to make sure! if (hNode.hasNestedTable()) { logger.error("Column has nested table. Cannot perform split operation."); return; } HNodePath selectedPath = null; List<HNodePath> columnPaths = worksheet.getHeaders().getAllPaths(); for (HNodePath path : columnPaths) { if (path.getLeaf().getId().equals(hNodeId)) { hNode = path.getLeaf(); selectedPath = path; break; } } // Convert the delimiter into character primitive type char delimiterChar = ','; if (delimiter.equalsIgnoreCase("space")) delimiterChar = ' '; else if (delimiter.equalsIgnoreCase("tab")) delimiterChar = '\t'; else { delimiterChar = new Character(delimiter.charAt(0)); } Collection<Node> nodes = new ArrayList<Node>(); worksheet.getDataTable().collectNodes(selectedPath, nodes); //pedro: 2012-10-09 // Need to save and clear the values before adding the nested table. // Otherwise we have both a value and a nested table, which is not legal. for (Node node : nodes) { if (oldNodeValueMap != null) oldNodeValueMap.put(node, node.getValue()); if (oldNodeStatusMap != null) oldNodeStatusMap.put(node, node.getStatus()); node.clearValue(NodeStatus.edited); } //pedro: 2012-10-09 // Now that we cleared the values it is safe to add the nested table. // // Add the nested new HTable to the hNode HTable newTable = hNode.addNestedTable("Comma Split Values", worksheet, factory); splitValueHNodeID = newTable.addHNode("Values", worksheet, factory) .getId(); for (Node node : nodes) { //String originalVal = node.getValue().asString(); String originalVal = oldNodeValueMap.get(node).asString(); if (originalVal != null && !originalVal.equals("")) { // Split the values CSVReader reader = new CSVReader(new StringReader(originalVal), delimiterChar); try { String[] rowValues = reader.readNext(); if (rowValues == null || rowValues.length == 0) continue; // Get the nested table for the node Table table = node.getNestedTable(); // Add the row one by one for (int i = 0; i < rowValues.length; i++) { String rowVal = rowValues[i]; if (!rowVal.trim().equals("")) { Row row = table.addRow(factory); row.setValue(splitValueHNodeID, rowVal, NodeStatus.edited, factory); } } reader.close(); } catch (IOException e) { logger.error("Error reading Line: " + originalVal, e); } // Clear the old value node.clearValue(NodeStatus.edited); } } // Get the new path with new split value hNode as leaf // and replace the old one with it int oldPathIndex = columnPaths.indexOf(selectedPath); for (HNodePath path : worksheet.getHeaders().getAllPaths()) { if (path.getLeaf().getId().equals(splitValueHNodeID)) { selectedPath = path; } } columnPaths.set(oldPathIndex, selectedPath); } }