package uk.ac.rdg.resc.edal.graphics.style.sld;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Node;

import uk.ac.rdg.resc.edal.graphics.style.ScaleRange;

public class SLDRange {

	public enum Spacing {
		LINEAR,
		LOGARITHMIC
	}
	
	private float minimum;
	private float maximum;
	private Spacing spacing;

	public SLDRange(Float minimum, Float maximum, Spacing spacing) throws SLDException {
		if (minimum > maximum) {
			throw new SLDException("The minimum of a range cannot be greater than the maximum.");
		} if (spacing == Spacing.LOGARITHMIC && minimum <= 0) {
			throw new SLDException("Cannot use a negative or zero value for logarithmic scale.");
		}
		this.minimum = minimum;
		this.maximum = maximum;
		this.spacing = spacing;
	}
	
	public Float getMinimum() {
		return minimum;
	}

	public Float getMaximum() {
		return maximum;
	}

	public Spacing getSpacing() {
		return spacing;
	}
	
	public ScaleRange getScaleRange() {
	    return new ScaleRange(getMinimum(), getMaximum(), getSpacing() == Spacing.LOGARITHMIC);
	}

	/**
	 * Parse range from an XML SLD document given the node of the document using
	 * XPath;
	 * 
	 * @param xPath
	 * @param function
	 * @return SLDRange
	 * @throws XPathExpressionException
	 * @throws SLDException
	 */
	public static SLDRange parseRange(XPath xPath, Node function) throws SLDException {
		try {
			String rangeMinText = (String) xPath.evaluate(
					"./resc:Range/resc:Minimum", function, XPathConstants.STRING);
			if (rangeMinText == null || rangeMinText.trim().equals("")) {
				throw new SLDException("The minimum of the range must be specified.");
			}
			Float rangeMin = Float.parseFloat(rangeMinText.trim());
			String rangeMaxText = (String) xPath.evaluate(
					"./resc:Range/resc:Maximum", function, XPathConstants.STRING);
			if (rangeMaxText == null || rangeMaxText.trim().equals("")) {
				throw new SLDException("The maximum of the range must be specified.");
			}
			Float rangeMax = Float.parseFloat(rangeMaxText.trim());
			String spacingText = (String) xPath.evaluate(
					"./resc:Range/resc:Spacing", function, XPathConstants.STRING);
			Spacing spacing;
			if (spacingText == null || spacingText.equals("")) {
				spacing = Spacing.LINEAR;
			} else if (spacingText.equals("linear")) {
				spacing = Spacing.LINEAR;
			} else if (spacingText.equals("logarithmic")) {
				spacing = Spacing.LOGARITHMIC;
			} else {
				throw new SLDException("The spacing may be specified as \"linear\" or " + 
						"\"logarithmic\" or omitted to default to linear.");
			}
			return new SLDRange(rangeMin, rangeMax, spacing);
		} catch(Exception e) {
			throw new SLDException(e);
		}
	}

}
