/* 
 * Copyright 2015 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 org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import de.avm.android.tr064.Tr064Log;

/*
 * SAX-Handler for FRITZ!Box TR-064 description
 */
public class SAXTr064DescHandler extends DefaultHandler
{
	private static final String TAG = "SAXTr064DescHandler";
	
	public static final String DEVICE_TYPE_IGD = "urn:dslforum-org:device:InternetGatewayDevice:1";
	private static final String DEVICE_TYPE_LAN = "urn:dslforum-org:device:LANDevice:1";
	private static final String SERVICE_TYPE_ONTEL = "urn:dslforum-org:service:X_AVM-DE_OnTel:1";
	private static final String SERVICE_TYPE_WLANCONF_PART = "urn:dslforum-org:service:WLANConfiguration:";
	private static final String SERVICE_TYPE_VOIP = "urn:dslforum-org:service:X_VoIP:1";
	private static final String SERVICE_TYPE_TAM = "urn:dslforum-org:service:X_AVM-DE_TAM:1";
	private static final String SERVICE_TYPE_DEVICEINFO = "urn:dslforum-org:service:DeviceInfo:1";
	private static final String SERVICE_TYPE_DEVICECONFIG = "urn:dslforum-org:service:DeviceConfig:1";
	private static final String SERVICE_TYPE_WAN_PPP_CONNECTION = "urn:dslforum-org:service:WANPPPConnection:1";
	private static final String SERVICE_TYPE_MY_FRITZ = "urn:dslforum-org:service:X_AVM-DE_MyFritz:1";
	private static final String SERVICE_TYPE_LAN_CONFIG_SECURITY = "urn:dslforum-org:service:LANConfigSecurity:1";
	private static final String SERVICE_TYPE_WAN_COMMON_IFACE_CONFIG = "urn:dslforum-org:service:WANCommonInterfaceConfig:1";
	private static final String SERVICE_TYPE_REMOTE_ACCESS = "urn:dslforum-org:service:X_AVM-DE_RemoteAccess:1";
	private static final String SERVICE_TYPE_WAN_IP_CONNECTION = "urn:dslforum-org:service:WANIPConnection:1";
	private static final String SERVICE_TYPE_USER_INTERFACE = "urn:dslforum-org:service:UserInterface:1";
    private static final String SERVICE_TYPE_HOSTS = "urn:dslforum-org:service:Hosts:1";
    private static final String SERVICE_TYPE_APP_SETUP = "urn:dslforum-org:service:X_AVM_DE_AppSetup:1";

	private static final String PATH_IGD = "/root/device";
	private static final String PATH_ONTEL = "/root/device/servicelist/service";
	private static final String PATH_VOIP = "/root/device/servicelist/service";
	private static final String PATH_LAN = "/root/device/devicelist/device";
	private static final String PATH_TAM = "/root/device/servicelist/service";
	private static final String PATH_WLANCONF = "/root/device/devicelist/device/servicelist/service";
	private static final String PATH_DEVICEINFO = "/root/device/servicelist/service";
	private static final String PATH_DEVICECONFIG = "/root/device/servicelist/service";
	private static final String PATH_WAN_PPP_CONNECTION = "/root/device/devicelist/device/devicelist/device/servicelist/service";
	private static final String PATH_MY_FRITZ = "/root/device/servicelist/service";
	private static final String PATH_LAN_CONFIG_SECURITY = "/root/device/servicelist/service";
	private static final String PATH_WAN_COMMON_IFACE_CONFIG = "/root/device/devicelist/device/servicelist/service";
	private static final String PATH_REMOTE_ACCESS = "/root/device/servicelist/service";
	private static final String PATH_WAN_IP_CONNECTION = "/root/device/deviceList/device/deviceList/device/serviceList/service";
	private static final String PATH_USER_INTERFACE = "/root/device/servicelist/service";
    private static final String PATH_HOSTS = "/root/device/devicelist/device/servicelist/service";
    private static final String PATH_APP_SETUP = "/root/device/servicelist/service";

	private String mCurrentPath = "";
	private String mCurrentScpdUrl = "";
	private String mCurrentUdn = "";
	private String mCurrentManufacturer = "";
	private String mCurrentModel = "";
	private String mCurrentFriendlyName = "";
	private String mCurrentString = "";

	private int mInIgd = 0;
	private int mInUdn = 0;
	private int mInManufacturer = 0;
	private int mInModel = 0;
	private int mInFriendlyName = 0;
	private int mInLan = 0;
	private int mInWlan = 0;
	private int mInOnTel = 0;
	private int mInVoIP = 0;
	private int mInTam = 0;
	private int mInScpdUrl = 0;
	private int mInDeviceInfo = 0;
	private int mInDeviceConfig = 0;
	private int mInWanPPPConnection = 0;
	private int mInMyFritz = 0;
	private int mInLanConfigSecurity = 0;
	private int mInWanCommonIfaceConfig = 0;
	private int mInRemoteAccess = 0;
	private int mInWanIPConnection = 0;
	private int mInUserInterface = 0;
    private int mInHosts = 0;
    private int mInAppSetup = 0;

	private String mUdn = "";
	private String mManufacturer = "";
	private String mModel = "";
	private String mFriendlyName = "";
	private String mOnTelPath = "";
	private String mWlanConfPath = "";
	private int mWlanInterfacesCount = 0;
	private String mVoIPPath = "";
	private String mTamPath = "";
	private String mDeviceInfoPath = "";
	private String mDeviceConfigPath = "";
	private String mWanPPPConnectionPath = "";
	private String mMyFritzPath = "";
	private String mLanConfigSecurityPath = "";
	private String mWanCommonIfaceConfigPath = "";
	private String mRemoteAccessPath = "";
	private String mWanIPConnectionPath = "";
	private String mUserInterfacePath = "";
    private String mHostsPath = "";
    private String mAppSetupPath = "";

	public String getUdn()
	{
		return mUdn;
	}
	
	public String getManufacturer()
	{
		return mManufacturer;
	}
	
	public String getModel()
	{
		return mModel;
	}
	
	public String getFriendlyName()
	{
		return mFriendlyName;
	}
	
	public String getDeviceInfoPath()
	{
		return mDeviceInfoPath;
	}
	
	public String getDeviceConfigPath()
	{
		return mDeviceConfigPath;
	}
	
	public String getOnTelPath()
	{
		return mOnTelPath;
	}
	
	public String getWlanConfPath()
	{
		return mWlanConfPath;
	}
	
	public int getWlanInterfacesCount()
	{
		return mWlanInterfacesCount;
	}
	
	public String getVoIPPath()
	{
		return mVoIPPath;
	}
	
	public String getTamPath()
	{
		return mTamPath;
	}
	
	public String getWanPPPConnectionPath()
	{
		return mWanPPPConnectionPath;
	}
	
	public String getMyFritzPath()
	{
		return mMyFritzPath;
	}
	
	public String getLanConfigSecurityPath()
	{
		return mLanConfigSecurityPath;
	}
	
	public String getWanCommonIfaceConfigPath()
	{
		return mWanCommonIfaceConfigPath;
	}
	
	public String getRemoteAccessPath()
	{
		return mRemoteAccessPath;
	}
	
	public String getWanIPConnectionPath()
	{
		return mWanIPConnectionPath;
	}
	
	public String getUserInterfacePath()
	{
		return mUserInterfacePath;
	}
	
	public String getHostsPath()
	{
		return mHostsPath;
	}

    public String getAppSetupPath()
    {
        return mHostsPath;
    }

	/**
	 * Instantiates a new sAX FRITZ!Box TR-064 description handler.
	 */
	public SAXTr064DescHandler()
	{
	}

	@Override
	public void startElement(String namespaceURI, String localName,
			String qName, Attributes atts) throws SAXException
	{
		mCurrentPath += "/" + localName;
		if (localName.equalsIgnoreCase("scpdurl"))
		{
			mInScpdUrl = mCurrentPath.length();
			mCurrentScpdUrl = "";
		}
		else if (mCurrentPath.equalsIgnoreCase(PATH_IGD + "/" + "UDN"))
		{
			mInUdn = mCurrentPath.length();
			mCurrentUdn = "";
		}
		else if (mCurrentPath.equalsIgnoreCase(PATH_IGD + "/" + "manufacturer"))
		{
			mInManufacturer = mCurrentPath.length();
			mCurrentManufacturer = "";
		}
		else if (mCurrentPath.equalsIgnoreCase(PATH_IGD + "/" + "modelName"))
		{
			mInModel = mCurrentPath.length();
			mCurrentModel = "";
		}
		else if (mCurrentPath.equalsIgnoreCase(PATH_IGD + "/" + "friendlyName"))
		{
			mInFriendlyName = mCurrentPath.length();
			mCurrentFriendlyName = "";
		}
		mCurrentString = "";
	}

	@Override
	public void endElement(String namespaceURI, String localName, String qName)
			throws SAXException
	{
		if (mCurrentString.length() > 0)
		{
			if ((mInIgd == 0) &&
					mCurrentPath.equalsIgnoreCase(PATH_IGD + "/" + "devicetype") &&
					mCurrentString.equals(DEVICE_TYPE_IGD))
			{
				mInIgd = PATH_IGD.length();
			}
			else
			{
				if ((mInLan == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_LAN + "/" + "devicetype") &&
						mCurrentString.equals(DEVICE_TYPE_LAN))
				{
					mInLan = PATH_LAN.length();
				}
				else if ((mInOnTel == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_ONTEL + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_ONTEL))
				{
					mInOnTel = PATH_ONTEL.length();
				}
				else if ((mInVoIP == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_VOIP + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_VOIP))
				{
					mInVoIP = PATH_VOIP.length();
				}
				else if ((mInLan > 0) && (mInWlan == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_WLANCONF + "/" + "servicetype") &&
						mCurrentString.startsWith(SERVICE_TYPE_WLANCONF_PART))
				{
					String indexString = mCurrentString
							.substring(SERVICE_TYPE_WLANCONF_PART.length());
					int interfaceIndex = 0;
					try { interfaceIndex = Integer.parseInt(indexString); }
					catch(Exception e)
					{
						Tr064Log.e(TAG, "Invalid WLAN configuration interface index in \"" +
                                mCurrentString + "\"", e);
					}
					if (mWlanInterfacesCount < interfaceIndex)
						mWlanInterfacesCount = interfaceIndex;
					if (interfaceIndex == 1)
						mInWlan = PATH_WLANCONF.length();
				}
				else if ((mInTam == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_TAM + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_TAM))
				{
					mInTam = PATH_TAM.length();
				}
				else if ((mInDeviceInfo == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_DEVICEINFO + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_DEVICEINFO))
				{
					mInDeviceInfo = PATH_DEVICEINFO.length();
				}
				else if ((mInDeviceConfig == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_DEVICECONFIG + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_DEVICECONFIG))
				{
					mInDeviceConfig = PATH_DEVICECONFIG.length();
				}
				else if ((mInWanPPPConnection == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_WAN_PPP_CONNECTION + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_WAN_PPP_CONNECTION))
				{
					mInWanPPPConnection = PATH_WAN_PPP_CONNECTION.length();
				}
				else if ((mInMyFritz == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_MY_FRITZ + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_MY_FRITZ))
				{
					mInMyFritz = PATH_MY_FRITZ.length();
				}
				else if ((mInLanConfigSecurity == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_LAN_CONFIG_SECURITY + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_LAN_CONFIG_SECURITY))
				{
					mInLanConfigSecurity = PATH_LAN_CONFIG_SECURITY.length();
				}
				else if ((mInWanCommonIfaceConfig == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_WAN_COMMON_IFACE_CONFIG + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_WAN_COMMON_IFACE_CONFIG))
				{
					mInWanCommonIfaceConfig = PATH_WAN_COMMON_IFACE_CONFIG.length();
				}
				else if ((mInRemoteAccess == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_REMOTE_ACCESS + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_REMOTE_ACCESS))
				{
					mInRemoteAccess = PATH_REMOTE_ACCESS.length();
				}
				else if ((mInWanIPConnection == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_WAN_IP_CONNECTION + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_WAN_IP_CONNECTION))
				{
					mInWanIPConnection = PATH_WAN_IP_CONNECTION.length();
				}
				else if ((mInUserInterface == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_USER_INTERFACE + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_USER_INTERFACE))
				{
					mInUserInterface = PATH_USER_INTERFACE.length();
				}
				else if ((mInHosts == 0) &&
						mCurrentPath.equalsIgnoreCase(PATH_HOSTS + "/" + "servicetype") &&
						mCurrentString.equals(SERVICE_TYPE_HOSTS))
				{
					mInHosts = PATH_HOSTS.length();
				}
                else if ((mInAppSetup == 0) &&
                        mCurrentPath.equalsIgnoreCase(PATH_APP_SETUP + "/" + "servicetype") &&
                        mCurrentString.equals(SERVICE_TYPE_APP_SETUP))
                {
                    mInAppSetup = PATH_HOSTS.length();
                }
			}
		}

		if (mCurrentPath.endsWith(localName))
		{
			if (localName.equalsIgnoreCase("service"))
			{
				if (mInOnTel == mCurrentPath.length())
					mOnTelPath = mCurrentScpdUrl;
				else if (mInWlan == mCurrentPath.length())
					mWlanConfPath = mCurrentScpdUrl;
				else if (mInVoIP == mCurrentPath.length())
					mVoIPPath = mCurrentScpdUrl;
				else if (mInTam == mCurrentPath.length())
					mTamPath = mCurrentScpdUrl;
				else if (mInDeviceInfo == mCurrentPath.length())
					mDeviceInfoPath = mCurrentScpdUrl;
				else if (mInDeviceConfig == mCurrentPath.length())
					mDeviceConfigPath = mCurrentScpdUrl;
				else if (mInWanPPPConnection == mCurrentPath.length())
					mWanPPPConnectionPath = mCurrentScpdUrl;
				else if (mInMyFritz == mCurrentPath.length())
					mMyFritzPath = mCurrentScpdUrl;
				else if (mInLanConfigSecurity == mCurrentPath.length())
					mLanConfigSecurityPath = mCurrentScpdUrl;
				else if (mInWanCommonIfaceConfig == mCurrentPath.length())
					mWanCommonIfaceConfigPath = mCurrentScpdUrl;
				else if (mInRemoteAccess == mCurrentPath.length())
					mRemoteAccessPath = mCurrentScpdUrl;
				else if (mInWanIPConnection == mCurrentPath.length())
					mWanIPConnectionPath = mCurrentScpdUrl;
				else if (mInUserInterface == mCurrentPath.length())
					mUserInterfacePath = mCurrentScpdUrl;
				else if (mInHosts == mCurrentPath.length())
					mHostsPath = mCurrentScpdUrl;
                else if (mInAppSetup == mCurrentPath.length())
                    mAppSetupPath = mCurrentScpdUrl;
			}
			if (mCurrentPath.equalsIgnoreCase(PATH_IGD))
			{
				if (mInIgd == mCurrentPath.length())
				{
					mUdn = mCurrentUdn;
					mManufacturer = mCurrentManufacturer;
					mModel = mCurrentModel;
					mFriendlyName = mCurrentFriendlyName;
				}
			}
			mCurrentPath = mCurrentPath.substring(0, mCurrentPath.length() - localName.length() - 1);
		}
		int len = mCurrentPath.length();
		if (len < mInIgd) mInIgd = 0;
		if (len < mInUdn) mInUdn = 0;
		if (len < mInManufacturer) mInManufacturer = 0;
		if (len < mInModel) mInModel = 0;
		if (len < mInFriendlyName) mInFriendlyName = 0;
		if (len < mInLan) mInLan = 0;
		if (len < mInWlan) mInWlan = 0;
		if (len < mInOnTel) mInOnTel = 0;
		if (len < mInVoIP) mInVoIP = 0;
		if (len < mInTam) mInTam = 0;
		if (len < mInScpdUrl) mInScpdUrl = 0;
		if (len < mInDeviceInfo) mInDeviceInfo = 0;
		if (len < mInDeviceConfig) mInDeviceConfig = 0;
		if (len < mInWanPPPConnection) mInWanPPPConnection = 0;
		if (len < mInMyFritz) mInMyFritz = 0;
		if (len < mInLanConfigSecurity) mInLanConfigSecurity = 0;
		if (len < mInWanCommonIfaceConfig) mInWanCommonIfaceConfig = 0;
		if (len < mInRemoteAccess) mInRemoteAccess = 0;
		if (len < mInWanIPConnection) mInWanIPConnection = 0;
		if (len < mInUserInterface) mInUserInterface = 0;
		if (len < mInHosts) mInHosts = 0;
        if (len < mInAppSetup) mInHosts = 0;
    }

	@Override
	public void characters(char ch[], int start, int length)
	{
		String str = new String(ch, start, length);
		if ((str == null) || (str.trim().length() <= 0)) return;

		if (mInScpdUrl > 0)
		{
			mCurrentScpdUrl += str;
		}
		else if (mInUdn > 0)
		{
			mCurrentUdn += str;
		}
		else if (mInManufacturer > 0)
		{
			mCurrentManufacturer += str;
		}
		else if (mInModel > 0)
		{
			mCurrentModel += str;
		}
		else if (mInFriendlyName > 0)
		{
			mCurrentFriendlyName += str;
		}
		else mCurrentString += str;
	}
}
