package org.my.package;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.opengis.filter.capability.FunctionName;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.ExpressionVisitor;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.Literal;

/**
 * 
 */
public class NumberFormatFunction implements Function {

	/** List of function parameters. */
	private final List<Expression> parameters;

	/** Fallback value. */
	private final Literal fallback;

	/**
	 * Make the instance of FunctionName available in a consistent spot.
	 */
	public static final FunctionName NAME = new Name();

	/**
	 * Describe how this function works. (should be available via FactoryFinder
	 * lookup...)
	 */
	public static class Name implements FunctionName {

		public final int getArgumentCount() {
			return 2; // indicating 2 arguments
		}

		public final List<String> getArgumentNames() {
			return Arrays.asList(new String[] { "Property Name",
					"Number format" });
		}

		public final String getName() {
			return "NumberFormat";
		}
	};

	public NumberFormatFunction() {
		this(new ArrayList<Expression>(), null);
	}

	public NumberFormatFunction(final List<Expression> someParameters,
			final Literal aFallback) {
		this.parameters = someParameters;
		this.fallback = aFallback;
	}

	/**
	 * @see org.opengis.filter.expression.Function#getFallbackValue()
	 */
	public final Literal getFallbackValue() {
		return fallback;
	}

	/**
	 * @see org.opengis.filter.expression.Function#getName()
	 */
	public final String getName() {
		return "NumberFormat";
	}

	/**
	 * @see org.opengis.filter.expression.Function#getParameters()
	 */
	public final List<Expression> getParameters() {
		return Collections.unmodifiableList(parameters);
	}

	/**
	 * @see org.opengis.filter.expression.Expression#accept(org.opengis.filter.expression.ExpressionVisitor,
	 *      java.lang.Object)
	 */
	public final Object accept(final ExpressionVisitor visitor,
			final Object extraData) {
		return visitor.visit(this, extraData);
	}

	/**
	 * @see org.opengis.filter.expression.Expression#evaluate(java.lang.Object)
	 */
	public final Object evaluate(final Object object) {
		return evaluate(object, Object.class);
	}

	/**
	 * @see org.opengis.filter.expression.Expression#evaluate(java.lang.Object,
	 *      java.lang.Class)
	 */
	@SuppressWarnings("unchecked")
	public final <T> T evaluate(final Object object, final Class<T> context) {
		Expression propertyName = parameters.get(0);
		Expression format = parameters.get(1);
		
		Double value = propertyName.evaluate(object, Double.class);
		String formatString = format.evaluate(object, String.class);
		
		DecimalFormat formatter = new DecimalFormat(formatString);

		return (T) formatter.format(value);
	}
}
