/***********************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * 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:
 * Actuate Corporation - initial API and implementation
 ***********************************************************************/

package org.eclipse.birt.chart.ui.swt.composites;

import java.text.ParseException;
import java.util.Date;

import org.eclipse.birt.chart.model.component.ComponentPackage;
import org.eclipse.birt.chart.model.component.Dial;
import org.eclipse.birt.chart.model.data.DataElement;
import org.eclipse.birt.chart.model.data.DateTimeDataElement;
import org.eclipse.birt.chart.model.data.NumberDataElement;
import org.eclipse.birt.chart.model.data.impl.DateTimeDataElementImpl;
import org.eclipse.birt.chart.model.data.impl.NumberDataElementImpl;
import org.eclipse.birt.chart.model.type.DialSeries;
import org.eclipse.birt.chart.ui.extension.i18n.Messages;
import org.eclipse.birt.chart.ui.util.ChartUIUtil;
import org.eclipse.birt.chart.ui.util.UIHelper;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;

/**
 * @author Actuate Corporation
 * 
 */
public class DialScaleDialog implements Listener
{

	private transient Group grpScale = null;

	private transient Label lblMin = null;

	private transient TextEditorComposite txtScaleMin = null;

	private transient Label lblMax = null;

	private transient TextEditorComposite txtScaleMax = null;

	private transient Label lblStep = null;

	private transient TextEditorComposite txtScaleStep = null;

	private transient Label lblGridCount = null;

	private transient IntegerSpinControl iscGridCount = null;

	private transient DialSeries series;

	private transient Shell shell;

	/**
	 * @param parent
	 */
	public DialScaleDialog( Shell parent, DialSeries series )
	{
		super( );
		this.series = series;;

		shell = new Shell( parent, SWT.DIALOG_TRIM
				| SWT.RESIZE
				| SWT.APPLICATION_MODAL );
		shell.setSize( 400, 150 );
		shell.setLayout( new FillLayout( ) );
		UIHelper.centerOnScreen( shell );
		placeComponents( );
		
		shell.addShellListener( new ShellAdapter( ) {

			public void shellClosed( ShellEvent e )
			{
				Control focusControl = Display.getDefault( ).getFocusControl( );
				if ( focusControl instanceof Text )
				{
					// Force saving the text by notifying focus out
					focusControl.notifyListeners( SWT.FocusOut, null );
				}
			}
		} );
		
		shell.setText( Messages.getString( "DialScaleDialog.Title.DialScale" ) ); //$NON-NLS-1$
		shell.layout( );
		shell.open( );
		while ( !shell.isDisposed( ) )
		{
			if ( !shell.getDisplay( ).readAndDispatch( ) )
			{
				shell.getDisplay( ).sleep( );
			}
		}
	}

	protected Composite placeComponents( )
	{
		GridLayout glContent = new GridLayout( );
		glContent.numColumns = 2;
		glContent.marginHeight = 7;
		glContent.marginWidth = 7;
		glContent.verticalSpacing = 5;

		Composite cmpContent = new Composite( shell, SWT.NONE );
		cmpContent.setLayout( glContent );

		GridLayout glScale = new GridLayout( );
		glScale.numColumns = 4;
		glScale.horizontalSpacing = 5;
		glScale.verticalSpacing = 5;
		glScale.marginHeight = 2;
		glScale.marginWidth = 7;

		grpScale = new Group( cmpContent, SWT.NONE );
		GridData gdGRPScale = new GridData( GridData.FILL_HORIZONTAL );
		gdGRPScale.horizontalSpan = 2;
		grpScale.setLayoutData( gdGRPScale );
		grpScale.setLayout( glScale );
		grpScale.setText( Messages.getString( "OrthogonalSeriesDataSheetImpl.Lbl.Scale" ) ); //$NON-NLS-1$

		lblMin = new Label( grpScale, SWT.NONE );
		GridData gdLBLMin = new GridData( );
		lblMin.setLayoutData( gdLBLMin );
		lblMin.setText( Messages.getString( "OrthogonalSeriesDataSheetImpl.Lbl.Minimum" ) ); //$NON-NLS-1$

		txtScaleMin = new TextEditorComposite( grpScale, SWT.BORDER
				| SWT.SINGLE );
		GridData gdTXTScaleMin = new GridData( GridData.FILL_HORIZONTAL );
		txtScaleMin.setLayoutData( gdTXTScaleMin );
		txtScaleMin.setText( getValue( getDialForProcessing( ).getScale( )
				.getMin( ) ) );
		txtScaleMin.addListener( this );

		lblMax = new Label( grpScale, SWT.NONE );
		GridData gdLBLMax = new GridData( );
		lblMax.setLayoutData( gdLBLMax );
		lblMax.setText( Messages.getString( "OrthogonalSeriesDataSheetImpl.Lbl.Maximum" ) ); //$NON-NLS-1$

		txtScaleMax = new TextEditorComposite( grpScale, SWT.BORDER
				| SWT.SINGLE );
		GridData gdTXTScaleMax = new GridData( GridData.FILL_HORIZONTAL );
		txtScaleMax.setLayoutData( gdTXTScaleMax );
		txtScaleMax.setText( getValue( getDialForProcessing( ).getScale( )
				.getMax( ) ) );
		txtScaleMax.addListener( this );

		lblStep = new Label( grpScale, SWT.NONE );
		GridData gdLBLStep = new GridData( );
		lblStep.setLayoutData( gdLBLStep );
		lblStep.setText( Messages.getString( "OrthogonalSeriesDataSheetImpl.Lbl.Step" ) ); //$NON-NLS-1$
		lblStep.setEnabled( true );

		txtScaleStep = new TextEditorComposite( grpScale, SWT.BORDER
				| SWT.SINGLE );
		GridData gdTXTScaleStep = new GridData( GridData.FILL_HORIZONTAL );
		txtScaleStep.setLayoutData( gdTXTScaleStep );
		String str = ""; //$NON-NLS-1$
		if ( getDialForProcessing( ).getScale( )
				.eIsSet( ComponentPackage.eINSTANCE.getScale_Step( ) ) )
		{
			str = String.valueOf( getDialForProcessing( ).getScale( ).getStep( ) );
		}
		txtScaleStep.setText( str );
		txtScaleStep.addListener( this );
		txtScaleStep.setEnabled( true );

		GridLayout glGridCount = new GridLayout( );
		glGridCount.numColumns = 2;
		glGridCount.horizontalSpacing = 5;
		glGridCount.marginHeight = 0;
		glGridCount.marginWidth = 0;

		Composite cmpGridCount = new Composite( grpScale, SWT.NONE );
		GridData gdCMPGridCount = new GridData( GridData.FILL_HORIZONTAL );
		gdCMPGridCount.horizontalSpan = 4;
		cmpGridCount.setLayoutData( gdCMPGridCount );
		cmpGridCount.setLayout( glGridCount );

		lblGridCount = new Label( cmpGridCount, SWT.NONE );
		GridData gdLBLGridCount = new GridData( );
		lblGridCount.setLayoutData( gdLBLGridCount );
		lblGridCount.setText( Messages.getString( "OrthogonalSeriesDataSheetImpl.Lbl.MinorGridCount" ) ); //$NON-NLS-1$

		iscGridCount = new IntegerSpinControl( cmpGridCount,
				SWT.NONE,
				getDialForProcessing( ).getScale( ).getMinorGridsPerUnit( ) );
		GridData gdISCGridCount = new GridData( GridData.FILL_HORIZONTAL );
		iscGridCount.setLayoutData( gdISCGridCount );
		iscGridCount.addListener( this );

		return cmpContent;
	}

	public Dial getDialForProcessing( )
	{
		return series.getDial( );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
	 */
	public void handleEvent( Event event )
	{
		if ( event.widget.equals( txtScaleMin ) )
		{
			if ( txtScaleMin.getText( ).length( ) == 0 )
			{
				getDialForProcessing( ).getScale( )
						.eUnset( ComponentPackage.eINSTANCE.getScale_Min( ) );
			}
			else
			{
				DataElement de = getTypedDataElement( txtScaleMin.getText( ) );
				if ( de != null )
				{
					getDialForProcessing( ).getScale( ).setMin( de );
				}
			}
		}
		else if ( event.widget.equals( txtScaleMax ) )
		{
			if ( txtScaleMax.getText( ).length( ) == 0 )
			{
				getDialForProcessing( ).getScale( )
						.eUnset( ComponentPackage.eINSTANCE.getScale_Max( ) );
			}
			else
			{
				DataElement de = getTypedDataElement( txtScaleMax.getText( ) );
				if ( de != null )
				{
					getDialForProcessing( ).getScale( ).setMax( de );
				}
			}
		}
		else if ( event.widget.equals( txtScaleStep ) )
		{
			try
			{
				if ( txtScaleStep.getText( ).length( ) == 0 )
				{
					getDialForProcessing( ).getScale( )
							.eUnset( ComponentPackage.eINSTANCE.getScale_Step( ) );
				}
				else
				{
					double dbl = Double.valueOf( txtScaleStep.getText( ) )
							.doubleValue( );
					if ( dbl == 0 )
					{
						getDialForProcessing( ).getScale( )
								.eUnset( ComponentPackage.eINSTANCE.getScale_Step( ) );
					}
					else
					{
						getDialForProcessing( ).getScale( ).setStep( dbl );
					}
				}
			}
			catch ( NumberFormatException e1 )
			{
				txtScaleStep.setText( String.valueOf( getDialForProcessing( ).getScale( )
						.getStep( ) ) );
			}
		}
		else if ( event.widget.equals( iscGridCount ) )
		{
			getDialForProcessing( ).getScale( )
					.setMinorGridsPerUnit( ( (Integer) event.data ).intValue( ) );
		}
	}

	private String getValue( DataElement de )
	{
		if ( de instanceof DateTimeDataElement )
		{
			Date dt = ( (DateTimeDataElement) de ).getValueAsCalendar( )
					.getTime( );
			SimpleDateFormat sdf = new SimpleDateFormat( "MM/dd/yyyy" ); //$NON-NLS-1$
			return sdf.format( dt );
		}
		else if ( de instanceof NumberDataElement )
		{
			return ChartUIUtil.getDefaultNumberFormatInstance( )
					.format( ( (NumberDataElement) de ).getValue( ) );
		}
		return ""; //$NON-NLS-1$
	}

	private DataElement getTypedDataElement( String strDataElement )
	{
		SimpleDateFormat sdf = new SimpleDateFormat( "MM/dd/yyyy" ); //$NON-NLS-1$
		NumberFormat nf = ChartUIUtil.getDefaultNumberFormatInstance( );
		try
		{
			// First try Date
			Date dateElement = sdf.parse( strDataElement );
			Calendar cal = Calendar.getInstance( );
			cal.setTime( dateElement );
			return DateTimeDataElementImpl.create( cal );
		}
		catch ( ParseException e )
		{
			// Next try double
			try
			{
				Number numberElement = nf.parse( strDataElement );
				return NumberDataElementImpl.create( numberElement.doubleValue( ) );
			}
			catch ( ParseException e1 )
			{
				return null;
			}
		}
	}

	public boolean disposed( )
	{
		return shell.isDisposed( );
	}
}
