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.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
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.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.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

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.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;




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

	/**
	 * Major version number.
	 */
	public static final int MAJOR_VERSION_NUMBER = 0;


	/**
	 * Minor version number.
	 */
	public static final int MINOR_VERSION_NUMBER = 3;


	/**
	 * Micro version number.
	 */
	public static final int MICRO_VERSION_NUMBER = 1;


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


	/**
	 * 
	 */
	public static final String COM_WOPEN = "wopen";


	/**
	 * 
	 */
	public static final String COM_ADD_DATE = "addData";


	/**
	 * 
	 */
	public static final String COM_READ_PROPERTY = "readProperty";

	

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

		// interpret command lines
		interpretCommands( args );


		// create a new thread
		if( PORT_NUMBER==-1 )
		{
			Connect c = new Connect();
		}
		else
		{
			try
			{
				// create a server socket object
				ServerSocket serverSocket
					= new ServerSocket( SGDrawingServer.PORT_NUMBER );

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

	}



	/**
	 * 
	 */
	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();
				}
			}
		}

	}




/**
 * Manage the lock file.
 * 
 */
private static class LockFileManager extends Thread
{

	/**
	 * 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 Connect mConnect = null;

	
	/**
	 * Create a thread object.
	 *
	 */
	protected LockFileManager( Connect 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( TMPDIR + FILE_SEPARATOR + fileName );

		Connect 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;
		}
	}

}




/**
 *  入出力スレッド
 */

private static class Connect extends Thread
	implements ActionListener, WindowListener, DropTargetListener
{



	/**
	 * 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;
	

	/**
	 * 
	 */
	public final String PROPERTY_FILE_READ_MSG_DIALOG_TITLE
		= "Property file has read.";

	/**
	 * 
	 */
	public static final String MSG_SUCCESSFUL_COMPLETION
		= "Successful completion.";

	/**
	 * 
	 */
	public static final String ERRMSG_PROPERTY_FILE_INCORRECT
		= "The property file is invalid.";

	/**
	 * 
	 */
	public static final String ERRMSG_DATA_TYPE_INCORRECT
		= "Data type is incorrect.";

	/**
	 * 
	 */
	public static final String ERRMSG_DATA_NUMBER_SHORTAGE
		= "Data number shortage.";

	/**
	 * 
	 */
	public static final String ERRMSG_DATA_NUMBER_EXCESS
		= "Data number excess.";

	/**
	 * 
	 */
	public static final String ERRMSG_FILE_OPEN_FAILURE
		= "Cannot open the selected file.";


	/**
	 * Server socket.
	 */
	private ServerSocket mServerSocket = null;


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


	/**
	 * The list of the names of data objects.
	 */
	private ArrayList mDataFileNameList = new ArrayList();

	
	/**
	 * File extension of the property files.
	 */
	public static final String PROPERTY_FILE_EXTENSION = "sgp";


	/**
	 * Description of the property files.
	 */
	public static final String PROPERTY_FILE_DESCRIPTION = "Samurai Graph Property File";


	/**
	 * Public ID of the property files.
	 */
	public static final String PROPERTY_FILE_PUBLIC_ID
		= "-/"+"/NILAB/"+"/DTD Samurai-Graph Property XML 1.0/"+"/EN";
	
	/**
	 * System ID of the property files.
	 */
	public static final String PROPERTY_FILE_SYSTEM_ID
		= "http:/"+"/samurai-graph.sourceforge.jp/property.dtd";

	/**
	 * URL of the XML file for the product information.
	 */
	public static final String PRODUCT_XML_FILE_NAME
		= "http:/"+"/samurai-graph.sourceforge.jp/product.xml";


	/**
	 * 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;


	/**
	 * A file chooser to save property files.
	 */
	private JFileChooser mPropertyFileChooser = new SGFileChooser();


	/**
	 * A file chooser to download the new version.
	 */
	private JFileChooser mUpgradeFileChooser = new SGFileChooser();



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


	/**
	 * Create a thread object with a server socket.
	 * @param serverSocket
	 */
	public Connect( ServerSocket serverSocket )
	{
		super();
		this.mServerSocket = serverSocket;

		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);


		// 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);

		// set the proxy
		this.setProxyOnStartUp();


		// update the preferences
		this.updatePreferences();


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

		// set default directory name and file name of the property file
		{
			JFileChooser chooser = this.mPropertyFileChooser;

			SGExtensionFileFilter ff = new SGExtensionFileFilter();
			ff.setDescription( PROPERTY_FILE_DESCRIPTION );
			ff.addExtension( PROPERTY_FILE_EXTENSION );
			chooser.setFileFilter(ff);

			chooser.setCurrentDirectory( new File( path ) );

			String fileName = DEFAULT_PROPERTY_FILE_NAME + "." + PROPERTY_FILE_EXTENSION;
			chooser.setSelectedFile( new File( fileName ) );
		}
		
		{
			this.mUpgradeFileChooser.setCurrentDirectory( new File( path ) );
		}



		//
		// infinite loop as a server process
		//
		if( this.mServerSocket!=null )
		{
			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.executeCommand(commandArray) == false )
					{
	// TODO:クライアントにエラーメッセージを返す
						continue;
					}
	
	// TODO:クライアントに成功したメッセージを返す
	
	
					// 入出力ストリームを閉じる
					in.close();
					out.close();
	
					// ソケットを閉じる
					socket.close();
	
				}
				catch(Exception ex)
				{
					ex.printStackTrace();
				}
			}
		}

	}



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



	/**
	 * 
	 * @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 )
					{
						printFirstChild( el, sb, depth );
					}
					else if( num>1 )
					{
						printFirstChild( el, sb, depth );
						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 );
							}
						}
					}
				}
				else if( tagName.equals("itemize") )
				{
					printNodeRecursively( el, sb, depth+1 );
				}
			}
			else if( child instanceof Text )
			{
				printText( child, sb, depth );
			}
		}

	}


	/**
	 * 
	 * @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 )
		{
			String space = "";
			for( int ii=0; ii<depth; ii++ )
			{
				space += "   ";
			}

			String prefix = "";
			if( depth==0 )
			{
				prefix = "  ";
			}
			if( depth>0 )
			{
				prefix = "- ";
			}

			sub = space + prefix + sub + "\n";

//System.out.println(depth);
//System.out.println(sub);
//System.out.println();

			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;
	}



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


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

	
	/**
	 * 
	 * @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;
	}



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

		// get URL
		URL url = null;
		try
		{
			if( this.mDirectAccessFlag )
			{
				url = new URL( PRODUCT_XML_FILE_NAME );
			}
			else
			{
				url = new URL(
						"http",
						this.mProxyHostName,
						this.mProxyPortNumber,
						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;
	}



	//
	// keys used in backing store
	//
	
	/**
	 * The key for the time Samurai Graph is used.
	 */
	public static final String PREF_KEY_DATE = "Date";

	/**
	 * The key of upgrade cycle.
	 */
	public static final String PREF_KEY_UPGRADE_CYCLE = "Upgrade Cycle";

	/**
	 * The key of major version number.
	 */
	public static final String PREF_KEY_MAJOR_VERSION_NUMBER = "Major Version";

	/**
	 * The key of minor version number.
	 */
	public static final String PREF_KEY_MINOR_VERSION_NUMBER = "Minor Version";

	/**
	 * The key of micro version number.
	 */
	public static final String PREF_KEY_MICRO_VERSION_NUMBER = "Micro Version";



	/**
	 * 
	 * @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 = this.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 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
	 */
	private 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;
	}




	//
	// Values for upgrade cycle.
	//

	/**
	 * Not upgrading automatically.
	 */
	public static final int NO_UPGRADE = 0;

	public static final int UPGRADE_EVERY_TIME = 1;
	public static final int UPGRADE_EVERY_DAY = 2;
	public static final int UPGRADE_EVERY_WEEK = 3;
	public static final int UPGRADE_EVERY_MONTH = 4;


	/**
	 * Default upgrade cycle.
	 */
	public static final int DEFAULT_UPGRADE_CYCLE = UPGRADE_EVERY_WEEK;



	/**
	 * 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;
	}



	/**
	 * 
	 * @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 = this.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 = SGDrawingServer.MAJOR_VERSION_NUMBER;
		final int mMinor = SGDrawingServer.MINOR_VERSION_NUMBER;
		final int mMicro = SGDrawingServer.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( this.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"
			+ "Upgrade now?\n";

		
		// get the change log
		StringBuffer sb = new StringBuffer("-- New Features --\n");
		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.setDetailText( 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;
		String osName = OS_NAME.toLowerCase();
		if( osName.startsWith("windows") )
		{
			name = "win32";
		}
		else if( osName.startsWith("mac os x") )
		{
			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 current and upper directory
		String currentDir = System.getProperty("user.dir");
		String upperDir = new File( currentDir ).getParent();


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


		File helperTempDir = new File( TMPDIR + 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;
		}


		//
		// start the helper application
		//

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

		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] = currentDir;	// 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;
	}



	/**
	 * Name of the upgrade helper application
	 */
	public static final String UPGRADE_HELPER_FILE_NAME = "upgrade-helper.jar";


	/**
	 * Temporary folder used by helper applications
	 */
	public static final String HELPER_TEMP_DIR_NAME = "SamuraiGraphTemp";



	/**
	 * 
	 * @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 )
	{
		FileOutputStream fos = null;
		BufferedOutputStream out = null;
		InputStream in = null;
		SGProgressMonitorDialog dg = null;

		boolean ret = false;

		try
		{
			// create output stream
			fos = new FileOutputStream(file);
			out = new BufferedOutputStream(fos);
	
			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();
					in = 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(in);
				dg.setOutputStream(out);
				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( in!=null )
			{
				try
				{
					in.close();
				}
				catch( IOException ex )
				{
					JOptionPane.showMessageDialog(
						owner,
						"Failed to close the input stream."
					);
					return false;
				}
			}
			
			if( out!=null )
			{
				try
				{
					out.close();
				}
				catch( IOException ex )
				{
					JOptionPane.showMessageDialog(
						owner,
						"Failed to close the output stream."
					);
					return false;
				}
			}

			if( fos!=null )
			{
				try
				{
					fos.close();
				}
				catch( IOException ex )
				{
					JOptionPane.showMessageDialog(
						owner,
						"Failed to close the output stream."
					);
					return false;
				}
			}

		}


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

		return true;
	}



	/**
	 * 
	 */
	public static final String PREF_KEY_PROXY_HOST_NAME = "Proxy Host Name";

	
	/**
	 * 
	 */
	public static final String PREF_KEY_PROXY_PORT_NUMBER = "Proxy Port Number";

	
	/**
	 * 
	 */
	public static final String PREF_KEY_DIRECT_ACCESS = "Direct Access";

	
	
	/**
	 * 
	 * @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;
	}
	
	
	


	/**
	 * Default class name of axis figure element.
	 */
	public static final String DEFAULT_CLASS_NAME_OF_AXIS_ELEMENT
		= "jp.riken.brain.ni.samuraigraph.figure.java2d.SGAxisElement";

	/**
	 * Default class name of sxy-graph figure element.
	 */
	public static final String DEFAULT_CLASS_NAME_OF_SXY_GRAPH_ELEMENT
		= "jp.riken.brain.ni.samuraigraph.figure.java2d.SGSXYGraphElement";

	/**
	 * Default class name of vxy-graph figure element.
	 */
	public static final String DEFAULT_CLASS_NAME_OF_VXY_GRAPH_ELEMENT
		= "jp.riken.brain.ni.samuraigraph.figure.java2d.SGVXYGraphElement";

	/**
	 * Default class name of string figure element.
	 */
	public static final String DEFAULT_CLASS_NAME_OF_STRING_ELEMENT
		= "jp.riken.brain.ni.samuraigraph.figure.java2d.SGStringElement";

	/**
	 * Default class name of legend figure element.
	 */
	public static final String DEFAULT_CLASS_NAME_OF_LEGEND_ELEMENT
		= "jp.riken.brain.ni.samuraigraph.figure.java2d.SGLegendElement";

	/**
	 * Default class name of axis break figure element.
	 */
	public static final String DEFAULT_CLASS_NAME_OF_AXIS_BREAK_ELEMENT
		= "jp.riken.brain.ni.samuraigraph.figure.java2d.SGAxisBreakElement";

	/**
	 * Default class name of significant difference figure element.
	 */
	public static final String DEFAULT_CLASS_NAME_OF_SIGNIFICANT_DIFFERENCE_ELEMENT
		= "jp.riken.brain.ni.samuraigraph.figure.java2d.SGSignificantDifferenceElement";

	/**
	 * Default class name of timing line figure element.
	 */
	public static final String DEFAULT_CLASS_NAME_OF_TIMING_LINE_ELEMENT
		= "jp.riken.brain.ni.samuraigraph.figure.java2d.SGTimingLineElement";


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

		// open the file
		FileInputStream fis = null;

		try
		{
			fis = new FileInputStream("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;
		}

		InputStreamReader isw = new InputStreamReader(fis);
		BufferedReader br = new BufferedReader(isw);

		try
		{
			// read the file
			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 )
				{
					
				}
			}
			if( isw!=null )
			{
				try
				{
					isw.close();
				}
				catch( IOException ex )
				{
					
				}
			}
			if( fis!=null )
			{
				try
				{
					fis.close();
				}
				catch( IOException ex )
				{
					
				}
			}
		}

		return true;

	}



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

		// 第1引数のコマンド名に応じて分岐
		boolean flag = true;
		if( SGDrawingServer.COM_WOPEN.equals( commandArray[0]) )
		{
			flag = this.wopen( commandArray );
		}
		else if( SGDrawingServer.COM_ADD_DATE.equals(commandArray[0]) )
		{
			flag = this.addDataByCommandLine( commandArray );
		}
		else if( SGDrawingServer.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();
		if( this.createDataFromFile( dataFileName, dataList ) == -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 );

		// 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() ) == 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;
/*
		try
		{
			// create a window
			wnd = this.createWindowFromPropertyFile(propertyFileName);
		}
		catch( Exception ex )
		{
			ex.printStackTrace();
		}
*/
		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;

	}




	/**
	 * 
	 * @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.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 )
	{

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

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

		// データの構築
		SGData data = this.createData( 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();


		// 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;

	}




	/**
	 * 
	 */
	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();

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

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


		//
		// 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;

	}



	/**
	 * determine the data-type from the first line
	 */
	private boolean getFileTypeCandidateList(
		final Window owner,
		final String pathName,
		final ArrayList cList,
		final ArrayList tokenNumList )
	{

		FileInputStream fis = null;
		InputStreamReader ir = null;
		BufferedReader br = null;

		try
		{
			fis = new FileInputStream( pathName );
			ir = new InputStreamReader(fis);
			br = new BufferedReader(ir);

			String line = SGUtilityText.readLine(br);
			if( line == null )
			{
				return false;
			}

			// break the string into tokens
			ArrayList tokenList = new ArrayList();
			SGUtilityText.tokenize( line, tokenList );
			int tokenNum = tokenList.size();	// the number of tokens
			if( tokenNum==0 )
			{
				return false;
			}

			// get candidates of data-type
			if( tokenNum==2		// x,y
				|| tokenNum==3		// x,y,string
				|| tokenNum==5		// x,y,e+,e-,string
				)
			{
				if( this.evaluateDataTypeSXY(tokenList) )
				{
					cList.add(SGDataTypeConstants.SXY_DATA);
				}
			}
			else if( tokenNum==4 )
			{
				if( this.evaluateDataTypeSXY(tokenList) )
				{
					cList.add(SGDataTypeConstants.SXY_DATA);
				}

//				cList.add(SGDataTypeConstants.VXY_DATA);
			}
			if( tokenNum>=2 )
			{
				if( this.evaluateDataTypeSXYMultiple(tokenList) )
				{
					cList.add(SGDataTypeConstants.SXY_MULTIPLE_DATA);
				}
			}
			if( tokenNum>=1 )
			{
				if( this.evaluateDataTypeSXYMultiple(tokenList) )
				{
					cList.add(SGDataTypeConstants.SXY_SAMPLING_DATA);
				}
			}

			tokenNumList.add( new Integer(tokenNum) );

		}
		catch( FileNotFoundException ex )
		{
//			Window owner = this.mSingleDataFileChooserWizardDilaog.getOwner();
			SGUtility.showFileNotFoundMessageDialog( owner );
			return false;
		}
		finally
		{
			if( br!=null )
			{
				try
				{
					br.close();
				}
				catch( IOException ex )
				{
					
				}
			}

			if( ir!=null )
			{
				try
				{
					ir.close();
				}
				catch( IOException ex )
				{
					
				}
			}
			
			if( fis!=null )
			{
				try
				{
					fis.close();
				}
				catch( IOException ex )
				{
					
				}
			}
		}

		return true;
	}



	/**
	 * 
	 */
	private boolean evaluateDataTypeSXY( final ArrayList tokenList )
	{

		int num = 0;
		if( tokenList.size()==2 || tokenList.size()==4 )
		{
			num = tokenList.size();
		}
		else if( tokenList.size()==3 )
		{
			num = 2;
		}
		else if( tokenList.size()==5 )
		{
			num = 4;
		}

		for( int ii=0; ii<num; ii++ )
		{
			String str = (String)tokenList.get(ii);
			Double d = SGUtilityText.getDouble(str);
			if( d==null )
			{
				return false;
			}
		}

		return true;

	}



	/**
	 * 
	 */
	private boolean evaluateDataTypeSXYMultiple( final ArrayList tokenList )
	{

		for( int ii=0; ii<tokenList.size(); ii++ )
		{
			String str = (String)tokenList.get(ii);
			Double d = SGUtilityText.getDouble(str);
			if( d==null )
			{
				return false;
			}
		}

		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();
		if( this.getFileTypeCandidateList( owner, pathName, cList, tokenNumList ) == false )
		{
			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 cancel button is pressed, this flag is false
		if( this.mCarryOnWizardFlag == false )
		{
			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;

	}






	/**
	 * 
	 * @return
	 */
	private SGData createData( final String pathName, final ArrayList infoList )
	{
//System.out.println("<< createData >>");
//System.out.println(infoList);

		if( pathName==null || infoList==null )
		{
			return null;
		}

		if( infoList.size()==0 )
		{
			return null;
		}


		SGData data = null;

		final String dataType = (String)infoList.get(0);
		if( dataType.equals( SGDataTypeConstants.SXY_DATA ) )
		{
			data = this.createSXYData(pathName);
		}
		else if( dataType.equals( SGDataTypeConstants.VXY_DATA ) )
		{
			
		}
		else if( dataType.equals( SGDataTypeConstants.SXY_MULTIPLE_DATA ) )
		{
			data = this.createSXYMultipleData(pathName);
		}
		else if( dataType.equals( SGDataTypeConstants.SXY_SAMPLING_DATA ) )
		{
			if( infoList.size()<=1 )
			{
				return null;
			}

			// 第2引数にはサンプリング周波数
			final double rate = ((Double)infoList.get(1)).doubleValue();

			data = this.createSXYSamplingData(pathName,rate);
		}

		return data;
	}



	/**
	 * 
	 */
	private int getColumnNumber( final String pathName )
	{
		// 最初の1行を読み込んで情報を取得する
		int num = -1;

		FileInputStream fis = null;
		InputStreamReader ir = null;
		BufferedReader br = null;

		try
		{
			fis = new FileInputStream( pathName );
			ir = new InputStreamReader(fis);
			br = new BufferedReader(ir);
	
			String line = SGUtilityText.readLine(br);
			if( line==null )
			{
				return num;
			}

			// break the string into tokens
			final ArrayList tokenList = new ArrayList();
			SGUtilityText.tokenize( line, tokenList );
			num = tokenList.size();

		}
		catch( FileNotFoundException ex )
		{
//			Window owner = this.mXYDataTypeSelectionWizardDialog.getOwner();
//			SGUtility.showFileNotFoundMessageDialog( owner );
			return num;
		}
		finally
		{
			if( br!=null )
			{
				try
				{
					br.close();
				}
				catch( IOException ex )
				{
					
				}
			}

			if( ir!=null )
			{
				try
				{
					ir.close();
				}
				catch( IOException ex )
				{
					
				}
			}
			
			if( fis!=null )
			{
				try
				{
					fis.close();
				}
				catch( IOException ex )
				{
					
				}
			}
		}


		return num;
	}



	/**
	 * 
	 */
	private ArrayList[] createListArray( final String pathName, final int num )
	{

		// リストの配列を作成
		ArrayList[] listArray = new ArrayList[num];
		for( int ii=0; ii<listArray.length; ii++ )
		{
			listArray[ii] = new ArrayList();
		}

		FileInputStream fis = null;
		InputStreamReader ir = null;
		BufferedReader br = null;

		try
		{
			fis = new FileInputStream( pathName );
			ir = new InputStreamReader(fis);
			br = new BufferedReader(ir);
	
			String line = null;
			while(true)
			{
				line = SGUtilityText.readLine(br);
				if( line==null )
				{
					break;
				}
		
				// break the string into tokens
				final ArrayList tokenList = new ArrayList();
				if( SGUtilityText.tokenize( line, tokenList ) == false )
				{
					return null;
				}
				if( tokenList.size() != num )
				{
					StringTokenizer stn = new StringTokenizer(line);

					// if the line has effective tokens, return null
					if( stn.hasMoreTokens() )
					{
						return null;
					}
					else
					{
						// otherwise, continue
						continue;
					}
				}

				// array of the tokens
				final String[] array = new String[num];
				for( int ii=0; ii<num; ii++ )
				{
					String str = (String)tokenList.get(ii);
					listArray[ii].add( str );
				}
			}
		}
		catch( FileNotFoundException ex )
		{
			Window owner = this.mXYDataTypeSelectionWizardDialog.getOwner();
			SGUtility.showFileNotFoundMessageDialog( owner );
			return null;
		}
		finally
		{
			if( br!=null )
			{
				try
				{
					br.close();
				}
				catch( IOException ex )
				{
					
				}
			}

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

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

		return listArray;
	}




	/**
	 * 
	 * @return
	 */
	private SGSXYData createSXYData( final String pathName )
	{
//System.out.println("<< createSXYData >>");

		// ファイルからデータ列数を取得
		final int num = this.getColumnNumber(pathName);
		if( num==-1 )
		{
			return null;
		}
		if( num<2 )
		{
			return null;
		}


		// リストの配列を作成
		ArrayList[] listArray = this.createListArray( pathName, num );
		if( listArray==null )
		{
			return null;
		}


		// check
		final int dataLength = listArray[0].size();
		for( int ii=1; ii<listArray.length; ii++ )
		{
			if( listArray[ii].size()!=dataLength )
			{
				return null;
			}
		}


		//
		// create data object
		//

		SGSXYData data = null;
		String str = null;
		Double d = null;
		{
			double[] xArray = new double[dataLength];
			double[] yArray = new double[dataLength];
			for( int ii=0; ii<dataLength; ii++ )
			{
				str = (String)listArray[0].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
				{
					return null;
				}
				xArray[ii] = d.doubleValue();

				str = (String)listArray[1].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
				{
					return null;
				}
				yArray[ii] = d.doubleValue();
			}

			double[] lArray = null;
			double[] uArray = null;
			String[] strArray = null;
			switch( num )
			{
				case 2 :
				{
					break;
				}
				case 4 :
				{
					lArray = new double[dataLength];
					uArray = new double[dataLength];
					for( int ii=0; ii<dataLength; ii++ )
					{
						str = (String)listArray[2].get(ii);
						d = SGUtilityText.getDouble(str);
						if( d==null )
						{
							return null;
						}
						lArray[ii] = d.doubleValue();

						str = (String)listArray[3].get(ii);
						d = SGUtilityText.getDouble(str);
						if( d==null )
						{
							return null;
						}
						uArray[ii] = d.doubleValue();
					}
					break;
				}
				case 3 :
				{
					strArray = new String[dataLength];
					for( int ii=0; ii<dataLength; ii++ )
					{
						strArray[ii] = (String)listArray[2].get(ii);
					}
					break;
				}
				case 5 :
				{
					lArray = new double[dataLength];
					uArray = new double[dataLength];
					strArray = new String[dataLength];
					for( int ii=0; ii<dataLength; ii++ )
					{
						str = (String)listArray[2].get(ii);
						d = SGUtilityText.getDouble(str);
						if( d==null )
						{
							return null;
						}
						lArray[ii] = d.doubleValue();

						str = (String)listArray[3].get(ii);
						d = SGUtilityText.getDouble(str);
						if( d==null )
						{
							return null;
						}
						uArray[ii] = d.doubleValue();

						strArray[ii] = (String)listArray[4].get(ii);
					}
					break;
				}
			
			}

			data = new SGSXYData( xArray, yArray, lArray, uArray, strArray );

		}


		return data;

	}




	/**
	 * 
	 * @return
	 */
	private SGSXYMultipleData createSXYMultipleData( final String pathName )
	{

		// ファイルからデータ列数を取得
		final int num = this.getColumnNumber(pathName);
		if( num==-1 )
		{
			return null;
		}
		if( num < 2 )
		{
			return null;
		}


		// リストの配列を作成
		ArrayList[] listArray = this.createListArray( pathName, num );
		if( listArray==null )
		{
			return null;
		}


		// check
		final int dataLength = listArray[0].size();
		for( int ii=1; ii<listArray.length; ii++ )
		{
			if( listArray[ii].size()!=dataLength )
			{
				return null;
			}
		}



		//
		// create data object
		//

		SGSXYMultipleData data = null;
		{
			double[] xArray = new double[dataLength];
			for( int ii=0; ii<dataLength; ii++ )
			{
				String str = (String)listArray[0].get(ii);
				Double d = SGUtilityText.getDouble(str);
				if( d==null )
				{
					return null;
				}
				xArray[ii] = d.doubleValue();
			}

			double[][] yArray = new double[num-1][];
			for( int ii=0; ii<num-1; ii++ )
			{
				yArray[ii] = new double[dataLength];
				for( int jj=0; jj<dataLength; jj++ )
				{
					String str = (String)listArray[ii+1].get(jj);
					Double d = SGUtilityText.getDouble(str);
					if( d==null )
					{
						return null;
					}
					yArray[ii][jj] = d.doubleValue();
				}
			}

			data = new SGSXYMultipleData( xArray, yArray );

		}

		return data;

	}



	/**
	 * 
	 * @return
	 */
	private SGSXYMultipleData createSXYSamplingData(
		final String pathName, final double sRate )
	{

		// ファイルからデータ列数を取得
		final int num = this.getColumnNumber(pathName);
		if( num==-1 )
		{
			return null;
		}
		if( num < 1 )
		{
			return null;
		}


		// リストの配列を作成
		ArrayList[] listArray = this.createListArray( pathName, num );
		if( listArray==null )
		{
			return null;
		}


		// check
		final int dataLength = listArray[0].size();
		for( int ii=1; ii<listArray.length; ii++ )
		{
			if( listArray[ii].size()!=dataLength )
			{
				return null;
			}
		}



		//
		// create data object
		//

		SGSXYSamplingData data = null;

		Double d = null;
		String str = null;
		{
			double[][] yArray = new double[num][];
			for( int ii=0; ii<num; ii++ )
			{
				yArray[ii] = new double[dataLength];
				for( int jj=0; jj<dataLength; jj++ )
				{
					str = (String)listArray[ii].get(jj);
					d = SGUtilityText.getDouble(str);
					if( d==null )
					{
						return null;
					}
					yArray[ii][jj] = d.doubleValue();
				}
			}

			data = new SGSXYSamplingData( sRate, yArray );
			
		}

		return data;

	}


	/**
	 * 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 )
	{
		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);


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

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

		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 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 );
		if( ret!=SGIConstants.SUCCESSFUL_COMPLETION )
		{
			return ret;
		}

		if( this.mDataFileNameList.size() != 0 )
		{
			ret = SGIConstants.DATA_NUMBER_EXCESS;
		}
		else
		{
			ret = SGIConstants.SUCCESSFUL_COMPLETION;
		}

		
		// add history
		wnd.initPropertiesHistory();

		return ret;

	}
	


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

		// 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 );

		// get the message
		String msg = null;
		if( ret == SGIConstants.SUCCESSFUL_COMPLETION )
		{
			msg = MSG_SUCCESSFUL_COMPLETION;
		}
		else if( ret == SGIConstants.DATA_NUMBER_SHORTAGE )
		{
			msg = ERRMSG_DATA_NUMBER_SHORTAGE;
		}
		else if( ret == SGIConstants.DATA_NUMBER_EXCESS )
		{
			msg = ERRMSG_DATA_NUMBER_EXCESS;
		}
		else if( ret == SGIConstants.FILE_OPEN_FAILURE )
		{
			msg = ERRMSG_FILE_OPEN_FAILURE;
		}
		else if( ret == SGIConstants.PROPERTY_FILE_INCORRECT )
		{
			msg = ERRMSG_PROPERTY_FILE_INCORRECT;
		}
		else if( ret == SGIConstants.DATA_TYPE_INCORRECT )
		{
			msg = ERRMSG_DATA_TYPE_INCORRECT;
		}
		else
		{
			throw new Error();
		}


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


		// 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 )
		{
			wnd.setVisible(false);
			this.removeWindow(wnd);
		}

		
		return wnd;
	}
	
	
	
	/**
	 * 
	 * @param elWnd
	 * @param wnd
	 * @return
	 */
	private int createFiguresFromPropertyFile(
		final Element elWnd,
		final SGDrawingWindow wnd )
	{
		final int ic = SGIConstants.PROPERTY_FILE_INCORRECT;

		NodeList nList = elWnd.getElementsByTagName( SGFigure.TAG_NAME_FIGURE );
		for( int ii=0; ii<nList.getLength(); ii++ )
		{
			Node node = nList.item(ii);
			if( node instanceof Element )
			{
				Element el = (Element)node;
				final int ret = this.createSingleFigureFromPropertyFile( el, wnd );
				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 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;

		
		figure.setGraphRectLocation( x, y );
		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 );
		

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


		//
		// data on figure
		//

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


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

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



		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 int ic = SGIConstants.PROPERTY_FILE_INCORRECT;

		NodeList nList = elFigure.getElementsByTagName( SGIGraphElement.TAG_NAME_DATA );
		for( int ii=0; ii<nList.getLength(); ii++ )
		{
			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;
			}


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

			
			// get the data file
			if( this.mDataFileNameList.size() == 0 )
			{
				return SGIConstants.DATA_NUMBER_SHORTAGE;
			}
			String fileName = (String)this.mDataFileNameList.remove(0);

			
			// check the type of data
			ArrayList cList = new ArrayList();
			ArrayList tokenNumList = new ArrayList();
			Frame owner = figure.getWindow();
			if( this.getFileTypeCandidateList( owner, 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.createData( fileName, infoList );
			if( data_ == null )
			{
				return SGIConstants.FILE_OPEN_FAILURE;
			}
			if( data.setData(data_) == false )
			{
				return SGIConstants.DATA_TYPE_INCORRECT;
			}


			//
			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);
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_SAVE_PROPERTY ) )
		{
			// create a property file
			this.createPropertyFile( wnd );
		}
		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);
		}
		else if( command.equals( SGDrawingWindow.NOTIFY_UPGRADE ) )
		{
			return this.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.showProxySettingDialog(wnd);
		}

		return true;
	}


	
	
	
	
	
	
	/**
	 * 
	 */
	public static final String TAG_NAME_PROPERTY = "Property";

	
	/**
	 * 
	 */
	public final String DEFAULT_PROPERTY_FILE_NAME = "property";

	
	/**
	 * 
	 */
	private String mPropertyFileName
		= DEFAULT_PROPERTY_FILE_NAME + "." + PROPERTY_FILE_EXTENSION;


	
	/**
	 * Create a property file.
	 * @return
	 */
	private boolean createPropertyFile( SGDrawingWindow wnd )
	{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = null;
		try
		{
			builder = factory.newDocumentBuilder();
		}
		catch( ParserConfigurationException ex )
		{
			return false;
		}
		DOMImplementation domImpl = builder.getDOMImplementation();

		// create a DocumentType object
		DocumentType docType = domImpl.createDocumentType(
			TAG_NAME_PROPERTY, PROPERTY_FILE_PUBLIC_ID, PROPERTY_FILE_SYSTEM_ID );
		
		// create a Document object
		Document document = domImpl.createDocument( "", TAG_NAME_PROPERTY, docType );

		// create a DOM tree
		if( wnd.createDOMTree( document ) == false )
		{
			return false;
		}
		
		// export to an XML file
		if( this.exportXMLPropertyFile( document, wnd ) == false )
		{
			return false;
		}
		
		return true;
	}

	
	
	/**
	 * Create an XML property file.
	 * @param document
	 * @param wnd
	 * @return
	 */
	private boolean exportXMLPropertyFile(
		final Document document, final SGDrawingWindow wnd )
	{

		// show a file chooser and get selected file
		File file = this.getPropertyFileFromFileChooser( wnd );
		if( file==null )
		{
			return true;
		}
		
		
		// export to the XML file
		FileOutputStream os = null;
		try
		{
			os = new FileOutputStream( file );
			StreamResult result = new StreamResult(os);
			DOMSource source = new DOMSource( document );
			TransformerFactory transFactory = TransformerFactory.newInstance();
			Transformer transformer = transFactory.newTransformer();

			// set the output properties
			transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
			transformer.setOutputProperty( OutputKeys.METHOD, "xml" );
			transformer.setOutputProperty( OutputKeys.DOCTYPE_SYSTEM, PROPERTY_FILE_SYSTEM_ID );
			transformer.setOutputProperty( OutputKeys.DOCTYPE_PUBLIC, PROPERTY_FILE_PUBLIC_ID );

			transformer.transform( source, result );
		}
		catch( Exception ex )
		{
			return false;
		}
		finally
		{
			if( os!=null )
			{
				try
				{
					os.close();
				}
				catch( IOException ex )
				{
					
				}
			}
		}
		
		return true;
	}

	
	
	
	/**
	 * 
	 * @param wnd
	 * @return
	 */
	private File getPropertyFileFromFileChooser( SGDrawingWindow wnd )
	{
		// create a file filter object
/*		SGExtensionFileFilter ff = new SGExtensionFileFilter();
		ff.setDescription( PROPERTY_FILE_DESCRIPTION );
		ff.addExtension( PROPERTY_FILE_EXTENTION );
*/
		JFileChooser chooser = this.mPropertyFileChooser;
//		chooser.setFileFilter(ff);

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

		File file = null;
		if( ret == JFileChooser.APPROVE_OPTION )
		{
			file = chooser.getSelectedFile();
		}

		return file;
	}



	
	

	/**
	 * 
	 */
	private SGUpgradeDialog mUpgradeDialog = null;


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

		this.mUpgradeDialog.setCenter(wnd);

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

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

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

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

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

			case Connect.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 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 )
	{
		this.mChangeLogDialog = new SGChangeLogDialog(owner,true);
		this.mChangeLogDialog.addActionListener( this );
		this.mChangeLogDialog.setCenter(owner);

		// create a Document object
		Document doc = this.createChangeLogDocument();
		if( doc==null )
		{
			JOptionPane.showMessageDialog(
				owner,
				"Failed to get log information."
			);
			return false;
		}

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

		// get the release node
		NodeList rList = root.getElementsByTagName("release");
		ArrayList sbList = new ArrayList();
		int len = rList.getLength();
		for( int ii=0; ii<len; ii++ )
		{
			Node node = rList.item(ii);
			if( node instanceof Element )
			{
				Element release = (Element)node;

				// get change log
				NodeList rInfoList = release.getElementsByTagName("releaseinfo");
				Element rInfo = (Element)rInfoList.item(0);

				NodeList cLogList = rInfo.getElementsByTagName("log");
				Element cLog = (Element)cLogList.item(0);

				NodeList descList = rInfo.getElementsByTagName("releasedesc");
				Element desc = (Element)descList.item(0);
				String descStr = "<< "+ desc.getFirstChild().toString() + " >>\n";

				NodeList dateList = rInfo.getElementsByTagName("releasedate");
				Element date = (Element)dateList.item(0);
				String dateStr = "Released at " + date.getFirstChild().toString() + ".\n";

				StringBuffer sb = new StringBuffer();
				sb.append( descStr );
				sb.append( dateStr );
				this.printNode( cLog, sb );
				if( ii!=len-1 )
				{
					sb.append( "\n" );
				}
				sbList.add( sb );
			}
		}

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

		StringBuffer sb = new StringBuffer();
		for( int ii=0; ii<len; ii++ )
		{
			sb.append( (StringBuffer)sbList.get(ii) );
		}
		this.mChangeLogDialog.setDetailText( new String(sb) );

		this.mChangeLogDialog.pack();


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

		return true;
	}


	/**
	 * 
	 */
//	private SGProxySettingDialog mProxySettingDialog = null;

	
	/**
	 * 
	 * @return
	 */
	private boolean showProxySettingDialog( Frame owner )
	{
		SGProxySettingDialog dg = new SGProxySettingDialog(owner,true);
//		this.mProxySettingDialog = dg;
		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;
	}


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

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

		String command = e.getActionCommand();


		// データの型を決定するためのダイアログ
		if( command.equals( SGWizardDialog.OK_BUTTON_TEXT ) )
		{
			this.mCarryOnWizardFlag = true;
			dg.setVisible(false);
		}
		else if( command.equals( SGWizardDialog.CANCEL_BUTTON_TEXT ) )
		{
			this.mCarryOnWizardFlag = false;
			dg.setVisible(false);
		}

		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 ) )
			{
				String pathName = this.mSingleDataFileChooserWizardDilaog.getFileName();

				// データファイルを開いて情報を取得し、データを構築する
				// ファイルの情報リスト
				ArrayList infoList = new ArrayList();
				ArrayList cList = new ArrayList();
				ArrayList tokenNumList = new ArrayList();
				if( this.getFileTypeCandidateList( owner, pathName, cList, tokenNumList ) == false )
				{
					SGUtility.showMessageDialog(
							owner,
							"Data file is invalid.",
							"Error",
							JOptionPane.WARNING_MESSAGE
						);
					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;
				}

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

			if( command.equals( SGWizardDialog.OK_BUTTON_TEXT ) )
			{

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

				String pathName = this.mSingleDataFileChooserWizardDilaog.getFileName();


				// データファイルを開いて情報を取得し、データを構築する
				// ファイルの情報リスト
				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 = this.createData( pathName, infoList );
				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 ) )
				{
					if( this.createNewFigure( wnd, figureID, data, new Point() ) == null )
					{
						SGUtility.showMessageDialog(
							owner,
							"Failed to create a new figure.",
							"Error",
							JOptionPane.WARNING_MESSAGE
						);
						return false;
					}
				}
				else
				{
					if( !figure.addData(data) )
					{
						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 );
				for( int jj=0; jj<dList.getLength(); 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;

		
		// 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;
		}

		
		if( source instanceof SGPropertyFileChooserWizardDialog )
		{
			if( this.fromPropertyFileChooserDialog( e, dg ) == false )
			{
				return false;
			}
		}
		else if( source instanceof SGMultiDataFileChooserWizardDialog )
		{
			if( this.fromMultiDataFileChooser(e) == false )
			{
				return false;
			}
		}


		return true;
	}


	
	/**
	 * 
	 */
	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.getSelectedFile();
		if( file.exists() == false )
		{
			SGUtility.showMessageDialog( 
				pdg, ERRMSG_FILE_OPEN_FAILURE, TITLE_FILE_CHECK, JOptionPane.ERROR_MESSAGE );
			return false;
		}

		
		// 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;
		}
		
		
		// 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, ERRMSG_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, ERRMSG_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, ERRMSG_PROPERTY_FILE_INCORRECT,
				TITLE_FILE_CHECK, JOptionPane.ERROR_MESSAGE );
			return false;
		}
		for( int ii=0; ii<figureNodeList.getLength(); 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();
			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, ERRMSG_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, ERRMSG_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 );


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

		
		// data name
		String[] nArray = new String[dataNum];
		for( int ii=0; ii<dataNum; ii++ )
		{
			nArray[ii] = (String)nList.get(ii);
		}

		
		// data type
		String[] cArray = new String[dataNum];
		for( int ii=0; ii<dataNum; ii++ )
		{
			cArray[ii] = (String)cList.get(ii);
		}

		
		String[] fArray = mdg.getSelectedFileNames();
		if( fArray.length==0 )	// only for the first time!
		{
			fArray = new String[dataNum];
		}
		
		// set to the dialog
		mdg.init( dataNum );
		mdg.setFigureIDArray( idArray );
		mdg.setDataNameArray( nArray );
		mdg.setDataTypeArray( cArray );
		mdg.setFileNameArray( fArray );
		
		return true;
	}

	
	
	/**
	 * 
	 * @param e
	 * @param mode
	 * @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 ) )
		{
			File[] files = mdg.getSelectedFiles();
			this.mDataFileNameList.clear();	// 一旦、クリアする
			for( int ii=0; ii<files.length; ii++ )
			{
				this.mDataFileNameList.add( files[ii].getAbsolutePath() );
			}

			// create a window
			SGDrawingWindow wnd
				= this.createWindowFromPropertyFile( this.mPropertyFileDocument );
			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;
	}



	/**
	 * 
	 */
	private boolean fromUpgradeDialog( 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 = Connect.NO_UPGRADE;
			}
			else if( cycle.equals( SGUpgradeDialog.EVERY_TIME ) )
			{
				type = Connect.UPGRADE_EVERY_TIME;
			}
			else if( cycle.equals( SGUpgradeDialog.EVERY_DAY ) )
			{
				type = Connect.UPGRADE_EVERY_DAY;
			}
			else if( cycle.equals( SGUpgradeDialog.EVERY_WEEK ) )
			{
				type = Connect.UPGRADE_EVERY_WEEK;
			}
			else if( cycle.equals( SGUpgradeDialog.EVERY_MONTH ) )
			{
				type = Connect.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 false;
			}
		}

		return true;
	}



	/**
	 * 
	 * @param e
	 * @return
	 */
	private boolean fromProxySettingDialog( final 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 );
		}

		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);
		}
		else if( source instanceof SGUpgradeDialog )
		{
			this.fromUpgradeDialog(e);
		}
		else if( source instanceof SGProxySettingDialog )
		{
			this.fromProxySettingDialog(e);
		}

	}




	/**
	 * 
	 */
	private boolean mCarryOnWizardFlag = true;



	/**
	 * 
	 */
	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 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
				this.mThread = new ThreadForDropEvent();
				this.mThread.mDropTargetDropEvent = dtde;
				this.mThread.mDroppedFileList = new ArrayList( list );

				// start the thread
				this.mThread.start();
			}
		}
		catch ( Exception ex )
		{

		}
		finally
		{
			dtde.dropComplete( false );
		}

	}

	
	/**
	 * 
	 */
	private ThreadForDropEvent mThread = null;

	private class ThreadForDropEvent extends Thread
	{
		DropTargetDropEvent mDropTargetDropEvent = null;
		ArrayList mDroppedFileList = null;

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

			if( fromDragAndDrop( p.x, p.y, wnd, this.mDroppedFileList ) == false )
			{
				
			}

			wnd.getContentPane().repaint();

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



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




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

		// 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( Connect.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;
			}
		}

		
		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, ERRMSG_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);

		
		// 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;
		}
		
		
		// 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 = this.createDataFromFile( file.getPath(), list );
			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);

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

				// フィギュア
				SGFigure figure = wnd.getFigure( figureID );
				if( figure==null )
				{
					Point pos = new Point(x,y);
					figure = this.createNewFigure(
						wnd, figureID, data, pos );
					if( figure==null )
					{
						return false;
					}
				}
				else
				{
					// add data to the figure
					if( figure.addData( data ) == false )
					{
						return false;
					}
				}

			}
			else if( com instanceof SGFigure )
			{
				SGFigure fig = (SGFigure)com;
				fig.addData(data);
			}
			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 )
	{

		// 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 );
		}


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


		// フィギュアにデータを追加
		if( !figure.addData(data) )
		{
			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();


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


		return figure;

	}



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

		return sw;
	}

}


}

