package orc;

import java.awt.Color;
import java.io.File;
import java.io.IOException;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;

import orc.ast.oil.Compiler;
import orc.ast.oil.Expr;
import orc.error.SourceLocation;
import orc.error.compiletime.CompilationException;
import orc.error.runtime.TokenException;
import orc.runtime.OrcEngine;
import orc.runtime.nodes.Node;
import orc.runtime.nodes.Pub;
import orc.runtime.values.Value;

import org.kohsuke.args4j.CmdLineException;

import com.apple.eawt.Application;
import com.apple.eawt.ApplicationAdapter;
import com.apple.eawt.ApplicationEvent;
import static javax.swing.SwingUtilities.invokeLater;

/**
 * First attempt at a GUI interface for Orc.
 * This outputs to its own window instead of the console.
 * @author quark
 */
public class OrcGUI {
	private OrcGUI() {}
	
	public static void main(String[] args) {
		// Read configuration options from the environment and the command line
		final Config cfg = new Config();
		cfg.processArgs(args);	
		run(cfg);
	}
	
	static void error(String title, String message) {
		JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE);
	}
	
	private static class OutputHandler {
		private StyledDocument doc;
		private JScrollBar scrollBar;
		private JFrame frame;
		public OutputHandler(JFrame frame, StyledDocument doc, JScrollBar scrollBar) {
			this.frame = frame;
			this.doc = doc;
			this.scrollBar = scrollBar;
		}
		public void output(final String style, final String message) {
			invokeLater(new Runnable() {
				public void run() {
					if (!frame.isVisible()) frame.setVisible(true);
					try {
						doc.insertString(doc.getLength(), message, doc.getStyle(style));
					} catch (BadLocationException e) {
						throw new AssertionError(e);
					}
					scrollBar.setValue(scrollBar.getMaximum());
				}
			});
		}
	}
	
	static void run(Config cfg) {
		// initialize document
		JTextPane pane = new JTextPane();
		pane.setEditable(false);
		StyledDocument doc = pane.getStyledDocument();
		
		//Initialize some styles.
		Style plain = doc.addStyle("plain",
			StyleContext.getDefaultStyleContext()
				.getStyle(StyleContext.DEFAULT_STYLE));
		StyleConstants.setFontFamily(plain, "SansSerif");
		Style s;
		s = doc.addStyle("print", plain);
		s = doc.addStyle("publish", plain);
		StyleConstants.setBold(s, true);
		s = doc.addStyle("error", plain);
		StyleConstants.setForeground(s, Color.RED);
		
		// initialize frame
		JFrame frame = new JFrame("Orc Output");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JScrollPane scrollPane = new JScrollPane(pane);
		frame.add(scrollPane);
		frame.pack();
		
		final OutputHandler output = new OutputHandler(frame, doc, scrollPane.getVerticalScrollBar());
		
		// Configure the runtime engine
		OrcEngine engine = new OrcEngine(cfg) {
			@Override
			public void print(String string, boolean newline) {
				output.output("print", string + (newline?"\n":""));
			}

			@Override
			public void publish(Object v) {
				output.output("publish", Value.write(v)+"\n");
			}

			@Override
			public void tokenError(TokenException problem) {
				output.output("error", "Error: " + problem.getMessage() + "\n");
				output.output("error", "Backtrace:\n");
				SourceLocation[] backtrace = problem.getBacktrace();
				for (SourceLocation location : backtrace) {
					output.output("error", location+"\n");
				}
				output.output("error", "\n");
			}
			
		};
		Node n;
		try {
			Expr ex = Orc.compile(cfg.getInstream(), cfg);
			n = Compiler.compile(ex, new Pub());
		} catch (CompilationException e) {
			error("Compilation Error", e.getMessage());
			return;
		} catch (IOException e) {
			error("Error Reading File", e.getMessage());
			return;
		}
		
		// Run the Orc program
		engine.run(n);
	}
}

@@ -2467,16 +2467,63 @@
 TYLE));%0A
+%09%09Style s;%0A%09%09s = doc.addStyle(%22print%22, plain);%0A
 %09%09StyleC
@@ -2545,21 +2545,17 @@
 tFamily(
-plain
+s
 , %22SansS
@@ -2560,32 +2560,24 @@
 sSerif%22);%0A%09%09
-Style s;
 %0A%09%09s = doc.a
@@ -2578,36 +2578,38 @@
  doc.addStyle(%22p
-rint
+ublish
 %22, plain);%0A%09%09s =
@@ -2609,41 +2609,56 @@
 ;%0A%09%09
-s = doc.addStyle(%22publish%22, plain
+StyleConstants.setFontFamily(plain, %22Monospaced%22
 );%0A%09
@@ -2691,16 +2691,19 @@
  true);%0A
+%09%09%0A
 %09%09s = do
@@ -2756,29 +2756,117 @@
 etFo
-reground(s, Color.RED
+ntFamily(plain, %22Monospaced%22);%0A%09%09StyleConstants.setForeground(s, Color.RED);%0A%09%09StyleConstants.setBold(s, true
 );%0A%09

Use monospaced font for errors and publications.