/*******************************************************************************
 * Copyright (c) 2009 Standards for Technology in Automotive Retail and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    David Carver - initial API and implementation
 *    Jesper Steen Moller - bug 283404 - fixed locale
 *     Mukul Gandhi - bug 280798 - PsychoPath support for JDK 1.4
 *******************************************************************************/

package org.eclipse.wst.xml.xpath2.processor.internal.types;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.FieldPosition;
import java.util.Locale;

/**
 * This is an XPath specific implementation of DecimalFormat to handle
 * some of the xpath specific formatting requirements.   Specifically
 * it allows for E# to be represented to indicate that the exponent value
 * is optional.  Otherwise all existing DecimalFormat patterns are handled
 * as is.
 * @author dcarver
 * @see 1.1
 *
 */
public class XPathDecimalFormat extends DecimalFormat {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -8229885955864187400L;
	private static final String NEG_INFINITY = "-INF";
	private static final String POS_INFINITY = "INF";

	public XPathDecimalFormat(String pattern) {
		// Xpath hardcodes this to US locale
		super(pattern, new DecimalFormatSymbols(Locale.US));
	}

	/**
	 * Formats the string dropping a Zero Exponent Value if it exists.
	 * @param obj
	 * @return
	 */
	public String xpathFormat(Object obj) {
		return formatXPath(obj);
	}

	private String formatXPath(Object obj) {
		String curPattern = toPattern();
		String newPattern = curPattern.replaceAll("E0", "");
		if (obj instanceof Float) {
            return formatFloatValue(obj, curPattern, newPattern);
		}
		if (obj instanceof Double) {
			return formatDoubleValue(obj, curPattern, newPattern);
		}
		return super.format(obj, new StringBuffer(), new FieldPosition(0)).toString();
	}

	private String formatDoubleValue(Object obj, String curPattern,
			String newPattern) {
		Double doubleValue = (Double) obj;
		if (isDoubleNegativeInfinity(doubleValue)) {
			return NEG_INFINITY;
		}
		if (isDoublePositiveInfinity(doubleValue)) {
			return POS_INFINITY;
		}
		doubleXPathPattern(obj, curPattern, newPattern);
		return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
	}

	private void doubleXPathPattern(Object obj, String curPattern,
			String newPattern) {
		BigDecimal doubValue = new BigDecimal((((Double) obj)).doubleValue());
		BigDecimal minValue = new BigDecimal("-1E6");
		BigDecimal maxValue = new BigDecimal("1E6");
		if (doubValue.compareTo(minValue) > 0 && doubValue.compareTo(maxValue) < 0) {
			applyPattern(newPattern);
		} else { //if (doubValue.compareTo(minValue) < 0) {
			applyPattern(curPattern.replaceAll("0\\.#", "0.0"));
		}
	}

	private boolean isDoublePositiveInfinity(Double doubleValue) {
		return doubleValue.doubleValue() == Double.POSITIVE_INFINITY;
	}

	private boolean isDoubleNegativeInfinity(Double doubleValue) {
		return doubleValue.doubleValue() == Double.NEGATIVE_INFINITY;
	}

	private String formatFloatValue(Object obj, String curPattern,
			String newPattern) {
		Float floatValue = (Float) obj;
		if (isFloatNegInfinity(floatValue)) {
			return NEG_INFINITY;
		}
		if (isFloatPosInfinity(floatValue)) {
			return POS_INFINITY;
		}
		floatXPathPattern(curPattern, newPattern, floatValue);
		return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
	}

	private boolean isFloatPosInfinity(Float floatValue) {
		return floatValue.floatValue() == Float.POSITIVE_INFINITY;
	}

	private boolean isFloatNegInfinity(Float floatValue) {
		return floatValue.floatValue() == Float.NEGATIVE_INFINITY;
	}

	private void floatXPathPattern(String curPattern, String newPattern,
			Float floatValue) {
		if (floatValue.floatValue() > -1E6f && floatValue.floatValue() < 1E6f) {
			
			applyPattern(newPattern);
		} else if (floatValue.floatValue() <= -1E6f) {
			applyPattern(curPattern.replaceAll("0\\.#", "0.0" ));
		}
	}
	
	
}
