import java.io.*;
import java.net.*;
import java.util.*;

import javax.net.ssl.*;
import java.security.cert.*;

import org.w3c.dom.Document;

/**
 * Arithmetic client
 */

public class Client {
    public static void main(String[] args) {
	new Client().go();
    }

    static BufferedReader stdin = new BufferedReader(
	new InputStreamReader(System.in));

    final int PORT = 3346;	// server port to connect to

    void go() {
	try {
	    SSLSocket sock = (SSLSocket) SSLSocketFactory.getDefault().createSocket(InetAddress.getByName("localhost"), PORT);
	    sock.setEnabledCipherSuites(sock.getSupportedCipherSuites());

	    // print out some interesting SSL parameters
	    SSLSession sess = sock.getSession();
	    System.out.println("-- SSL Session info --");
	    System.out.println("  CipherSuite = " + sess.getCipherSuite());
	    System.out.println("  Protocol = " + sess.getProtocol());
	    System.out.println("  PeerHost = " + sess.getPeerHost());
	    try {
		Certificate[] certs = sess.getPeerCertificates();
		for (int i=0; i<certs.length; ++i) {
		    System.out.println("  PeerCert = " + certs[i]);
		}
	    } catch (SSLPeerUnverifiedException ex) {
		System.out.println("Server NOT authenticated");
	    }
	    XMLSocketThread xml = new XMLSocketThread(sock);
	    Receiver rr = new Receiver(xml);
	    xml.setDOMProcessor(rr);
	    xml.start();

	    // main loop, asks for an expression, parses it, sends it
	    // to the server, and prints the response

	    while (true) {
		System.out.println();
		System.out.println("Enter an arithmetic expression");
		System.out.print("> ");
		String line = stdin.readLine();
		line = line.trim();
		if (line.length() == 0) continue;

		Document d = new Parser().eval(line);

		System.out.println();
		System.out.println("sending to server");
		XML.format(System.out, d);

		xml.send(d);	// send it
		
		d = rr.get();	// wait for response
		System.out.println();
		System.out.println("received from server");
		XML.format(System.out, d);
	    }
	    
	} catch (Exception ex) {
	    System.out.println("Shutting down because of exception");
	    ex.printStackTrace(System.out);
	}
    }

    /**
     * helper class implements DOMProcessor interface.  It gets notified
     * when response in received.  It uses a typical "blocking queue" pattern.
     */
    class Receiver implements DOMProcessor {
	XMLSocketThread xml;

	Receiver(XMLSocketThread xml) {
	    this.xml = xml;
	}

	LinkedList q = new LinkedList();

	/**
	 * This method blocks until there is something in the queue to return
	 */
	public synchronized Document get() {
	    while (q.isEmpty()) {
		try {
		    wait();
		} catch (InterruptedException ex) {
		    ex.printStackTrace();
		}
	    }
	    return (Document) q.removeFirst();
	}
	/**
	 * this method is called from the XMLSocketThread when a message from
	 * the server is received
	 */
	public synchronized void process(Document doc) {
	    q.add(doc);
	    notify();
	}
    }
}
