package com.hero.util;

import java.math.BigDecimal;

import com.hero.HeroDesigner;

/**
 * Copyright (c) 2000 - 2005, CompNet Design, Inc. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, is prohibited unless the following conditions are met: 1.
 * Express written consent of CompNet Design, Inc. is obtained by the developer.
 * 2. Redistributions must retain this copyright notice. THIS SOFTWARE IS
 * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * @author CompNet Design, Inc.
 * @version $Revision$
 */

public class Rounder {

	public static long roundDown(double val) {
		BigDecimal bd = new BigDecimal(val);
		bd = bd.setScale(0, val >= 0 ? BigDecimal.ROUND_DOWN
				: BigDecimal.ROUND_UP);
		return bd.longValue();
	}

	public static long roundHalfDown(double val) {
		int num = HeroDesigner.getInstance().getPrefs()
				.getNumberDigitsForRounding();
		if (num <= 1) {
			BigDecimal bd = new BigDecimal(val + .00000000001);
			bd = bd.setScale(num, BigDecimal.ROUND_DOWN);
			val = bd.doubleValue();
		}
		while (num > 1) {
			val = Rounder.roundHalfDown(val, num);
			num--;
		}

		BigDecimal bd = new BigDecimal(val);
		// bd = bd.setScale(num, bd.ROUND_DOWN);
		// bd = new BigDecimal(bd.doubleValue());
		bd = bd.setScale(0, BigDecimal.ROUND_HALF_DOWN);
		return bd.longValue();
	}

	private static double roundHalfDown(double val, int dig) {
		BigDecimal bd = new BigDecimal(val + .00000000001);
		bd = bd.setScale(dig, BigDecimal.ROUND_DOWN);
		bd = new BigDecimal(bd.doubleValue() - .0000000001);
		/*
		 * The subtraction of a small amount is necessary to take care of
		 * internal rounding/cropping of values 1.55 will turn into 1.6
		 * otherwise.
		 */
		bd = bd.setScale(dig - 1, BigDecimal.ROUND_HALF_DOWN);
		return bd.doubleValue();
	}

	public static long roundHalfUp(double val) {
		int num = HeroDesigner.getInstance().getPrefs()
				.getNumberDigitsForRounding();
		if (num <= 1) {
			BigDecimal bd = new BigDecimal(val);
			bd = bd.setScale(num, BigDecimal.ROUND_DOWN);
			val = bd.doubleValue();
		}
		while (num > 1) {
			val = Rounder.roundHalfUp(val, num);
			num--;
		}

		BigDecimal bd = new BigDecimal(val);
		bd = bd.setScale(0, BigDecimal.ROUND_HALF_UP);
		return bd.longValue();
	}

	private static double roundHalfUp(double val, int digits) {
		BigDecimal bd = new BigDecimal(val);
		bd = bd.setScale(digits, BigDecimal.ROUND_DOWN);
		bd = new BigDecimal(bd.doubleValue() + .0000000001);
		/*
		 * The addition of a small amount is necessary to handle internal
		 * rounding/cropping of values. Otherwise 1.55 may be rounded to 1.5
		 * rather than 1.6
		 */
		bd = bd.setScale(digits - 1, BigDecimal.ROUND_HALF_UP);
		return bd.doubleValue();
	}

	public static long roundUp(double val) {
		BigDecimal bd = new BigDecimal(val);
		bd = bd.setScale(0, val >= 0 ? BigDecimal.ROUND_UP
				: BigDecimal.ROUND_DOWN);
		return bd.longValue();
	}

	public Rounder() {
	}
}