/**
* This file is part of CloudML [ http://cloudml.org ]
*
* Copyright (C) 2012 - SINTEF ICT
* Contact: Franck Chauvel <franck.chauvel@sintef.no>
*
* Module: root
*
* CloudML is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* CloudML is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with CloudML. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.cloudml.ui.shell;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.cloudml.facade.CloudML;
import org.cloudml.facade.commands.CloudMlCommand;
import org.cloudml.ui.shell.commands.Script;
import org.cloudml.ui.shell.commands.ShellCommand;
import org.cloudml.ui.shell.commands.ShellCommandHandler;
import org.cloudml.ui.shell.configuration.Command;
import org.cloudml.ui.shell.configuration.Configuration;
import org.cloudml.ui.shell.configuration.Loader;
import org.cloudml.ui.shell.terminal.Formatter;
import org.cloudml.ui.shell.terminal.InputDevice;
import org.cloudml.ui.shell.terminal.OutputDevice;
import static org.cloudml.ui.shell.terminal.Message.*;
import static org.cloudml.ui.shell.terminal.Color.*;
import static org.cloudml.ui.shell.util.dbc.Contracts.*;
import static org.hamcrest.Matchers.*;
/**
* The CloudML Shell
*
* It allows the user to interact with the models and, in turn, with the
* application deployed in the Cloud. This shell is based on the well-known
* "command pattern": the input of the user is first parsed to get a Command
* object, which can be stored or execute, or forwarded to the cloudML facade.
*
*/
public class Shell implements ShellCommandHandler {
private final CloudML proxy;
private final Configuration configuration;
private final History history;
private final InputDevice input;
private final Formatter output;
private final Mailbox mailbox;
private boolean running;
public Shell(InputDevice input, OutputDevice output, CloudML proxy) {
require(proxy, is(not(nullValue())));
this.proxy = proxy;
require(input, is(not(nullValue())));
this.input = input;
require(output, is(not(nullValue())));
this.output = new Formatter(output);
this.configuration = Loader.getInstance().getConfiguration();
this.history = new History(output, configuration);
this.mailbox = new Mailbox(output);
proxy.register(mailbox.new EventHandler());
}
/**
* Start the interaction with the user
*/
public void start() {
running = true;
displayOpening();
while (running) {
execute(prompt());
}
proxy.terminate();
}
private void displayOpening() {
output.print(format(configuration.getVersion()).eol().in(WHITE));
output.print(format(configuration.getCopyright()).eol().in(WHITE));
output.print(format(configuration.getLogo()).eol().in(CYAN));
output.print(format(configuration.getDisclaimer()).eol().in(WHITE));
}
private String prompt() {
if (mailbox.hasNewMessages()) {
output.print(format("%d new message(s).", mailbox.size()).eol().in(GREEN));
}
return input.prompt();
}
/**
* Parse and execute the command whose text is given as input
*
* @param text the text of the command to execute
*/
public void execute(String text) {
if (!text.isEmpty()) {
final ShellCommand command = ShellCommand.fromText(text);
history.record(command);
command.execute(this);
}
}
public void unknownCommand() {
output.print(format("command not supported yet!").in(RED));
}
public void exit() {
running = false;
output.print(format(configuration.getClosingMessage()).eol());
}
public void version() {
output.print(format(configuration.getVersion()).eol());
}
public void history(int depth) {
output.showHistory(history.selectLast(depth));
}
public void help(String subject) {
if (subject == null) {
output.showHelp(configuration.getCommands());
} else {
output.showHelp(findCommandAbout(subject));
}
}
private Command findCommandAbout(String subject) {
for(Command each: configuration.getCommands()) {
if (each.getSyntax().contains(subject)) {
return each;
}
}
return null;
}
public void dumpTo(int depth, String destination) {
try {
new Script(history.selectLast(depth)).toFile(destination);
output.success();
} catch (FileNotFoundException ex) {
output.error(format("Error: Unable to find in file '%s'. Is this path valid?", destination));
}
}
public void replay(String pathToScript) {
try {
ShellCommand script = ShellCommand.fromFile(pathToScript);
script.execute(this);
} catch (FileNotFoundException ex) {
output.print(format("Error: Unable to open the script at '%s'. Is this path valid?", pathToScript).eol().in(RED));
} catch (IOException ex) {
output.print(format("Error: Unexpected I/O error while reading the script at '%s'", pathToScript).eol().in(RED));
}
}
public void showMessages(int depth) {
mailbox.showMessages(depth);
}
public void delegate(CloudMlCommand command, boolean runInBackground) {
if (runInBackground) {
proxy.fireAndForget(command);
} else {
mailbox.followUp(command);
proxy.fireAndWait(command);
mailbox.discard(command);
}
}
}