import java.util.*;
/*
* Nathaniel Lim CS334 HW8
*/
/**
* A simple TextEditor class. The Editor maintains a buffer of
* characters in the current "document", and updates the contents of
* the documents based on commands from the user. While a real text
* editor would recieve keystroke and mouse events through the GUI, we
* will use commands entered a terminal prompt to change the buffer.
* See the handout for a list of supported commands.
*
*/
public class TextEditor {
/** The "document" that the editor operates on. */
protected Buffer buffer;
/** The scanner for reading input. */
protected Scanner input;
/** The Stack of EditCommands performed that have been executed */
protected Stack<EditCommand> history = new Stack<EditCommand>();
/** The Stack of EditCommands performed that have been undone */
protected Stack<EditCommand> commandsUndone = new Stack<EditCommand>();
/**
* Default constructor creates an empty buffer. Pass in the
* Scanner from which to read commands.
*/
public TextEditor(Scanner input) {
buffer = new Buffer();
this.input = input;
}
/**
* Return the current cursor position in the buffer.
*/
protected int getCursor() {
return buffer.getCursor();
}
/**
* Set the current cursor position in the buffer.
* <p>
* Clips the cursor movement to the ends of the buffer. Ie, if loc
* < 0, move cursor to 0, and if loc > buffer.size() move cursor
* to buffer.size().
*/
protected void setCursor(int loc) {
if (loc < 0) {
loc = 0;
}
if (loc > buffer.size()) {
loc = buffer.size();
}
buffer.setCursor(loc);
}
/**
* Insert the given text into the buffer at the current cursor
* position and move the cursor to the end of the inserted text.
*/
protected void insert(String text) {
buffer.insert(text);
buffer.setCursor(buffer.getCursor() + text.length());
}
/**
* Delete count characters to the right of the cursor.
*
* <pre> pre: You must not delete past end of buffer </pre>
*/
protected void delete(int count) {
buffer.delete(count);
}
/**
* Undo the previous editing command
* (either a move, insert, or delete).
*/
protected void undo() {
if (!history.isEmpty()){
EditCommand toBeUndone = history.pop();
toBeUndone.undo();
commandsUndone.push(toBeUndone);
}
}
/**
* Print the commands on the undo stack.
*/
protected void printHistory() {
Stack<EditCommand> toPrint = new Stack<EditCommand>();
Iterator<EditCommand> it = history.iterator();
while (it.hasNext()){
toPrint.push(it.next());
}
Iterator<EditCommand> it2 = toPrint.iterator();
while(it2.hasNext()){
System.out.println(it2.next());
}
}
/**
* Redo the last undone editing command, if possible
*/
protected void redo() {
if (!commandsUndone.isEmpty()){
EditCommand toBeRedone = commandsUndone.pop();
toBeRedone.execute();
history.push(toBeRedone);
}
}
/**
* Return the contents of the buffer.
*/
public String toString() {
return buffer.toString();
}
/**
* Read the next piece of input from Scanenr in as an integer, if
* it is in fact an integer. Otherwise, return 1 if there is no
* input or generate an exception if there is something
* unexpected.
*/
protected int readOptionalInt(Scanner in) {
if (in.hasNextInt()) {
return in.nextInt();
} else if (in.hasNext()) {
throw new InputMismatchException("Missing number");
} else {
return 1;
}
}
/**
* Read and process one command from the user. Returns true if
* additional commands should be read, or false if the user has
* quit.
*/
public boolean processOneCommand() {
System.out.print("? ");
if (!input.hasNext()) return false; // end of input
// create temp scanner for one line of input
String commandStr = input.nextLine();
Scanner commandScanner = new Scanner(commandStr);
try {
String letter = commandScanner.next().toUpperCase();
if (letter.equals("I")) {
commandScanner.skip(" "); // skip space after 'I'
String text = commandScanner.nextLine();
//Construct a new InsertCommmand
InsertCommand ic = new InsertCommand(buffer, text);
ic.execute();
history.push(ic);
} else if (letter.equals("D")) {
//Construct a new DeleteCommand
DeleteCommand dc = new DeleteCommand(buffer, readOptionalInt(commandScanner));
dc.execute();
history.push(dc);
//delete(readOptionalInt(commandScanner));
} else if (letter.equals("<")) {
boolean left = true;
//Constuct a new MoveCommand, with the left boolean flag
MoveCommand mc = new MoveCommand(buffer, readOptionalInt(commandScanner), left);
mc.execute();
history.push(mc);
//setCursor(getCursor() - readOptionalInt(commandScanner));
} else if (letter.equals(">")) {
boolean left = false;
//Constuct a new MoveCommand, with the left boolean flag
MoveCommand mc = new MoveCommand(buffer, readOptionalInt(commandScanner), left);
mc.execute();
history.push(mc);
//setCursor(getCursor() + readOptionalInt(commandScanner));
} else if (letter.equals("U")) {
undo();
} else if (letter.equals("R")) {
redo();
} else if (letter.equals("P")) {
printHistory();
} else if (letter.equals("Q")) {
return false;
} else {
System.out.println("Invalid command: '" + commandStr + "'");
}
} catch (InputMismatchException e) {
// when there is a non-number where number expected
System.out.println("Invalid Command: '" + commandStr + "'");
} catch (NoSuchElementException e) {
// when there is no input left when input is still expected
System.out.println("Invalid Command: '" + commandStr + "'");
}
return true;
}
/**
* Create a new TextEditor that reads commands from the terminal
* window. Process commands until the user enters "Q".
*/
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
TextEditor editor = new TextEditor(input);
while (true) {
System.out.println(editor.toString());
if (!editor.processOneCommand()) break;
}
}
}