/*
 *  iReport  --  Visual designer for generating JasperReports Documents
 *  Copyright (C) 2002  Giulio Toffoli gt@businesslogic.it
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Giulio Toffoli
 *  Via T.Aspetti, 233
 *  35100 Padova ITALY
 *  gt@businesslogic.it
 */
package com.businesslogic.ireport.ui;

import com.ms.wfc.core.*;
import com.ms.wfc.ui.*;
import java.math.*;
import com.ms.lang.Delegate;

/**
 * Questa classe è un componente grafico. Il punto di ingresso per l'esecuzione
 * della classe è il costruttore.
 */
public class NumberEdit extends Edit
{
	
	private boolean isDouble;
	private int decimals;
	private double value;
	private boolean viewPlus;
	private boolean separatoreMigliaia;
	
	private static final Object EVENT_VALUECHANGED = new Object();
	
	public NumberEdit()
	{
		super();
		initForm();
		viewPlus=false;
		separatoreMigliaia=true;
	}
	
	public double getValue()
	{
		return value;
	}
	
	public void setValue(double value)
	{
		this.value = value;
		this.setText(this.doubleToString(value));
	}
	
	public void setValue(int value)
	{
		this.value = (new Integer(value)).doubleValue();
		this.setText(this.doubleToString(this.value));
	}
	
	public void setValue(long value)
	{
		this.value = (new Long(value)).doubleValue();
		this.setText(this.doubleToString(this.value));
	}
	
	public boolean getViewPlus()
	{
		return viewPlus;
	}
	
	public void setViewPlus(boolean viewPlus)
	{
		this.viewPlus = viewPlus;
	}
	
	public boolean getSeparatoreMigliaia()
	{
		return separatoreMigliaia;
	}
	
	public void setSeparatoreMigliaia(boolean separatoreMigliaia)
	{
		this.separatoreMigliaia = separatoreMigliaia;
	}
	
	public boolean getIsDouble()
	{
		return isDouble;
	}
	
	public void setIsDouble(boolean isDouble)
	{
		this.isDouble = isDouble;
	}
	
	public int getDecimals()
	{
		return decimals;
	}
	
	public void setDecimals(int decimals)
	{
		this.decimals = decimals;
	}
	
	public void onKeyDown(Object source, KeyEvent e)
	{
	}
	
	public void onLostFocus(Object source, Event e)
	{
		double new_value;
		try {
			if (isDouble)
				new_value = Double.valueOf(this.getText()).doubleValue();
			else
				new_value = Integer.valueOf(this.getText()).longValue();
		} catch (NumberFormatException ex)
		{
			new_value = value;
		}
		
		if (new_value != value)
		{
			value = new_value;
			onValueChanged(new Event());
		}	
		this.setText(this.doubleToString(value));
	
	}
	
	public void onGotFocus(Object source, Event e)
	{
		this.setText(this.doubleToNumberString(value));
		this.setSelectionRange(0,this.getText().length());
	}

	public void onKeyPress(Object source, KeyPressEvent e)
	{
		 
		if ( e.getKeyChar() == '0' ||
			 e.getKeyChar() == '1' ||
			 e.getKeyChar() == '2' ||
			 e.getKeyChar() == '3' ||
			 e.getKeyChar() == '4' ||
			 e.getKeyChar() == '5' ||
			 e.getKeyChar() == '6' ||
			 e.getKeyChar() == '7' ||
			 e.getKeyChar() == '8' ||
			 e.getKeyChar() == '9' ||
			 e.getKeyChar() == '+' ||
			 e.getKeyChar() == '-' ||
			 e.getKeyChar() == Key.BACK  ||
			 (isDouble && e.getKeyChar() == '.') ||
			 (isDouble && e.getKeyChar() == ',') ||
			 e.getKeyChar() == Key.RETURN)
		{
			if (e.getKeyChar() == '+')
			{
				if (this.getText().length() > 0 && this.getSelectionEnd() > 0  )
					e.handled = true;
			}
			if (e.getKeyChar() == '-')
			{
				if (this.getSelectionEnd() == this.getText().length() && this.getSelectionStart() == 0) ;	
				else if (this.getText().length() > 0 && this.getSelectionEnd() > 0  )
					e.handled = true;
			}
			else if  (e.getKeyChar() == '.')
			{
				if (this.getText().indexOf('.') > -1)
					e.handled = true;
			}
			else if  (e.getKeyChar() == ',')
			{
				if (this.getText().indexOf(',') > -1)
					e.handled = true;
			}
			else if (this.getSelectionEnd() ==0 && this.getText().length() >0 &&  (this.getText().charAt(0) == '-' || this.getText().charAt(0) == '+'))
				e.handled = true;
		}
		else
			e.handled = true;
	}
	
	
	/**
	 * Converte un double nel formato:
	 * 1.000.000.000.000.000...000,000000000000000000
	 */
	public String doubleToString(double d)
	{
		String str = "";
		double d2;
		// Odine massimo
		double ordine = 1.0e20;
		
		// Se d e' 0.0 ritorn 0.0000000...
		if (d == 0.0) {
			String r;
			if (viewPlus) r = "+0";
			else r = "0";
			if (isDouble){
				r += ",";
				for (int i=0; i<decimals; ++i)
					r+="0";
			}
			return r;
		}
		
		//Aumentiamo d2 del numero di ordini che ci interessa (decimals)...
		d2 = d;
		if (d2<0) d2=-d2;
		for (int i=0; i<this.decimals; ++i){
			d2 = d2 *10.0;
		}
		
		// Converte i numeri da 10^20 a 10^0
		// Arrotondamenti: validi massimo 
		
		int i=0;
		for (i=0; i<21; ++i)
		{
			//if (ordine == 1.0e2 && isDouble) str += ",";	
			if (i == (21-decimals) && isDouble)  str += ",";	
			if (d2 >= ordine)
			{ 
				if (i<(21-decimals) )
				{
					if (((i+decimals)%3) == 0 && separatoreMigliaia) str += ".";
				}
				// Estrapoliamo la cifra dell'ordine...
				int cifra = (int)((d2%(ordine*10.0))/ordine);
				str += cifra+"";
			}
			ordine = ordine/10.0;
		}
		
		if (str.charAt(0) == '.'){
			str = str.substring(1);
		}
		
		if (str.charAt(0) == ','){
			str = "0"+str;
		}
		
		if (d<0) str = "-"+str;
		else if (viewPlus) str = "+"+str;
		return str;
	}
	
	
	public String doubleToNumberString()
	{
		return doubleToNumberString(this.value);
	}
	
	
	public String doubleToNumberString(double d)
	{
		String str = "";
		double d2;
		double ordine = 1.0e20;
		if (d == 0.0)
			return "0";
		d2 = d;
		
		if (d2<0) d2=-d2;
		
		for (int i=0; i<this.decimals; ++i)
		{
			d2 = d2*10.0;
		}
		
		//str = d + "\n";
		// Converte i numeri da 10^20 a 10^0
		// Arrotondamenti: validi massimo 
		int i=0;
		for (i=0; i<21; ++i)
		{
			if (i == (21-decimals)) str += ".";	
			if (d2 >= ordine)
			{ 
				// Estrapoliamo la cifra dell'ordine...
				int cifra = (int)((d2%(ordine*10.0))/ordine);
				str += cifra+"";
			}
			ordine = ordine/10.0;
		}
		
		if (str.charAt(0) == '.'){
			str = "0"+str;
		}
		//str += "\n"+d;
		if (d<0)
			str = "-"+str;
		return str;
	}
	
	static public String doubleToString(double d,boolean isDouble,int decimals,boolean viewPlus)
	{
		return doubleToString(d,isDouble,decimals,viewPlus,true);
	}
	static public String doubleToString(double d,boolean isDouble,int decimals,boolean viewPlus,boolean viewMigliaia)
	{
		String str = "";
		double d2;
		// Odine massimo
		double ordine = 1.0e20;
		
		// Se d e' 0.0 ritorn 0.0000000...
		if (d == 0.0) {
			String r;
			if (viewPlus) r = "+0";
			else r = "0";
			if (isDouble){
				r += ",";
				for (int i=0; i<decimals; ++i)
					r+="0";
			}
			return r;
		}
		
		//Aumentiamo d2 del numero di ordini che ci interessa (decimals)...
		d2 = d;
		if (d2<0) d2=-d2;
		for (int i=0; i<decimals; ++i){
			d2 = d2 *10.0;
		}
		
		// Converte i numeri da 10^20 a 10^0
		// Arrotondamenti: validi massimo 
		
		int i=0;
		for (i=0; i<21; ++i)
		{
			//if (ordine == 1.0e2 && isDouble) str += ",";	
			if (i == (21-decimals) && isDouble)  str += ",";	
			if (d2 >= ordine)
			{ 
				if (i<(21-decimals) )
				{
					if (((i+decimals)%3) == 0 && viewMigliaia) str += ".";
				}
				// Estrapoliamo la cifra dell'ordine...
				int cifra = (int)((d2%(ordine*10.0))/ordine);
				str += cifra+"";
			}
			ordine = ordine/10.0;
		}
		
		if (str.charAt(0) == '.'){
			str = str.substring(1);
		}
		
		if (str.charAt(0) == ','){
			str = "0"+str;
		}
		
		if (d<0) str = "-"+str;
		else if (viewPlus) str = "+"+str;
		return str;
	}
	
	
	protected void onValueChanged(Event e) {
             fireEvent(EVENT_VALUECHANGED, e);
    }	
	
	public void addOnValueChanged(EventHandler value) {
        addEventHandler(EVENT_VALUECHANGED, value);
	}

    public void removeOnValueChanged(EventHandler value) {
       removeEventHandler(EVENT_VALUECHANGED,value);
    }
	
	protected void fireEvent(Object key, Event e) {
        com.ms.lang.Delegate handler = getEventHandler(key);
        if (handler != null) ((EventHandler)handler).invoke(this, e);
    }
	
	/**
	 * NOTA: il seguente codice è richiesto dalla finestra di progettazione form 
	 * di Visual J++. È possibile modificarlo con l'Editor di form.  Non modificarlo
	 * con l'Editor del codice.
	 */
	Container components = new Container();

	private void initForm()
	{
		this.setSize(new Point(297, 56));
		this.setText("NumberEdit");
		this.addOnKeyDown(new KeyEventHandler(onKeyDown));
		this.addOnKeyPress(new KeyPressEventHandler(onKeyPress));
		this.addOnLostFocus(new EventHandler(onLostFocus));
		this.addOnGotFocus(new EventHandler(onGotFocus));
		
	}

	public static class ClassInfo extends Edit.ClassInfo
	{
		public static final PropertyInfo isDouble =
                                               new PropertyInfo(NumberEdit.class, "isDouble", Boolean.TYPE,
            CategoryAttribute.Appearance,
            LocalizableAttribute.NO ,
            new DescriptionAttribute("E' un numero in virgola?"));
		
		public static final PropertyInfo decimals =
                                               new PropertyInfo(NumberEdit.class, "decimals", Integer.TYPE,
            CategoryAttribute.Appearance,
            LocalizableAttribute.NO ,
            new DescriptionAttribute("Quante cifre dopo la virgola?"));

		public static final PropertyInfo value =
            new PropertyInfo(NumberEdit.class, "value", Double.TYPE,
            CategoryAttribute.Appearance,
            LocalizableAttribute.NO ,
            new DescriptionAttribute("VaLORE"));
		
		public static final PropertyInfo viewPlus =
            new PropertyInfo(NumberEdit.class, "viewPlus", Boolean.TYPE,
            CategoryAttribute.Appearance,
            LocalizableAttribute.NO ,
            new DescriptionAttribute("Mostra il + nei numeri positivi"));
	
		public static final PropertyInfo separatoreMigliaia =
            new PropertyInfo(NumberEdit.class, "separatoreMigliaia", Boolean.TYPE,
            CategoryAttribute.Appearance,
            LocalizableAttribute.NO ,
            new DescriptionAttribute("Imposta separatore"));
				
		public static final EventInfo OnValueChanged =
            new EventInfo(NumberEdit.class, "valueChanged", EventHandler.class,
            CategoryAttribute.Action ,
           new DescriptionAttribute("Occurs when value is changed!"));
			 
      // Add the properties.
      public void getProperties(IProperties props) {
		  super.getProperties(props);
         props.add(isDouble);
		 props.add(decimals);
		 props.add(value);
		 props.add(viewPlus);
		 props.add(separatoreMigliaia);

         //props.add(backColor);
      }
			
      // Add the events.
      public void getEvents(IEvents events) {
         super.getEvents(events);
		 events.add(OnValueChanged);
      }
	}
}
