/* 
 * 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.fritzapp.com;

import java.io.IOException;
import java.io.StringBufferInputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidParameterException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Wrapper for jason_boxinfo.xml
 */
@SuppressWarnings("deprecation")  // StringBufferInputStream wird benötigt
public class JasonBoxinfo
{
	private static final String FILEPATH = "/jason_boxinfo.xml";
	private static final String NAMESPACE = "http://jason.avm.de/updatecheck/";
	
	private Node mBoxInfoNode = null;
	
	/**
	 * @param host box' host address
	 * @return URI to info file on host
	 * @throws URISyntaxException host is invalid
	 */
	public static URI createUri(String host)
		throws  URISyntaxException
	{
		return new URI("http", host, FILEPATH, null);
	}
	
	/**
	 * @return box' product name
	 */
	public String getName()
	{
		return getTextNode("name");
	}
	
	/**
	 * @return box' version
	 */
	public String getVersion()
	{
		String version = getTextNode("version");
		String revision = getTextNode("revision");
		
		int pos = version.indexOf('-');
		if ((pos < 0) || (revision.length() == 0) || version.endsWith(revision))
			return version;
		return version.substring(0, pos + 1) + revision;
	}

	/**
	 * Compares version with major/minor
	 * 
	 * @param major
	 * 		major version number to compare with
	 * @param minor
	 * 		minor version number to compare with
	 * @return 
	 * 		a negative value if the value of this is less than major/minor;
	 * 		0 if the value of this and major/minor are equal;
	 * 		a positive value if the value of this is greater than major/minor. 
	 */
	public int compareVersion(int major, int minor)
	{
		String version = getTextNode("version");
		Matcher m = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+).*$")
				.matcher(version);
		if (m.find())
		{
			int majorVersion = Integer.parseInt(m.group(2));
			int minorVersion = Integer.parseInt(m.group(3));
			if (majorVersion == major)
			{
				if (minorVersion == minor) return 0;
				return (minorVersion > minor) ? 1 : -1;
			}
			else return (majorVersion > major) ? 1 : -1;
		}
		else throw new IllegalStateException();
	}
	
	/**
	 * @return box' lab name if any
	 */
	public String getLab()
	{
		return getTextNode("lab");
	}

	/**
	 * Creates instance from XML string
	 * @param xml XML string
	 * @throws InvalidParameterException Error parsing XML string
	 * @throws FactoryConfigurationError Error creating XML parser
	 * @throws ParserConfigurationException Error creating XML parser
	 */
	public JasonBoxinfo(String xml)
		throws InvalidParameterException, FactoryConfigurationError, ParserConfigurationException
	{
		try
		{
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			factory.setNamespaceAware(true);
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document document = builder.parse(new StringBufferInputStream(xml));

			NodeList nodes = document.getElementsByTagNameNS(NAMESPACE, "BoxInfo");
			if (nodes.getLength() == 1)
				mBoxInfoNode = nodes.item(0);
			else
				throw new InvalidParameterException();
		}
		catch (SAXException e)
		{
			throw new InvalidParameterException();
		}
		catch (IOException e)
		{
			throw new InvalidParameterException();
		}
	}

	/**
	 * Retrieves first text part of elements content
	 * @param tag name of element node
	 * @return text part
	 */
	private String getTextNode(String tag)
	{
		NodeList nodes = mBoxInfoNode.getChildNodes();
		for (int ii = 0; ii < nodes.getLength(); ii++)
		{
			Node node = nodes.item(ii);
			if ((node.getNodeType() == Node.ELEMENT_NODE) &&
				NAMESPACE.equals(node.getNamespaceURI()) &&
				tag.equalsIgnoreCase(node.getLocalName()))
			{
				// first text value
				NodeList childNodes = node.getChildNodes();
				for (int jj = 0; jj < childNodes.getLength(); jj++)
				{
					Node childNode = childNodes.item(jj);
					if (childNode.getNodeType() == Node.TEXT_NODE)
						return childNode.getNodeValue();
				}
				break;
			}
		}
		
		return "";
	}
}
