package jmathlib.ui.swing; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Date; import java.text.DateFormat; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; public class CommandHistoryManager { private static CommandHistoryManager DEFAULT_INSTANCE; private static int AFTER_LAST = -99; private int selectedSession = 0; private int selectedIndex = AFTER_LAST; private Session currentSession; private ArrayList<Session> allSessions = new ArrayList<Session>(); private static final String SERIALIZED_FILENAME = "session_history.dat"; private static final String ROOT_NODENAME = "Sessions"; private static final String SESSION_NODENAME = "Session"; private static final String DATE_ATTRNAME = "Date"; private static final String COMMAND_NODENAME = "Command"; public static interface SessionCommandListener { public void commandAdded(Command command); } private ArrayList<SessionCommandListener> listeners; private CommandHistoryManager() { listeners = new ArrayList<SessionCommandListener>(); loadSessionHistory(); addSession(startCurrentSession()); resetToLastCommand(); } private void addSession(Session s) { allSessions.add(s); if (allSessions.size() > ApplicationConfiguration.getInstance().getIntProperty(ApplicationConfiguration.SESSION_HISTORY_SESSIONCOUNT_PROPERTY)) allSessions.remove(0); } public void addCommand(String command) { this.currentSession.addCommand(command); resetToLastCommand(); } public String nextCommand() { //Check if hanging off the end of the history if (selectedIndex == AFTER_LAST) { return null; } selectedIndex++; //Check to see if the index is outside the current session command size if (selectedIndex >= allSessions.get(selectedSession).commandCount()) { selectedSession++; selectedIndex = 0; //Check to see if we have wrapped to the end of all sessions if (selectedSession >= allSessions.size()) { selectedSession = allSessions.size() - 1; selectedIndex = AFTER_LAST; return ""; } } if (allSessions.get(selectedSession).commandCount() == 0) { return ""; } return allSessions.get(selectedSession).getCommand(selectedIndex).getCommand(); } public String prevCommand() { if (selectedSession < 0) { return null; } if ((selectedIndex == AFTER_LAST) && (allSessions.get(selectedSession).commandCount() > 0)) { selectedIndex = allSessions.get(selectedSession).commandCount() - 1; } else if (selectedIndex <= 0) { selectedSession--; if (selectedSession < 0) { selectedSession = 0; selectedIndex = 0; return null; } if (selectedSession >= 0 && allSessions.size() > selectedSession) { selectedIndex = allSessions.get(selectedSession).commandCount() - 1; } else { if (selectedSession < 0) { selectedSession = 0; } return null; } } else { selectedIndex--; // moving index to prev command } if (allSessions.get(selectedSession).commandCount() == 0) { return null; } return allSessions.get(selectedSession).getCommand(selectedIndex).getCommand(); } public String currentCommand() { if (selectedSession > 0 && selectedSession < allSessions.size()) { if (selectedIndex > 0 && selectedIndex < allSessions.get(selectedSession).commandCount()) { return allSessions.get(selectedSession).getCommand(selectedIndex).getCommand(); } } return null; } public void resetToLastCommand() { selectedSession = allSessions.size() - 1; selectedIndex = AFTER_LAST; } public void clearCurrentSession() { currentSession.clearCommands(); resetToLastCommand(); } private Session startCurrentSession() { this.currentSession = new Session(new Date(System.currentTimeMillis())); return this.currentSession; } private void fireCommandAdded(Command command) { for (int i = 0; i < this.listeners.size(); i++) { this.listeners.get(i).commandAdded(command); } } public void addChangeListener(SessionCommandListener listener) { this.listeners.add(listener); } public void removeChangeListener(SessionCommandListener listener) { this.listeners.remove(listener); } public int getSessionCount() { return this.allSessions.size(); } public Session getSession(int index) { return this.allSessions.get(index); } public int indexOfSession(Session session) { return this.allSessions.indexOf(session); } public class Session { private ArrayList<Command> commands; private Date startTime; public Session(Date sessionStartTime) { this.commands = new ArrayList<Command>(); this.startTime = sessionStartTime; } Command addCommand(String command) { Command c = new Command(this, command); this.commands.add(c); if (commands.size() > ApplicationConfiguration.getInstance().getIntProperty(ApplicationConfiguration.SESSION_HISTORY_SESSIONCMDCOUNT_PROPERTY)) commands.remove(0); fireCommandAdded(c); return c; } void clearCommands() { commands.clear(); } public int commandCount() { return this.commands.size(); } public Command getCommand(int index) { return this.commands.get(index); } public Date getStartTime() { return startTime; } public int indexOfCommand(String command) { return this.commands.indexOf(command); } public int compareTo(Object other) { return startTime.compareTo(((Session)other).startTime); } @Override public String toString() { return "Session: " + DateFormat.getDateTimeInstance().format(startTime); } } public class Command { private String command; private Session session; Command(Session session, String command) { this.command = command; this.session = session; } @Override public String toString() { return command; } public String getCommand() { return this.command; } public Session getSession() { return session; } } public static CommandHistoryManager getDefaultInstance() { if (DEFAULT_INSTANCE == null) { DEFAULT_INSTANCE = new CommandHistoryManager(); } return DEFAULT_INSTANCE; } /* * * Session Reading and Writting */ private void loadSessionHistory() { File dir = ApplicationConfiguration.getConfigurationDirectory(); if (dir != null) { File f = new File(dir, SERIALIZED_FILENAME); if (f.exists() && f.canRead()) { FileInputStream in = null; try { in = new FileInputStream(f); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse(in); Element root = doc.getDocumentElement(); Element[] kids = getElements(root); for (int i = 0; i < kids.length; i++) { if (kids[i].getNodeName().equals(SESSION_NODENAME)) { String dateString = kids[i].getAttribute(DATE_ATTRNAME); if (dateString == null) { continue; } long date = Long.parseLong(dateString, 16); Session s = new Session(new Date(date)); Element[] kids2 = getElements(kids[i]); for (int j = 0; j < kids2.length; j++) { if (kids2[j].getNodeName().equals(COMMAND_NODENAME)) { s.addCommand(kids2[j].getTextContent()); } } addSession(s); } } } catch (Exception ex) { //What more to do? //Need to create a message class to display errors. ex.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (Exception e) { //Do nothing. } } } } } } public void writeSessionHistory() { File dir = ApplicationConfiguration.getConfigurationDirectory(); if (dir != null) { File f = new File(dir, SERIALIZED_FILENAME); if (!f.exists() || f.canWrite()) { FileOutputStream out = null; try { out = new FileOutputStream(f); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.newDocument(); Element root = doc.createElement(ROOT_NODENAME); doc.appendChild(root); for (int i = 0; i < allSessions.size(); i++) { if (allSessions.get(i).commandCount() > 0) { Element elem = doc.createElement(SESSION_NODENAME); root.appendChild(elem); elem.setAttribute(DATE_ATTRNAME, Long.toHexString(allSessions.get(i).getStartTime().getTime()).toUpperCase()); for (int j = 0; j < allSessions.get(i).commandCount(); j++) { Element comElem = doc.createElement(COMMAND_NODENAME); comElem.setTextContent(allSessions.get(i).getCommand(j).getCommand()); elem.appendChild(comElem); } } } Transformer transformer = TransformerFactory.newInstance().newTransformer(); DOMSource source = new DOMSource(root); StreamResult result = new StreamResult(out); transformer.transform(source, result); } catch (Exception ex) { //TODO: Need to see if there is some sort of error reporting mechanism } finally { try { out.close(); } catch (IOException ex) { //Nothing can be done. } } } } } private static Element[] getElements(Element elem) { ArrayList<Element> children = new ArrayList<Element>(); Node node = elem.getFirstChild(); while (node != null) { switch (node.getNodeType()) { case Node.ELEMENT_NODE: children.add((Element) node); break; } node = node.getNextSibling(); } return children.toArray(new Element[0]); } }