package relational.email;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import java.lang.reflect.*;
import java.util.*;
import java.rmi.RemoteException;
import relational.*;

/**
 * The panel that displays a single message. Can also be configured to allow
 * an outgoing message to be composed (edited) in the same view object.
 */
public class MessageView extends JPanel {
	JTextArea bodyArea, headerArea;
	JButton sendButton;
	boolean composing;

	Database sendDB = null;	// where to send outgoing messages

	public MessageView() {
		super();

		this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		headerArea = new JTextArea();
		headerArea.setLineWrap(true);
		headerArea.setWrapStyleWord(true);
		JScrollPane headerJSP = new JScrollPane(headerArea);
//		headerJSP.setMinimumSize(new Dimension(200, 20));
//		headerJSP.setPreferredSize(new Dimension(400, 100));

		bodyArea = new JTextArea();
		JScrollPane bodyJSP = new JScrollPane(bodyArea);
//		bodyJSP.setMinimumSize(new Dimension(200, 50));
//		bodyJSP.setPreferredSize(new Dimension(400, 300));

		JSplitPane splitp = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
			headerJSP, bodyJSP);
		splitp.setDividerLocation(100);
			// TODO: allocate just enough to show the "interesting" headers
			// that are present for this message.

		add(splitp);

		sendButton = new JButton("Send");
		sendButton.addActionListener(new SendListener());
		add(sendButton);

		setComposing(false);

		setPreferredSize(new Dimension(400, 100));
		setMinimumSize(new Dimension(100, 100));
	}

	public void loadMessage(Database db, Message m)
		throws RemoteException {

		sendDB = db;	// stash, since we don't know yet how we're handling
						// sends.

		Vector bv = InternalDatabase.select(db, Body.class,
			Where.equals(Body.f_msg, m.primaryKey));
		String bs;
		if (bv.size()>=1) {
			Body b = (Body) bv.elementAt(0);
			bs = b.body;
		} else {
			bs = "[No body]";
		}

		StringBuffer headers = new StringBuffer();
		Vector hv = InternalDatabase.select(db, Header.class,
			Where.equals(Header.f_msg, m.primaryKey));

		// priority mode: sort headers by priority, and
		// TODO: highlight the first couple headers.
		Collections.sort(hv, HeaderPriorityComparator.getComp());

		for (int i=0; i<hv.size(); i++) {
			Header h = (Header) hv.elementAt(i);
			// headers.append("<"+h.order+">");
			headers.append(h.name);
			headers.append(": ");
			headers.append(h.value);
			headers.append('\n');
		}
		loadMessage(headers.toString(), bs);
	}

	public void loadMessage(String headers, String body) {
		if (composing) {
			// don't destroy outgoing message!
			throw new RuntimeException("Hey, can't you see I'm composing a message here?");
		}
		try {
			Document bd = bodyArea.getDocument();
			bd.remove(0, bd.getLength());
			bd.insertString(0, body, null);
			// JScrollBar jsb = ((JScrollPane) bodyArea.getParent().getParent())
			//					.getVerticalScrollBar();
			// System.out.println("body scroll bar now: "+jsb.getValue());
			// System.out.println("body scroll min now: "+jsb.getMinimum());
			// jsb.setValue(jsb.getMinimum());
			// System.out.println("body scroll bar new: "+jsb.getValue());
			bodyArea.getCaret().setDot(0);
	
			Document hd = headerArea.getDocument();
			hd.remove(0, hd.getLength());
			hd.insertString(0, headers, null);
			headerArea.getCaret().setDot(0);
			// jsb = ((JScrollPane) headerArea.getParent().getParent())
			//					.getVerticalScrollBar();
			// jsb.setValue(jsb.getMinimum());
		} catch (BadLocationException ex) {
			ex.printStackTrace();
		}
	}

	public void setComposing(boolean state) {
		this.composing = state;
		headerArea.setEditable(composing);
		bodyArea.setEditable(composing);
		sendButton.setVisible(composing);
	}

	class SendListener
		implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			try {
				Database db = sendDB;
	
				// Create a new message
				Message m = new Message(db);
				m.insert();
	
				// parse headers
				Header lastHeader = null;
				Document hd = headerArea.getDocument();
				String hs = hd.getText(0, hd.getLength());
				StringTokenizer st = new StringTokenizer(hs, "\n");
				while (st.hasMoreTokens()) {
					String tok = st.nextToken();
					if (tok.startsWith("	") || tok.startsWith(" ")) {
						// append to previous header
						if (lastHeader==null) {
							throw new RuntimeException(
					"Unparseable headers (continuation as first header line.");
						}
						lastHeader.value += "\n"+tok;
						lastHeader.update();
					} else {
						int index = tok.indexOf(":");
						if (index<0) {
							throw new RuntimeException(
								"Unparseable headers (no colon).");
						}
						int index2=index+1; 
						while (index2<tok.length()
							&& Character.isWhitespace(tok.charAt(index2))) {
							index2++;
						}
						String hname = tok.substring(0, index);	// drop colon
						String hvalue = tok.substring(index2);
							// everything after colon and following whitespace
	
						Header newHeader = new Header(db);
						newHeader.setMsg(m);
						newHeader.name = hname;
						newHeader.value = hvalue;
						newHeader.insert();
						lastHeader = newHeader;
					}
				}
	
				// load body
				Document bd = bodyArea.getDocument();
				Body b = new Body(db);
				b.setMsg(m);
				b.body = bd.getText(0, bd.getLength());
				b.insert();

				setComposing(false);
			} catch (Exception ex) {
				throw new RuntimeException("Can't send message: "
					+ex.toString());
			}
		}
	}
}
