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

public class XMLSocket implements Runnable {
	private Socket client = null;
	private InputStream is;
	private BufferedReader br;
	private OutputStream os;
	private PrintWriter pw;
	private LinkedList incoming = new LinkedList();
	private boolean done = false;
	private boolean throwit = true;
	private Thread thread = null;
	public XMLSocket(Socket client) throws IOException {
		this.client = client;
			os = client.getOutputStream();
			is = client.getInputStream();
			br = new BufferedReader(new InputStreamReader(is));
			pw = new PrintWriter(os,true);
		thread = new Thread(this);
		thread.start();
	}
	public void setThrowEvent(boolean t) {
		throwit = true;
	}
	
	//reader thread
	public void run() {
		while (!done) {
			try {
				String xml = getXML();
				System.err.println("Recv'd:"+xml);
				XMLString xmlStr = new XMLString(xml);
				incoming.add(xmlStr);
				if (throwit) {
					pcs.firePropertyChange("newMessage", null, xmlStr);
				}
			} catch (IOException e) {

			}
		}
	}
	public synchronized void sendMessage(String message) {
		pw.println(message);
	}
	public boolean hasMessage() {
		return (!incoming.isEmpty());
	}
	public XMLString getNextMessage() {
		return (XMLString)(incoming.removeFirst());
	}
	public void unPopMessage(XMLString xml) {
		incoming.addFirst(xml);
	}
	public void parseXML(XParser up,Reader read) throws SAXException,IOException {
		XMLReader xr = XMLReaderFactory.createXMLReader();
                xr.setContentHandler( up );
                xr.parse(new InputSource(read));
	}
	public 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();
			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();
	}
	private String getXML() throws IOException { //throw an exception
		String parent = "";
		String parentS = "<";
		String parentE =  ">";
		String parentTag = "";
		String endParent = "";
		String endParentS = "</";
		String endParentE = ">";
		boolean par = true;
		boolean body = false;
		boolean done = false;
		StringBuffer xml = new StringBuffer("");
		int parentIndex = 0;
		int count = 0;
		while (!done) {
			int chi = br.read();
			if (chi==-1) {
				done = true;
			}
			char ch = (char)chi;
			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 == 0) {
					if (ch == parentS.charAt(0)) {
						parentIndex++;
						parent = ""+ch;
					} else {
						parent = "";
						parentIndex = 0;
					}
				} else { //parent body
					if (ch == parentE.charAt(0)) {
						parent = parent + ch;
						parentTag = parent.substring(1,parent.length()-1);
						body = true;
						par = false;
						parentIndex = 0;
						endParent = endParentS + parentTag + endParentE;
						xml.append(parent);
					} else {
						parent = parent + ch;
						parentIndex++;
					}
				}
			}
		}
		return xml.toString();
	}
	private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
	public void addPropertyChangeListener( PropertyChangeListener pcl) { 
		pcs.addPropertyChangeListener(pcl);
	}
	public void addPropertyChangeListener(String propertyName, PropertyChangeListener pcl) {
		pcs.addPropertyChangeListener(propertyName,pcl);
	}
	public void close() throws IOException {
		client.close();
	}
}

