/**
 * 
 */
package com.tandbergtv.watchpoint.pmm.action.asset.processing;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Utility class that provides methods to read the configured criteria for
 * encoder profiles from a configuration file.
 * 
 * @author Imran Naqvi
 * 
 */
public class EncoderProfileCriteriaLoader {

	private static final Logger logger = Logger
			.getLogger(EncoderProfileCriteriaLoader.class);

	private static final String RESOURCE_NAME = "/template-actions/encoderprofile_config.xml";

	private static final String PROFILES_XPATH = "//profile/@name";

	private static final String DEFAULT_PROFILE_XPATH = "//default/@name";

	private static EncoderProfileCriteriaLoader criteriaLoader = null;

	private List<EncoderProfileCriteria> profiles = new ArrayList<EncoderProfileCriteria>();

	private String defaultProfileName;

	/**
	 * 
	 */
	private EncoderProfileCriteriaLoader() {
		read();
	}

	public static synchronized EncoderProfileCriteriaLoader getInstance() {
		if (criteriaLoader == null)
			criteriaLoader = new EncoderProfileCriteriaLoader();

		return criteriaLoader;
	}

	/**
	 * @return the profiles
	 */
	public List<EncoderProfileCriteria> getProfiles() {
		return profiles;
	}

	/**
	 * @return the defaultProfileName
	 */
	public String getDefaultProfileName() {
		return defaultProfileName;
	}

	/*
	 * Reads the profile criteria configuration file.
	 */
	private void read() {
		try {
			DocumentBuilder builder = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder();
			Document document = builder.parse(this.getClass()
					.getResourceAsStream(RESOURCE_NAME));

			XPath xpath = XPathFactory.newInstance().newXPath();
			NodeList nodes = (NodeList) xpath.evaluate(PROFILES_XPATH,
					document, XPathConstants.NODESET);

			int nodeCount = (nodes != null) ? nodes.getLength() : 0;
			for (int i = 0; i < nodeCount; i++) {
				Node node = nodes.item(i);
				String profileName = node.getNodeValue();

				// Skip over blank profile names
				if (profileName == null || profileName.trim().length() == 0)
					continue;

				HashMap<String, String> criteria = new HashMap<String, String>();
				String expression = "//profile[@name='" + profileName
						+ "']/param";
				NodeList variableNodes = (NodeList) xpath.evaluate(expression,
						document, XPathConstants.NODESET);
				int variableNodeCount = (variableNodes != null) ? variableNodes
						.getLength() : 0;
				for (int j = 0; j < variableNodeCount; j++) {
					Node variableNode = variableNodes.item(j);
					if (!(variableNode instanceof Element))
						continue;

					Element element = (Element) variableNode;
					String name = element.getAttribute("name");
					String value = element.getAttribute("value");
					criteria.put(name, value);
				}

				profiles.add(new EncoderProfileCriteria(profileName, criteria));
			}

			/* Get Default profile name if specified */
			Node defaultProfile = (Node) xpath.evaluate(DEFAULT_PROFILE_XPATH,
					document, XPathConstants.NODE);
			if (defaultProfile != null)
				this.defaultProfileName = defaultProfile.getTextContent();
		} catch (Exception ex) {
			String msg = "Failed to load Encoder Profile Criteria configuration from file: "
					+ RESOURCE_NAME;
			logger.error(msg, ex);
		}
	}
}
