/* 
 * Copyright 2012 by AVM GmbH <info@avm.de>
 *
 * This software contains free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License ("License") as 
 * published by the Free Software Foundation  (version 3 of the License). 
 * This software is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the copy of the 
 * License you received along with this software for more details.
 */

package de.avm.android.tr064.sax;

import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import de.avm.android.tr064.Tr064Capabilities;

import android.text.TextUtils;

/*
 * SAX-Handler base class for FRITZ!Box SCPD description
 */
public abstract class SAXScpdHandler extends DefaultHandler
{
	/**
	 * Checks if capability belongs to this TR-064 interface
	 * @param cap capabiliies to check for
	 * @return true if one of cap's capabilities belongs to this interface
	 */
	public abstract boolean isCapabilitiyOfInterface(Tr064Capabilities cap);
	
	/**
	 * Gets interface capabilities after parsing
	 * 
	 * @return
	 * 		capability info
	 */
	public abstract Tr064Capabilities getCapabilities();

	public SAXScpdHandler()
	{
	}
	
	protected class ActionInfo
	{
		public String mName = "";
		public boolean mIsAvailable = false;
		public ArrayList<String> mArguments = null;

		public ActionInfo(String name)
		{
			mName = name;
		}
	}
	
	/**
	 * Array of action names to check for.
	 * Has to be filled in derived classes before parsing.
	 * 
	 * Availabitity and arguments of action could be read after parsing. 
	 */
	protected ActionInfo[] mActions = null;
	
	private static final String ACTION_PATH = "/scpd/actionlist/action";
	private static final String NAME_SUBPATH = "/name";
	private static final String ARGUMENT_SUBPATH = "/argumentList/argument/name";
	private String mCurrentPath = "";
	private boolean mInAction = false;
	private boolean mInActionName = false;
	private String mCurrentActionName = "";
	private boolean mInArgumentName = false;
	private String mCurrentArgumentName = "";
	private ArrayList<String> mCurrentArguments = null;

	protected void initActionsArray(String[] names)
	{
		if ((names == null) || (names.length == 0))
			throw new IllegalArgumentException("Argument names must not be empty or null");
		
		mActions = new ActionInfo[names.length];
		for (int ii = 0; ii < names.length; ii++)
			mActions[ii] = new ActionInfo(names[ii]); 
	}

	protected String getCurrentPath()
	{
		return mCurrentPath;
	}
	
	/* (non-Javadoc)
	 * @see org.xml.sax.helpers.DefaultHandler#startDocument()
	 */
	@Override
	public void startDocument()
		throws SAXException
	{
	}

	/* (non-Javadoc)
	 * @see org.xml.sax.helpers.DefaultHandler#endDocument()
	 */
	@Override
	public void endDocument()
		throws SAXException
	{
	}

	/* (non-Javadoc)
	 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
	 */
	@Override
	public void startElement(String namespaceURI, String localName,
			String qName, Attributes atts) throws SAXException
	{
		mCurrentPath += "/" + localName;

		if (mInAction)
		{
			mInActionName = mCurrentPath.equalsIgnoreCase(ACTION_PATH + NAME_SUBPATH); 
			if (mInActionName) mCurrentActionName = "";
			mInArgumentName = mCurrentPath.equalsIgnoreCase(ACTION_PATH + ARGUMENT_SUBPATH);
			if (mInArgumentName) mCurrentArgumentName = "";
		}
		else if (mCurrentPath.equalsIgnoreCase(ACTION_PATH))
		{
			mInAction = true;
			mCurrentArguments = new ArrayList<String>();
		}
	}

	/**
	 * on closing tags like: </tag>.
	 * 
	 * @param namespaceURI
	 *            the namespace uri
	 * @param localName
	 *            the local name
	 * @param qName
	 *            the q name
	 * 
	 * @throws SAXException
	 *             the SAX exception
	 */
	@Override
	public void endElement(String namespaceURI, String localName, String qName)
			throws SAXException
	{
		if (mCurrentPath.endsWith(localName))
		{
			if (mInActionName)
			{
				mInActionName = false;
			}
			else if (mInArgumentName)
			{
				mInArgumentName = false;
				if (!TextUtils.isEmpty(mCurrentArgumentName))
					mCurrentArguments.add(mCurrentArgumentName);
			}
			else if (mInAction && mCurrentPath.equalsIgnoreCase(ACTION_PATH))
			{
				mInAction = false;
				if (!TextUtils.isEmpty(mCurrentActionName))
				{
					for (ActionInfo action : mActions)
						if (action.mName.equalsIgnoreCase(mCurrentActionName))
						{
							action.mIsAvailable = true;
							action.mArguments = mCurrentArguments;
							break;
						}
				}
			}
			mCurrentPath = mCurrentPath.substring(0, mCurrentPath.length() - localName.length() - 1);
		}
	}

	/**
	 * Gets be called on the following structure: <tag>characters</tag>.
	 * 
	 * @param ch
	 *            the ch
	 * @param start
	 *            the start
	 * @param length
	 *            the length
	 */
	@Override
	public void characters(char ch[], int start, int length)
	{
		if (mInActionName)
		{
			String str = new String(ch, start, length);
			if (!TextUtils.isEmpty(str)) mCurrentActionName += str;
		}
		else if (mInArgumentName)
		{
			String str = new String(ch, start, length);
			if (!TextUtils.isEmpty(str)) mCurrentArgumentName += str;
		}
	}
}
