package jp.riken.brain.ni.samuraigraph.application;

import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Rectangle2D;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.prefs.Preferences;

import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.UIManager;

import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGDefaultValues;
import jp.riken.brain.ni.samuraigraph.base.SGDialog;
import jp.riken.brain.ni.samuraigraph.base.SGDrawingWindow;
import jp.riken.brain.ni.samuraigraph.base.SGExtensionFileFilter;
import jp.riken.brain.ni.samuraigraph.base.SGFigure;
import jp.riken.brain.ni.samuraigraph.base.SGFileChooser;
import jp.riken.brain.ni.samuraigraph.base.SGIAxisBreakElement;
import jp.riken.brain.ni.samuraigraph.base.SGIAxisElement;
import jp.riken.brain.ni.samuraigraph.base.SGIConstants;
import jp.riken.brain.ni.samuraigraph.base.SGIFigureElement;
import jp.riken.brain.ni.samuraigraph.base.SGIGraphElement;
import jp.riken.brain.ni.samuraigraph.base.SGILegendElement;
import jp.riken.brain.ni.samuraigraph.base.SGISignificantDifferenceElement;
import jp.riken.brain.ni.samuraigraph.base.SGIStringElement;
import jp.riken.brain.ni.samuraigraph.base.SGITimingLineElement;
import jp.riken.brain.ni.samuraigraph.base.SGUtility;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityNumber;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.data.SGDataTypeConstants;
import jp.riken.brain.ni.samuraigraph.data.SGSXYData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYMultipleData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYSamplingData;
import jp.riken.brain.ni.samuraigraph.data.SGVXYData;
import jp.riken.brain.ni.samuraigraph.figure.SGIFigureConstants;
import jp.riken.brain.ni.samuraigraph.figure.SGSXYFigure;
import jp.riken.brain.ni.samuraigraph.figure.SGVXYFigure;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;




/**
 * グラフ描画サーバクラス
 */
public class SGDrawingServer
{


	/**
	 * 
	 */
	public static String LOOK_AND_FEEL = null;


	/**
	 * 
	 */
	public static int PORT_NUMBER = -1;



	/**
	 * main method
	 * @param args
	 */
	public static void main( String args[] )
	{

		// interpret command lines
		interpretCommands( args );

		// create a Main thread
		Main m = new Main();

		// create a new thread
		if( PORT_NUMBER!=-1 )
		{
			try
			{
				// wait till the end of Main thread
				m.join();

				// create a server socket object
				ServerSocket serverSocket
					= new ServerSocket( SGDrawingServer.PORT_NUMBER );

//System.out.println("Connect");
				// create Connect thread
				Connect c = new Connect( m, serverSocket );
			}
			catch ( Exception ex )
			{
				JOptionPane.showOptionDialog(
					null,
					"Failed to start up Samurai Graph.",
					"Error",
					JOptionPane.DEFAULT_OPTION,
					JOptionPane.WARNING_MESSAGE, 
					null,
					null,
					null
				);
			}
			
		}

//System.out.println("END");
	}



	/**
	 * 
	 */
	private static void interpretCommands( final String[] commands )
	{
		
		for( int ii=0; ii<commands.length; ii++ )
		{
			if( commands[ii].equals("-p") )
			{
				if( ii+1<commands.length )
				{
					Integer n = SGUtilityText.getInteger( commands[ii+1] );
					if( n==null )
					{
						continue;
					}
					PORT_NUMBER = n.intValue();
				}
			}
			else
			{
				String className = getLookAndFeelClassName( commands[ii].toLowerCase() );
				if( className!=null )
				{
					LOOK_AND_FEEL = className;
				}
			}
		}

	}


	/**
	 * Returns the class name of look and feel.
	 * @param name - the short name of look and feel
	 * @return the class name of look and feel
	 */
	private static String getLookAndFeelClassName( String name )
	{
		if( name==null )
		{
			throw new IllegalArgumentException("name==null");
		}
		UIManager.LookAndFeelInfo[] lafArray
			= UIManager.getInstalledLookAndFeels();
		for( int ii=0; ii<lafArray.length; ii++ )
		{
			String name_ = lafArray[ii].getName().toLowerCase();
			if( name_.equals(name.toLowerCase()) )
			{
				LOOK_AND_FEEL = lafArray[ii].getClassName();
			}
		}
		return null;
	}




/**
 * Manage the lock file.
 * 
 */
private static class LockFileManager extends Thread
	implements SGIConstants, SGIApplicationConstants
{

	/**
	 * Name of the lock file.
	 */
	public static final String LOCK_FILE_NAME_EXTENSION = "lock";


	/**
	 * Cycle of creating the lock file.
	 */
	public static final int CYCLE = 1000;

	
	/**
	 * 
	 */
	private Main mConnect = null;

	
	/**
	 * Create a thread object.
	 *
	 */
	private LockFileManager( Main c )
	{
		super();
		this.mConnect = c;
		this.start();
	}
	

	/**
	 * 
	 */	
	public void run()
	{
		String fileName = "samurai-graph-"
			+ MAJOR_VERSION_NUMBER + "."
			+ MINOR_VERSION_NUMBER + "."
			+ MICRO_VERSION_NUMBER + "."
			+ LOCK_FILE_NAME_EXTENSION;
		File f = new File( TMP_DIR + FILE_SEPARATOR + fileName );

		Main c = this.mConnect;

		try
		{
			if( f.exists() )
			{
				// if the lock file is not so old, delete it and exit
				final long diff  = System.currentTimeMillis() - f.lastModified();
				if( diff < 2*CYCLE )
				{
					f.delete();
					System.exit(0);
				}
			}

			// loop of observing the lock file
			while( true )
			{
				if( f.exists()==false )
				{
					// except the start-up of application, create a new window
					final int num = c.getWindowNumber();
					if( num!=0 )
					{
						SGDrawingWindow wnd = c.createNewWindow();
						wnd.setVisible(true);
					}
				}
				
				// recreate the lock file
				f.delete();
				f.createNewFile();
				f.deleteOnExit();
				f.setReadOnly();

				// stop this thread
				Thread.sleep(CYCLE);
			}
		}
		catch( Exception ex )
		{
			return;
		}
	}

}



/**
 * A class to handle proxy connection.
 * 
 */
private static class ProxyManager
	implements ActionListener, SGIPreferencesConstants
{

	/**
	 * A flag whether access to the internet is direct.
	 */
	private boolean mDirectAccessFlag = true;
	

	/**
	 * The name of proxy server.
	 */
	private String mProxyHostName = null;
	
	
	/**
	 * The port number of proxy.
	 */
	private int mProxyPortNumber = -1;


	/**
	 * 
	 *
	 */
	private ProxyManager()
	{
		this.setProxyOnStartUp();
	}


	/**
	 * 
	 * @return
	 */
	private boolean setProxyOnStartUp()
	{
		Preferences pref = Preferences.userNodeForPackage( this.getClass() );
		final boolean direct = pref.getBoolean( PREF_KEY_DIRECT_ACCESS, true );
		final String hostName = pref.get( PREF_KEY_PROXY_HOST_NAME, "" );
		final int portNumber = pref.getInt( PREF_KEY_PROXY_PORT_NUMBER, -1 );

		this.mDirectAccessFlag = direct;
		if( hostName.equals("") == false )
		{
			this.mProxyHostName = hostName;
		}
		if( portNumber!=-1 )
		{
			this.mProxyPortNumber = portNumber;
		}
		return true;
	}
	


	/**
	 * 
	 * @return
	 */
	public boolean isDirectAccess()
	{
		return this.mDirectAccessFlag;
	}

	
	/**
	 * 
	 * @param b
	 */
	public void setDirectAccess( boolean b )
	{
		this.mDirectAccessFlag = b;
	}
	
	
	/**
	 * 
	 * @return
	 */
	public String getProxyHostName()
	{
		return this.mProxyHostName;
	}

	
	/**
	 * 
	 * @return
	 */
	public int getProxyPortNumber()
	{
		return this.mProxyPortNumber;
	}

	
	/**
	 * 
	 * @param name
	 */
	public void setProxyHostName( final String name )
	{
		this.mProxyHostName = name;
	}

	
	/**
	 * 
	 * @param num
	 */
	public void setProxyPortNumber( final int num )
	{
		this.mProxyPortNumber = num;
	}


	/**
	 * 
	 * @return
	 */
	private boolean showProxySettingDialog( Frame owner )
	{
		SGProxySettingDialog dg = new SGProxySettingDialog(owner,true);
		dg.addActionListener( this );
		dg.setCenter(owner);

		// set properties
		dg.setDirectAccess( this.mDirectAccessFlag );
		dg.setHostName( this.mProxyHostName );
		dg.setPortNumber( this.mProxyPortNumber );

		// show dialog
		dg.setVisible(true);
		
		return true;
	}



	/**
	 * 
	 */
	public void actionPerformed( ActionEvent e )
	{
		Object source = e.getSource();
		SGProxySettingDialog dg = (SGProxySettingDialog)source;
		String command = e.getActionCommand();
		if( command.equals( SGDialog.OK_BUTTON_TEXT ) )
		{
			this.mDirectAccessFlag = dg.isDirectAccess();
			this.mProxyHostName = dg.getHostName();
			this.mProxyPortNumber = dg.getPortNumber();
			
			Preferences pref = Preferences.userNodeForPackage( this.getClass() );
			pref.putBoolean( PREF_KEY_DIRECT_ACCESS, this.mDirectAccessFlag );
			pref.put( PREF_KEY_PROXY_HOST_NAME, this.mProxyHostName );
			pref.putInt( PREF_KEY_PROXY_PORT_NUMBER, this.mProxyPortNumber );
		}
	}


}



/**
 * A class to manage upgrade of the application.
 */
private static class UpgradeManager
	implements ActionListener,
		SGIConstants, SGIUpgradeConstants,
		SGIApplicationConstants, SGIPreferencesConstants
{

	/**
	 * A file chooser to download the new version.
	 */
	private JFileChooser mUpgradeFileChooser;


	/**
	 * 
	 */
	private SGUpgradeDialog mUpgradeDialog;


	/**
	 * 
	 */
	private ProxyManager mProxyManager;


	/**
	 * 
	 *
	 */
	private UpgradeManager( ProxyManager p )
	{
		this.mProxyManager = p;
		this.mUpgradeFileChooser = new SGFileChooser();
		this.mUpgradeFileChooser.setCurrentDirectory( new File( USER_HOME ) );
	}
	
	
	/**
	 * 
	 */
	public void actionPerformed( final ActionEvent e )
	{
		Object source = e.getSource();
		String command = e.getActionCommand();

		int type;
		if( command.equals( SGDialog.OK_BUTTON_TEXT ) )
		{
			String cycle = this.mUpgradeDialog.getUpgradeCycle();

			if( cycle.equals( SGUpgradeDialog.NO_UPGRADE ) )
			{
				type = NO_UPGRADE;
			}
			else if( cycle.equals( SGUpgradeDialog.EVERY_TIME ) )
			{
				type = UPGRADE_EVERY_TIME;
			}
			else if( cycle.equals( SGUpgradeDialog.EVERY_DAY ) )
			{
				type = UPGRADE_EVERY_DAY;
			}
			else if( cycle.equals( SGUpgradeDialog.EVERY_WEEK ) )
			{
				type = UPGRADE_EVERY_WEEK;
			}
			else if( cycle.equals( SGUpgradeDialog.EVERY_MONTH ) )
			{
				type = UPGRADE_EVERY_MONTH;
			}
			else
			{
				throw new Error();
			}

			// update the upgrade cycle
			Preferences pref = Preferences.userNodeForPackage( this.getClass() );
			pref.putInt( PREF_KEY_UPGRADE_CYCLE, type );

		}
		else if( command.equals( SGUpgradeDialog.UPGRADE_NOW ) )
		{
			SGUpgradeDialog dg = (SGUpgradeDialog)source;
			if( this.upgradeByCommand(dg) == false )
			{
				return;
			}
		}

	}

	
	/**
	 * 
	 * @param wnd
	 * @return
	 */
	private boolean showUpgradeDialog( Frame owner )
	{
		this.mUpgradeDialog = new SGUpgradeDialog( owner,true );
		this.mUpgradeDialog.addActionListener( this );

		this.mUpgradeDialog.setCenter(owner);

		Preferences pref = Preferences.userNodeForPackage( this.getClass() );
		final int cycleType = pref.getInt( PREF_KEY_UPGRADE_CYCLE, NO_UPGRADE );

		String cycle = null;
		switch( cycleType )
		{
			case NO_UPGRADE:
			{
				cycle = SGUpgradeDialog.NO_UPGRADE;
				break;
			}

			case UPGRADE_EVERY_TIME:
			{
				cycle = SGUpgradeDialog.EVERY_TIME;
				break;
			}

			case UPGRADE_EVERY_DAY:
			{
				cycle = SGUpgradeDialog.EVERY_DAY;
				break;
			}

			case UPGRADE_EVERY_WEEK:
			{
				cycle = SGUpgradeDialog.EVERY_WEEK;
				break;
			}

			case UPGRADE_EVERY_MONTH:
			{
				cycle = SGUpgradeDialog.EVERY_MONTH;
				break;
			}

			default:
			{
				cycle = SGUpgradeDialog.NO_UPGRADE;
			}
		}
		this.mUpgradeDialog.setUpgradeCycle( cycle );


		// show
		this.mUpgradeDialog.setVisible(true);

		return true;
	}



	/**
	 * 
	 *
	 */
	private boolean upgradeOnStartup( Window owner )
	{
		return this.upgrade(owner,true);
	}


	/**
	 * 
	 *
	 */
	private boolean upgradeByCommand( Window owner )
	{
		return this.upgrade(owner,false);
	}

	

	/**
	 * 
	 * @param owner
	 * @param onStartUp
	 */
	private boolean upgrade( final Window owner, final boolean onStartUp )
	{

		final boolean direct = this.mProxyManager.isDirectAccess();
		String host = this.mProxyManager.getProxyHostName();
		int port = this.mProxyManager.getProxyPortNumber();


		// get URL
		URL url = null;
		try
		{
			if( direct )
			{
				url = new URL( PRODUCT_XML_FILE_NAME );
			}
			else
			{
				url = new URL(
						"http",
						host,
						port,
						PRODUCT_XML_FILE_NAME
					);
			}
		}
		catch( Exception ex )
		{
			JOptionPane.showMessageDialog(
					owner,
					"URL is invalid."
				);
			return false;
		}

		// create a Document object
		Document doc = SGUtilityText.getDocument( url );
		if( doc==null )
		{
			JOptionPane.showMessageDialog(
				owner,
				"Failed to get information of the latest version."
			);
			return false;
		}


		// update the date
		if( onStartUp )
		{
			Preferences pref = Preferences.userNodeForPackage( this.getClass() );
			pref.putLong( PREF_KEY_DATE, System.currentTimeMillis() );
		}


		// get root element - product
		Element root = doc.getDocumentElement();

		// compare the version number
		if( this.compareVersion( root ) )
		{
			// start installation
			if( this.installLatestVersion(
				root,
				owner,
				onStartUp ) == false )
			{
				return false;
			}
		}
		else
		{
			if( !onStartUp )
			{
				// show a message dialog
				String msg = "The latest version is already installed.";
				JOptionPane.showMessageDialog( owner, msg );
			}
		}
	
		return true;
	}


	/**
	 * 
	 * @return
	 */
	private boolean compareVersion( Element root )
	{
		Preferences pref = Preferences.userNodeForPackage( this.getClass() );
		final int major = pref.getInt( PREF_KEY_MAJOR_VERSION_NUMBER, -1 );
		final int minor = pref.getInt( PREF_KEY_MINOR_VERSION_NUMBER, -1 );
		final int micro = pref.getInt( PREF_KEY_MICRO_VERSION_NUMBER, -1 );

		final int nMajor = this.getVersion( root, "majorver" );
		final int nMinor = this.getVersion( root, "minorver" );
		final int nMicro = this.getVersion( root, "microver" );
		final boolean b = Utility.compareVersionNumber( major, minor, micro, nMajor, nMinor, nMicro );
		return b;
	}






	/**
	 * 
	 * @param root
	 * @param tagName
	 * @return
	 */
	private int getVersion( Element root, String tagName )
	{
		Element ver = (Element)root.getElementsByTagName(tagName).item(0);
		String verString = ver.getFirstChild().getNodeValue();
		final int verNumber = Integer.parseInt( verString );
		return verNumber;
	}

	
	
	/**
	 * 
	 * @param root
	 * @return
	 * @throws Exception
	 */
	private boolean installLatestVersion(
		Element root, final Window owner, final boolean onStartUp )
	{
		// current version numbers
		final int mMajor = MAJOR_VERSION_NUMBER;
		final int mMinor = MINOR_VERSION_NUMBER;
		final int mMicro = MICRO_VERSION_NUMBER;
		
		// get later releases and the latest release
		NodeList rList = root.getElementsByTagName("release");
		Element latestRelease = null;
		ArrayList laterReleaseList = new ArrayList();
		for( int ii=0; ii<rList.getLength(); ii++ )
		{
			Element el = (Element)rList.item(ii);
			String value = el.getAttribute("latest");
			if( Boolean.TRUE.toString().equals(value) )
			{
				latestRelease = el;
			}

			final int nMajor = this.getVersion( el, "majorver" );
			final int nMinor = this.getVersion( el, "minorver" );
			final int nMicro = this.getVersion( el, "microver" );
			if( Utility.compareVersionNumber( mMajor,mMinor,mMicro,nMajor,nMinor,nMicro ) )
			{
				laterReleaseList.add(el);
			}
		}

		if( latestRelease==null )
		{
			JOptionPane.showMessageDialog(
				owner,
				"Statement in the XML file is wrong."
			);
			return false;
		}


		// get the latest version numbers
		final int nMajor = this.getVersion( latestRelease, "majorver" );
		final int nMinor = this.getVersion( latestRelease, "minorver" );
		final int nMicro = this.getVersion( latestRelease, "microver" );

		final String major = new Integer( nMajor ).toString();
		final String minor = new Integer( nMinor ).toString();
		final String micro = new Integer( nMicro ).toString();

		// create a message
		String msg = "Samurai Graph Ver." + major + "." + minor + "." + micro + " is found.\n"
			+ "Download now?\n";

		
		// get the change log
		StringBuffer sb = new StringBuffer("<html><head></head><body>-- New Features --");
//		StringBuffer sb = new StringBuffer("-- New Features --\n");
		String fSize = "<font size=\"3\">";
		sb.append(fSize);
		for( int ii=0; ii<laterReleaseList.size(); ii++ )
		{
			Element release = (Element)laterReleaseList.get(ii);
			StringBuffer sb_ = new StringBuffer();
			NodeList rInfoList = release.getElementsByTagName("releaseinfo");
			Element rInfo = (Element)rInfoList.item(0);
			NodeList cLogList = rInfo.getElementsByTagName("changelog");
			Element cLog = (Element)cLogList.item(0);
			this.printNode(cLog,sb_);
			sb.append(sb_);
		}

		
		// create a message dialog
		SGUpgradeConfirmDialog cfDialog = null;
		if( owner instanceof Frame )
		{
			cfDialog = new SGUpgradeConfirmDialog( (Frame)owner, true );
		}
		else if( owner instanceof Dialog )
		{
			cfDialog = new SGUpgradeConfirmDialog( (Dialog)owner, true );
		}
		cfDialog.setMessage(msg);
		cfDialog.setPage( new String(sb) );
		cfDialog.pack();
		cfDialog.setCenter(owner);

		// show a message dialog
		cfDialog.setVisible(true);

		// if upgrade is canceled, return true
		if( cfDialog.isCanceled() )
		{
			return true;
		}


		// get OS name
		String name = null;
		if( SGUtility.identifyOS( OS_NAME_WINDOWS ) )
		{
			name = "win32";
		}
		else if( SGUtility.identifyOS( OS_NAME_MACOSX ) )
		{
			name = "macosx";
		}
		else
		{
			name = "other";
		}


		// upgrade
		NodeList pList = latestRelease.getElementsByTagName("package");
		for( int ii=0; ii<pList.getLength(); ii++ )
		{
			Element el = (Element)pList.item(ii);
			String attr = el.getAttribute("category");

			if( attr.equals("win32") )
			{
				if( name.equals("win32") )
				{
					if( this.forWin32(el,major,minor,micro,owner,onStartUp) )
					{
						break;
					}
					else
					{
						return false;
					}
				}
			}
			else if( attr.equals("macosx") )
			{
				if( name.equals("macosx") )
				{
					if( this.forMacOSX(el,major,minor,micro,owner,onStartUp) )
					{
						break;
					}
					else
					{
						return false;
					}
				}
			}
			else if( attr.equals("bin") )
			{
				if( name.equals("other") )
				{
					if( this.forOtherPlatform(el,major,minor,micro,owner,onStartUp) )
					{
						break;
					}
					else
					{
						return false;
					}
				}
			}
			else if( attr.equals("src") )
			{

			}

		}

		return true;
	}



	/**
	 * 
	 * @param el
	 * @param major Major version number of the new version
	 * @param minor Minor version number of the new version
	 * @param micro Micro version number of the new version
	 * @param owner Dialog owner
	 * @param onStartUp whether this upgrade is on the start-up
	 * @return true:success, false:failure
	 */
	private boolean forWin32(
		final Element el,
		final String major,
		final String minor,
		final String micro,
		final Window owner,
		final boolean onStartUp )
	{

		final String failed = "Upgrade is failed for some reason.";

		// show a message dialog
		if( !onStartUp )
		{
			String msg = "This application will be terminated.\n"
				+"Present work will be lost.";
			String title = "Warning";
			Object[] options = { "OK", "Cancel" };
			final int ret = JOptionPane.showOptionDialog(
				owner,
				msg,
				title,
				JOptionPane.DEFAULT_OPTION,
				JOptionPane.WARNING_MESSAGE, 
				null,
				options,
				options[0]
			);
			if( ret==JOptionPane.NO_OPTION || ret==JOptionPane.CLOSED_OPTION )
			{
				return true;
			}
		}


		// get the root directory
		String classpath = System.getProperty("java.class.path");
		StringTokenizer stk = new StringTokenizer( classpath, PATH_SEPARATOR );
		String root = null;
		while( stk.hasMoreTokens() )
		{
			String str = stk.nextToken();
			if( str.endsWith("samurai-graph.jar") )
			{
				root = new File( str ).getParent();
				break;
			}
		}
		if( root==null )
		{
			JOptionPane.showMessageDialog(
				owner,
				failed
			);
			return false;
		}

//JOptionPane.showMessageDialog( null, root );

		// copy the helper application from ./lib to the temporay directory
		File helper = new File( root + FILE_SEPARATOR + "lib" + FILE_SEPARATOR + UPGRADE_HELPER_FILE_NAME );
		if( helper.exists() == false )
		{
			JOptionPane.showMessageDialog(
				owner,
//				"Helper application is not found."
				failed
			);
			return false;
		}

//JOptionPane.showMessageDialog( null, helper );


		File helperTempDir = new File( TMP_DIR + FILE_SEPARATOR + HELPER_TEMP_DIR_NAME );
		if( helperTempDir.mkdir() == false )
		{
			JOptionPane.showMessageDialog(
				owner,
//				"Failed to create a temporary directory."
				failed
			);
			return false;
		}
		File helperTemp = new File( helperTempDir.getAbsolutePath() + FILE_SEPARATOR + UPGRADE_HELPER_FILE_NAME );

		try
		{
			SGApplicationUtility.copyBinaryFile( helper, helperTemp );
		}
		catch( IOException ex )
		{
			JOptionPane.showMessageDialog(
				owner,
//				"Failed to copy the helper application."
				failed
			);
			return false;
		}



		//
		// download the installer
		//

		File installer = null;
		try
		{
			installer = File.createTempFile( "tmp_", ".exe" );
		}
		catch( IOException ex )
		{
			return false;
		}
		finally
		{
			if( installer!=null )
			{
				installer.delete();
			}
		}

		if( this.download( el, owner, installer ) == false )
		{
			JOptionPane.showMessageDialog(
				owner,
//				"Failed to download the latest version."
				failed
			);
			installer.delete();
			return false;
		}

//installer = new File("D:\\Tmp\\samurai-graph-win32-0.3.1.exe");

		//
		// start the helper application
		//

		String upperDir = new File( root ).getParent();

//JOptionPane.showMessageDialog( owner, "current@"+currentInstDir );
//JOptionPane.showMessageDialog( owner, "upper@"+upperDir );

		String instPath = installer.getAbsolutePath();
		String suffix = major + "." + minor + "." + micro;
//		String pathNew = upperDir + FILE_SEPARATOR + "Samurai Graph "+major+"."+minor+"."+micro;

String pathNew = root;

//JOptionPane.showMessageDialog( owner, "pathNew@"+pathNew );

		String[] cmdArray = new String[6];
		cmdArray[0] = System.getProperty("java.home") + FILE_SEPARATOR + "bin" + FILE_SEPARATOR + "javaw.exe";
		cmdArray[1] = "-jar";
		cmdArray[2] = helperTemp.getAbsolutePath();
		cmdArray[3] = root;			// A pathname string of the old version
		cmdArray[4] = instPath;		// A pathname string of the installer
		cmdArray[5] = pathNew;		// A pathname string of the new version

		if( helperTemp.exists() == false )
		{
			JOptionPane.showMessageDialog(
				owner,
//				"Helper application is not found."
				failed
			);
			return false;
		}

		try
		{
			Runtime.getRuntime().exec( cmdArray, null, new File( upperDir ) );
		}
		catch( IOException ex )
		{
			JOptionPane.showMessageDialog(
				owner,
//				"Failed to start the helper application."
				failed
			);
			return false;
		}
		

		return true;
	}






	/**
	 * 
	 * @param el
	 * @return
	 * @throws Exception
	 */
	private boolean forOtherPlatform(
		final Element el, final String major, final String minor, final String micro,
		final Window owner, final boolean onStartUp )// throws Exception
	{
		return this.downloadWithFileChooser(
			el, major, minor, micro, owner, onStartUp,
			"samurai-graph-bin", "zip", "Zip Archive" );
	}



	/**
	 * 
	 * @param el
	 * @return
	 * @throws Exception
	 */
	private boolean forMacOSX(
		final Element el, final String major, final String minor, final String micro,
		final Window owner, final boolean onStartUp )// throws Exception
	{
		return this.downloadWithFileChooser(
			el, major, minor, micro, owner, onStartUp,
			"samurai-graph-mac", "dmg.gz", "Compressed Disk Image" );
	}



	/**
	 * 
	 * @param el
	 * @param major
	 * @param minor
	 * @param micro
	 * @param owner
	 * @param onStartUp
	 * @param extension
	 * @param description
	 * @return
	 * @throws Exception
	 */
	private boolean downloadWithFileChooser(
		final Element el, final String major, final String minor, final String micro,
		final Window owner, final boolean onStartUp, final String name, final String extension,
				final String description )
	{
		JFileChooser chooser = this.mUpgradeFileChooser;

		// create a file filter object
		SGExtensionFileFilter ff = new SGExtensionFileFilter();
		ff.setDescription( extension );
		ff.addExtension( description );
		chooser.setFileFilter( ff );


		// set file name
		String fileName = name + "-" + major + "." + minor + "." + micro + "." + extension;
		chooser.setSelectedFile( new File( fileName ) );


		// show save dialog
		final int ret = chooser.showSaveDialog(owner);

		File fileSaved = null;
		switch( ret )
		{
			// selected
			case JFileChooser.APPROVE_OPTION :
			{
				fileSaved = chooser.getSelectedFile();
				break;
			}

			// canceled
			case JFileChooser.CANCEL_OPTION :
			{
				return true;
			}

			// error
			case JFileChooser.ERROR_OPTION :
			{
				throw new Error();
			}

			default :
			{
				
			}
		}

		String path = fileSaved.getAbsolutePath();
		if( path.endsWith( extension ) == false
			&& path.endsWith( extension.toUpperCase() ) == false )
		{
			path += "." + extension;
		}
		File file = new File(path);

		// download
		if( this.download( el, owner, file ) == false )
		{
			return false;
		}

		return true;
	}



	/**
	 * 
	 * @param el
	 * @param owner
	 * @param suffix
	 * @return
	 * @throws Exception
	 */
	private boolean download(
		final Element el, final Window owner, final File file )
	{
		BufferedOutputStream bos = null;
		BufferedInputStream bis = null;
		SGProgressMonitorDialog dg = null;

		boolean ret = false;

		try
		{
			// create output stream
			bos = new BufferedOutputStream( new FileOutputStream(file) );
	
			NodeList urlList = el.getElementsByTagName("url");
			for( int ii=0; ii<urlList.getLength(); ii++ )
			{
				Element urlElement = (Element)urlList.item(ii);
				String urlStr = urlElement.getFirstChild().getNodeValue();
	
				// create an URL instance
				URL url = null;
				try
				{
					url = new URL(urlStr);
				}
				catch( MalformedURLException ex )
				{
					continue;
				}
	
				// get input stream
				URLConnection co = null;
				try
				{
					co = url.openConnection();
					bis = new BufferedInputStream( co.getInputStream() );
				}
				catch( IOException ex )
				{
					continue;
				}

				// get file name
				String path = file.getAbsolutePath();
/*				final int nameLen = 20;
				if( path.length() > nameLen )
				{
					path = path.substring(0,nameLen);
					path += "...";
				}
*/

				// get file size
				final int fileSize = co.getContentLength();

				// create a progress monitor dialog
				boolean modal = true;
				if( owner instanceof Dialog )
				{
					dg = new SGProgressMonitorDialog( (Dialog)owner, modal );
				}
				else if( owner instanceof JFrame )
				{
					dg = new SGProgressMonitorDialog( (Frame)owner, modal );
				}


				// set properties of the progress bar
				JProgressBar pBar = dg.getProgressBar();
				pBar.setMinimum(0);
				pBar.setMaximum(fileSize);
				pBar.setStringPainted(true);


				// set properties of the dialog
				dg.setInputSize(fileSize);
				dg.setInputStream(bis);
				dg.setOutputStream(bos);
				dg.setLabel(path);
				dg.pack();
				dg.setCenter(owner);


				// set the mouse cursor
				owner.setCursor(
					Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );


				// start download
				Thread th = new Thread(dg);
				th.start();

				dg.setVisible(true);


				if( dg.isCanceled() == true )
				{
					return false;
				}

				ret = true;
				break;
			}

		}
		catch( FileNotFoundException ex )
		{
			JOptionPane.showMessageDialog(
				owner,
				"Local file is missing."
			);
			return false;
		}
		finally
		{

			// set default cursor
			owner.setCursor( Cursor.getDefaultCursor() );

			// clear attributes
			dg.setInputStream(null);
			dg.setOutputStream(null);

			// close streams
			if( bis!=null )
			{
				try
				{
					bis.close();
				}
				catch( IOException ex )
				{
				}
			}
			
			if( bos!=null )
			{
				try
				{
					bos.close();
				}
				catch( IOException ex )
				{
				}
			}
		}


		// when connection failed, return false
		if( !ret )
		{
			JOptionPane.showMessageDialog(
				owner,
				"Connection failed."
			);
			return false;
		}

		return true;
	}



	/**
	 * 
	 * @param element
	 * @param tagList
	 * @param out
	 */
	private void printNode(
		Element element, StringBuffer sb )
	{
		printNodeRecursively( element, sb, -1 );
	}



	/**
	 * 
	 * @param node
	 * @return
	 */
	private void printNodeRecursively(
		Element element, StringBuffer sb, final int depth )
	{
		NodeList childList = element.getChildNodes();
		for( int ii=0; ii<childList.getLength(); ii++ )
		{
			Node child = childList.item(ii);
			if( child instanceof Element )
			{
				Element el = (Element)child;
				String tagName = el.getTagName();
				if( tagName.equals("item") )
				{
					NodeList nList = el.getChildNodes();
					final int num = nList.getLength();
					if( num==1 )
					{
						sb.append("<li>");
						printFirstChild( el, sb, depth );
						sb.append("</li>");
					}
					else if( num>1 )
					{
						sb.append("<li>");
						printFirstChild( el, sb, depth );
						sb.append("<ul>");
						for( int jj=0; jj<num; jj++ )
						{
							Node node = nList.item(jj);
							if( node instanceof Element )
							{
								Element el_ = (Element)node;
								printNodeRecursively( el_, sb, depth+1 );
							}
						}
						sb.append("</ul>");
						sb.append("</li>");
					}
				}
				else if( tagName.equals("itemize") )
				{
					sb.append("<ul>");
					printNodeRecursively( el, sb, depth+1 );
					sb.append("</ul>");
				}
			}
			else if( child instanceof Text )
			{
				
			}
		}

	}


	/**
	 * 
	 * @param node
	 * @param out
	 * @param depth
	 */
	private void printFirstChild(
		Node node, StringBuffer sb, final int depth )
	{
		Node child = node.getFirstChild();
		printText( child, sb, depth );
	}


	/**
	 * 
	 * @param node
	 * @param out
	 * @param depth
	 */
	private void printText(
		Node node, StringBuffer sb, final int depth )
	{
		String line = node.toString();
		String sub = tokenize(line);
		if( sub.length()!=0 )
		{
			sb.append(sub);
		}
	}


	/**
	 * 
	 * @param line
	 * @return
	 */
	private String tokenize( String line )
	{
		StringTokenizer tkn = new StringTokenizer(line);
		ArrayList tokenList = new ArrayList();
		while( tkn.hasMoreTokens() )
		{
			tokenList.add( tkn.nextToken() );
		}

		String subStr = "";
		for( int ii=0; ii<tokenList.size(); ii++ )
		{
			String str = (String)tokenList.get(ii);
			subStr += str;
			if( ii!=tokenList.size()-1 )
			{
				subStr += " ";
			}
		}

		return subStr;
	}



}



/**
 * An utility class with static methods.
 */
private static class Utility
{
	

	/**
	 * Check whether one version is released later than the other version.
	 * @param m1
	 * @param m2
	 * @param m3
	 * @param n1
	 * @param n2
	 * @param n3
	 * @return	whether the version n is released later than version m
	 */
	public static boolean compareVersionNumber(
		final int m1, final int m2, final int m3,
		final int n1, final int n2, final int n3 )
	{
		boolean b;
		if( m1 < n1 )
		{
			b = true;
		}
		else if( m1 == n1 )
		{
			if( m2 < n2 )
			{
				b = true;
			}
			else if( m2 == n2 )
			{
				b = ( m3 < n3 );
			}
			else
			{
				b = false;
			}
		}
		else
		{
			b = false;
		}

		return b;
	}

}



/**
 * 
 */
private static class Connect extends Thread
{
	
	/**
	 * Server socket.
	 */
	private ServerSocket mServerSocket = null;


	/**
	 * Main object.
	 */
	private Main mMain;


	/**
	 * Create a thread object with a server socket.
	 * @param main
	 * @param serverSocket
	 */
	private Connect( Main main, ServerSocket serverSocket )
	{
		super();
		this.mMain = main;
		this.mServerSocket = serverSocket;

		this.start();
	}
	

	/**
	 * 
	 */
	public void run()
	{
		//
		// infinite loop as a server process
		//

		while( true )
		{
			try
			{
				// クライアントからの接続を待つ
				Socket socket = mServerSocket.accept();

				// 出力ストリームを取得
				PrintWriter out = new PrintWriter( socket.getOutputStream(), true );

				// 入力ストリームを取得
				BufferedReader in = new BufferedReader(
					new InputStreamReader( socket.getInputStream() ) );

				// 入力ストリームからの読み込み
				ArrayList commandList = new ArrayList();
				String inputLine;
				while( (inputLine = in.readLine()) != null )
				{
					commandList.add( new String( inputLine ) );
				}
				if( commandList.size() == 0 )
				{
					System.out.println("入力がありません。");
					continue;
				}
				String[] commandArray = new String[commandList.size()];
				for( int ii=0; ii<commandArray.length; ii++ )
				{
					commandArray[ii] = (String)commandList.get(ii);
				}


				//
				// コマンドラインに応じた処理
				//
				
				if( this.mMain.executeCommand(commandArray) == false )
				{
// TODO:クライアントにエラーメッセージを返す
					continue;
				}

// TODO:クライアントに成功したメッセージを返す


				// 入出力ストリームを閉じる
				in.close();
				out.close();

				// ソケットを閉じる
				socket.close();

			}
			catch(Exception ex)
			{
				ex.printStackTrace();
			}
		}
			
	}

}




/**
 * 
 * @author kuromaru
 *
 * この生成されたコメントの挿入されるテンプレートを変更するため
 * ウィンドウ > 設定 > Java > コード生成 > コードとコメント
 */
private static class DropEventHandler extends Thread
{

	/**
	 * 
	 */
	private Main mMain;


	/**
	 * 
	 */
	private DropTargetDropEvent mDropTargetDropEvent = null;


	/**
	 * 
	 */
	private ArrayList mDroppedFileList = null;


	/**
	 * 
	 * @param m
	 */
	private DropEventHandler( Main m, DropTargetDropEvent dtde, List list )
	{
		super();

		this.mMain = m;
		this.mDropTargetDropEvent = dtde;
		this.mDroppedFileList = new ArrayList( list );
		
		this.start();
	}


	/**
	 * 
	 */
	public void run()
	{
		DropTargetDropEvent dtde = this.mDropTargetDropEvent;
		DropTarget tg = (DropTarget)dtde.getSource();
		Component com = tg.getComponent();
		SGDrawingWindow wnd = (SGDrawingWindow)com;
		Point p = dtde.getLocation();

		this.mMain.fromDragAndDrop( p.x, p.y, wnd, this.mDroppedFileList );

		wnd.getContentPane().repaint();

		this.mDropTargetDropEvent = null;
		this.mDroppedFileList = null;
	}

}




/**
 *  The main thread.
 */
private static class Main extends Thread
	implements ActionListener, WindowListener, DropTargetListener,
		SGIConstants,
		SGIUpgradeConstants, SGIApplicationCommandConstants,
		SGIApplicationConstants, SGIPropertyFileConstants,
		SGIPreferencesConstants, SGIApplicationTextConstants
{


	/**
	 * The class object for SGIAxisElement.
	 */
	private Class mClassOfAxisElement = null;


	/**
	 * The class object for SGIGraphElement of the scalar XY-type.
	 */
	private Class mClassOfSXYGraphElement = null;


	/**
	 * The class object for SGIGraphElement of the vector XY-type.
	 */
	private Class mClassOfVXYGraphElement = null;


	/**
	 * The class object for SGILegendElement.
	 */
	private Class mClassOfLegendElement = null;


	/**
	 * The class object for SGIStringElement.
	 */
	private Class mClassOfStringElement = null;

	
	/**
	 * The class object for SGIAxisBreakElement.
	 */
	private Class mClassOfAxisBreakElement = null;

	
	/**
	 * The class object for SGISignificantDifferenceElement.
	 */
	private Class mClassOfSignificantDifferenceElement = null;
	
	
	/**
	 * The class object for SGITimingLineElement.
	 */
	private Class mClassOfTimingLineElement = null;
	

	/**
	 * The list of windows.
	 */
	private TreeMap mWndMap = new TreeMap();


	/**
	 * Image file creator.
	 */
	private SGImageExportManager mImageFileCreator;


	/**
	 * Property file creator.
	 */
	private SGPropertyFileCreator mPropertyFileCreator;


	/**
	 * Proxy manager.
	 */
	private ProxyManager mProxyManager;


	/**
	 * Upgrade manager.
	 */
	private UpgradeManager mUpgradeManager;


	/**
	 * Data creator.
	 */
	private SGDataCreator mDataCreator;



	/**
	 * Create a thread object.
	 *
	 */
	public Main()
	{
		super();
		this.start();
	}


	/**
	 * 
	 */
	public void run()
	{

		// create a lock file
		LockFileManager lfc = new LockFileManager(this);

		
		// remove temporary files used in upgrade
		this.removeTemporaryFiles();


		// create and show the splash window
		SGSplashWindow sw = this.createSplashWindow();
		if( sw==null )
		{
			return;
		}
		sw.setVisible(true);


		// set Look & Feel
		try
		{
			if( LOOK_AND_FEEL==null )
			{
				UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
			}
			else
			{
				UIManager.setLookAndFeel( LOOK_AND_FEEL );
			}
		}
		catch( Exception ex )
		{
			
		}


		// create instances in attributes
		this.mDataCreator = new SGDataCreator();
		this.mPropertyFileCreator = new SGPropertyFileCreator();
		this.mImageFileCreator = new SGImageExportManager();
		this.mProxyManager = new ProxyManager();
		this.mUpgradeManager = new UpgradeManager( this.mProxyManager );


		// create the figure element
		try
		{
			if( this.setFigureElementClass() == false )
			{
				throw new Exception();
			}
		}
		catch( Exception ex )
		{
			JOptionPane.showMessageDialog(
				null,
				"Failed to create instances of SGFigureElement classes."
			);
			this.exit(0);
		}


		// create a window
		SGDrawingWindow wnd = this.createNewWindow();
		if( wnd==null )
		{
			JOptionPane.showMessageDialog(
				null,
				"Failed to create a window."
			);
			return;
		}
		wnd.setVisible(true);

		
		// hide the splash window
		sw.setVisible(false);


		// update the preferences
		this.updatePreferences();


		// decide whether to upgrade
		if( this.checkDate() )
		{
			// upgrade
			if( this.mUpgradeManager.upgradeOnStartup(wnd) == false )
			{
				return;
			}
		}

	}



	/**
	 * Remove temporary files used in upgrade.
	 */
	private void removeTemporaryFiles()
	{
		File temp = new File( TMP_DIR + FILE_SEPARATOR + HELPER_TEMP_DIR_NAME );
		try
		{
			temp = temp.getCanonicalFile();
		}
		catch( IOException ex )
		{
			return;
		}
		if( temp.exists() )
		{
			SGApplicationUtility.deleteRecursively( temp );
		}
	}




	/**
	 * 
	 * @return
	 */
	private void updatePreferences()
	{
		Preferences pref = Preferences.userNodeForPackage( this.getClass() );

		// update the upgrade cycle at the first installation
		final int cycle = pref.getInt( PREF_KEY_UPGRADE_CYCLE, -1 );
		if( cycle==-1 )
		{
			pref.putInt( PREF_KEY_UPGRADE_CYCLE, DEFAULT_UPGRADE_CYCLE );
		}

		// update the version numbers
		final String date = pref.get( PREF_KEY_DATE, null );
		final int major = pref.getInt( PREF_KEY_MAJOR_VERSION_NUMBER, -1 );
		final int minor = pref.getInt( PREF_KEY_MINOR_VERSION_NUMBER, -1 );
		final int micro = pref.getInt( PREF_KEY_MICRO_VERSION_NUMBER, -1 );
		boolean b = false;

		// At the first installation
		if( date==null || major==-1 || minor==-1 || micro==-1 )
		{
			b = true;
		}
		// At the start-up of the application
		else
		{
			b = Utility.compareVersionNumber(
				major, minor, micro,
				MAJOR_VERSION_NUMBER, MINOR_VERSION_NUMBER, MICRO_VERSION_NUMBER );
		}

		if( b )
		{
			pref.putLong( PREF_KEY_DATE, System.currentTimeMillis() );
			pref.putInt( PREF_KEY_MAJOR_VERSION_NUMBER, MAJOR_VERSION_NUMBER );
			pref.putInt( PREF_KEY_MINOR_VERSION_NUMBER, MINOR_VERSION_NUMBER );
			pref.putInt( PREF_KEY_MICRO_VERSION_NUMBER, MICRO_VERSION_NUMBER );
		}
	}




	/**
	 * Check whether to do auto-upgrade.
	 * @return whether to do auto-upgrade
	 */
	private boolean checkDate()
	{
		Preferences pref = Preferences.userNodeForPackage( this.getClass() );
		final long time = pref.getLong( PREF_KEY_DATE, 0 );
		final long current = System.currentTimeMillis();
		final long diff = current - time;

		final long day = 1000*3600*24;
		final long week = 7*day;
		final long month = 30*day;
		final int cycle = pref.getInt( PREF_KEY_UPGRADE_CYCLE, UPGRADE_EVERY_TIME );

		boolean b;
		switch( cycle )
		{
			case NO_UPGRADE :
			{
				b = false;
				break;
			}

			case UPGRADE_EVERY_TIME :
			{
				b = true;
				break;
			}

			case UPGRADE_EVERY_DAY :
			{
				b = ( diff > day );
				break;
			}

			case UPGRADE_EVERY_WEEK :
			{
				b = ( diff > week );
				break;
			}

			case UPGRADE_EVERY_MONTH :
			{
				b = ( diff > month );
				break;
			}

			default :
			{
				b = false;
			}
		}

		return b;
	}




	/**
	 * Create instances of the figure elements.
	 */
	private boolean setFigureElementClass()
		throws ClassNotFoundException, InstantiationException, IllegalAccessException
	{

		// open the file
		FileReader fr = null;
		BufferedReader br = null;

		try
		{
			try
			{
				fr = new FileReader("ListOfFigureElement.txt");
			}
			catch( FileNotFoundException ex )
			{
				// If the file is not found, create instances of the default class.
				this.mClassOfAxisElement = Class.forName(DEFAULT_CLASS_NAME_OF_AXIS_ELEMENT);
				this.mClassOfSXYGraphElement = Class.forName(DEFAULT_CLASS_NAME_OF_SXY_GRAPH_ELEMENT);
				this.mClassOfVXYGraphElement = Class.forName(DEFAULT_CLASS_NAME_OF_VXY_GRAPH_ELEMENT);
				this.mClassOfStringElement = Class.forName(DEFAULT_CLASS_NAME_OF_STRING_ELEMENT);
				this.mClassOfLegendElement = Class.forName(DEFAULT_CLASS_NAME_OF_LEGEND_ELEMENT);
				this.mClassOfAxisBreakElement = Class.forName(DEFAULT_CLASS_NAME_OF_AXIS_BREAK_ELEMENT);
				this.mClassOfSignificantDifferenceElement = Class.forName(DEFAULT_CLASS_NAME_OF_SIGNIFICANT_DIFFERENCE_ELEMENT);
				this.mClassOfTimingLineElement = Class.forName(DEFAULT_CLASS_NAME_OF_TIMING_LINE_ELEMENT);
				return true;
			}

			br = new BufferedReader( fr );

			String line = null;
			Class cl = null;

			// SGAxisElement
			if( (line=SGUtilityText.readLine(br)) == null )
			{
				return false;
			}
			if( (line=SGUtilityText.getPropertyFromLine(line,"SGAxisElement")) == null )
			{
				return false;
			}
			cl = Class.forName(line);
			if( ( cl.newInstance() instanceof SGIAxisElement ) == false )
			{
				return false;
			}
			this.mClassOfAxisElement = cl;


			// SGSXYGraphElement
			if( (line=SGUtilityText.readLine(br)) == null )
			{
				return false;
			}
			if( (line=SGUtilityText.getPropertyFromLine(line,"SGSXYGraphElement")) == null )
			{
				return false;
			}
			cl = Class.forName(line);
			if( ( cl.newInstance() instanceof SGIGraphElement ) == false )
			{
				return false;
			}
			this.mClassOfSXYGraphElement = cl;


			// SGVXYGraphElement
			if( (line=SGUtilityText.readLine(br)) == null )
			{
				return false;
			}
			if( (line=SGUtilityText.getPropertyFromLine(line,"SGVXYGraphElement")) == null )
			{
				return false;
			}
			cl = Class.forName(line);
			if( ( cl.newInstance() instanceof SGIGraphElement ) == false )
			{
				return false;
			}
			this.mClassOfVXYGraphElement = cl;


			// SGLegendElement
			if( (line=SGUtilityText.readLine(br)) == null )
			{
				return false;
			}
			if( (line=SGUtilityText.getPropertyFromLine(line,"SGLegendElement")) == null )
			{
				return false;
			}
			cl = Class.forName(line);
			if( ( cl.newInstance() instanceof SGILegendElement ) == false )
			{
				return false;
			}
			this.mClassOfLegendElement = cl;


			// SGStringElement
			if( (line=SGUtilityText.readLine(br)) == null )
			{
				return false;
			}
			if( (line=SGUtilityText.getPropertyFromLine(line,"SGStringElement")) == null )
			{
				return false;
			}
			cl = Class.forName(line);
			if( ( cl.newInstance() instanceof SGIStringElement ) == false )
			{
				return false;
			}
			this.mClassOfStringElement = cl;

			
			// SGAxisBreakElement
			if( (line=SGUtilityText.readLine(br)) == null )
			{
				return false;
			}
			if( (line=SGUtilityText.getPropertyFromLine(line,"SGAxisBreakElement")) == null )
			{
				return false;
			}
			cl = Class.forName(line);
			if( ( cl.newInstance() instanceof SGIAxisBreakElement ) == false )
			{
				return false;
			}
			this.mClassOfAxisBreakElement = cl;

			
			// SGSignificantDifferenceElement
			if( (line=SGUtilityText.readLine(br)) == null )
			{
				return false;
			}
			if( (line=SGUtilityText.getPropertyFromLine(line,"SGSignificantDifferenceElement")) == null )
			{
				return false;
			}
			cl = Class.forName(line);
			if( ( cl.newInstance() instanceof SGISignificantDifferenceElement ) == false )
			{
				return false;
			}
			this.mClassOfSignificantDifferenceElement = cl;

			
			// SGTimingLineElement
			if( (line=SGUtilityText.readLine(br)) == null )
			{
				return false;
			}
			if( (line=SGUtilityText.getPropertyFromLine(line,"SGTimingLineElement")) == null )
			{
				return false;
			}
			cl = Class.forName(line);
			if( ( cl.newInstance() instanceof SGITimingLineElement ) == false )
			{
				return false;
			}
			this.mClassOfTimingLineElement = cl;

		}
		finally
		{
			if( br!=null )
			{
				try
				{
					br.close();
				}
				catch( IOException ex )
				{
					
				}
			}
		}

		return true;

	}



	/**
	 * 
	 */
	private boolean executeCommand( final String[] commandArray )
	{

		// 第1引数のコマンド名に応じて分岐
		boolean flag = true;
		if( COM_WOPEN.equals( commandArray[0]) )
		{
			flag = this.wopen( commandArray );
		}
		else if( COM_ADD_DATE.equals(commandArray[0]) )
		{
			flag = this.addDataByCommandLine( commandArray );
		}
		else if( COM_READ_PROPERTY.equals(commandArray[0]) )
		{
			flag = this.readWindowProperty( commandArray );
		}
		else
		{
			System.out.println("コマンド名が不正です。");
			return false;
		}

		if( !flag )
		{
			return false;
		}


		return true;

	}



	/**
	 * 
	 */
	private boolean wopen( final String[] commandArray )
	{

		if( commandArray.length < 1 )
		{
			return false;
		}


		// ウインドウ番号
		int windowID;
		if( commandArray.length > 1 )
		{
			String str = commandArray[1];
			Integer ID = this.getWindowIDFromString(str);
			if( ID==null )
			{
				return false;
			}
			windowID = ID.intValue();
		}
		else
		{
			windowID = this.getCurrentWindowID();
		}

		SGDrawingWindow wnd = this.getWindow(windowID);
		if( wnd != null )
		{
			System.out.println("そのウインドウは既に存在しています。");
			return false;
		}
		wnd = this.createWindow(windowID);
		if( wnd==null )
		{
			return false;
		}
		wnd.initPropertiesHistory();


		// show the window
		wnd.setVisible(true);


		return true;

	}



	/**
	 * 
	 */
	private SGDrawingWindow getWindowForCommand( final int windowID )
	{

		SGDrawingWindow wnd = this.getWindow( windowID );
		if( wnd==null )
		{
			System.out.println("指定されたウインドウはありません。");
			System.out.println("ウインドウを新規作成します。");
					
			// ウインドウを作成
			wnd = this.createWindow(windowID);
			if( wnd == null )
			{
				System.out.println("ウインドウの生成に失敗しました。");
				return null;
			}
			wnd.initPropertiesHistory();
		}

		return wnd;
	}



	/**
	 * 
	 */
	public static final int MAX_WINDOW_ID = 256;


	/**
	 * 
	 */
	private Integer getWindowIDFromString( final String str )
	{

		Integer ID;
		try
		{
			ID = Integer.valueOf(str);
		}
		catch ( Exception ex )
		{
			System.out.println("引数が不正です。");
			return null;
		}

		int id = ID.intValue();
		if( id < 1 )
		{
			System.out.println("ウインドウ番号は正の整数を入力して下さい。");
			return null;
		}
		else if( id > MAX_WINDOW_ID )
		{
			System.out.println("ウインドウ番号が大き過ぎます。");
			return null;
		}

		return ID;
	}



	/**
	 * 
	 */
	private boolean addDataByCommandLine( final String[] commandArray )
	{

		// ファイル名、[ウインドウ番号]、[フィギュア番号]を取得する
		if( commandArray.length < 2 )
		{
			System.out.println("コマンド引数が足りません。");
			return false;
		}

		// データファイル名
		String dataFileName = commandArray[1];


		// ウインドウ番号
		int windowID;
		if( commandArray.length > 2 )
		{
			final String str = commandArray[2];
			Integer ID = this.getWindowIDFromString(str);
			if( ID==null )
			{
				return false;
			}
			windowID = ID.intValue();
		}
		else
		{
			windowID = this.getCurrentWindowID();
		}


		// ウインドウの取得
		SGDrawingWindow wnd = this.getWindowForCommand( windowID );
		if( wnd==null )
		{
			return false;
		}


		// フィギュア番号
		int figureID;
		if( commandArray.length > 3 )
		{
			String str = commandArray[3];
			figureID = (Integer.valueOf(str)).intValue();
		}
		else
		{
			figureID = wnd.getCurrentFigureId();
		}


		// create a wizard dialog to select data-type
		this.mXYDataTypeSelectionWizardDialogFromCLorDD
			= new SGXYDataTypeSelectionWizardDialog( wnd, true );
		this.mXYDataTypeSelectionWizardDialogFromCLorDD.addActionListener(this);
		this.mXYDataTypeSelectionWizardDialogFromCLorDD.mPreviousButton.setEnabled(false);


		// create data object from file
		ArrayList dataList = new ArrayList();
		int ret;
		try
		{
			ret = this.createDataFromFile( dataFileName, dataList );
		}
		catch( FileNotFoundException ex )
		{
			SGUtility.showFileNotFoundMessageDialog( wnd );
			return false;
		}
		if( ret==-1 )
		{
			return false;
		}

		SGData data = (SGData)dataList.get(0);
		if( data == null )
		{
			System.out.println("データの構築に失敗しました。");
			return false;
		}


		// get the figure from the window
		SGFigure figure = wnd.getFigure( figureID );


		// create the data name
		String name = this.getNewDataName( figure, dataFileName );
		if( name==null )
		{
			return false;
		}


		// if figure does not exist or invisible, create a new figure
		if( figure==null || ( figure!=null && figure.isVisible()==false ) )
		{
			if( this.createNewFigure( wnd, figureID, data, new Point(), name ) == null )
			{
				return false;
			}
		}
		else
		// else add data to the figure
		{
			if( !figure.addData(data) )
			{
				System.out.println("データの型がフィギュアに合いません。");
				return false;
			}
		}


		return true;

	}




	/**
	 * 
	 */
	private boolean readWindowProperty( final String[] commandArray )
	{
/*
		if( commandArray.length < 3 )
		{
			System.out.println("引数が不足しています。");
			return false;
		}


		// プロパティファイル名
		final String propertyFileName = commandArray[1];



		// データを格納したファイル名をリストに保存
		this.mDataFileNameList.clear();	// 一旦、クリアする
		for( int ii=2; ii<commandArray.length; ii++ )
		{
			this.mDataFileNameList.add(commandArray[ii]);
		}

		// ウインドウにプロパティファイルを読み込ませる
		SGDrawingWindow wnd = null;

		if( wnd == null )
		{
			System.out.println("プロパティファイルの読み込みに失敗しました。");
		}
*/

		return true;

	}



	/**
	 * 
	 */
	private boolean readFigureProperty( final String[] commandArray )
	{
/*
		// 引数チェック
		if( commandArray.length < 3 )
		{
			System.out.println("引数が不足しています。");
			return false;
		}


		// ウインドウ番号の読み込み
		int windowID = -1;
		try
		{
			windowID = ( Integer.valueOf( commandArray[1] ) ).intValue();
		}
		catch( Exception ex )
		{
			ex.printStackTrace();
		}


		// 引数で指定されたウインドウを開く
		SGDrawingWindow wnd = this.getWindow( windowID );
		if( wnd == null )
		{
			System.out.println("指定されたウインドウはありません。");
			return false;
		}


		// データを格納したファイル名をリストに保存
		this.mDataFileNameList.clear();	// 一旦、クリアする
		for( int ii=2; ii<commandArray.length; ii++ )
		{
			this.mDataFileNameList.add(commandArray[ii]);
		}

*/

		return true;

	}



	/**
	 * Get the simple path name from absolute path name.
	 * @param aPath - given absolute path name
	 * @return simple path name
	 */
	private String getSimpleFileName( final String aPath )
	{
		final String fs = FILE_SEPARATOR;
		StringTokenizer stk = new StringTokenizer( aPath, fs );
		String sub = null;
		while( stk.hasMoreTokens() )
		{
			sub = stk.nextToken();
		}
		if( sub==null )
		{
			throw new Error();
		}

		String name = null;
		StringTokenizer stk2 = new StringTokenizer( sub, Character.toString('.') );
		while( stk2.hasMoreTokens() )
		{
			name = stk2.nextToken();
			break;
		}
		if( name==null )
		{
			name = sub;
		}

		return name;
	}



	/**
	 * Returns a string for the name of new data.
	 * @param figure
	 * @param aPath
	 * @return
	 */
	private String getNewDataName(
		final SGFigure figure, final String aPath )
	{
		String name = this.getSimpleFileName( aPath );
		if( name==null )
		{
			return null;
		}

		ArrayList list = figure.getVisibleDataList();
		ArrayList dNameList = new ArrayList();
		for( int ii=0; ii<list.size(); ii++ )
		{
			SGData data = (SGData)list.get(ii);
			String dName = figure.getDataName(data);
			dNameList.add( dName );
		}
		
		name = SGUtilityText.getSerialName( dNameList, name );

		return name;
	}



	/**
	 * 
	 * @param wnd
	 * @return
	 */
	private boolean setWindowLocation( final SGDrawingWindow wnd )
	{
		// set the location
		final Dimension scSize = Toolkit.getDefaultToolkit().getScreenSize();
		final int x = (int)( scSize.getWidth() - wnd.getWidth() )/2;
		final int y = (int)( scSize.getHeight() - wnd.getHeight() )/2;
		wnd.setLocation(x,y);
	
		return true;
	}


	/**
	 * 
	 */
	public SGDrawingWindow getWindow( final int wndID )
	{
		return (SGDrawingWindow)this.mWndMap.get( new Integer(wndID) );
	}


	/**
	 * 
	 * @return
	 */
	public int getWindowNumber()
	{
		return this.mWndMap.size();
	}


	/**
	 * 
	 */
	private SGFigure createFigure(
		final int figureID,
		final SGDrawingWindow wnd,
		final SGData data )
	{

		SGFigure figure = null;

		// XY型データの場合
		if( data instanceof SGSXYData || data instanceof SGSXYMultipleData )
		{
			figure = new SGSXYFigure( wnd );
		}
		else if( data instanceof SGVXYData )
		{
			figure = new SGVXYFigure( wnd );
		}
		else
		{
			return null;
		}

		figure.setVisible( false );

		//
		figure.setID(figureID);


		// SGFigureElementオブジェクトの追加
		if( this.createFigureElements( figure, data ) == false )
		{
			return null;
		}


		//
		float w = SGDefaultValues.DEFAULT_FIGURE_WIDTH;
		float h = w/SGIConstants.GOLDEN_RATIO;
		figure.setGraphRectSize( w, h );

		return figure;

	}



	/**
	 * 
	 */
	private boolean createFigureElements(
		final SGFigure figure,
		final SGData data )
	{

		try
		{

			// dialog owner
			Frame owner = figure.getWindow();


			// create a SGAxisElement
			SGIAxisElement axisElement = (SGIAxisElement)this.setIElement(
				this.mClassOfAxisElement, SGFigure.LAYER_AXIS, figure, owner );
			figure.setAxisElement(axisElement);


			// create a SGGraphElement
			Class clGraph = null;
			if( data instanceof SGSXYData || data instanceof SGSXYMultipleData)
			{
				clGraph = this.mClassOfSXYGraphElement;
			}
			else if( data instanceof SGVXYData )
			{
				clGraph = this.mClassOfVXYGraphElement;
			}
			else
			{
				return false;
			}
			SGIGraphElement graphElement = (SGIGraphElement)this.setIElement(
				clGraph, SGFigure.LAYER_GRAPH, figure, owner );
			figure.setGraphElement( graphElement );


			// create a SGLegendElement
			SGILegendElement legendElement = (SGILegendElement)this.setIElement(
				this.mClassOfLegendElement, SGFigure.LAYER_LEGEND, figure, owner );
			figure.setLegendElement( legendElement );


			// create a SGStringElement
			SGIStringElement stringElement = (SGIStringElement)this.setIElement(
				this.mClassOfStringElement, SGFigure.LAYER_STRING, figure, owner );
			figure.setStringElement( stringElement );


			// SGAxisBreakElement
			SGIAxisBreakElement axisBreakElement = (SGIAxisBreakElement)this.setIElement(
				this.mClassOfAxisBreakElement, SGFigure.LAYER_AXIS_BREAK, figure, owner );
			figure.setAxisBreakElement( axisBreakElement );

			
			// SGSignificantDifferenceElement
			SGISignificantDifferenceElement sigDiffElement = (SGISignificantDifferenceElement)this.setIElement(
				this.mClassOfSignificantDifferenceElement, SGFigure.LAYER_SIGNIFICANT_DIFFERENCE, figure, owner );
			figure.setSignificantDifferenceElement( sigDiffElement );
			

			// SGTimingLineElement
			SGITimingLineElement timingLineElement = (SGITimingLineElement)this.setIElement(
					this.mClassOfTimingLineElement, SGFigure.LAYER_TIMING_LINE, figure, owner );
			figure.setTimingLineElement( timingLineElement );


			// set relation between SGIFigureElement objects
			this.setRelationOfFigureElements( figure );

		}
		catch( Exception ex )
		{
			return false;
		}
		
		return true;
	}



	private void setRelationOfFigureElements( final SGFigure figure )
	{
		SGIAxisElement axis = figure.getAxisElement();
		SGIGraphElement graph = figure.getGraphElement();
		SGILegendElement legend = figure.getLegendElement();
		SGIStringElement string = figure.getStringElement();
		SGIAxisBreakElement axisBreak = figure.getAxisBreakElement();
		SGISignificantDifferenceElement sigDiff = figure.getSignigicantDifferenceElement();
		SGITimingLineElement timingLine = figure.getTimingLineElement();

		graph.setAxisElement( axis );
		legend.setAxisElement( axis );
		legend.setGraphElement( graph );
		axisBreak.setAxisElement( axis );
		sigDiff.setAxisElement( axis );
		timingLine.setAxisElement( axis );
		axis.setTimingLineElement( timingLine );
		string.setAxisElement( axis );
	}
	

	private SGIFigureElement setIElement(
		final Class cl, final int layer, final SGFigure figure, final Frame owner )
	{
		Object obj = null;
		try
		{
			obj = cl.newInstance();
		}
		catch( Exception ex )
		{
			return null;
		}

		JComponent com = (JComponent)obj;
		com.setBounds( 0, 0, figure.getWidth(), figure.getHeight() );
		com.setVisible(true);
		com.setOpaque(false);
		figure.add(com);
		figure.setLayer(com,layer);

		SGIFigureElement element = (SGIFigureElement)obj;
		element.addActionListener(figure);
		element.setDialogOwner(owner);

		return element;
	}




	/**
	 * データファイルを開いて情報を取得し、データを構築する
	 */
	private int createDataFromFile(
		final String pathName, final ArrayList dataList )
			throws FileNotFoundException
	{

		// ファイルの情報リスト
		ArrayList infoList = new ArrayList();

		// ファイルから情報を取得
		int ret = this.readFile( pathName, infoList );
		if( ret!=0 )
		{
			return ret;
		}

		// データの構築
		SGData data = this.mDataCreator.create( pathName, infoList );
		if( data==null )
		{
			return -1;
		}
		dataList.add(data);

		return 0;
	}




	/**
	 * 
	 */
	private SGFigureIDSelectionWizardDialog mFigureIDSelectionWizardDialog = null;


	/**
	 * 
	 */
	private SGMultiDataFileChooserWizardDialog mMultiDataFileChooserWizardDialog = null;


	/**
	 * 
	 */
	private SGSingleDataFileChooserWizardDialog mSingleDataFileChooserWizardDilaog = null;



	/**
	 * 
	 */
	private SGXYDataTypeSelectionWizardDialog mXYDataTypeSelectionWizardDialog = null;



	/**
	 * 
	 */
	private SGXYDataTypeSelectionWizardDialog mXYDataTypeSelectionWizardDialogFromCLorDD = null;


	/**
	 * 
	 */
	private SGPropertyFileChooserWizardDialog mPropertyFileChooserWizardDilaog = null;



	/**
	 * 
	 */
	private boolean createAllWizardDialogsForDataAdditionFromToolBar( final SGDrawingWindow owner )
	{

		//
		// create dialog objects
		//

		final int id = owner.getID();

		// dialog to select ID of window and figure
		this.mFigureIDSelectionWizardDialog
			= new SGFigureIDSelectionWizardDialog( owner, true );
		this.mFigureIDSelectionWizardDialog.getOKButton().setVisible(false);
		this.mFigureIDSelectionWizardDialog.getPreviousButton().setVisible(false);
		this.mFigureIDSelectionWizardDialog.pack();


		// dialog to select data files
		this.mSingleDataFileChooserWizardDilaog
			= new SGSingleDataFileChooserWizardDialog( owner, true );
		this.mSingleDataFileChooserWizardDilaog.getOKButton().setVisible(false);
		this.mSingleDataFileChooserWizardDilaog.pack();


		// set the selected file name
		String path = this.getCurrentFileDirectory();
		this.mSingleDataFileChooserWizardDilaog.setFile( path, this.mCurrentDataFileName );


		// dialog to select data-type
		this.mXYDataTypeSelectionWizardDialog
			= new SGXYDataTypeSelectionWizardDialog( owner, true );
		this.mXYDataTypeSelectionWizardDialog.getNextButton().setVisible(false);
		this.mXYDataTypeSelectionWizardDialog.pack();


		//
		// set next and previous dialogs
		//
		
		this.mFigureIDSelectionWizardDialog.setNext( this.mSingleDataFileChooserWizardDilaog );
		this.mSingleDataFileChooserWizardDilaog.setPrevious( this.mFigureIDSelectionWizardDialog );
		this.mSingleDataFileChooserWizardDilaog.setNext( this.mXYDataTypeSelectionWizardDialog );
		this.mXYDataTypeSelectionWizardDialog.setPrevious( this.mSingleDataFileChooserWizardDilaog );


		//
		// add action listener
		//

		this.mFigureIDSelectionWizardDialog.addActionListener(this);
		this.mSingleDataFileChooserWizardDilaog.addActionListener(this);
		this.mXYDataTypeSelectionWizardDialog.addActionListener(this);


		return true;

	}



	/**
	 * Path name of the selected data file.
	 */
//	private String mCurrentFileDirectory = null;


	/**
	 * 
	 */
	private String mCurrentDataFileName = null;


	/**
	 * 
	 */
	private String mCurrentPropertyFileName = null;



	/**
	 * Initialize the file path.
	 *
	 */
	private String getCurrentFileDirectory()
	{
		Preferences pref = Preferences.userNodeForPackage( this.getClass() );
		final String currentDir = pref.get( PREF_KEY_CURRENT_DIRECTORY, "" );
		if( currentDir==null )
		{
			String path = USER_HOME;
			if( SGUtility.identifyOS( OS_NAME_WINDOWS ) )
			{
				path += FILE_SEPARATOR + MY_DOCUMENTS;
			}
			this.setCurrentFileDirectory(path);
		}
		
		return currentDir;

//		if( this.mCurrentFileDirectory==null )
//		{
//			String path = USER_HOME;
//			if( SGUtility.identifyOS( OS_NAME_WINDOWS ) )
//			{
//				path += FILE_SEPARATOR + MY_DOCUMENTS;
//			}
//			this.setCurrentFileDirectory(path);
//		}
//		return this.mCurrentFileDirectory;
	}



	/**
	 * 
	 * @param path
	 */
	private void setCurrentFileDirectory( final String path )
	{
		Preferences pref = Preferences.userNodeForPackage( this.getClass() );
		pref.put( PREF_KEY_CURRENT_DIRECTORY, path );
//		this.mCurrentFileDirectory = path;
//System.out.println(path);
	}


	/**
	 * 
	 */
	private boolean createAllWizardDialogsToLoadPropertyFromToolBar(
		final SGDrawingWindow owner )
	{
		
		//
		// create dialog objects
		//

		// dialog to load property file
		this.mPropertyFileChooserWizardDilaog
			= new SGPropertyFileChooserWizardDialog( owner, true );
		this.mPropertyFileChooserWizardDilaog.getPreviousButton().setVisible(false);
		this.mPropertyFileChooserWizardDilaog.getOKButton().setVisible(false);
		this.mPropertyFileChooserWizardDilaog.pack();


		// dialog to select data files
		this.mMultiDataFileChooserWizardDialog
			= new SGMultiDataFileChooserWizardDialog( owner, true );
		this.mMultiDataFileChooserWizardDialog.getNextButton().setVisible(false);
		this.mMultiDataFileChooserWizardDialog.pack();


		// create a file filter object
		SGExtensionFileFilter ff = new SGExtensionFileFilter();
		ff.setDescription( PROPERTY_FILE_DESCRIPTION );
		ff.addExtension( PROPERTY_FILE_EXTENSION );
		this.mPropertyFileChooserWizardDilaog.setFileFilter(ff);


		// get current path
		String path = this.getCurrentFileDirectory();

		// set the selected file name
		this.mPropertyFileChooserWizardDilaog.setFile( path, this.mCurrentPropertyFileName );

		// set the selected file name
		this.mMultiDataFileChooserWizardDialog.setFile( path, this.mCurrentDataFileName );

//System.out.println(path);
//System.out.println(this.mCurrentPropertyFileName);
//System.out.println(this.mCurrentDataFileName);
//System.out.println();


		//
		// next and previous dialog
		//

		this.mPropertyFileChooserWizardDilaog.setNext(
			this.mMultiDataFileChooserWizardDialog );
		this.mMultiDataFileChooserWizardDialog.setPrevious(
			this.mPropertyFileChooserWizardDilaog );				


		//
		// add action listener
		//

		this.mPropertyFileChooserWizardDilaog.addActionListener(this);
		this.mMultiDataFileChooserWizardDialog.addActionListener(this);


		return true;
	}



	/**
	 * 
	 */
	private int readFile(
		final String pathName,
		final ArrayList infoList )
	{

		final Window owner = this.mXYDataTypeSelectionWizardDialogFromCLorDD.getOwner();

		ArrayList cList = new ArrayList();
		ArrayList tokenNumList = new ArrayList();
		try
		{
			if( this.mDataCreator.getFileTypeCandidateList( pathName, cList, tokenNumList ) == false )
			{
				return -1;
			}
		}
		catch( FileNotFoundException ex )
		{
			return -1;
		}

		if( cList.size() == 0 )
		{
			return -1;
		}


		String fileType = null;

		// set candidate data-type to the dialog
		if( this.mXYDataTypeSelectionWizardDialogFromCLorDD.setEffectiveDataType(cList) == false )
		{
			return -1;
		}


		// set the location of wizard dialog
		this.mXYDataTypeSelectionWizardDialogFromCLorDD.setCenter( owner );


		// show a modal dialog to choose data-type from candidates
		this.mXYDataTypeSelectionWizardDialogFromCLorDD.setVisible(true);


		//
		// A modal dialog is shown.
		//

		// if canceled, return 1
		final int status = this.mXYDataTypeSelectionWizardDialogFromCLorDD.getCloseOption();
		if( status==SGWizardDialog.CANCEL_OPTION )
		{
			return 1;
		}

	
		// get selected file type
		fileType = this.mXYDataTypeSelectionWizardDialogFromCLorDD.getSelectedDataType();
		if( fileType == null )
		{
			return -1;
		}


		// add information to the list
		infoList.add(fileType);


		// create an array for data-retention
		if( fileType.equals(SGDataTypeConstants.SXY_SAMPLING_DATA) )
		{
			// infoList にサンプリングレートの情報を追加する
			Double d = this.mXYDataTypeSelectionWizardDialogFromCLorDD.getSamplingRate();
			if( d==null )
			{
				return -1;
			}
			infoList.add(d);
		}


		return 0;
	}




	/**
	 * 
	 */
	private boolean readFile2(
		final String pathName,
		final ArrayList infoList )
	{

		// get selected file type
		final String fileType = this.mXYDataTypeSelectionWizardDialog.getSelectedDataType();
		if( fileType == null )
		{
			return false;
		}


		// add information to the list
		infoList.add(fileType);


		// create an array for data-retention
		if( fileType.equals(SGDataTypeConstants.SXY_SAMPLING_DATA) )
		{
			// infoList にサンプリングレートの情報を追加する
			Double d = this.mXYDataTypeSelectionWizardDialog.getSamplingRate();
			if( d==null )
			{
				return false;
			}
			infoList.add(d);
		}


		return true;

	}




	/**
	 * Create a new window.
	 * @return a created window
	 */
	public SGDrawingWindow createNewWindow()
	{
		SGDrawingWindow wnd = this.createWindow();
		if( wnd==null )
		{
			return null;
		}
		wnd.initPropertiesHistory();
		return wnd;
	}


	/**
	 * Create a new window.
	 * @return a created window
	 */
	private SGDrawingWindow createWindow()
	{
		final int id = this.getCurrentWindowID();
		SGDrawingWindow wnd = this.createWindow(id);
		return wnd;
	}



	/**
	 * Create a window with given ID number.
	 * @param id ID number
	 * @return a created window
	 */
	private SGDrawingWindow createWindow( final int id )
	{
		
		// create an instance
		SGDrawingWindow wnd = new SGDrawingWindow();

		// set ID number
		wnd.setID( id );

		// put into the map
		this.mWndMap.put( new Integer(id), wnd );

		// set the close operation
		wnd.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );


		// set window title
		String title = SGDrawingWindow.WINDOW_TITLE_PREFIX + wnd.getID();
		wnd.setTitle(title);


		// add this class as an action listener of the window
		wnd.addActionListener(this);

		// add this class as a window listener of the window
		wnd.addWindowListener(this);


		// create and set the drop target
		DropTarget target = new DropTarget(
			wnd,
			DnDConstants.ACTION_COPY_OR_MOVE,
			this,
			true
		);
		wnd.setDropTarget(target);


		//
		wnd.setImageFileCreator( this.mImageFileCreator );


		// set the location of the window
		{
			wnd.setLocation(100,100);
		}

		// initialize
		if( wnd.init() == false )
		{
			return null;
		}

		// set the menus enabled
		this.setPasteMenuEnabled();	// paste

		return wnd;
	}



	/**
	 * Returns the ID number for a window to be created.
	 * @return ID number
	 */
	private int getCurrentWindowID()
	{
		int id;
		if( this.mWndMap.size()==0 )
		{
			id = 1;
		}
		else
		{
			id = ((Integer)this.mWndMap.lastKey()).intValue() + 1;
		}
		return id;
	}



	/**
	 * 
	 */
	private int createWindowFromPropertyFile(
		final SGDrawingWindow wnd,
		final Element elWnd,
		final TreeMap dataMap )
	{
		final String cm = SGUtilityNumber.cm;
		final String pt = SGUtilityNumber.pt;
		final float ratio = SGIConstants.CM_POINT_RATIO;
		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;
		
		String str = null;
		Number num = null;
		Boolean b = null;
		Color cl = null;

		
		// width
		str = elWnd.getAttribute( SGDrawingWindow.KEY_PAPER_WIDTH );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat( str, cm );
		if( num==null )
		{
			return ic;
		}
		final float width = num.floatValue()/ratio;

		
		// height
		str = elWnd.getAttribute( SGDrawingWindow.KEY_PAPER_HEIGHT );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat( str, cm );
		if( num==null )
		{
			return ic;
		}
		final float height = num.floatValue()/ratio;
		
		
		// grid visible
		str = elWnd.getAttribute( SGDrawingWindow.KEY_GRID_VISIBLE );
		if( str.length()==0 )
		{
			return ic;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return ic;
		}
		final boolean gridVisible = b.booleanValue();

		
		// grid interval
		str = elWnd.getAttribute( SGDrawingWindow.KEY_GRID_INTERVAL );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat( str, cm );
		if( num==null )
		{
			return ic;
		}
		final float gridInterval = num.floatValue()/ratio;
		
		
		// grid line width
		str = elWnd.getAttribute( SGDrawingWindow.KEY_GRID_LINE_WIDTH );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat( str, cm );
		if( num==null )
		{
			return ic;
		}
		final float gridLineWidth = num.floatValue();
		
		
		// background color
		str = elWnd.getAttribute( SGDrawingWindow.KEY_BACKGROUND_COLOR );
		if( str.length()==0 )
		{
			return ic;
		}
		cl = SGUtilityText.getColorFromString( str );
		if( cl==null )
		{
			return ic;
		}
		final Color bgColor = cl;

		
		// grid line color
		str = elWnd.getAttribute( SGDrawingWindow.KEY_GRID_COLOR );
		if( str.length()==0 )
		{
			return ic;
		}
		cl = SGUtilityText.getColorFromString( str );
		if( cl==null )
		{
			return ic;
		}
		final Color gridColor = cl;

		
		// set properties to the window
		wnd.setPaperSize( width, height );
		wnd.setBackgroundColor( bgColor );
		wnd.setGridVisible( gridVisible );
		wnd.setGridInterval( gridInterval );
		wnd.setGridLineWidth( gridLineWidth );
		wnd.setGridLineColor( gridColor );


		// create figure objects in a window
		int ret = this.createFiguresFromPropertyFile(
			elWnd, wnd, dataMap );
		if( ret!=SGIConstants.SUCCESSFUL_COMPLETION )
		{
			return ret;
		}
		ret = SGIConstants.SUCCESSFUL_COMPLETION;

		
		// add history
		wnd.initPropertiesHistory();

		return ret;

	}
	


	
	/**
	 * 
	 * @return
	 */
	public SGDrawingWindow createWindowFromPropertyFile(
		final Document doc,
		final TreeMap dataMap )
	{

		// get root element - property
		Element root = doc.getDocumentElement();

		// get the node of window
		NodeList wList = root.getElementsByTagName( SGDrawingWindow.TAG_NAME_WINDOW );
		if( wList.getLength()==0 )
		{
			return null;
		}
		Element elWnd = (Element)wList.item(0);

		// create a window instance
		SGDrawingWindow wnd = this.createWindow();

		// set the property of the created window from property file
		int ret = this.createWindowFromPropertyFile( wnd, elWnd, dataMap );

		// get the message
		String msg = null;
		if( ret == SGIConstants.SUCCESSFUL_COMPLETION )
		{
			msg = MSG_SUCCESSFUL_COMPLETION;
		}
		else if( ret == SGIConstants.DATA_NUMBER_SHORTAGE )
		{
			msg = MSG_DATA_NUMBER_SHORTAGE;
		}
		else if( ret == SGIConstants.DATA_NUMBER_EXCESS )
		{
			msg = MSG_DATA_NUMBER_EXCESS;
		}
		else if( ret == SGIConstants.FILE_OPEN_FAILURE )
		{
			msg = MSG_FILE_OPEN_FAILURE;
		}
		else if( ret == SGIConstants.PROPERTY_FILE_INCORRECT )
		{
			msg = MSG_PROPERTY_FILE_INCORRECT;
		}
		else if( ret == SGIConstants.DATA_TYPE_INCORRECT )
		{
			msg = MSG_DATA_TYPE_INCORRECT;
		}
		else
		{
			throw new Error();
		}


		// show the message dialog
		if( msg!=MSG_SUCCESSFUL_COMPLETION )
		{
			SGUtility.showMessageDialog(
				wnd, msg, PROPERTY_FILE_READ_MSG_DIALOG_TITLE,
				JOptionPane.ERROR_MESSAGE
			);
		}


		if( ret==SGIConstants.PROPERTY_FILE_INCORRECT )
		{
			this.removeWindow(wnd);
		}


		// show the window
		wnd.setVisible(true);
		
		return wnd;
	}
	
	
	
	/**
	 * 
	 * @param elWnd
	 * @param wnd
	 * @return
	 */
	private int createFiguresFromPropertyFile(
		final Element elWnd,
		final SGDrawingWindow wnd,
		final Map dataMap )
	{
		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;

		Set keySet = dataMap.keySet();
		ArrayList dataListList = new ArrayList( dataMap.values() );

		NodeList nList = elWnd.getElementsByTagName( SGFigure.TAG_NAME_FIGURE );
		final int len = nList.getLength();
		for( int ii=0; ii<len; ii++ )
		{
			Node node = nList.item(ii);
			if( node instanceof Element )
			{
				Element el = (Element)node;
				ArrayList dataList = (ArrayList)dataListList.get(ii);
				if( dataList.contains( SGMultiDataFileChooserWizardDialog.NO_DATA ) )
				{
					dataList = new ArrayList();
				}
				final int ret = this.createSingleFigureFromPropertyFile(
					el, wnd, dataList );
				if( ret!=SGIConstants.SUCCESSFUL_COMPLETION )
				{
					return ret;
				}
			}
		}
		
		return SGIConstants.SUCCESSFUL_COMPLETION;
	}

	
	
	/**
	 * 
	 * @param elFigure
	 * @param figure
	 * @return
	 */
	private int createSingleFigureFromPropertyFile(
		final Element elFigure,
		final SGDrawingWindow wnd,
		final ArrayList dataList )
	{
		
		final String cm = SGUtilityNumber.cm;
		final String pt = SGUtilityNumber.pt;
		final float ratio = SGIConstants.CM_POINT_RATIO;
		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;
		
		String str = null;
		Number num = null;
		Boolean b = null;
		Color cl = null;


		//
		// the name of instance
		//

		str = elFigure.getAttribute( SGFigure.KEY_FIGURE_TYPE );
		if( str.length()==0 )
		{
			return ic;
		}
		String className;
		if( str.equals( SGIFigureConstants.FIGURE_TYPE_SXY ) )
		{
			className = SGSXYFigure.class.getName();
		}
		else if( str.equals( SGIFigureConstants.FIGURE_TYPE_VXY ) )
		{
			className = SGVXYFigure.class.getName();
		}
		else
		{
			return ic;
		}


		//
		// create a figure
		//

		SGFigure figure = null;
		try
		{
			Class fClass = Class.forName( className );
			figure = (SGFigure)fClass.newInstance();
		}
		catch( Exception ex )
		{
			return ic;
		}
		figure.setWindow( wnd );
		final int figureID = wnd.getCurrentFigureId();
		figure.setID(figureID);
		
		
		// x
		str = elFigure.getAttribute( SGFigure.KEY_FIGURE_X_IN_CLIENT );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return ic;
		}
		final float x = num.floatValue()/ratio;

		
		// y
		str = elFigure.getAttribute( SGFigure.KEY_FIGURE_Y_IN_CLIENT );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return ic;
		}
		final float y = num.floatValue()/ratio;

		
		// width
		str = elFigure.getAttribute( SGFigure.KEY_FIGURE_WIDTH );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return ic;
		}
		final float width = num.floatValue()/ratio;


		// height
		str = elFigure.getAttribute( SGFigure.KEY_FIGURE_HEIGHT );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return ic;
		}
		final float height = num.floatValue()/ratio;


		Rectangle2D cRect = wnd.getClientRect();
		final float xx = x + (float)cRect.getX();
		final float yy = y + (float)cRect.getY();
		figure.setGraphRectLocation( xx, yy );
		figure.setGraphRectSize( width, height );

		
		// space axis line and numbers
		str = elFigure.getAttribute( SGFigure.KEY_SPACE_AXIS_LINE_AND_NUMBER );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return ic;
		}
		final float spaceLN = num.floatValue()/ratio;


		// space numbers and title
		str = elFigure.getAttribute( SGFigure.KEY_SPACE_NUMBER_AND_TITLE );
		if( str.length()==0 )
		{
			return ic;
		}
		num = SGUtilityText.getFloat(str,cm);
		if( num==null )
		{
			return ic;
		}
		final float spaceNT = num.floatValue()/ratio;
		

		// background color
		str = elFigure.getAttribute( SGFigure.KEY_FIGURE_BACKGROUND_COLOR );
		if( str.length()==0 )
		{
			return ic;
		}
		cl = SGUtilityText.getColorFromString(str);
		if( cl==null )
		{
			return ic;
		}
		figure.setBackgroundColor( cl );

		
		// transparent
		str = elFigure.getAttribute( SGFigure.KEY_FIGURE_BACKGROUND_TRANSPARENT );
		if( str.length()==0 )
		{
			return ic;
		}
		b = SGUtilityText.getBoolean(str);
		if( b==null )
		{
			return ic;
		}
		final boolean transparent = b.booleanValue();
		figure.setTransparent( transparent );

		

		
		//
		// create SGIFigureElement objects
		//

		if( this.createFigureElementFromPropertyFile( figure, elFigure ) == ic )
		{
			return ic;
		}

		
		//
		SGIAxisElement aElement = figure.getAxisElement();
		aElement.setSpaceAxisLineAndNumber( spaceLN );
		aElement.setSpaceNumberAndTitle( spaceNT );
		

		// create data objects
		final int ret = this.createDataObjectsFromPropertyFile(
			elFigure, figure, dataList );
		if( ret!=SGIConstants.SUCCESSFUL_COMPLETION )
		{
			return ret;
		}


		// add the figure to the window
		final int id = wnd.getCurrentFigureId();
		wnd.addFigure( id, figure );


		//
		figure.notifyFigureElement( figure.getAxisElement() );
		figure.notifyFigureElement( figure.getGraphElement() );

		
		//
		// initialize properties of the figure and figure elements
		//
		
		figure.initPropertiesHistory();


		// move figure to the front 	 
		wnd.moveToFront( figure );


		return SGIConstants.SUCCESSFUL_COMPLETION;
	}
	
	

	
	/**
	 * 
	 * @param figure
	 * @param element
	 * @return
	 */
	public int createFigureElementFromPropertyFile(
		final SGFigure figure, final Element fElement )
	{
		NodeList nList = null;
		Element element = null;
		SGIFigureElement el = null;

		Frame owner = figure.getWindow();
		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;
		Rectangle2D gRect = figure.getGraphRect();
		
		
		// axis
		el = this.setIElement( this.mClassOfAxisElement, SGFigure.LAYER_AXIS, figure, owner );
		if( el==null )
		{
			return ic;
		}
		el.setGraphRect( gRect );
		SGIAxisElement axis = (SGIAxisElement)el;
		figure.setAxisElement( axis );
		nList = fElement.getElementsByTagName( SGIAxisElement.TAG_NAME_AXES );
		element = (Element)nList.item(0);
		if( el.readProperty( element ) == false )
		{
			return ic;
		}


		// graph
		nList = fElement.getElementsByTagName( SGIGraphElement.TAG_NAME_GRAPH );
		element = (Element)nList.item(0);
		final Class cl;
		if( figure instanceof SGSXYFigure )
		{
			cl = this.mClassOfSXYGraphElement;
		}
		else if( figure instanceof SGVXYFigure )
		{
			cl = this.mClassOfVXYGraphElement;
		}
		else
		{
			throw new Error();
		}
		el = this.setIElement( cl, SGFigure.LAYER_GRAPH, figure, owner );
		if( el==null )
		{
			return ic;
		}
		el.setGraphRect( gRect );
		SGIGraphElement graph = (SGIGraphElement)el;
		figure.setGraphElement( graph );
		

		// legend
		el = this.setIElement( this.mClassOfLegendElement, SGFigure.LAYER_LEGEND, figure, owner );
		if( el==null )
		{
			return ic;
		}
		el.setGraphRect( gRect );
		SGILegendElement legend = (SGILegendElement)el;
		figure.setLegendElement( legend );
		legend.setAxisElement(axis);	// set in advance
		nList = fElement.getElementsByTagName( SGILegendElement.TAG_NAME_LEGEND );
		element = (Element)nList.item(0);
		if( el.readProperty( element ) == false )
		{
			return ic;
		}


		// string
		el = this.setIElement( this.mClassOfStringElement, SGFigure.LAYER_STRING, figure, owner );
		if( el==null )
		{
			return ic;
		}
		el.setGraphRect( gRect );
		SGIStringElement string = (SGIStringElement)el;
		figure.setStringElement( string );
		string.setAxisElement(axis);		// set in advance
		nList = fElement.getElementsByTagName( SGIStringElement.TAG_NAME_STRING_ELEMENT );
		element = (Element)nList.item(0);
		if( el.readProperty(element) == false )
		{
			return ic;
		}

		
		// axis break
		el = this.setIElement( this.mClassOfAxisBreakElement, SGFigure.LAYER_AXIS_BREAK, figure, owner );
		if( el==null )
		{
			return ic;
		}
		el.setGraphRect( gRect );
		SGIAxisBreakElement axisBreak = (SGIAxisBreakElement)el;
		figure.setAxisBreakElement( axisBreak );
		axisBreak.setAxisElement(axis);		// set in advance
		nList = fElement.getElementsByTagName( SGIAxisBreakElement.TAG_NAME_AXIS_BREAK );
		element = (Element)nList.item(0);
		if( el.readProperty(element) == false )
		{
			return ic;
		}

		
		// significant difference
		el = this.setIElement( this.mClassOfSignificantDifferenceElement, SGFigure.LAYER_SIGNIFICANT_DIFFERENCE, figure, owner );
		if( el==null )
		{
			return ic;
		}
		el.setGraphRect( gRect );
		SGISignificantDifferenceElement sigDiff = (SGISignificantDifferenceElement)el;
		figure.setSignificantDifferenceElement( sigDiff );
		sigDiff.setAxisElement(axis);	// set in advance
		nList = fElement.getElementsByTagName( SGISignificantDifferenceElement.TAG_NAME_SIGNIFICANT_DIFFERENCE );
		element = (Element)nList.item(0);
		if( el.readProperty(element) == false )
		{
			return ic;
		}

		
		// timing line
		el = this.setIElement( this.mClassOfTimingLineElement, SGFigure.LAYER_TIMING_LINE, figure, owner );
		if( el==null )
		{
			return ic;
		}
		el.setGraphRect( gRect );
		SGITimingLineElement timingLine = (SGITimingLineElement)el;
		figure.setTimingLineElement( timingLine );
		timingLine.setAxisElement(axis);	// set in advance
		nList = fElement.getElementsByTagName( SGITimingLineElement.TAG_NAME_TIMING_LINES );
		element = (Element)nList.item(0);
		if( el.readProperty(element) == false )
		{
			return ic;
		}


		// set relation between SGIFigureElement objects
		this.setRelationOfFigureElements( figure );

		
		return SGIConstants.SUCCESSFUL_COMPLETION;
	}


	
	
	/**
	 * データオブジェクトを作成
	 */
	private int createDataObjectsFromPropertyFile(
		final Element elFigure, final SGFigure figure, final ArrayList dataList )
	{

		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;

		NodeList nList = elFigure.getElementsByTagName( SGIGraphElement.TAG_NAME_DATA );
		if( nList.getLength()!=dataList.size() )
		{
			return ic;
		}

		final int len = nList.getLength();
		for( int ii=0; ii<len; ii++ )
		{

			//
			// get information from the Element object
			//

			Node node = nList.item(ii);
			if( ( node instanceof Element ) == false )
			{
				continue;
			}

			Element elData = (Element)node;

			ArrayList infoList = new ArrayList();

			// class
			String dataType = elData.getAttribute( SGIGraphElement.KEY_DATA_TYPE );
			if( dataType==null )
			{
				return ic;
			}
			infoList.add(dataType);

			
			String className = null;
			if( dataType.equals(SGDataTypeConstants.SXY_DATA) )
			{
				className = SGSXYData.class.getName();
			}
			else if( dataType.equals(SGDataTypeConstants.VXY_DATA) )
			{
				className = SGVXYData.class.getName();
			}
			else if( dataType.equals(SGDataTypeConstants.SXY_MULTIPLE_DATA) )
			{
				className = SGSXYMultipleData.class.getName();
			}
			else if( dataType.equals(SGDataTypeConstants.SXY_SAMPLING_DATA) )
			{
				className = SGSXYSamplingData.class.getName();

				String str = elData.getAttribute( SGIGraphElement.PF_SAMPLING_RATE );
				if( str.length()==0 )
				{
					return ic;
				}
				Double d = SGUtilityText.getDouble(str);
				if( d==null )
				{
					return ic;
				}
				infoList.add(d);
			}
			else
			{
				return ic;
			}


			// get the Class object
			Class cl = null;
			try
			{
				cl = Class.forName(className);
			}
			catch( ClassNotFoundException ex )
			{
				return ic;
			}
			if( cl==null )
			{
				return ic;
			}


			// create a new SGData object
			SGData data = null;
			try
			{
				data = (SGData)cl.newInstance();
			}
			catch( Exception ex )
			{
				return ic;
			}
			if( data==null )
			{
				return ic;
			}


			// get the data file
			if( dataList.size() == 0 )
			{
				return SGIConstants.DATA_NUMBER_SHORTAGE;
			}


			// get an object from dataList
			Object obj = dataList.get(ii);
			if( obj instanceof String )
			{
				String fileName = (String)obj;
			
				// check the type of data
				ArrayList cList = new ArrayList();
				ArrayList tokenNumList = new ArrayList();
				Frame owner = figure.getWindow();

				try
				{
					if( this.mDataCreator.getFileTypeCandidateList( fileName, cList, tokenNumList ) == false )
					{
						return ic;
					}
					if( cList.size()==0 || cList.contains(dataType)==false )
					{
						return SGIConstants.DATA_TYPE_INCORRECT;
					}
			
					// create data object
					SGData data_ = this.mDataCreator.create( fileName, infoList );
					if( data_ == null )
					{
						return SGIConstants.FILE_OPEN_FAILURE;
					}
					if( data.setData(data_) == false )
					{
						return SGIConstants.DATA_TYPE_INCORRECT;
					}
				}
				catch( FileNotFoundException ex )
				{
					return SGIConstants.FILE_OPEN_FAILURE;
				}

			}
			else if( obj instanceof SGData )
			{
				SGData data_ = (SGData)obj;
				if( data.setData( data_ ) == false )
				{
					return ic;
				}
			}
			else
			{
				return ic;
			}


			//
			if( figure.createDataObjectFromPropertyFile( elData, data ) == false )
			{
				return SGIConstants.PROPERTY_FILE_INCORRECT;
			}

			
		}
		
		
		SGIFigureElement[] array = figure.getIFigureElementArray();
		for( int ii=0; ii<array.length; ii++ )
		{
			array[ii].initPropertiesHistory();
		}

		return SGIConstants.SUCCESSFUL_COMPLETION;

	}



	/**
	 * 
	 */
	private boolean fromWindow( final ActionEvent e )
	{

		Object source = e.getSource();
		String command = e.getActionCommand();

		SGDrawingWindow wnd = (SGDrawingWindow)source;

		if( command.equals( SGDrawingWindow.NOTIFY_OPEN_WINDOW ) )
		{
			SGDrawingWindow w = this.createNewWindow();
			if( w==null )
			{
				return false;
			}
			w.setVisible(true);
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_EXIT ) )
		{
			this.exit(0);
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_ADD_DATA ) )
		{
			// create wizard dialogs
			this.createAllWizardDialogsForDataAdditionFromToolBar( wnd );

			// set location
			this.mFigureIDSelectionWizardDialog.setCenter( wnd );

			// show the first wizard dialog
			this.mFigureIDSelectionWizardDialog.setVisible(true);

			// update the selected file name
			File f = this.mSingleDataFileChooserWizardDilaog.getSelectedFile();
			if( f!=null )
			{
				this.updateCurrentFile( f, FILE_TYPE_DATA );
			}
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_SAVE_PROPERTY ) )
		{
			// set the selected file name
			this.mPropertyFileCreator.setFile(
				this.getCurrentFileDirectory(), this.mCurrentPropertyFileName );

			// create a property file
			this.mPropertyFileCreator.create( wnd );

			File f = this.mPropertyFileCreator.getSelectedFile();
			if( f!=null )
			{
				this.updateCurrentFile( f, FILE_TYPE_PROPERTY );
			}
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_LOAD_PROPERTY ) )
		{
			// create wizard dialogs
			this.createAllWizardDialogsToLoadPropertyFromToolBar( wnd );

			// set location
			this.mPropertyFileChooserWizardDilaog.setCenter( wnd );

			// show the first wizard dialog
			this.mPropertyFileChooserWizardDilaog.setVisible(true);
			
			// update the selected file name
			File pf = this.mPropertyFileChooserWizardDilaog.getSelectedFile();
			File df = this.mMultiDataFileChooserWizardDialog.getSelectedFile();
			final long pUsed = this.mPropertyFileChooserWizardDilaog.lastUsed();
			final long dUsed = this.mMultiDataFileChooserWizardDialog.lastUsed();
			if( pf!=null & df!=null )
			{
				if( pUsed < dUsed )
				{
					this.updateCurrentFile( df, FILE_TYPE_DATA );
				}
				else
				{
					this.updateCurrentFile( pf, FILE_TYPE_PROPERTY );
				}
			}
			else if( pf!=null )
			{
				this.updateCurrentFile( pf, FILE_TYPE_PROPERTY );
			}
			else if( df!=null )
			{
				this.updateCurrentFile( df, FILE_TYPE_DATA );
			}
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_CUT ) )
		{
			this.cutAndCopy( wnd, false );
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_COPY ) )
		{
			this.cutAndCopy( wnd, true );
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_PASTE ) )
		{
			this.pasteToWindow( wnd );
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_DUPLICATE ) )
		{
			if( this.duplicateFocusedFigures(wnd) == false )
			{
				return false;
			}
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_EXPORT_IMAGE ) )
		{
			this.mImageFileCreator.setBaseDirectory( this.getCurrentFileDirectory() );
			wnd.exportAsImage();
			this.setCurrentFileDirectory( this.mImageFileCreator.getBaseDirectory() );
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_PRINT ) )
		{
			wnd.printImage();
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_UPGRADE ) )
		{
			this.mUpgradeManager.showUpgradeDialog( wnd );
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_SHOW_CHANGE_LOG ) )
		{
			return this.showChangeLogDialog(wnd);
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_SET_PROXY ) )
		{
			return this.mProxyManager.showProxySettingDialog( wnd );
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_SHOW_ABOUT_DIALOG ) )
		{
			this.showAboutDialog(wnd);
		}

		return true;
	}



	/**
	 * Cut or copy the objects.
	 * @param wnd
	 * @param isCopy a flag to set cut/copy
	 * @return true:succeeded, false:failed
	 */
	private boolean cutAndCopy( final SGDrawingWindow wnd, final boolean isCopy )
	{
		// initialize the lists
		this.mCopiedObjectsBuffer.clear();
		this.mCopiedDataObjectBuffer.clear();
		this.mCopiedDataNameBuffer.clear();
		this.mCopiedDataPropertiesBuffer.clear();

		// get copied objects list and add them to the buffer of the attribute
		ArrayList cList = wnd.getCopiedObjectsList();
		this.mCopiedObjectsBuffer.addAll( cList );

		ArrayList dList = wnd.getCopiedObjectsDataList();
		this.mCopiedDataObjectBuffer.addAll( dList );

		ArrayList nList = wnd.getCopiedDataNameList();
		this.mCopiedDataNameBuffer.addAll( nList );

		ArrayList pList = wnd.getCopiedDataPropertiesMapList();
		this.mCopiedDataPropertiesBuffer.addAll( pList );


		WindowInfo info = new WindowInfo();

		if( isCopy )
		{
			if( this.copyFocusedFigures( wnd, info ) == false )
			{
				return false;
			}
		}
		else
		{
			if( this.cutFocusedFigures( wnd, info ) == false )
			{
				return false;
			}
		}

		// set to the attribute
		this.mWindowInfo = info;


		// set the paste menu enabled
		this.setPasteMenuEnabled();

		return true;
	}


	/**
	 * 
	 *
	 */
	private void setPasteMenuEnabled()
	{
		final boolean b1 = (this.mCopiedObjectsBuffer.size()!=0);
		final boolean b2 = (this.mCopiedDataObjectBuffer.size()!=0);

		boolean b3 = false;
		if( this.mWindowInfo!=null )
		{
			Document doc = this.mWindowInfo.mDocument;
			NodeList nodeList = doc.getElementsByTagName( SGFigure.TAG_NAME_FIGURE );
			final int len = nodeList.getLength();
			b3 = (len!=0);
		}

		final boolean b = ( b1 | b2 | b3 );

		ArrayList wList = new ArrayList( this.mWndMap.values() );
		for( int ii=0; ii<wList.size(); ii++ )
		{
			SGDrawingWindow wnd = (SGDrawingWindow)wList.get(ii);
			wnd.setPasteMenuEnabled(b);
		}
	}



	/**
	 * Paste objects to the window.
	 * @param wnd - the target object
	 * @return
	 */
	private boolean pasteToWindow( SGDrawingWindow wnd )
	{
		// paste the copied objects to figures
		wnd.pasteToFigures(
			this.mCopiedObjectsBuffer,
			this.mCopiedDataObjectBuffer,
			this.mCopiedDataNameBuffer,
			this.mCopiedDataPropertiesBuffer );


		// paste the copied figure objects
		WindowInfo info = this.mWindowInfo;
		if( info==null )
		{
			return false;
		}
		Map dListMap = info.mDataListMap;
	
		// get root element
		Element root = info.mDocument.getDocumentElement();

		// get the node of window
		NodeList wList = root.getElementsByTagName( SGDrawingWindow.TAG_NAME_WINDOW );
		if( wList.getLength()==0 )
		{
			return false;
		}
		Element elWnd = (Element)wList.item(0);

		final int before = wnd.getFigureMap().size();

		// create figures from a DOM tree
		final int ret = this.createFiguresFromPropertyFile( elWnd, wnd, dListMap );
		if( ret!=SGIConstants.SUCCESSFUL_COMPLETION )
		{
			return false;
		}

		final int after = wnd.getFigureMap().size();
	
		wnd.setChanged( before!=after );

		return true;
	}




	/**
	 * Show the about dialog.
	 * @param wnd
	 */
	private void showAboutDialog( SGDrawingWindow wnd )
	{
		SGAboutDialog dg = new SGAboutDialog(wnd,true);

		final int width = dg.getWidth();
		final int height = dg.getHeight();

		final int x = wnd.getX() + wnd.getWidth()/2 - width/2;
		final int y = wnd.getY() + wnd.getHeight()/2 - height/2;

		dg.setLocation(x,y);

		// show a modal dialog
		dg.setVisible(true);
			
		dg.terminate();
		System.gc();
	}

	
	
	
	/**
	 * 
	 */
	public static final String TAG_NAME_FOCUSED_FIGURES = "FocusedFigures";

	
	/**
	 * 
	 * @return
	 */
	private boolean duplicateFocusedFigures( SGDrawingWindow wnd )
	{
		DOMImplementation domImpl = SGApplicationUtility.getDOMImplementation();
		if( domImpl==null )
		{
			return false;
		}
	
		// create a Document object
		Document document = domImpl.createDocument( "", TAG_NAME_FOCUSED_FIGURES, null );

		// create a DOM tree
		if( wnd.createDOMTree( document, SGDrawingWindow.FOCUSED_FIGURES_FOR_DUPLICATION ) == false )
		{
			return false;
		}


		// create a map of figure ID and data list
		TreeMap map = new TreeMap();

		ArrayList fList = wnd.getFocusedObjectsList();
		for( int ii=0; ii<fList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)fList.get(ii);
			ArrayList dList = figure.getVisibleDataList();
			dList = (ArrayList)dList.clone();
			map.put( Integer.toString( figure.getID() ), dList );
		}


		// get root element - property
		Element root = document.getDocumentElement();

		// get the node of window
		NodeList wList = root.getElementsByTagName( SGDrawingWindow.TAG_NAME_WINDOW );
		if( wList.getLength()==0 )
		{
			return false;
		}
		Element elWnd = (Element)wList.item(0);

		int before = wnd.getFigureMap().size();

		final int ret = this.createFiguresFromPropertyFile( elWnd, wnd, map );
		if( ret!=SGIConstants.SUCCESSFUL_COMPLETION )
		{
			return false;
		}

		int after = wnd.getFigureMap().size();
		
		wnd.setChanged( before!=after );

		return true;
	}



	/**
	 * 
	 * @return
	 */
	private boolean cutFocusedFigures(
		SGDrawingWindow wnd,
		WindowInfo info )
	{
		if( this.copyFocusedFigures( wnd, info ) == false )
		{
			return false;
		}
		
		if( info.mDataListMap.size()!=0 )
		{
			wnd.hideSelectedObjects();
		}

		return true;
	}


	/**
	 * 
	 * @return
	 */
	private boolean copyFocusedFigures( SGDrawingWindow wnd, WindowInfo info )
	{
		DOMImplementation domImpl = SGApplicationUtility.getDOMImplementation();
		if( domImpl==null )
		{
			return false;
		}

		// create a Document object
		Document document = domImpl.createDocument( "", TAG_NAME_FOCUSED_FIGURES, null );

		// create a DOM tree
		if( wnd.createDOMTree( document, SGDrawingWindow.FOCUSED_FIGURES_FOR_DUPLICATION ) == false )
		{
			return false;
		}

		// create a map of figure ID and data list
		Map dListMap = new TreeMap();
		ArrayList fList = wnd.getCopiedFiguresList();
		for( int ii=0; ii<fList.size(); ii++ )
		{
			SGFigure figure = (SGFigure)fList.get(ii);
			ArrayList dList = figure.getVisibleDataList();
			dList = (ArrayList)dList.clone();

			String key = Integer.toString( figure.getID() );
			dListMap.put( key, dList );
		}


		// set to the attribute
		info.mDocument = document;
		info.mDataListMap = dListMap;

		return true;
	}




	
	
	/**
	 * The list of copied objects.
	 */
	private ArrayList mCopiedObjectsBuffer = new ArrayList();
	
	
	/**
	 * 
	 */
	private ArrayList mCopiedDataObjectBuffer = new ArrayList();
	
	
	/**
	 * 
	 */
	private ArrayList mCopiedDataNameBuffer = new ArrayList();
	
	
	/**
	 * 
	 */
	private ArrayList mCopiedDataPropertiesBuffer = new ArrayList();


	/**
	 * 
	 */
	private ArrayList mCopiedDataPropertiesForLegendBuffer = new ArrayList();



	/**
	 * Inforamation of the focused figures.
	 */
	private WindowInfo mWindowInfo;


	/**
	 * A private class to store information of a figure.
	 */
	private class WindowInfo
	{
		/**
		 * A DOM tree object of figures.
		 */	
		private Document mDocument;

		/**
		 * The map of the list of data objects.
		 */		
		private Map mDataListMap = new TreeMap();

	}






	private SGChangeLogDialog mChangeLogDialog = null;


	
	private Document createChangeLogDocument()
	{
		Class inClass = getClass();
		URL url = inClass.getResource( RESOURCES_DIRNAME + "ChangeLog.xml" );
		if( url==null )
		{
			return null;
		}
		Document doc = SGUtilityText.getDocument(url.toString());
		return doc;
	}
	
	
	
	/**
	 * 
	 * @return
	 */
	private boolean showChangeLogDialog( Frame owner )
	{
		// create and set a dialog object
		this.mChangeLogDialog = new SGChangeLogDialog(owner,true);
		this.mChangeLogDialog.addActionListener( this );
		this.mChangeLogDialog.setCenter(owner);

		// set a message
		String msg = "Change Log of Samurai Graph.";
		this.mChangeLogDialog.setMessage(msg);

		// get the file of change log
		Class inClass = getClass();
		URL url = inClass.getResource( RESOURCES_DIRNAME + "ChangeLog.html" );
		if( url==null )
		{
			JOptionPane.showMessageDialog(
				owner,
				"Failed to get log information."
			);
			return false;
		}
		
		// set the html file
		this.mChangeLogDialog.setPage( url );
		this.mChangeLogDialog.pack();

		// show
		this.mChangeLogDialog.setVisible(true);

		return true;
	}



	/**
	 * 
	 */
	private boolean fromCLorDDWizardDialog( final ActionEvent e )
	{
		Object source = e.getSource();
		SGWizardDialog dg = (SGWizardDialog)source;
		String command = e.getActionCommand();
		return true;
	}



	/**
	 * 
	 * @param e
	 * @return
	 */
	private boolean addDataByToolBar( final ActionEvent e )
	{

		Object source = e.getSource();
		SGWizardDialog dg = (SGWizardDialog)source;
		SGWizardDialog prev = dg.getPrevious();
		SGWizardDialog next = dg.getNext();
		String command = e.getActionCommand();
		Window owner = dg.getOwner();

		
		// cancel or previous
		if( command.equals( SGWizardDialog.CANCEL_BUTTON_TEXT ) )
		{
			dg.setVisible(false);
			return true;
		}
		else if( command.equals( SGWizardDialog.PREVIOUS_BUTTON_TEXT ) )
		{
			dg.showPrevious();
			return true;
		}


		// figure ID
		if( source.equals( this.mFigureIDSelectionWizardDialog ) )
		{
			if( command.equals( SGWizardDialog.NEXT_BUTTON_TEXT ) )
			{
				dg.showNext();
			}
		}
		// data file
		else if( source.equals( this.mSingleDataFileChooserWizardDilaog ) )
		{
			if( command.equals( SGWizardDialog.NEXT_BUTTON_TEXT ) )
			{
				File file = this.mSingleDataFileChooserWizardDilaog.getSelectedFileFromTextField();
				if( file.exists() == false )
				{
					SGUtility.showFileNotFoundMessageDialog( this.mSingleDataFileChooserWizardDilaog );
					return false;
				}
				String pathName = file.getPath();

				ArrayList infoList = new ArrayList();
				ArrayList cList = new ArrayList();
				ArrayList tokenNumList = new ArrayList();
				try
				{
					if( this.mDataCreator.getFileTypeCandidateList( pathName, cList, tokenNumList ) == false )
					{
						SGUtility.showMessageDialog(
								owner,
								"Data file is invalid.",
								"Error",
								JOptionPane.WARNING_MESSAGE
							);
						return false;
					}
				}
				catch( FileNotFoundException ex )
				{
					SGUtility.showFileNotFoundMessageDialog(owner);
					return false;
				}
				
				if( cList.size() == 0 )
				{
					SGUtility.showMessageDialog(
						owner,
						"Data file is invalid.",
						"Error",
						JOptionPane.WARNING_MESSAGE
					);
					return false;
				}
				
				// set candidate data-type to the dialog
				if( this.mXYDataTypeSelectionWizardDialog.setEffectiveDataType(cList) == false )
				{
					SGUtility.showMessageDialog(
						owner,
						"Data file is invalid.",
						"Error",
						JOptionPane.WARNING_MESSAGE
					);
					return false;
				}

				// set to the file chooser
				this.mSingleDataFileChooserWizardDilaog.setSelectedFile(file);

				dg.showNext();
			}
	
		}
		// data type
		else if( source.equals( this.mXYDataTypeSelectionWizardDialog ) )
		{

			if( command.equals( SGWizardDialog.OK_BUTTON_TEXT ) )
			{
				// set invisible the dialog
				dg.setVisible(false);

				SGDrawingWindow wnd = dg.getOwnerWindow();
				final int windowID = wnd.getID();
				final int figureID = this.mFigureIDSelectionWizardDialog.getFigureID();

				File f = this.mSingleDataFileChooserWizardDilaog.getSelectedFile();
				String pathName = f.getPath();


				// データファイルを開いて情報を取得し、データを構築する
				// ファイルの情報リスト
				ArrayList infoList = new ArrayList();
				
				
				// get selected file type
				String fileType = this.mXYDataTypeSelectionWizardDialog.getSelectedDataType();
				if( fileType == null )
				{
					SGUtility.showMessageDialog(
						owner,
						"Failed to get the data type.",
						"Error",
						JOptionPane.WARNING_MESSAGE
					);
					return false;
				}
				
				
				// add information to the list
				infoList.add(fileType);
				
				
				// create an array for data-retention
				if( fileType.equals(SGDataTypeConstants.SXY_SAMPLING_DATA) )
				{
					// infoList にサンプリングレートの情報を追加する
					Double d = this.mXYDataTypeSelectionWizardDialog.getSamplingRate();
					if( d==null )
					{
						SGUtility.showMessageDialog(
							owner,
							"Failed to get the sampling rate.",
							"Error",
							JOptionPane.WARNING_MESSAGE
						);
						return false;
					}
					infoList.add(d);
				}
				
				
				// データの構築
				if( infoList.size()==0 )
				{
					return false;
				}
				SGData data;
				try
				{
					data = this.mDataCreator.create( pathName, infoList );
				}
				catch( FileNotFoundException ex )
				{
					SGUtility.showFileNotFoundMessageDialog( wnd );
					return false;
				}
				if( data == null )
				{
					SGUtility.showMessageDialog(
						owner,
						"Failed to create a data object.",
						"Error",
						JOptionPane.WARNING_MESSAGE
					);
					return false;
				}


				// フィギュア
				SGFigure figure = wnd.getFigure( figureID );

				// フィギュアが存在しない場合には、フィギュアを新規作成
				if( figure==null || (figure!=null & figure.isVisible()==false) )
				{
					String name = this.getSimpleFileName( pathName );
					if( name==null )
					{
						return false;
					}

					if( this.createNewFigure( wnd, figureID, data, new Point(), name ) == null )
					{
						SGUtility.showMessageDialog(
							owner,
							"Failed to create a new figure.",
							"Error",
							JOptionPane.WARNING_MESSAGE
						);
						return false;
					}

				}
				else
				{
					String name = this.getNewDataName( figure, pathName );
					if( name==null )
					{
						return false;
					}

					if( !figure.addData(data,name) )
					{
						SGUtility.showMessageDialog(
							owner,
							"Data file is invalid.",
							"Error",
							JOptionPane.WARNING_MESSAGE
						);
						return false;
					}

				}

				// hide the wizard dialog
				dg.setVisible(false);

			}

		}


		return true;
	}




	/**
	 * determine the data-type from the property file
	 */
	private boolean getDataInfoFromPropertyFile(
		final Document doc, final ArrayList nList, final ArrayList cList )
	{

		// get root element - property
		Element root = doc.getDocumentElement();

		// get the node of window
		NodeList wList = root.getElementsByTagName( SGDrawingWindow.TAG_NAME_WINDOW );
		if( wList.getLength()==0 )
		{
			return false;
		}
		Element wnd = (Element)wList.item(0);

		// get the node list of figures
		NodeList fList = wnd.getElementsByTagName( SGFigure.TAG_NAME_FIGURE );
		for( int ii=0; ii<fList.getLength(); ii++ )
		{
			Node node = fList.item(ii);
			if( node instanceof Element )
			{
				Element figure = (Element)node;
				NodeList dList = figure.getElementsByTagName( SGIGraphElement.TAG_NAME_DATA );
				final int dLength = dList.getLength();
				if( dLength==0 )
				{
					nList.add(null);
					cList.add(null);
				}
				else
				{
					for( int jj=0; jj<dLength; jj++ )
					{
						Node node_ = dList.item(jj);
						if( node_ instanceof Element )
						{
							Element data = (Element)node_;
							String name = data.getAttribute( SGIGraphElement.KEY_DATA_NAME );
							nList.add(name);
							String type = data.getAttribute( SGIGraphElement.KEY_DATA_TYPE );
							cList.add(type);
						}
					}
				}
			}
		}
		
		return true;
	}



	/**
	 * 
	 */
	public static final String TITLE_FILE_CHECK = "Check the file";



	/**
	 * 
	 * @param e
	 * @return
	 */
	private boolean loadProperty( final ActionEvent e )
	{
		Object source = e.getSource();
		String command = e.getActionCommand();
		SGWizardDialog dg = (SGWizardDialog)source;

		if( source instanceof SGPropertyFileChooserWizardDialog )
		{
			SGPropertyFileChooserWizardDialog pdg
				= (SGPropertyFileChooserWizardDialog)dg;

			File f = pdg.getSelectedFile();
			if( f!=null )
			{
				this.updateCurrentFile( f, FILE_TYPE_PROPERTY );
				this.mMultiDataFileChooserWizardDialog.setFile(
					this.getCurrentFileDirectory(), this.mCurrentDataFileName );
			}
			
			if( this.fromPropertyFileChooserDialog( e, dg ) == false )
			{
				return false;
			}
		}
		else if( source instanceof SGMultiDataFileChooserWizardDialog )
		{
			SGMultiDataFileChooserWizardDialog mdg
				= (SGMultiDataFileChooserWizardDialog)dg;

			File f = mdg.getSelectedFile();
			if( f!=null )
			{
				this.updateCurrentFile( f, FILE_TYPE_DATA );
				if( source.equals( this.mMultiDataFileChooserWizardDialog ) )
				{
					this.mPropertyFileChooserWizardDilaog.setFile(
						this.getCurrentFileDirectory(), this.mCurrentPropertyFileName );
				}
			}

			if( this.fromMultiDataFileChooser(e) == false )
			{
				return false;
			}
		}

		// cancel or previous
		if( command.equals( SGWizardDialog.CANCEL_BUTTON_TEXT ) )
		{
			dg.setVisible(false);
		}
		else if( command.equals( SGWizardDialog.PREVIOUS_BUTTON_TEXT ) )
		{
			dg.showPrevious();
		}

		return true;
	}




	public static final int FILE_TYPE_DATA = 0;
	public static final int FILE_TYPE_PROPERTY = 1;
	public static final int FILE_TYPE_IMAGE = 2;


	/**
	 * 
	 * @param f
	 * @param type
	 */
	private void updateCurrentFile( File f, int type )
	{
		String path = f.getPath();
		String parent = f.getParent();
		this.setCurrentFileDirectory(parent);
		String name = path.substring( parent.length() + 1 );
		if( type==FILE_TYPE_DATA )
		{
			this.mCurrentDataFileName = name;
		}
		else if( type==FILE_TYPE_PROPERTY )
		{
			this.mCurrentPropertyFileName = name;
		}
	}


	
	/**
	 * 
	 */
	private Document mPropertyFileDocument = null;

	

	/**
	 * 
	 * @param e
	 * @param dg
	 * @return
	 */
	private boolean fromPropertyFileChooserDialog( ActionEvent e, SGWizardDialog dg )
	{
		String command = e.getActionCommand();
		Window owner = dg.getOwner();
		SGWizardDialog next = dg.getNext();
		if( ( dg instanceof SGPropertyFileChooserWizardDialog ) == false )
		{
			return false;
		}
		if( ( next instanceof SGMultiDataFileChooserWizardDialog ) == false )
		{
			return false;
		}
		SGPropertyFileChooserWizardDialog pdg = (SGPropertyFileChooserWizardDialog)dg;
		SGMultiDataFileChooserWizardDialog mdg = (SGMultiDataFileChooserWizardDialog)next;
		if( command.equals( SGWizardDialog.NEXT_BUTTON_TEXT ) )
		{
			if( this.fromPropertyFileChooserDialogNext(pdg,mdg) == false )
			{
				return false;
			}
		}

		return true;
	}


	
	/**
	 * 
	 * @param pdg
	 * @param mdg
	 * @return
	 */
	private boolean fromPropertyFileChooserDialogNext(
		final SGPropertyFileChooserWizardDialog pdg,
		final SGMultiDataFileChooserWizardDialog mdg )
	{

		// get file type from the selected file
		File file = pdg.getSelectedFileFromTextField();
		if( file.exists() == false )
		{
			SGUtility.showFileNotFoundMessageDialog( pdg );
			return false;
		}

		// set the selected file to the file chooser
		pdg.setSelectedFile( file );

		// get information from the property file
		ArrayList idList = new ArrayList();
		ArrayList nList = new ArrayList();
		ArrayList cList = new ArrayList();
		if( this.getInfoFromPropertyFile( file, pdg, idList, nList, cList ) == false )
		{
			return false;
		}

		// initialize the dialog
		mdg.init( idList.size() );		

		// set the id list and the class type list
		// to the multi data file chooser
		if( this.setMultiDataFileChooser( idList, nList, cList, mdg )==false )
		{
			return false;
		}
		
		// show the multi data chooser dialog
		pdg.showNext();

		return true;
	}
	
	

	/**
	 * 
	 * @param file
	 * @param com
	 * @param idList
	 * @param nList
	 * @param cList
	 * @return
	 */
	private boolean getInfoFromPropertyFile(
		final File file,
		final Component com,
		final ArrayList idList,
		final ArrayList nList,
		final ArrayList cList )
	{
		
		String path = SGUtility.getCanonicalPath( file.getPath() );
		if( path==null )
		{
			SGUtility.showMessageDialog( 
				com, MSG_FILE_OPEN_FAILURE, TITLE_FILE_CHECK, JOptionPane.ERROR_MESSAGE );
			return false;
		}

		// check validity of the file
		URL url = null;
		try
		{
			url = file.toURL();
		}
		catch( MalformedURLException ex )
		{
			return false;
		}

		
		// create a Document object
		Document doc = SGUtilityText.getDocument( url );
		if( doc==null )
		{
			SGUtility.showMessageDialog(
				com, MSG_PROPERTY_FILE_INCORRECT,
				TITLE_FILE_CHECK, JOptionPane.ERROR_MESSAGE );
			return false;
		}
		this.mPropertyFileDocument = doc;


		// figure ID
		NodeList figureNodeList
			= doc.getElementsByTagName( SGFigure.TAG_NAME_FIGURE );
		if( figureNodeList.getLength()==0 )
		{
			// if figure does not exist, return false
			SGUtility.showMessageDialog(
				com, MSG_PROPERTY_FILE_INCORRECT,
				TITLE_FILE_CHECK, JOptionPane.ERROR_MESSAGE );
			return false;
		}
		final int fnLength = figureNodeList.getLength();
		for( int ii=0; ii<fnLength; ii++ )
		{
			Node node = figureNodeList.item(ii);
			if( ( node instanceof Element ) == false )
			{
				continue;
			}

			Element figure = (Element)node;
			NodeList dataList = figure.getElementsByTagName(
				SGIGraphElement.TAG_NAME_DATA );
			final int id = ii+1;
			final int dataNum = dataList.getLength();
			if( dataNum==0 )
			{
				idList.add( new Integer(id) );
			}
			else
			{
				for( int jj=0; jj<dataNum; jj++ )
				{
					idList.add( new Integer(id) );
				}
			}
		}

		
		// read the property file and get a list of candidates of data-type
		if( this.getDataInfoFromPropertyFile( doc, nList, cList ) == false )
		{
			SGUtility.showMessageDialog(
				com, MSG_PROPERTY_FILE_INCORRECT,
				TITLE_FILE_CHECK, JOptionPane.ERROR_MESSAGE );
			return false;
		}


		// if the candidate does not exist, return false
/*		if( cList.size()==0 )
		{
			SGUtility.showMessageDialog(
				com, ERRMSG_PROPERTY_FILE_INCORRECT,
				TITLE_FILE_CHECK, JOptionPane.ERROR_MESSAGE );
			return false;
		}
*/		if( cList.size() != idList.size() )
		{
			SGUtility.showMessageDialog(
				com, MSG_PROPERTY_FILE_INCORRECT,
				TITLE_FILE_CHECK, JOptionPane.ERROR_MESSAGE );
			return false;
		}
		
		
		
		return true;
	}
	
	

	
	/**
	 * 
	 * @param idList
	 * @param cList
	 * @param mdg
	 * @return
	 */
	private boolean setMultiDataFileChooser(
		final ArrayList idList,
		final ArrayList nList,
		final ArrayList cList,
		final SGMultiDataFileChooserWizardDialog mdg )
	{
		final int dataNum = cList.size();

		// set the number of files
		mdg.setFileNumber( dataNum );

		final String NO = SGMultiDataFileChooserWizardDialog.NO_DATA;

		// figure id
		String[] idArray = new String[dataNum];
		for( int ii=0; ii<dataNum; ii++ )
		{
			idArray[ii] = ((Integer)idList.get(ii)).toString();
		}

		ArrayList noDataList = new ArrayList();
		
		// data name
		String[] nArray = new String[dataNum];
		for( int ii=0; ii<dataNum; ii++ )
		{
			Object obj = nList.get(ii);
			if( obj==null )
			{
				obj = NO;
				noDataList.add( new Integer(ii) );
			}
			nArray[ii] = (String)obj;
		}

		
		// data type
		String[] cArray = new String[dataNum];
		for( int ii=0; ii<dataNum; ii++ )
		{
			Object obj = cList.get(ii);
			if( noDataList.contains( new Integer(ii) ) )
			{
				obj = NO;
			}
			cArray[ii] = (String)obj;
		}


		// data name
		String[] fArray = new String[dataNum];
		for( int ii=0; ii<dataNum; ii++ )
		{
			if( noDataList.contains( new Integer(ii) ) )
			{
				fArray[ii] = NO;
			}
		}

		
		// set to the dialog
		mdg.setFigureIDArray( idArray );
		mdg.setDataNameArray( nArray );
		mdg.setDataTypeArray( cArray );
		mdg.setFileNameArray( fArray );
		
		return true;
	}

	
	
	/**
	 * 
	 * @param e
	 * @return
	 */
	private boolean fromMultiDataFileChooser( final ActionEvent e )
	{
		Object source = e.getSource();
		SGWizardDialog dg = (SGWizardDialog)source;
		String command = e.getActionCommand();
		SGMultiDataFileChooserWizardDialog mdg = (SGMultiDataFileChooserWizardDialog)dg;

		//
		if( command.equals( SGWizardDialog.OK_BUTTON_TEXT ) )
		{
			// get the map of data file list
			TreeMap map = mdg.getSelectedFilePathListMap();

			// create a window
			SGDrawingWindow wnd
				= this.createWindowFromPropertyFile(
					this.mPropertyFileDocument, map );
			if( wnd==null )
			{
				return false;								
			}

			// hide the wizard dialog
			dg.setVisible(false);

		}
		else if( command.equals( SGWizardDialog.CANCEL_BUTTON_TEXT ) )
		{
			dg.setVisible(false);
		}

		return true;
	}




	/**
	 * 
	 */
	private boolean fromWizardDialog( final ActionEvent e )
	{

		Object source = e.getSource();
		SGWizardDialog dg = (SGWizardDialog)source;

		String command = e.getActionCommand();

		//
		// from the command line or drag&drop
		//

		if( source.equals( this.mXYDataTypeSelectionWizardDialogFromCLorDD ) )
		{
			return this.fromCLorDDWizardDialog(e);
		}
		

		//
		// from the tool bar
		//

		// New Graph
		if( source.equals( this.mFigureIDSelectionWizardDialog )
			|| source.equals( this.mSingleDataFileChooserWizardDilaog )
			|| source.equals( this.mXYDataTypeSelectionWizardDialog ) )
		{
			return this.addDataByToolBar(e);
		}

		// Load Property
		if( source.equals( this.mPropertyFileChooserWizardDilaog )
			|| source.equals( this.mMultiDataFileChooserWizardDialog )
			|| source.equals( this.mMultiDataFileChooserWizardDialogDD ) )
		{
			return this.loadProperty(e);
		}

		return true;
	}






	
	
	
	/**
	 * 
	 */
	public void actionPerformed( final ActionEvent e )
	{

		Object source = e.getSource();
		String command = e.getActionCommand();

		// From the windows
		if( source instanceof SGDrawingWindow )
		{
			this.fromWindow(e);
		}
		// From the wizard dialogs
		else if( source instanceof SGWizardDialog )
		{
			this.fromWizardDialog(e);
		}

	}


	/**
	 * 
	 */
	public void windowOpened( final WindowEvent e )
	{
		
	}


	/**
	 * 
	 */
	public void windowClosed( final WindowEvent e )
	{

	}



	/**
	 * 
	 */
	public void windowClosing( final WindowEvent e )
	{
		Object source = e.getSource();
		if( source instanceof SGDrawingWindow )
		{
			// remove the window from the map
			final SGDrawingWindow wnd = (SGDrawingWindow)e.getSource();
			this.removeWindow(wnd);

			// run the garbage collector
			System.gc();

			// if all windows are closed, exit the application
			if( this.mWndMap.size() == 0 )
			{
				this.exit(0);
			}
		}

	}



	/**
	 * Exit the application.
	 * @param status exit status.
	 */
	public void exit( final int status )
	{
		System.exit(status);
	}




	/**
	 * Remove the window from window map.
	 */
	public boolean removeWindow( final SGDrawingWindow wnd )
	{

		if( wnd==null )
		{
			return false;
		}

		final int id = wnd.getID();
		this.mWndMap.remove( new Integer(id) );
		wnd.removeWindowListener( this );
		wnd.removeActionListener(this);

		return true;

	}



	/**
	 * 
	 */
	public void windowActivated( final WindowEvent e )
	{
		
	}


	/**
	 * 
	 */
	public void windowDeactivated( final WindowEvent e )
	{
		
	}


	/**
	 * 
	 */
	public void windowIconified( final WindowEvent e )
	{
		
	}


	/**
	 * 
	 */
	public void windowDeiconified( final WindowEvent e )
	{
		
	}


	/**
	 * 
	 */
	public void dragEnter( final DropTargetDragEvent dtde )
	{
		dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
	}


	/**
	 * 
	 */
	public void dragExit( final DropTargetEvent dte )
	{
	}


	/**
	 * 
	 */
	public void dropActionChanged( final DropTargetDragEvent dtde )
	{
	}


	/**
	 * 
	 */
	public void dragOver( final DropTargetDragEvent dtde )
	{
	}



	/**
	 * 
	 */
	public void drop( final DropTargetDropEvent dtde )
	{
		DropTarget tg = (DropTarget)dtde.getSource();
		Component com = tg.getComponent();
		SGDrawingWindow wnd = (SGDrawingWindow)com;
		dtde.acceptDrop( DnDConstants.ACTION_COPY_OR_MOVE );
		try
		{
			if( ( dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE ) != 0 )
			{
				Transferable trans = dtde.getTransferable();
				List list = (List)trans.getTransferData( DataFlavor.javaFileListFlavor );

				// set attributes
				DropEventHandler th = new DropEventHandler( this, dtde, list );
			}
		}
		catch ( Exception ex )
		{

		}
		finally
		{
			dtde.dropComplete( false );
		}

	}

	


	/**
	 * 
	 */
	private boolean fromDragAndDrop(
		final int x, final int y,
		final SGDrawingWindow wnd, final ArrayList fileList )
	{

		// set unabled the window
		wnd.setEnabled(false);
		
		try
		{
			// analyze the file list
			ArrayList dataFileList = new ArrayList();
			File propertyFile = null;
			for( int ii=0; ii<fileList.size(); ii++ )
			{
				File file = (File)fileList.get(ii);
				String path = file.getAbsolutePath();
			
				// as property file
				if( path.endsWith( PROPERTY_FILE_EXTENSION ) )
				{
					if( propertyFile==null )
					{
						propertyFile = file;
					}
					else
					{
						return false;
					}
				}
				else
				// as data file
				{
					dataFileList.add(file);
				}
			}


			// add data
			if( propertyFile==null )
			{
				if( this.addDataByDragAndDrop(
					x, y, wnd, dataFileList ) == false )
				{
					return false;
				}
			}
			else
			// use property file
			{
				if( this.fromDragAndDropPropertyFile(
					propertyFile, dataFileList, wnd ) == false )
				{
					return false;
				}
			}
		}
		finally
		{
			// set enabled the window
			wnd.setEnabled(true);
		}

		return true;
	}


	
	/**
	 * 
	 */
	private SGMultiDataFileChooserWizardDialog
		mMultiDataFileChooserWizardDialogDD = null;

	
	/**
	 * 
	 * @param propertyFile
	 * @param fileList
	 * @return
	 */
	private boolean fromDragAndDropPropertyFile(
		final File propertyFile,
		final ArrayList dataFileList,
		final Frame owner )
	{

		if( propertyFile.exists() == false )
		{
			SGUtility.showMessageDialog( 
				owner, MSG_FILE_OPEN_FAILURE, TITLE_FILE_CHECK, JOptionPane.ERROR_MESSAGE );
			return false;
		}

		
		// create data chooser dialog
		this.mMultiDataFileChooserWizardDialogDD
			= new SGMultiDataFileChooserWizardDialog(owner,true);

		SGMultiDataFileChooserWizardDialog dg
			= this.mMultiDataFileChooserWizardDialogDD;
		
		dg.getPreviousButton().setVisible(false);
		dg.getNextButton().setVisible(false);
		dg.pack();
		dg.addActionListener(this);


		// set directory
		this.mMultiDataFileChooserWizardDialogDD.setFile(
			this.getCurrentFileDirectory(), this.mCurrentDataFileName );

		
		// get information from the property file
		ArrayList idList = new ArrayList();
		ArrayList nList = new ArrayList();
		ArrayList cList = new ArrayList();
		if( this.getInfoFromPropertyFile(
			propertyFile, owner, idList, nList, cList ) == false )
		{
			return false;
		}
		
		// initialize the dialog
		dg.init( idList.size() );		

		// set the id list and the class type list
		// to the multi data file chooser
		if( this.setMultiDataFileChooser(
			idList, nList, cList, dg ) == false )
		{
			return false;
		}
		
		// show dialog
		dg.setCenter( owner );
		dg.setVisible(true);
		
		return true;
	}
	
	

	/**
	 * 
	 */
	private boolean addDataByDragAndDrop(
		final int x, final int y,
		final SGDrawingWindow wnd, final ArrayList fileList )
	{

		// dialog to select data-type
		this.mXYDataTypeSelectionWizardDialogFromCLorDD
			= new SGXYDataTypeSelectionWizardDialog( wnd, true );
		this.mXYDataTypeSelectionWizardDialogFromCLorDD.addActionListener(this);
		this.mXYDataTypeSelectionWizardDialogFromCLorDD.mPreviousButton.setVisible(false);
		this.mXYDataTypeSelectionWizardDialogFromCLorDD.mNextButton.setVisible(false);
		this.mXYDataTypeSelectionWizardDialogFromCLorDD.pack();

		// create data objects
		for( int ii=0; ii<fileList.size(); ii++ )
		{
			File file = (File)fileList.get(ii);

			ArrayList list = new ArrayList();
			int ret;
			try
			{
				ret = this.createDataFromFile( file.getPath(), list );
			}
			catch( FileNotFoundException ex )
			{
				SGUtility.showFileNotFoundMessageDialog( wnd );
				return false;
			}
			if( ret==-1 )
			{
				SGUtility.showMessageDialog(
					wnd,
					"Data file is invalid.",
					"Error",
					JOptionPane.WARNING_MESSAGE
				);
				return false;
			}

			if( ret==1 )
			{
				return true;
			}

			if( list.size() == 0 )
			{
				return false;
			}
			SGData data = (SGData)list.get(0);

			String path = file.getAbsolutePath();

			Component com = wnd.getComponent(x,y);
			if( com instanceof SGDrawingWindow )
			{
				// フィギュア番号
				int figureID = wnd.getCurrentFigureId();

				// フィギュア
				SGFigure figure = wnd.getFigure( figureID );
				if( figure==null )
				{
					String name = this.getSimpleFileName( path );
					if( name==null )
					{
						return false;
					}

					Point pos = new Point(x,y);
					figure = this.createNewFigure(
						wnd, figureID, data, pos, name );
					if( figure==null )
					{
						return false;
					}
				}
				else
				{
					String name = this.getNewDataName( figure, path );
					if( name==null )
					{
						return false;
					}

					// add data to the figure
					if( figure.addData( data, name ) == false )
					{
						return false;
					}
				}

			}
			else if( com instanceof SGFigure )
			{
				SGFigure figure = (SGFigure)com;
				String name = this.getNewDataName( figure, path );
				if( name==null )
				{
					return false;
				}

				if( figure.addData( data,name ) == false )
				{
					return false;
				}
			}
			else
			{
				return false;
			}

		}

		return true;
	}

	
	
	
	/**
	 * 
	 * @param wnd
	 * @param figureID
	 * @param data
	 * @param pos
	 * @return
	 */
	private SGFigure createNewFigure(
		final SGDrawingWindow wnd,
		final int figureID,
		final SGData data,
		final Point pos,
		final String name )
	{

		// create a figure instance
		SGFigure figure = this.createFigure( figureID, wnd, data );
		if( figure==null )
		{
			return null;
		}

/*
		// init the history of the properties before the data is added
		if( figure.getGraphElement().initPropertiesHistory() == false )
		{
			return null;
		}
*/

		// ウインドウにフィギュアをaddする
		TreeMap map = wnd.getFigureMap();
		if( map.containsValue(figure) == false )
		{
			wnd.addFigure( figureID, figure, pos );
		}


		// フィギュアにデータを追加
		if( !figure.addData(data,name) )
		{
			return null;
		}


		// init the history of the properties after the data is added
		SGIFigureElement[] array = figure.getIFigureElementArray();
		for( int ii=0; ii<array.length; ii++ )
		{
/*			if( array[ii] instanceof SGIGraphElement )
			{
				continue;
			}
*/			if( array[ii].initPropertiesHistory() == false )
			{
				return null;
			}
		}


		//
		wnd.drawBackFigure( figure );


		// initialize the history of the properties
		// after drawn back
		figure.initPropertiesHistory();


		//
		figure.setVisible(true);
		wnd.setChanged(true);
		wnd.notifyToRoot();


		// show the window and figure
		wnd.setVisible(true);
//		figure.setVisible(true);


		// update the items after the figure is set visible
		wnd.updateItemsByFigureNumbers();

		return figure;

	}



	/**
	 * 
	 * @param wnd
	 * @return
	 */
	private SGSplashWindow createSplashWindow()
	{
		// set the image and the text
		Class inClass = getClass();
		String name = RESOURCES_DIRNAME + "About.png";
		URL url = inClass.getResource(name);
		Image image = Toolkit.getDefaultToolkit().getImage( url );
		SGSplashWindow sw = new SGSplashWindow( image );

		return sw;
	}

}


}

