package kr.gui.util;

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;

/**
 * Restricts RestrictedFields and RestrictedTextAreas by only allowing
 * floating point numbers
 */
public class DecimalRestrictor extends InsertRestrictor
{
	private int digitsBeforeDecimal;
	private int digitsAfterDecimal;
	private boolean allowNegatives;
	
	/**
	   @param digitsAfterDecimal ignored if non-positive
	 */
	public DecimalRestrictor(int digitsAfterDecimal)
	{
		this(-1, digitsAfterDecimal, false);
	}
	
	/**
	   @param digitsBeforeDecimal ignored if negative
	   @param digitsAfterDecimal ignored if non-positive
	 */
	public DecimalRestrictor(int digitsBeforeDecimal, int digitsAfterDecimal)
	{
		this(digitsBeforeDecimal, digitsAfterDecimal, false);
	}

	/**
	   @param digitsAfterDecimal ignored if non-positive
	   @param allowNegatives if true, negative values are allowed, otherwise false
	 */
	public DecimalRestrictor(int digitsAfterDecimal, boolean allowNegatives)
	{
		this(-1, digitsAfterDecimal, allowNegatives);
	}

	/**
	   @param digitsBeforeDecimal ignored if negative
	   @param digitsAfterDecimal ignored if non-positive
	   @param allowNegatives if true, negative values are allowed, otherwise false
	 */
	public DecimalRestrictor(int digitsBeforeDecimal, int digitsAfterDecimal, boolean allowNegatives)
	{
		super();
		this.digitsBeforeDecimal = digitsBeforeDecimal;
		this.digitsAfterDecimal = digitsAfterDecimal;
		this.allowNegatives = allowNegatives;
	}

	public static boolean verboseCheck(String s, int digitsBeforeDecimal, int digitsAfterDecimal, boolean allowNegatives)
	{
		boolean ret = check(s, digitsBeforeDecimal, digitsAfterDecimal, allowNegatives);
		
		if (! ret)
			System.err.println("DecimalRestrictor string='" + s
				+ "' isn't in the proper decimal format ("
				+ digitsAfterDecimal + " digits after decimal point)");

		return ret;
	}
	
	public static boolean check(String s, int digitsBeforeDecimal, int digitsAfterDecimal, boolean allowNegatives)
	{
		char[] source = s.toCharArray();
		boolean decimal = false;
		int dBeforeDecimal = 0;
		int dAfterDecimal = 0;
		
		for (int i = 0; i < source.length; i++)
		{
			if (Character.isDigit(source[i]))
			{
				if (decimal)
				{
					if (digitsAfterDecimal > 0
						&& dAfterDecimal >= digitsAfterDecimal)
						return false;
					else
						dAfterDecimal++;
				}
				else
				{
					if (digitsBeforeDecimal >= 0
						&& dBeforeDecimal >= digitsBeforeDecimal)
						return false;
					else
						dBeforeDecimal++;
				}
			}
			else if (source[i] == '.' && ! decimal)
				decimal = true;
			else if (source[i] != '-' || i !=0 || !allowNegatives)
				return false;
		}

		return true;
	}
	
	public String insertStringImpl(Document d, int offs, 
								   String str,
								   AttributeSet a) 
		throws BadLocationException
	{
		String docStr = d.getText(0, d.getLength());
		
		if (! verboseCheck(docStr, digitsBeforeDecimal, digitsAfterDecimal, allowNegatives))
		{
			return "";
		}

		StringBuffer docStrBuf = new StringBuffer(docStr);
		char[] source = str.toCharArray();
		char[] result = new char[source.length];
		int j = 0;
		boolean beeped = false;
		
		for (int i = 0; i < source.length; i++)
		{
			char c = source[i];
			
			if (Character.isDigit(c) || c == '.' || (c == '-' && allowNegatives))
			{
				docStrBuf.insert(offs++, c);
				if (check(docStrBuf.toString(), digitsBeforeDecimal, digitsAfterDecimal, allowNegatives))
					result[j++] = c;
				else if (! beeped)
				{
					beeped = true;
					//Toolkit.getDefaultToolkit().beep();
				}
			}
			else if (! beeped)
			{
				beeped = true;
				//Toolkit.getDefaultToolkit().beep();
			}
		}

		String s = new String(result, 0, j);
// 		System.err.println("DecimalRestrictor end:'" + s + "'");
		return s;
	}
}
