package com.cybershopmgr.server.dbmgr.dbquerylanguage;

import java.util.StringTokenizer;
import java.util.Stack;
import java.util.HashMap;
import java.util.Enumeration;
import java.io.StringReader;

import org.xmldb.api.base.*;
import org.jdom.*;
import org.jdom.input.*;

import sjm.parse.tokens.Token;

import com.cybershopmgr.server.dbmgr.Crud;
import com.cybershopmgr.server.dbmgr.DocumentNotFound;

/**
 *  Description of the Class
 *
 *@author     Mark J Stang
 *@created    November 17, 2001
 */
public class QlCommand implements sjm.utensil.PubliclyCloneable
{
	protected Crud _crud = null;
	protected HashMap _hits = new HashMap();
	private int _clauseCount = 0;
	private boolean _foundAnd = false;
	private boolean _foundOr = false;
	private boolean _foundAttribute = false;
	private boolean _isKey = false;
	private Stack _stack = null;
	private String _key = null;
	private String _document = null;
	private String _documentType = null;
	private String _collection = null;
	private String _fieldName = null;
	private String _result = null;
	private String _text = null;
	private String _content = null;
	private Namespace _ns = null;
	private StringTokenizer _st = null;
	private String _tagName = null;
	private String _attributeName = null;
	
	public QlCommand()
	{
	}
	public void setCrud(Crud crud)
	{
		_crud = crud;
	}

	public void setDocument(String document)
	{
		_document = document;
	}
	public void setDocumentType(String documentType)
	{
		_st = new StringTokenizer(documentType, "'");
		while (_st.hasMoreTokens())
		{
			_documentType = _st.nextToken();
		}
	}
	public void setContent(String content)
	{
		_content = content;
	}
	public void setStack(Stack stack)
	{
		_stack = stack;
	}
	public void setResult(String result)
	{
		_result = result;
	}
	public void setText(String text)
	{
		_st = new StringTokenizer(text, "'");
		while (_st.hasMoreTokens())
		{
			_text = _st.nextToken();
		}
	}
	public void setKey(String key)
	{
		_st = new StringTokenizer(key, "'");
		while (_st.hasMoreTokens())
		{
			_key = _st.nextToken();
		}
	}
	public void setCollection(String collection)
	{
		_st = new StringTokenizer(collection, "'");
		while (_st.hasMoreTokens())
		{
			_collection = _st.nextToken();
		}
	}
	public void setFieldName(String fieldName)
	{
		_st = new StringTokenizer(fieldName, "'");
		while (_st.hasMoreTokens())
		{
			_fieldName = _st.nextToken();
		}
	}
	public Stack getStack()
	{
		return _stack;
	}
	public HashMap getHits()
	{
		return _hits;
	}
	public Crud getCrud()
	{
		return _crud;
	}
	public int getClauseCount()
	{
		return _clauseCount;
	}
	public void incClauseCount()
	{
		_clauseCount++;
	}
	public boolean ifFoundAnd()
	{
		return _foundAnd;
	}
	public boolean ifFoundAttribute()
	{
		return _foundAttribute;
	}
	public boolean ifFoundOr()
	{
		return _foundOr;
	}
	public boolean isKey()
	{
		return _isKey;
	}
	public String getDocument()
	{
		return _document;
	}
	public String getDocumentType()
	{
		return _documentType;
	}
	public String getContent()
	{
		return _content;
	}
	public String getFieldName()
	{
		return _fieldName;
	}
	public String getKey()
	{
		return _key;
	}
	public String getResult()
	{
		return _result;
	}
	public String getText()
	{
		return _text;
	}
	public String getCollection()
	{
		return _collection;
	}
	public String toString()
	{
		return "key='"+_key+"'"+" document='"+_document+"'"+" fieldName='"+_fieldName+"'"+" collection='"+_collection+"'";
	}
	public void execute()
	{
		System.out.println("in QlCommand execute");
	}
	public Object clone()
	{
		QlCommand qlc = null;
		try
		{
			qlc = (QlCommand) super.clone();
			qlc.setStack(getStack());
			qlc.setCrud(getCrud());
		}
		catch (CloneNotSupportedException e)
		{
			// this shouldn't happen, since we are Cloneable
			throw new InternalError();
		}
		return qlc;
	}
	public void findHits(boolean bHasDocumentType)
	{
		checkForAnd();
		String xpath = null;
		Token token = null;
		Stack s = getStack();
		Enumeration e = s.elements();
		if (bHasDocumentType)
		{
			setDocumentType(((Token)e.nextElement()).sval());
		}
		setCollection(((Token)e.nextElement()).sval());
		while(e.hasMoreElements())
		{
			token = (Token) e.nextElement();
			if (token.sval().equalsIgnoreCase("key"))
			{
				setKey(((Token)e.nextElement()).sval());
				_isKey = true;
				try
				{
					_crud = new Crud(getCollection());
					setResult(_crud.read(getKey()));
					_clauseCount++;
				}
				catch (DocumentNotFound exception)
				{
					setResult(null);
				}
			}
			else if (token.sval().equalsIgnoreCase("attribute"))
			{
				_foundAttribute = true;
			}
			else if (token.sval().equalsIgnoreCase("and"))
			{
				// ignore
			}
			else if (token.sval().equalsIgnoreCase("or"))
			{
				// ignore
			}
			else
			{
				setFieldName(token.sval());
				token = (Token) e.nextElement();
				setText(((Token)e.nextElement()).sval());
				if (token.sval().equals("="))
				{
					if (_foundAttribute)
					{
						_st = new StringTokenizer(getFieldName(), ".");
						_tagName = _st.nextToken();
						xpath = "//*/"+_tagName+"[@"+_st.nextToken()+"='"+getText()+"']";
					}
					else
					{
						xpath = "//*/"+getFieldName()+"[text()='"+getText()+"']";
					}
					search(xpath);
					_clauseCount++;
					_foundAttribute = false;
				}
				else if (token.sval().equalsIgnoreCase("contains"))
				{
					if (_foundAttribute)
					{
						_st = new StringTokenizer(getFieldName(), ".");
						_tagName = _st.nextToken();
						xpath = "//*/"+_tagName+"[contains(@"+_st.nextToken()+",'"+getText()+"')]";
					}
					else
					{
						xpath = "//*/"+getFieldName()+"[contains(self::*,'"+getText()+"')]";
					}
					search(xpath);
					_clauseCount++;
					_foundAttribute = false;
				}
				else if (token.sval().equalsIgnoreCase("starts"))
				{
					if (_foundAttribute)
					{
						_st = new StringTokenizer(getFieldName(), ".");
						_tagName = _st.nextToken();
						xpath = "//*/"+_tagName+"[starts-with(@"+_st.nextToken()+",'"+getText()+"')]";
					}
					else
					{
						xpath = "//*[starts-with("+getFieldName()+",'"+getText()+"')]";
					}
					search(xpath);
					_clauseCount++;
					_foundAttribute = false;
				}
			}
		}
	}
	private void search(String xpath)
	{
		//System.out.println("xpath="+xpath);
		Crud crud = null;
		ResourceSet resultSet = null;
		// Build the document with SAX and Xerces, no validation
		SAXBuilder builder = new SAXBuilder();
		Document doc = null;
		ResourceIterator results = null;
		Resource res = null;
		Element root = null;
		String key = null;
		try
		{
			crud = new Crud(getCollection());
			resultSet = crud.search(xpath);
			if (resultSet != null)
			{
				results = resultSet.getIterator();
				while (results.hasMoreResources())
				{
					res = results.nextResource();
					_content = (String) res.getContent();
					doc = builder.build(new StringReader(_content));
					root = doc.getRootElement();
					//System.out.println("content="+_content);
					//System.out.println("xpath="+xpath+" content="+_content);
					//System.out.println("root="+root);
					_ns = root.getNamespace("src");
					_key = root.getAttribute("key", _ns).getValue();
					Hit hit = null;
					hit = (Hit)_hits.get(_key.toString());
					if (hit == null)
					{
						Element e = (Element) root.clone();
						hit = new Hit(_key, xpath, e);
					}
					else
					{
						Element e = (Element) root.clone();
						hit.addClauseHit(xpath, e);
					}
					_hits.put(_key.toString(), hit);
				}
			}
		}
		catch (XMLDBException e)
		{
			System.err.println("XML:DB Exception occured " + e.errorCode);
		}
		catch (org.jdom.JDOMException e)
		{
			System.err.println("jdom exception " + e);
		}
		catch (DocumentNotFound e)
		{
			System.err.println("Document Not Found exception " + e);
		}
	}
	private void checkForAnd()
	{
		Token token = null;
		Stack s = getStack();
		Enumeration e = s.elements();
		while(e.hasMoreElements())
		{
			token = (Token) e.nextElement();
			if (token.sval().equalsIgnoreCase("and"))
			{
				_foundAnd = true;
			}
			else if (token.sval().equalsIgnoreCase("or"))
			{
				_foundOr = true;
			}
		}
	}
}
