package org.wojc.client;


import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import org.wojc.common.WOJCKitUtil;
import org.wojc.localization.Messages;

import com.webobjects.eoapplication.EOApplication;
import com.webobjects.foundation.NSDictionary;


/**
 * Facilitates establishing a connection to the WO server from the client
 * application. Provides the capability to connect to multiple alternate URLs
 * (see the {@link #start(String[])} method for more info on that). This class
 * should be subclassed by the class that is a start point for WOJC
 * applications.
 * 
 * @version 1.0 Jul 22, 2008
 * @author Florijan Stamenkovic (flor385@mac.com)
 */
public class EOAppSubclass extends EOApplication{
	
	//	a flag indicating how much time can elapse before the
	//	next in sequence of URLs of WO applications is used
	private static final int TIMEOUT = 5000;
	
	private static final String ApplicationURLProperty = "-applicationURL"; //$NON-NLS-1$
	
	//	a monitor used to synchronize multiple threads involved
	//	in establishing a connection to a WO server
	private static final Integer monitor = new Integer(1);
	
	//	cache for the application, used by the application() method.
	private static EOAppSubclass application;
	
	//	an indication used between threads indicating if the
	//	connection to the server has been established
	private static volatile boolean connected = false;
	
	/**
	 * Attempts to establish a connection to a WO server at any of the URLs
	 * passed as parameter. If it succeeds, the {@link #finishInit()} method
	 * will be called once the connection is established. This method will
	 * return on the thread that called it, while <tt>finishInit()</tt> will be
	 * called on AWT's EDT. Calling this method from AWT's EDT will cause a
	 * runtime exception.
	 * 
	 * @param urls See above.
	 * @return If or not the connection was established.
	 */
	public static boolean start(String[] urls){
		
		if(SwingUtilities.isEventDispatchThread())
			throw new RuntimeException("This method can not be called on the EDT");
		
		//	try to connect to all given urls
		for(String url : urls){
			url = url.trim();
System.out.println("Will try to establish a connection to application server at: " + //$NON-NLS-1$
WOJCKitUtil.quote(url));	

			try{
				//	set arguments
				NSDictionary<String, String> arguments = 
					new NSDictionary<String, String>(url, ApplicationURLProperty);
				EOApplication.setArguments(arguments);
				//	try to connect
				com.webobjects.eoapplication.client.EOClientApplicationSupport.main(
						new String[]{ApplicationURLProperty, url});
				
				//	wait for the specified timeout
				synchronized(monitor){
					if(connected) return true;
					monitor.wait(TIMEOUT);
				}
				//	if connection has been established, return
				if(connected) return true;
				
				/*
				 * The above code can fail if the finishInitialization() is
				 * called exactly at this point (in a different thread). This
				 * however should not happen because it should be called
				 * immediately after the call to
				 * EOClientApplicationSupport.main(...), which gives Thread
				 * scheduling the period defined by TIMEOUT to allow the EDT to
				 * call finishInitialization().
				 */
				
			}catch(Throwable th){}
		}

		// could not connect	
		return false;
			
	}
	
	/**
	 * This method is called by EOF once the distribution channel is
	 * established, and frameworks are initialized. It makes sure the
	 * application startup continues.
	 */
	public final void finishInitialization(){
		synchronized(monitor){
			application = this;
			connected = true;
			monitor.notifyAll();
		}
		finishInit();
	}
	
	/**
	 * Program flow is returned to the client application through this method,
	 * once the connection is successfully established to the WO server using
	 * the {@link #start(String[])} method. This method is called on AWT's event
	 * dispatch thread. Override to do whatever you need to do.
	 */
	protected void finishInit(){}
	
	/**
	 * Used to retrieve the <tt>EOAppSubclass</tt> instance that is created as a
	 * result of a successful connection establishment.
	 * 
	 * @return See above.
	 */
	public static EOAppSubclass application(){
		return application;
	}
	
	/**
	 * Informs the user (using the Swing <tt>JOptionPane</tt>) that the client
	 * could not connect to the server, in a localized way.
	 */
	public static void informUserOfFailure(){
		if(!SwingUtilities.isEventDispatchThread()){
			// switch to the EDT
			try{
				SwingUtilities.invokeAndWait(new Runnable(){
					public void run(){
						informUserOfFailure();
					}
				});
			}catch(Exception e){ throw new RuntimeException(e); }
			
			return;
		}
		
		System.err.println(
		"Failed to establish connection to server. Will inform user and quit."); //$NON-NLS-1$

		JOptionPane.showMessageDialog(null, WOJCKitUtil.padRight(ClientVersion
				.defaultVersion())
				+ Messages.getString("EOAppSubclass.0"), //$NON-NLS-1$
				Messages.getString("EOAppSubclass.1"), //$NON-NLS-1$
				JOptionPane.ERROR_MESSAGE);
		
		System.exit(0);
	}

	/**
	 * Terminates the execution of the client application, utilizes the
	 * superclass implementation to do that, and only adds a single log
	 * statement to the process.
	 */
	public void quit(){
System.out.println("*** "+ClientVersion.defaultVersion()	//$NON-NLS-1$
		+" is quitting"); //$NON-NLS-1$
		
		//if the app was not initialized, then just exit
		if(application == null) System.exit(0);
		super.quit();
	}
}
