package jas2.swingstudio;

import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.util.*;
import java.util.zip.*;
import java.io.*;
import java.lang.reflect.*;
import jas2.util.*;
import jas2.util.SplashScreen;
import jas2.util.xml.*;
import jas2.util.tree.*;
import jas2.util.layout.*;
import jas2.util.moverlayeredpane.MLPArrowFactory;
import jas2.util.moverlayeredpane.MLPLabelFactory;
import jas2.util.moverlayeredpane.MoverLayeredPane;
import jas2.util.multifunctionpanel.MultiFunctionPanel;
import jas2.util.xmlmenus.*;
import jas2.util.pluginmanager.*;
import jas2.plugin.*;
import jas2.loader.*;

import jas2.hist.*;
import jas2.jds.interfaces.*;
import jas2.jds.module.*;
//import jas2.hist.test.*;

import javax.swing.*;
import javax.swing.text.*;
import javax.swing.tree.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.filechooser.FileFilter;

public final class JavaAnalysisStudio extends Application
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private static int makeCount = 0;

	private ClassPathLoader m_extensionLoader;
	private CommandProcessor m_currentSelection;
        private ExtensionPluginContext pluginContext;
	private JASConsoleTabbedPane m_JASConsoleTabbedPane;
	private WindowManager m_windowManager;
	private JMenuBar m_disconnectedMenuBar;
	private JASJob m_job = null;
	private JTree m_tree;
	private JASTopBottomSplitPane m_topBottomSplitPane;
	private JASLeftRightSplitPane m_leftRightSplitPane;
	private static JavaAnalysisStudio theApp;

	private JASToolbarHolder m_toolbarHolder;
    private JFrame frame;
	private JTabbedPane m_controlPane;
	private StatusBar m_status;
	private boolean m_statusBarVisible;
	private UserProperties userProp = getUserProperties();
	private int nPages = 0;
	private String[] m_lastJobs, m_lastFiles;
	// lastFiles is the array of programs
	private JASCommand m_jasCommand;
	private JASStoppableManager m_stopMan = new JASStoppableManager();
	private URL m_homePage;
	private boolean m_noTopBottomSplitPane = true;
	private String menuFile = "menus.xml";
	private PluginManager pluginmanager;
	final String m_lastJobPath_Key = "LastJobPath";
	
	final static private String m_WindowsLAF = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
	final static private String m_MotifLAF   = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
	final static private String m_JavaLAF    = "javax.swing.plaf.metal.MetalLookAndFeel";

	final static private String m_TabbedWM   = "jas2.swingstudio.JASWindowManager";
	final static private String m_InternalWM = "jas2.swingstudio.InternalFramesWindowManager";

	final static private String versionURL = "http://jas.freehep.org/version.asp";
	final static boolean jobSavingDisabled = true;
	
	static final long checkWord = 3457768635619245585L;
	static
	{
		try
		{
			// check that java 3d and the plot3d routines are both available
			Class.forName("javax.media.j3d.Canvas3D");
			Class.forName("gov.fnal.plot3d.jas.SpecialLego");
			Class.forName("gov.fnal.plot3d.jas.SpecialSurface");

         if (JPopupMenu.getDefaultLightWeightPopupEnabled())
         {
            JPopupMenu.setDefaultLightWeightPopupEnabled(false);
         }
		}
		catch (Throwable t)
		{
		}
	}	
	static final String[][] knownDebugFlags = 
	{
		{ "loader",        "Debug Class Loaders" },
		{ "eventDelivery", "Remote Event Delivery" },
		{ "caching",       "Caching of Remote Data"},
		{ "extensions",    "Extension loading"},
		{ "printing",      "Printing"},
		{ "help",          "Help"},
		{ "all",           "Turn on all known debug flags"},
	};

	protected void doHelp()
	{
		System.out.println();
		System.out.println(getVersionName());
		System.out.println();
		super.doHelp();
		System.out.println();
		System.out.println("Parameters:");
		System.out.println("\tp1 - A job file to read at startup");
		System.out.println();
		System.out.println("Known debug flags:");
		for (int i=0; i 0)
				jobToLoad = m_lastJobs[0];
		}
		final String jobToOpen = jobToLoad;
		final GetOptions gopt = getGetOptions();
		//frame.setBounds(userProp.getRectangle("Window", new Rectangle(10,10,450,450)));
	
	}
	
	/*
	public JFrame getFrame(){
		
		return frame;
	}
	*/
	
	String getUserExtensionsDir()
	{
		return resolveSymbols(System.getProperty("jas.user.extensions","{user.home}/JASExtensions"));
	}
	String getGroupExtensionsDir()
	{
		return resolveSymbols(System.getProperty("jas.group.extensions"));
	}
	String getSystemExtensionsDir()
	{
		return resolveSymbols(System.getProperty("jas.system.extensions","lib"+File.separator+"extensions"));
	}

	/**
	 * Show it
	 */
	public void showIt(boolean show){

		frame.setVisible(show);
	
        

 }
	
	
	/**
	 * Close it
	 */
	public void close(){
		m_lastJobs=null;
		frame.setVisible(false);
		frame.dispose();
        

 }

        public JASToolbarHolder getToolbar(){

                return m_toolbarHolder;

         }


	/** 
	 * Search the extensions directory for JAR files, and add them to the extensions
	 * CLASSPATH.
	 */
	private void loadExtensions()
	{
		boolean debugExtensions = System.getProperty("debugExtensions") != null;
		ClassPath extensionClasspath = new ClassPath();
		Vector plugins = new Vector();
		Vector plugininfo = new Vector();
		
		// We look for extensions:
		//    a) In the directory specified by the jas.user.extensions System property
		//    b) In the directory specified by the jas.group.extensions System property
		//    c) In the directory specified by the jas.system.extensions System property
		// The following defaults apply if the property is not specified
		//    a) {user.home}/JASExtensions
		//    b) none
		//    c) {java.home}/JASExtensions
		
		String[] extDirs = 
		{
			getUserExtensionsDir(),
			getGroupExtensionsDir(),
			getSystemExtensionsDir()
		};
		scanExtensionDirectories(extDirs,extensionClasspath,plugins,plugininfo,debugExtensions);
		
		// Create the extension Loader.
		
		m_extensionLoader = new ClassPathLoader(extensionClasspath,"ExtensionLoader");
		
		// Create a plugin context to pass to the plugins
		pluginContext = new JASPluginContext(this);
		
		// Now try loading the plugins
		Enumeration e = plugins.elements();
		Enumeration info = plugininfo.elements();
		File file;
		pluginmanager = new PluginManager(getSystemExtensionsDir(),getUserExtensionsDir());
		while (e.hasMoreElements())
		{
			String name = (String) e.nextElement();
			file = ((File) info.nextElement());
			String infopath = file.getParent();
			String infofile = file.getName();
			
			try
			{
				System.out.println("Loading extension: "+name);	
				Class c = m_extensionLoader.loadClass(name,true);
				IExtensionPlugin p = (IExtensionPlugin) c.newInstance();
				p.setPluginContext(pluginContext);
				if(p instanceof IPluginInfo){
					pluginmanager.setPluginLoadedAtStart(((IPluginInfo) p).getName(),((IPluginInfo) p).getVersion(), infopath, infofile);
					
				}else pluginmanager.setPluginLoadedAtStart(infofile,"unknown",infopath, infofile);
			}
			catch (Throwable t)
			{
				System.err.println("Unable to load plugin "+name);
				t.printStackTrace();
			}
		}
	}


        public ExtensionPluginContext getPluginContext(){

               return pluginContext;

        }
	
	private void scanExtensionDirectories(String[] dirs, ClassPath extensionClasspath, Vector plugins, Vector plugininfo,boolean debugExtensions)
	{
		for (int i=0; i 0) out.append(in.substring(0,start));
			String prop = System.getProperty(in.substring(start+1,end-start));
			if (prop != null) out.append(prop);
			if (end + 1 < in.length()) out.append(in.substring(end+1));
			in = out.toString();
		}
		return in;
	}
	private void scanExtensionDirectory(File extdir, ClassPath extensionClasspath, Vector plugins,Vector plugininfo,boolean debugExtensions)
	{
		String[] files = extdir.list();
		for (int i=0; i 0){
					try
					{
					
						//path = f.getParent();
						ZipFile zipFile = new ZipFile(f);
						ZipEntry manifest = zipFile.getEntry("JAS-inf/plugins.txt");
						if (manifest != null )
						{
							// Each line of the manifest should contain the name of a Plugin class file
							LineNumberReader reader = new LineNumberReader(new InputStreamReader(zipFile.getInputStream(manifest)));
							for (;;)
							{
								String line = reader.readLine();
								if (line == null) break;
								if (plugins.indexOf(line) < 0)
								{
									plugins.addElement(line);
									plugininfo.addElement(f);
								}
							}
							reader.close();
						}
						if (debugExtensions) System.out.println("\tFound: "+files[i]);						
						extensionClasspath.add(zipFile);
					}
					catch (IOException x)
					{
						System.err.println("Extension jar file "+files[i]+" could not be loaded"+x);	
					}
				}else{ // Files with length 0 have been flagged for deletion by the plugin manager.
					boolean removed = f.delete();		
				}
			}
		}
	}
	private void reconnect(String connect) throws Exception
	{
		StringTokenizer t = new StringTokenizer(connect,"/");
		if (t.countTokens() != 2) throw new ConnectException("Invalid connect option "+connect); 
		String node = t.nextToken();
		String jobName = t.nextToken();
		JavaDataServer jds = JASJobAdaptor.connectToServer(node,null,0,this);
      if (jds == null) return;
		JASJob jasJob = new JASJob(jobName);
		JASJobAdaptor job = new JASJobAdaptor(jasJob,jobName,jds,this);
		jasJob.setJob(job);
		setJob(jasJob, true);
		job.listItems();
	}
	public JASPage getCurrentPage()
	{
		try
		{
			Component c = m_windowManager.getWindow( m_windowManager.getSelectedWindow() );
			return (JASPage) c;
		}
		catch (Exception e)
		{
			return null;
		}
	}
	public JTabbedPane getControlPane()
	{
		return m_controlPane;
	}
	public JTabbedPane getConsolePane()
	{
		return m_JASConsoleTabbedPane;
	}
	public JASPage newPage(int nx, int ny)
	{
		nPages++;
		JASPage page = new JASPage(nx,ny);
		m_windowManager.newWindow("Page "+nPages,page);
		return page;
	}
		
	public void setNPages(int nPages)
	{
		this.nPages = nPages;
	}
	public  void setStatusBarVisible(boolean visible)
	{
		m_statusBarVisible = visible;
		if (visible) add(BorderLayout.SOUTH,m_status);
		else remove(m_status);
		revalidate();
	}
	public JMenuBar getMenuBar()
	{
		return m_disconnectedMenuBar;
	}
	
	public JASJob getJob()
	{
		return m_job;
	}
	public ClassPathLoader getExtensionLoader()
	{
		return m_extensionLoader;
	}
	public static String getVersionNumber()
	{
      // Dont return anything but i.j.k here, or it messes up the plugin manager
		return "2.2.8";
	}
	String getVersionName()
	{
		return "Java Analysis Studio - "+getVersionNumber()+" (10 April 2002)";
	}
	public static void main(String argv[])
	{
		try 
		{
			theApp = new JavaAnalysisStudio();
		}
		catch (Throwable e)
		{
			System.err.println("Java Analysis Studio Failed to Initialize");
			e.printStackTrace();
			System.exit(1);
		}
	}
	void openLastJob()
	{
		if (m_lastJobs == null || m_lastJobs.length == 0)
		{
			error("There is no last job to open.");
			return;
		}
		try
		{
			readJob( new File(m_lastJobs[0]) );
		}
		catch (Throwable e)
		{
			// readJob should take care of details; we just have to notify user
			error("Could not open last job", e);
		}
	}
	// This is only public for jas.bean.plot
	public static JavaAnalysisStudio getApp()
	{
		return theApp;
	}
	// This is only public for jas.bean.plot
	public TreeModel getTreeModel()
	{
		return m_tree.getModel();
	}
	void setCurrentSelection(CommandProcessor o)
	{
		if (m_currentSelection != null) getCommandManager().remove(m_currentSelection);
		m_currentSelection = o;
		if (m_currentSelection != null) getCommandManager().add(m_currentSelection);
	}
	public void setMessage(String message)
	{
		m_status.setMessage(message);
	}
	void setRebinModel(BoundedRangeModel xModel, BoundedRangeModel yModel)
	{
		m_toolbarHolder.setRebinModel(xModel,yModel);
	}
	OutputStream getOutputStream(String name)
	{
		return m_JASConsoleTabbedPane.getOutputStream(name);
	}
	void setModel(BoundedRangeModel model)
	{
		m_status.setModel(model);
	}
	WindowManager getWindowManager()
	{
		return m_windowManager;
	}
	public JASPage createNewPage()
	{
		return newPage(1, 1);
	}
	/**
	 * Note: This routine may popup a dialog asking the user which page to use as the
	 * current plot. It only returns null if the user cancels the dialog.
	 */
	public JASPage createCurrentPage()
	{
		// find current plot
		final int i = m_windowManager.getSelectedWindow();
		final Component c = i < 0 ? null : m_windowManager.getWindow(i);
		if (i >= 0 && c instanceof JASPage) return ((JASPage) c);
		else
		{
			final Vector pages = m_windowManager.openPages(JASPage.class);
			final int nPages = pages.size();
			if (nPages == 0)
			{
				return newPage(1, 1);
			}
			else if (nPages == 1)
			{
				final JASPage page = (JASPage) pages.elementAt(0);
				selectPage(page);
				return page;
			}
			else // There are multiple pages to choose from
			{
				final int[] indexes = new int[nPages + 1]; // the indexes of the JASPage windows
				int k = 1;
				indexes[0] = -1;
				final int n = m_windowManager.getWindowCount();
				final JComboBox choices = new JComboBox();
				choices.addItem("Create a new window");
				for (int j = 0; j < n; j++)
					if (m_windowManager.getWindow(j) instanceof JASPage)
					{
						indexes[k++] = j;
						choices.addItem(m_windowManager.getWindowName(j));
					}
				final JPanel p = new JPanel(new BorderLayout());
				p.add(BorderLayout.NORTH, new JLabel("Select the page to show the data on, "+
					"or click on \"Cancel\"."));
				p.add(BorderLayout.SOUTH, choices);
				if (JOptionPane.showConfirmDialog(this, p, "Select a page", JOptionPane.OK_CANCEL_OPTION) ==
					JOptionPane.OK_OPTION)
				{
					final int h = indexes[choices.getSelectedIndex()];
					if (h == -1)
					{
						return newPage(1, 1);
					}
					else
					{
						m_windowManager.selectWindow(h);
						return getCurrentPage();
					}
				}
				return null;
			}
		}
	}
	private void selectPage(JASPage page)
	{
		final int i = m_windowManager.find(page);
		if (i >= 0)
			m_windowManager.selectWindow(i);
	}
	private void exit() throws JASException, IOException
	{
		if (querySaveJob())
		{
			if (!m_noTopBottomSplitPane) {
				m_topBottomSplitPane.saveState();
			}
			m_leftRightSplitPane.saveState();
			if (m_job != null) m_job.close();

			// Save window size and position
			if (getFrame().getBounds().x > 0)
				userProp.setRectangle("Window",getFrame().getBounds());
			/*
			 * The above if tests whether the frame is open.  Often in Windows, users right
			 * click on the icon when the frame is collapsed to close the application.
			 * Previously, that caused the application to save its bounds with negative values
			 * for x and y and upon reopen, the frame would be collapsed.  Now, the frame
			 * bounds are not saved when the frame is collapsed (i.e., when
			 * getFrame().getBounds().x < 0) and that last saze is used.
			 */

			userProp.setBoolean("StatusBarVisible",m_statusBarVisible);
			userProp.setStringArray("LastJobs", m_lastJobs);
			userProp.setStringArray("LastFiles",m_lastFiles);

			try
			{
				userProp.save();
			}
			catch (FileNotFoundException e)
			{
				error("Could not save properties", e);
			}

		//	System.exit(0);
                        close();
		}
	}
	private XMLMenuBuilder xmb;
	public XMLMenuBuilder getXMLMenuBuilder() {
		return xmb;
	}
	protected static final class AppCloser extends WindowAdapter 
	{
		AppCloser()
		{
		}
        public void windowClosing(WindowEvent e) 
		{
			JavaAnalysisStudio app = JavaAnalysisStudio.getApp();
			try
			{
				app.exit();
			}
			catch (IOException x)
			{
				app.error("Error during window close",x);
			}
			catch (JASException x)
			{
				app.error("Error during window close",x);
			}
		}
    }
	private void readJob(File file) throws Throwable
	// responsible for doing all cleanup if read fails !!
	{
		closeCurrentJob();
//		try
//		{
//			FileInputStream istream = new FileInputStream(file);
//			ObjectInputStream p = new JASInputStream(istream);
//			Frame frame = getFrame();
//			Cursor oldCursor = frame.getCursor();
//			frame.setCursor(new Cursor(Cursor.WAIT_CURSOR));
//			try
//			{
//				long readCheck = p.readLong();
//				if (readCheck != checkWord) throw new JASException("File does not contain a Java Analysis Studio Job");
//				double v = p.readDouble();
//				String s = (String) p.readObject();
//
//				if (v > getVersionNumber()) throw new JASException("File was written with newer version of Java Analysis Studio - Cannot be read");
//				if (v < getVersionNumber()) System.err.println("Reading file written with JAS version: "+v+" "+s);
//
//				setJob( (JASJob) p.readObject(), false );
//				m_job.setFilePath(file.getAbsolutePath());
//				userProp.setString(m_lastJobPath_Key, file.getParent());
//				m_windowManager.restoreState(p);
//				updateRecentJobs(file.getAbsolutePath());
//			}
//			catch (ClassNotFoundException x)
//			{
//				throw new JASException("Corrupt job file: "+file,x);
//			}
//			finally
//			{
//				frame.setCursor(oldCursor);
//				p.close();
//			}
//		}
//		// if an exception is thrown, pass it along after closing the error-prone new job and
//		// setting an "empty job" in its place
//		catch (Throwable e)
//		{
//			closeCurrentJob();
//			setToEmptyJob();
//			throw e;
//		}
	}
	private void writeJob(String file) throws IOException
	{	
		// Now uses XML to save entire job, not serialization
		XMLWriter xml = new XMLWriter(new FileWriter(file));

		//p.writeObject(m_job);
		m_job.setFilePath(file);
		m_windowManager.saveState(xml);
			
		xml.close();
		//if (xml.checkError()) throw new IOException("Error while writing XML file");
	}
	void updateRecentFiles(File newFile)
	{
		try
		{
			m_lastFiles = userProp.updateStringArray(m_lastFiles, newFile.getCanonicalPath(), RecentFilesMenu.length_Key);
		}
		catch (IOException e)
		{
			m_lastFiles = userProp.updateStringArray(m_lastFiles, newFile.getAbsolutePath(), RecentFilesMenu.length_Key);
		}
	}
	private void updateRecentJobs(String newJob)
	{
		m_lastJobs = userProp.updateStringArray(m_lastJobs, newJob, RecentJobsMenu.length_Key);
	}
	String[] getLastJobs()
	{
		return m_lastJobs;
	}
	String[] getLastFiles()
	{
		return m_lastFiles;
	}
	void openJob(final File file)
	// called from RecentJobs menu
	{
		try
		{
			if (file != null && querySaveJob())
			{
				readJob(file);
			}
		}
		catch (Throwable e)
		{
			// readJob does cleanup, so all we have to do is notify user
			error("Cannot read job file", e);
		}
	}
	public void openFile(File f) throws FileError, JASException, MalformedURLException
	{
		if (f.getName().endsWith(".java")) openJavaFile(f);
		else if (f.getName().endsWith(".javahist")) openJavaHistFile(f);
		else if (f.getName().endsWith(".plotml")) openPlotMLFile(f);
		//else if (f.getName().endsWith(".aidaml")) openAidaMLFile(f);//comment out before checkin
		else if (f.getName().endsWith(".html") ||
				 f.getName().endsWith(".htm") ) showHTMLPage("HTML Page",new URL("file:"+f.getAbsolutePath()),true);
		else
		{
			// Add any extra filters from DIMs which implement LocalDIM2
			
			Enumeration e = JASRegistry.elements();
			while (e.hasMoreElements())
			{
				Object o = e.nextElement();
				if (o instanceof LocalDIM2)
				{
					LocalDIM2 dim = (LocalDIM2) o;
					FileFilter ff = dim.getFileFilter();
					if (ff.accept(f))
					{
						openDataSet(f,dim);
						return;
					}
				}
			}
			int rc = JOptionPane.showConfirmDialog(this,"Unrecognised file type, open in text editor?");
			if (rc == JOptionPane.OK_OPTION) openJavaFile(f);
		}
	}
	private void openDataSet(File f, LocalDIM2 dim) throws FileError, JASException
	{
		try
		{
			// There are two cases to worry about
			// 1. A local job currently open
			// 2. A remote job currently open
		
			if (m_job.getJob() instanceof LocalJob)
			{
				JASLocalJobBuilder ljb = new JASLocalJobBuilder((LocalJob) m_job.getJob());
				dim.setLocalJobBuilder(ljb);
				ljb.setDIM(dim);
				ljb.createJob(f.getCanonicalPath());	
			}
			else if (querySaveJob()) // Remote job
			{
				JASLocalJobBuilder ljb = getLocalJobBuilder();
				ljb.setJobName("Untitled");
				dim.setLocalJobBuilder(ljb);
				ljb.setDIM(dim);
				ljb.createJob(f.getCanonicalPath());	
			}
		}
		catch (IOException x) { throw new FileError("Error opening file",x); }
	}
	private void openJavaHistFile(File f) throws FileError, JASException
	{
		if (!(m_job.getJob() instanceof LocalJob))
			throw new JASException("You can not read a .javahist file into a remote job");
		
		ObjectInputStream in = null;
		try
		{
			 in = new ObjectInputStream(new GZIPInputStream(
				  new BufferedInputStream(new FileInputStream(f))));
			 
			 // This works somewhat by magic. If the top item in the file is a Histogram
			 // or HistogramFolder etc, then it will automatically by hooked into the top
			 // level HistogramFolderSet by the serialization support in AbstractNamedObject.
			 // If the top level item is a hep.analysis.JobFolder, we need to do some work 
			 // ourselves.
			 Object o = in.readObject();

			 //System.out.print("I got an "+o);
			 //if (o instanceof hep.analysis.NamedObject) 
			 //	 System.out.print(" and its parent is "+((hep.analysis.NamedObject) o).getFolder());
			 //System.out.println();
			 
			 if (o instanceof hepjas.analysis.NamedObject)
			 {
				hepjas.analysis.NamedObject no = (hepjas.analysis.NamedObject) o;
				if (no.getFolder() == null) // Must be a hep.analysis.JobFolder
				{
					// Note: If we supported multiple simultaneous jobs then it would make sense
					// to create a new Job here, instead of shoehorning this in here. 
					LocalJob local = (LocalJob) m_job.getJob();
					jas2.job.JobFolder peer = (jas2.job.JobFolder) local.getTreeRoot();
					peer.addNotify(no);
				}
			 }
			 updateRecentFiles(f);
		}
		catch (Exception x)
		{
			throw new FileError("Error reading .javahist file",x);
		}
		finally
		{
			try
			{
				if (in != null) in.close();
			}
			catch (IOException x) {}
		}
	}
	private void openJavaFile(File f) throws FileError
	{
		final int n = m_windowManager.getWindowCount();
		for (int i = 0; i < n; i++)
		{
			final Component c = m_windowManager.getWindow(i);
			if (c instanceof ProgramPage)
			{
				final String path = ((ProgramPage) c).getCanonicalPath();
				try
				{
					if (path != null && f.getCanonicalPath().equals(path))
					{
						m_windowManager.selectWindow(i);
						updateRecentFiles(f);
						return;
					}
				}
				catch (IOException e)
				{
					throw new FileError("Error opening java file",e);
				}
			}
		}
		m_windowManager.newWindow(f.getName(), new ProgramPage(f));
		updateRecentFiles(f);
	}
	private void openPlotMLFile(File f) throws JASException
	{
		try
		{
			XMLHistBuilder xhb = new XMLHistBuilder(new BufferedReader(new FileReader(f)),f.getName());
			JASPage page = new JASPage(1,1);
			xhb.modifyPlot(page.getCurrentPlot());
			m_windowManager.newWindow("PlotML",page);
			updateRecentFiles(f);
		}
		catch (Throwable t)
		{
			error("Error reading PlotML file",t);
		}
	}
	//comment this method out before checkin
	/**private void openAidaMLFile(File f) throws JASException
	{
		try
		{
			AidaXMLHistBuilder axhb = new AidaXMLHistBuilder(new BufferedReader(new FileReader(f)),f.getName());
			JASPage page = new JASPage(1,1);
			axhb.modifyPlot(page.getCurrentPlot());
			m_windowManager.newWindow("AidaML",page);
		}
		catch (Throwable t)
		{
			error("Error reading AidaML file",t);
		}
	}*/
	private void showHTMLPage(String title,URL url,boolean forceNewPage)
	{
		Vector pages = m_windowManager.openPages(HTMLPage.class);
		if (forceNewPage || pages.isEmpty())
		{
			m_windowManager.newWindow(title,new HTMLPage(url));
		}
		else
		{
			HTMLPage page = (HTMLPage) pages.elementAt(0);
			page.showURL(url);
			m_windowManager.selectWindow(m_windowManager.find(page));
		}	
		
	}
	JASLocalJobBuilder getLocalJobBuilder()
	{
		return new JASLocalJobBuilder();
	}

	/*
	 * returns false to indicate that the operation calling querySaveJob should 
	 * be aborted
	 */
	private boolean querySaveJob() throws IOException, JASException
	{
		boolean windowHasChanged = windowHasChanged();
		boolean jobHasChanged = m_job.isChanged();

		// Currently we dont test for windowListChanged because the initial HTML page
		// counts as a change, but should not.
		
		if (jobHasChanged || windowHasChanged) // || m_windowManager.windowListChanged())
		{
			int rc = JOptionPane.showConfirmDialog
				(this,"Save changes to job "+m_job.getName()+"?",
				 "Save Changes?",JOptionPane.YES_NO_CANCEL_OPTION,
				 JOptionPane.WARNING_MESSAGE);

			if (rc == JOptionPane.CANCEL_OPTION) return false;
			if (rc == JOptionPane.CLOSED_OPTION) return false;
			if (rc == JOptionPane.YES_OPTION) 
			{
				if (jobSavingDisabled) throw new NotImplemented("Job Saving and Restoring");
				return saveJob();
			}
		}
		return true;
	}
	private boolean windowHasChanged()
	{
		final int n = m_windowManager.getWindowCount();
		for (int i = 0; i < n; i++)
		{
			Component c = m_windowManager.getWindow(i);
			if (c instanceof ChangableContainer && ((ChangableContainer) c).hasChanged())
				return true;
		}
		return false;
	}
	boolean saveJob() throws IOException
	{
		String file = m_job.getFilePath();
		if (file == null) return saveJobAs();
		writeJob(file);
		updateRecentJobs(file);
		return true;
	}
	boolean saveJobAs() throws IOException
	{
		JFileChooser dlg = new JFileChooser(userProp.getString(m_lastJobPath_Key, System.getProperty("user.home")));
		dlg.setDialogTitle("Save Job As...");
		dlg.setFileFilter(new JASFileFilter());
		dlg.setSelectedFile(new File(m_job.getName().concat(".jas")));
		if (dlg.showSaveDialog(getFrame()) != JFileChooser.APPROVE_OPTION) return false;
		File file = dlg.getSelectedFile();
		if (! file.getName().endsWith(".jas")) file = new File(file.getAbsolutePath().concat(".jas"));
		writeJob(file.getAbsolutePath());
		updateRecentJobs(file.getAbsolutePath());
		userProp.setString(m_lastJobPath_Key, file.getParent());
		return true;
	}
	void closeCurrentJob()
	{
		m_job.close();
	}
	void setToEmptyJob()
	{
		// Create a local job with no dataset
		String jobName = "Default Job";
		JASJob m_job = new JASJob(jobName);
		LocalJob localJob = new LocalJob(m_job, jobName);
		m_job.setJob(localJob);
		setJob(m_job, true);			
	}
	
	
	public void setJob(JASJob job, boolean newJob)
	{
		// closeCurrentJob must be called before this method
		if (newJob)
		{
			/*
			 * If it is a new job then we want to clear out all of the
			 * old windows and put in the default first page.  Otherwise,
			 * WindowManager.restoreState() will set up the windows when
			 * the old job is loaded.
			 */
			m_windowManager.closeAllWindows();
			newPage(1, 1);
		}
		m_job = job;
		m_job.setTreeModel(m_tree);
		m_job.setEventSourceModel(m_toolbarHolder.getEventSourceComboBox());
	}
	private class JASCommand extends JASCommandProcessor
	{
		void forceSetChanged()
		{
			setChanged();
		}
		public void onNewJob() throws IOException, JASException
		{
			if (querySaveJob()) new JASWizard(getFrame(), "New Job Wizard", new NewJobPage());
		}
		public void onReconnect() throws ConnectFailed, IOException, JASException
		{
			if (querySaveJob()) new JASWizard(getFrame(), "Connect to Server", new ConnectPage());
		}
		public void onOpenJob() throws IOException, JASException
		{
			if (jobSavingDisabled) throw new NotImplemented("Saving and restoring jobs");
			
			JFileChooser dlg = new JFileChooser(userProp.getString(m_lastJobPath_Key, System.getProperty("user.home")));
			dlg.setDialogTitle("Open Job...");
			dlg.setFileFilter(new JASFileFilter());
			if (dlg.showOpenDialog(getFrame()) == JFileChooser.APPROVE_OPTION)
			{
				final File file = dlg.getSelectedFile();
				try
				{
					readJob(file);
				}
				catch (Throwable e)
				{
					// readJob is responsible for cleanup, so we just have to notify users
					error("Could not open job", e);
				}
				finally
				{
					setChanged();
				}
			}
		}
		public void onOpen() throws FileError, JASException, MalformedURLException
		{
			JFileChooser dlg = new JFileChooser(userProp.getString("LastProgramPath", System.getProperty("user.home")));
			dlg.setDialogTitle("Open File...");
		
			AllSupportedFileFilter all = new AllSupportedFileFilter();
			
			// Add any extra filters from DIMs which implement LocalDIM2
			
			Enumeration e = JASRegistry.elements();
			while (e.hasMoreElements())
			{
				Object o = e.nextElement();
				if (o instanceof LocalDIM2)
				{
					FileFilter ff = ((LocalDIM2) o).getFileFilter();
					all.add(ff);
					dlg.addChoosableFileFilter(ff);
				}
			}
			FileFilter ff = new FileTypeFileFilter("html","HTML File (*.html)");
			all.add(ff);
			dlg.addChoosableFileFilter(ff);
			ff = new FileTypeFileFilter("javahist","Java Histogram File (*.javahist)");
			all.add(ff);
			dlg.addChoosableFileFilter(ff);
			ff = new FileTypeFileFilter("plotml","XML Plot File (*.plotml)");
			all.add(ff);
			dlg.addChoosableFileFilter(ff);
			ff = new FileTypeFileFilter("java","Java File (*.java)");
			all.add(ff);
			dlg.addChoosableFileFilter(ff);
			//comment out next 3 lines before check in
			//ff = new FileTypeFileFilter("aidaml","Aida XML Plot File (*.aidaml)");
			//all.add(ff);
			//dlg.addChoosableFileFilter(ff);
			dlg.setFileFilter(all);
			
			if (dlg.showOpenDialog(getFrame()) == JFileChooser.APPROVE_OPTION)
			{
				final File f = dlg.getSelectedFile();
				userProp.setString("LastProgramPath", f.getParent());
				openFile(f);
			}
		}
		public void onNewProgramWizard()
		{
			onProgramUsingWizard();
		}
		public void onProgramUsingWizard()
		{
			new JASWizard(getFrame(), "New Program Page Wizard", new NewProgramPage());
		}
		public void onBlankProgramPage()
		{
			final ProgramPage p = new ProgramPage();
			p.setClassName("Untitled");
			m_windowManager.newWindow("Untitled      ", p); // extra space for file extension
		}
		public void onExit() throws JASException, IOException
		{
			exit();
		}
		public void onHome() throws IOException
		{
			showHTMLPage("Welcome",m_homePage,false);
		}
		public void onWebPage() throws IOException
		{
			Vector pages = m_windowManager.openPages(HTMLPage.class);
			WebPageDialog dlg = new WebPageDialog(getFrame(),!pages.isEmpty());
			if (dlg.doModal()) showHTMLPage("Web Page",dlg.getURL(),dlg.getNewPage());
		}
		public void onStatusBar(boolean b)
		{
			setStatusBarVisible(b);
		}
		public void onOptions()
		{
			new JASOptionsDialog(getFrame());
		}
		public void onRegistries()
		{
			new JASRegistryDialog(getFrame());
		}
		public void enableStatusBar(JASCheckboxState state)
		{
			state.setCheckbox(m_statusBarVisible);
			state.setEnabled(true);
		}
		public void onAbout()
		{
			Dialog dlg = new AboutBox(JavaAnalysisStudio.this.getFrame());
			dlg.show();
		}
		public void onSubmitBugReport() throws MalformedURLException, IOException
		{
			URL bugURL = new URL("http://www-sldnt.slac.stanford.edu/jas/bugs/bugreport_form.asp");
			showHTMLPage("Bug Report",bugURL,true);
		}
		public void onReleaseNotes() throws MalformedURLException, IOException
		{
			showHelpTopic("relnotes");
		}
		public void onCheckVersion(){
			JASVersion checkversion = new JASVersion(getFrame(),"JAS",versionURL,getVersionNumber(),userProp);		
			checkversion.showOptionsDialog();
			
		}
		public void onPluginManager(){
			if(pluginmanager.getReadPluginXMLOK())pluginmanager.showPluginManager(getFrame());
			else{
				pluginmanager.initializePluginList();
				if(pluginmanager.getReadPluginXMLOK())pluginmanager.showPluginManager(getFrame());
			}
			
		}
		public void onTutorial() throws MalformedURLException, IOException
		{
			showHelpTopic("tutorial.part1");
		}
		public void onWelcome() throws MalformedURLException, IOException
		{
			showHelpTopic("tutorial.jasintro");
		}
		public void onHelpContents() throws MalformedURLException, IOException
		{
			showHelpContents();
		}
		public void onSearch() throws MalformedURLException, IOException
		{
			showHelpSearch();
		}
		public void onHelpIndex() throws MalformedURLException, IOException
		{
			showHelpIndex();
		}
		public void onheppackages() throws MalformedURLException, IOException
		{
			showHelpTopic("API.hepPackages.packageList");
		}
		public void onjaspackages() throws MalformedURLException, IOException
		{
			showHelpTopic("API.jasPackages.packageList");
		}
		public void enableTabbedPanels(JASCheckboxState state)
		{
			enableWM(state, m_TabbedWM);
		}
		public void onTabbedPanels()
		{
			setWM(m_TabbedWM);
		}
		public void enableInternalFrames(JASCheckboxState state)
		{
			enableWM(state, m_InternalWM);
		}
		public void onInternalFrames()
		{
			setWM(m_InternalWM);
		}
		private void enableWM(JASCheckboxState state, String name)
		{
			state.setCheckbox(m_windowManager.getClass().getName().equals(name));
			try
			{
				state.setEnabled(Class.forName(name) != null);
			}
			catch (Exception e)
			{
				state.setEnabled(false);
			}
		}
		private void setWM(final String name)
		{
			if (m_windowManager.getClass().getName().equals(name)) return;
			// no point in doing anything if this one is already selected
			WindowManager oldManager = m_windowManager;
			WindowItem[] wa = oldManager.getItems();
			Vector l = oldManager.getPageListeners();
			try
			{
				//m_topBottomSplitPane.saveState();
				//m_leftRightSplitPane.saveState();
				m_windowManager = (WindowManager) Class.forName(name).newInstance();
				JComponent c = (JComponent) m_windowManager;
				c.setMinimumSize(new Dimension(40, 40));
				m_leftRightSplitPane.setRightComponent(c);
				m_leftRightSplitPane.validate(); // I don't think revalidate() is needed here.
				//m_topBottomSplitPane.restoreState();
				c.repaint();
				userProp.setString("WindowManager", name);
				m_windowManager.initialize(wa, l);
			}
			catch (Exception e)
			{
				error("Could not open window manager "+ name, e);
				m_windowManager = oldManager;
			}
			setChanged();
		}
		public void enableWindows(JASCheckboxState state)
		{
			enableLAF(state, m_WindowsLAF);
		}
		public void onWindows() throws Exception
		{
			onLAF(m_WindowsLAF);
		}
		public void enableMotif(JASCheckboxState state)
		{
			enableLAF(state, m_MotifLAF);
		}
		public void onMotif() throws Exception
		{
			onLAF(m_MotifLAF);
		}
		public void enableJava(JASCheckboxState state)
		{
			enableLAF(state, m_JavaLAF);
		}
		public void onJava() throws Exception
		{
			onLAF(m_JavaLAF);
		}
		private void enableLAF(JASCheckboxState state, String lafName)
		{
			try
			{
				Class c = Class.forName(lafName);
				LookAndFeel laf = (LookAndFeel) c.newInstance(); 
				state.setCheckbox(UIManager.getLookAndFeel().getName().equals(laf.getName()));
				state.setEnabled(laf.isSupportedLookAndFeel());
			}
			catch (Exception e)
			{
				state.setEnabled(false);
			}
		}
		private void onLAF(String lafName) throws Exception
		{
			//m_topBottomSplitPane.saveState();
			//m_leftRightSplitPane.saveState();
			UIManager.setLookAndFeel(lafName);
			SwingUtilities.updateComponentTreeUI(JavaAnalysisStudio.this.getFrame());
			//m_topBottomSplitPane.restoreState();
			userProp.put("LookAndFeel", lafName);
			setChanged();
		}
		public void onEnableToolTips(boolean value)
		{
			ToolTipManager.sharedInstance().setEnabled(value);
			userProp.setBoolean("EnableToolTips",value);
		}
		public void enableEnableToolTips(JASCheckboxState state)
		{
			state.setCheckbox(ToolTipManager.sharedInstance().isEnabled());
			state.setEnabled(true);
		}
		public void enableFullScreen(JASState state)
		{
			state.setEnabled(getWindowManager().getSelectedWindow() >= 0);
		}
		public void onFullScreen()
		{
			getWindowManager().doFullScreen();
		}
		public void on1x1()
		{
			newPage(1,1);
		}
		public void on1x2()
		{
			newPage(1,2);
		}
		public void on2x1()
		{
			newPage(2,1);
		}
		public void on2x2()
		{
			newPage(2,2);
		}
		public void on3x3()
		{
			newPage(3,3);
		}
		public void on4x4()
		{
			newPage(4,4);
		}
		public void onStop()
		{
			m_stopMan.stop();
		}
		public void enableStop(JASState state)
		{
			state.setEnabled(m_stopMan.getStopEnabled());
		}
	}
	StoppableExecutionMonitor registerStoppable(StoppableExecution stoppable)
	{
		return m_stopMan.registerStoppable(stoppable);
	}
	private class JASStoppableManager
	{
		StoppableExecutionMonitor registerStoppable(StoppableExecution stoppable)
		{
			JASStoppableExecutionMonitor monitor =
				new JASStoppableExecutionMonitor(stoppable);
			m_stoppables.addElement(monitor);
			return monitor;
		}
		void removeStoppable(StoppableExecutionMonitor monitor)
		{
			m_stoppables.removeElement(monitor);
		}
		void stop()
		{
			Enumeration e = m_stoppables.elements();
			JASStoppableExecutionMonitor monitor;
			while (e.hasMoreElements())
			{
				monitor = (JASStoppableExecutionMonitor) e.nextElement();
				if (monitor.isRunning())
					monitor.stop();
			}
			m_jasCommand.forceSetChanged();
		}
		boolean getStopEnabled()
		{
			Enumeration e = m_stoppables.elements();
			while (e.hasMoreElements())
			{
				if (((JASStoppableExecutionMonitor) e.nextElement()).isRunning())
					return true;
			}
			return false;
		}
		private Vector m_stoppables = new Vector();
	}
	private class JASStoppableExecutionMonitor implements StoppableExecutionMonitor
	{
		JASStoppableExecutionMonitor(StoppableExecution stoppable)
		{
			m_stoppable = stoppable;
			doStopEnabling();
		}
		boolean isRunning()
		{
			return m_stoppable.isRunning();
		}
		public void setProgressModel(BoundedRangeModel model) // optional (overrides previous progress model)
		{
			m_status.setModel(model);
		}
		public void doStopEnabling()
		{
			m_jasCommand.forceSetChanged();
		}
		public void end() // done for good
		{
			m_stopMan.removeStoppable(this);
		}
		void stop()
		{
			m_stoppable.stop();
		}
		private StoppableExecution m_stoppable;
	}
	final private class JASFitListener implements FitListener
	{
		public void fitStarted(final Fitter fitter)
		{
			new FitWatcher(fitter);
		}
	}
	private class FitWatcher implements Observer, StoppableExecution
	{
		private StoppableExecutionMonitor m_stopMonitor;
		private BoundedRangeModel model;
		private Fitter m_fitter;
		private final java.text.NumberFormat format =
			java.text.NumberFormat.getInstance();
		private String m_funcTitle;
		FitWatcher(final Fitter fit)
		{
			format.setMaximumFractionDigits(6);
			model = m_status.getModel();
			model.setMinimum(0);
			model.setMaximum(100);
			m_fitter = fit;
			m_fitter.addObserver(this);
			m_stopMonitor = registerStoppable(this);
			m_funcTitle = m_fitter.getFunction().getTitle();
		}
		Fitter clearFit()
		{
			Fitter fit = m_fitter;
			if (fit != null)
			{
				fit.deleteObserver(this);
				fit.getFunction().clearFit();
				m_fitter = null;
				m_stopMonitor.end();
			}
			return fit;
		}
		public void update(Observable obs, Object arg)
		{
			if (arg instanceof FitUpdate)
			{
				FitUpdate fu = (FitUpdate) arg;
				int state = fu.getState();
				if (state == Fitter.OUTAHERE)
				{
					clearFit();
				}
				else
				{
					model.setValue( fu.getPercent() );
					if (state == Fitter.FAILED)
					{
						setMessage("Fit failed.  Exception was: "+ fu.getReason());
						clearFit();
					}
					else if (state == Fitter.FIT)
						setMessage(m_funcTitle +" fit complete.  \u03c7\u00b2 = "+
							format.format( m_fitter.getChiSquared() ));
					else if (state == Fitter.FITTING)
						setMessage("Now fitting function "+ m_funcTitle);
					m_stopMonitor.doStopEnabling();
				}
				if (m_fitter != null)
					m_fitter.getFunction().setChanged();
			}
		}
		public boolean isRunning()
		{
			return m_fitter != null && m_fitter.getState() == Fitter.FITTING;
		}
		public void stop()
		{
			if (m_fitter != null)
			{
				m_fitter.stop();
				m_fitter.deleteObserver(this);
				m_fitter.getFunction().clearFit();
				m_fitter = null;
				m_status.setMessage("Fitter stopped before completion");
				m_status.getModel().setValue(0);
			}
		}
	}
	private class DoubleClickAdaptor implements MouseListener, CommandSource
	{ 
		public void mouseClicked(MouseEvent e) 
		{ 
			if (e.getClickCount() == 2) 
			{
				if (m_target != null) m_target.invoke();
			}
		}
		public void mousePressed(MouseEvent e){};
		public void mouseReleased(MouseEvent e){};
		public void mouseEntered(MouseEvent e){};
		public void mouseExited(MouseEvent e){};
		public String getCommand()
		{
			return "DoubleClick";
		}
		public CommandTarget getTarget()
		{
			return m_target;
		}
		public boolean setTarget(CommandTarget target)
		{
			if (target instanceof SimpleCommandTarget)
			{
				m_target = (SimpleCommandTarget) target;
				return true;
			}
			return false;
		}
		public void clearTarget()
		{
			m_target = null;
		}
		private SimpleCommandTarget m_target;
	}
	private class SelectAdaptor implements TreeSelectionListener , CommandSource
	{ 
		public void valueChanged(TreeSelectionEvent e) 
		{ 
			if (m_target != null && e.isAddedPath()) m_target.invoke();
		}
		public String getCommand()
		{
			return "Select";
		}
		public CommandTarget getTarget()
		{
			return m_target;
		}
		public boolean setTarget(CommandTarget target)
		{
			if (target instanceof SimpleCommandTarget)
			{
				m_target = (SimpleCommandTarget) target;
				return true;
			}
			return false;
		}
		public void clearTarget()
		{
			m_target = null;
		}
		private SimpleCommandTarget m_target;
	}
	public MLPArrowFactory getTheArrowFactory() {
		// TODO Auto-generated method stub
		return null;
	}
	public MLPLabelFactory getTheLabelFactory() {
		// TODO Auto-generated method stub
		return null;
	}
	public MoverLayeredPane getMLP() {
		// TODO Auto-generated method stub
		return null;
	}
	public MultiFunctionPanel getMFP() {
		// TODO Auto-generated method stub
		return null;
	}

}//JavaAnalysisStudio

 

Ads help maintain this website.