import java.net.*;
import java.io.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

public class NetworkHandler {
	private static NetworkHandler nh = null;
	private Socket client = null;
	static public InetAddress currentHost = null;
	static public int currentPort = 6783;
	private InetAddress host = null;
	private int port = 0;
	private InputStream is;
	private BufferedReader br;
	private OutputStream os;
	private PrintWriter pw;
	private static boolean newHost = false;
	public static void setCurrentHost(InetAddress i) {
		currentHost = i;
		newHost = true;
	}
	public static void setCurrentPort(int i) {
		currentPort = i;
		newHost = true;
	}
	public static InetAddress getCurrentHost() {
		return currentHost;
	}
	public static int setCurrentPort() {
		return currentPort;
	}
	public static NetworkHandler networkHandler() {
		if (nh == null) {
			if (currentHost == null) {
				try {
					currentHost = InetAddress.getLocalHost();
				} catch (java.net.UnknownHostException uhe) {
					System.err.println("LocalAddress Not Found!");
					System.exit(1);
				}
			}
			nh = new NetworkHandler(currentHost,currentPort);
		}
		return nh;
	}
	private NetworkHandler(InetAddress host,int port) {
		this.host = host;	
		this.port = port;
	}
	private void _connect() throws IOException {
		if (newHost && client!=null) {
			client.close();
			newHost = false;
		}
		if (client==null) {
			client = new Socket(host,port);
			os = client.getOutputStream();
			is = client.getInputStream();
			br = new BufferedReader(new InputStreamReader(is));
			pw = new PrintWriter(os,true);
			newHost = false;
		} 
	}
	public void disconnect(Connection conn) throws IOException {
		_connect();
		String out = "<disconnect><connection>"+conn.getID()+"</connection></disconnect>";
		pw.println(out);
	}
	public void unPatch(Connection connIn,Connection connOut)throws IOException  {
		_connect();
		pw.println("<unPatch><from>"+connIn.getID()+"</from><to>"+connOut.getID()+"</to></unPatch>");

	}
	public void patch(Connection connIn,Connection connOut) throws IOException{
		_connect();
		pw.println("<patch><from>"+connIn.getID()+"</from><to>"+connOut.getID()+"</to></patch>");

	}
	public Object [] getView() throws IOException {
		try {
			_connect();
			String out = "<request>update</request>";
			System.out.println(out);
			pw.println(out);
			String xml = getXML("update"); //catch exception
			System.err.println("We got :"+xml);
			if (xml == null) { throw new IOException("No input!"); }
			UpdateParser up = new UpdateParser();
			//parseXML(up,br);
			parseXML(up,xml);
			return up.getViewObjects();
		} catch (SAXException e) {
			throw new IOException(e.getMessage());
		}
	}
	private void parseXML(XParser up,Reader read) throws SAXException,IOException {
		XMLReader xr = XMLReaderFactory.createXMLReader();
                xr.setContentHandler( up );
                xr.parse(new InputSource(read));
	}
	private void parseXML(XParser up,String xml) throws SAXException,IOException {
		XMLReader xr = XMLReaderFactory.createXMLReader();
                xr.setContentHandler( up );
                xr.parse(new InputSource(new StringReader(xml)));
	}
	private String getXML(String parentTag) throws IOException { //throw an exception
		String parent = "<"+parentTag+">";
		String endParent = "</"+parentTag+">";
		boolean par = true;
		boolean body = false;
		boolean done = false;
		StringBuffer xml = new StringBuffer("");
		int parentIndex = 0;
		int count = 0;
		while (!done) {
			int ch = br.read();
			System.err.println((count++) + " - "+(char)ch);
			if (ch==-1) {
				done = true;
			}
			if (body) {
				if (ch == endParent.charAt(parentIndex) && parentIndex <  endParent.length()) {
					parentIndex++;
					if (parentIndex == endParent.length()) {
						done = true;
					}
				} else  {
					parentIndex = 0;
				}
				xml.append((char)ch);
			} else if (par == true) { 	//we can use a simple one because
						//of < > in XML
				if (parentIndex < parent.length() && ch == parent.charAt(parentIndex)) {
					parentIndex++;
					if (parentIndex == parent.length()) {
						xml.append(parent);
						body = true;
						par = false;
						parentIndex = 0;
					}
				} else {
					return null;
				}
			}
		}
		return xml.toString();
	}
}

