package no.divvun.Analyzer.Communication;

import java.io.*;
import javax.xml.parsers.*;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class ResponseParser extends DefaultHandler {
	private static final int STATE_NOBLOCK = 0;
	private static final int STATE_PARSE_ANALYSIS = 1;
	private static final int STATE_PARSE_PARADIGM = 2;
	private static final int STATE_PARSE_HYPHENATION = 3;
	private static final int STATE_PARSE_GENERATION = 4;
	private SAXParserFactory parserFactory;
	private SAXParser xmlParser;
	private int state;
	private Response response;
	private FilterInputStream nonClosingInputStream;
	private AnalysisResponseParser analysisParser;
	private ParadigmResponseParser paradigmParser;
	private HyphenationResponseParser hyphenationParser;
	private GenerationResponseParser generationParser;
	
	public ResponseParser() throws ResponseParserException {
		try {
			parserFactory = SAXParserFactory.newInstance();
			xmlParser = parserFactory.newSAXParser();
			
		}
		catch (SAXException e) {
			throw new ResponseParserException(e.getMessage());
		}
		catch (ParserConfigurationException e) {
			throw new ResponseParserException(e.getMessage());
		}
	}
	
	public Response getResponse() {
		return response;
	}
	
	public void parseResponse(StringBuilder xml)
		throws ResponseParserException
	{
		int start = -1, end = -1;
		
		if((start = xml.indexOf("<?xml")) != -1) {
			end = xml.indexOf("?>");
			start = -1;
		}
		
		try {
			this.startDocument();
			
			if((start = xml.indexOf("<", end)) != -1) {
				end = xml.indexOf(">", start);
				this.processFirstBlock(xml.substring(start+1, end));
			}
			
			switch(state) {
			case STATE_PARSE_PARADIGM:
				paradigmParser.parseResponse(xml, end+1);
				break;
			case STATE_PARSE_HYPHENATION:
				hyphenationParser.parseResponse(xml, end+1);
				break;
			case STATE_PARSE_GENERATION:
				generationParser.parseResponse(xml, end+1);
				break;
			}
		}
		
		catch(SAXException e)
        {
        		if (!e.getMessage().equalsIgnoreCase("EOS"))
        			throw new ResponseParserException(e.getMessage());
        }
	}
	
	public void parseResponse(InputStream xmlInputStream)
		throws ResponseParserException 
	{
		try
        {
			/**
			 * This non-closing input stream issue is done because SAXParser
			 * calls stream's close method and we don't want to close the
			 * connection.
			 */
			nonClosingInputStream = new FilterInputStream(xmlInputStream)
			{
				public void close() throws IOException {}
			};
			
            	xmlParser.parse(nonClosingInputStream, this);
        }
        catch(SAXException e)
        {
        		if (!e.getMessage().equalsIgnoreCase("EOS"))
        			throw new ResponseParserException(e.getMessage());
        }
        catch(IOException e)
        {
            throw new ResponseParserException(" IO " + e.getMessage());
        }
	}
	
	public void startDocument() throws SAXException {
		response = new Response();
		state = STATE_NOBLOCK;
	}

	public void endDocument() throws SAXException {
	}
	
	private void processFirstBlock(String blockName)
		throws SAXException
	{
		if(blockName.equalsIgnoreCase(XMLTags.TAG_RESPONSE_ANALYSIS)) {
			state = STATE_PARSE_ANALYSIS;
			response = new Response();
			analysisParser = new AnalysisResponseParser(response.getElementContainer());
		}
		
		else if(blockName.equalsIgnoreCase(XMLTags.TAG_RESPONSE_PARA)) {
			state = STATE_PARSE_PARADIGM;
			response = new Response();
			paradigmParser = new ParadigmResponseParser(response.getElementContainer());
		}
		
		else if(blockName.equalsIgnoreCase(XMLTags.TAG_RESPONSE_HYPH)) {
			state = STATE_PARSE_HYPHENATION;
			response = new Response();
			hyphenationParser = new HyphenationResponseParser(response.getElementContainer());
		}
		
		else if(blockName.equalsIgnoreCase(XMLTags.TAG_RESPONSE_GEN)) {
			state = STATE_PARSE_GENERATION;
			response = new Response();
			generationParser = new GenerationResponseParser(response.getElementContainer());
		}
	}
	
	public void startElement (String namespaceURI, String localName, String blockName, Attributes attributes)
		throws SAXException
	{
		if(state == STATE_NOBLOCK)
			processFirstBlock(blockName);
		
		switch(state) {
		case STATE_PARSE_ANALYSIS:
			analysisParser.startElement(namespaceURI, localName, blockName, attributes);
			break;
		case STATE_PARSE_PARADIGM:
			paradigmParser.startElement(namespaceURI, localName, blockName, attributes);
			break;
		case STATE_PARSE_GENERATION:
			generationParser.startElement(namespaceURI, localName, blockName, attributes);
			break;
		}
	}
	
	
	/* (non-Javadoc)
	 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
	 */
	public void endElement(String uri, String localName, String blockName) throws SAXException {
		if(blockName.equalsIgnoreCase(XMLTags.TAG_RESPONSE_ANALYSIS) ||
		   blockName.equalsIgnoreCase(XMLTags.TAG_RESPONSE_PARA) ||
		   blockName.equalsIgnoreCase(XMLTags.TAG_RESPONSE_GEN)) 
		{
			throw new SAXException("EOS");
		}
	}
}
