//----------------------------BEGIN LICENSE----------------------------
/* 
 * Willow : the Open Source WorkFlow Project
 * Distributable under GNU LGPL license by gun.org
 *
 * Copyright (C) 2004-2010 huihoo.org 
 * Copyright (C) 2004-2010  ZosaTapo <dertyang@hotmail.com> 
 * 
 * ====================================================================
 * Project Homepage : http://www.huihoo.org/god4j
 * Source Forge     : http://sourceforge.net/projects/huihoo
 * Mailing list     : god4j@lists.sourceforge.net 
 */
//----------------------------END  LICENSE-----------------------------
package org.huihoo.god4j;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.UIManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.huihoo.god4j.actions.ActionMap;
import org.huihoo.god4j.actions.Close;
import org.huihoo.god4j.actions.Open;
import org.huihoo.god4j.editor.elements.XPDLPackage;
import org.huihoo.god4j.jgraph.BeginActivity;
import org.huihoo.god4j.jgraph.EndActivity;
import org.huihoo.god4j.jgraph.JGraphActivity;
import org.huihoo.god4j.jgraph.JGraphConstants;
import org.huihoo.god4j.jgraph.JGraphTransition;
import org.huihoo.god4j.jgraph.XPDLJGraphCell;
import org.huihoo.god4j.tree.ExplorerNode;
import org.huihoo.god4j.tree.ExplorerUtilities;
import org.huihoo.god4j.util.ImageLoader;
import org.huihoo.god4j.util.StringManager;
import org.huihoo.god4j.util.ToolUtils;
import org.huihoo.workflow.WorkflowComplexComponent;
import org.huihoo.workflow.xpdl.ExtendedAttribute;
import org.huihoo.workflow.xpdl.WorkflowActivity;
import org.huihoo.workflow.xpdl.WorkflowApplication;
import org.huihoo.workflow.xpdl.WorkflowPackage;
import org.huihoo.workflow.xpdl.WorkflowParameter;
import org.huihoo.workflow.xpdl.WorkflowProcess;
import org.huihoo.workflow.xpdl.WorkflowTransition;
import org.huihoo.workflow.xpdl.XPDLGlobals;
import org.jgraph.graph.DefaultGraphCell;
public class GOD4J extends JFrame
{
	private static Log log = LogFactory.getLog(GOD4J.class);
	private static StringManager sm = StringManager.getManager(GOD4JConstants.PACKAGE);
	private static StringManager sm_jgraph = StringManager.getManager(JGraphConstants.PACKAGE);

	//------------------------------------------------------
	private WorkflowPackage workflow_package = null;
	private XPDLPackage xpdl_cache = null;
	//------------------------------------------------------

	private ControlPanel controlPanel = null;
	private ExplorerPanel explorerPanel = null;

	private ActionMap actionMap = null;

	private String filename;
	private File workingDirectory = new File(System.getProperty("user.dir"));
	private boolean dirtyFlag = false;

	private MenuBarEx menuBar = null;
	private ToolBarEx toolBar = null;
	private JTextField statusPanel = null;

	private JMenu recentFilesMenu = null;
	private Object updateCaller = null;

	/**
	 * Checks if java version is >= 1.4, sets application title and icon, as
	 * well as logo icon.
	 */
	static {
		try
		{
			String vers = System.getProperty("java.version");
			if (vers.compareTo("1.4") < 0)
			{
				System.out.println("!!!WARNING: GOD4J must be run with a " + "1.4 or higher version VM!!!");
				System.exit(1);
			}

			UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");

			// creating USER_HOME/.GOD4J directory if it doesn't exist
			File ujdir = new File(GOD4JConstants.GOD4J_USER_HOME);
			if (!ujdir.exists())
			{
				try
				{
					ujdir.mkdir();
				}
				catch (Exception exc)
				{
				};
			}

		}
		catch (Throwable t)
		{
			System.err.println("uncaught exception: " + t);
			t.printStackTrace();
		}
	}

	public GOD4J()
	{
		//only call once here
		GOD4JFactory.setGOD4J(this);

		this.getContentPane().setLayout(new BorderLayout());
		this.addWindowListener(new WindowAdapterEx());
		this.setIconImage(ImageLoader.getImage(ImageLoader.getImageName("Icon")));
	}

	public void init()
	{
		this.actionMap = new ActionMap();

		this.menuBar = new MenuBarEx();
		this.setJMenuBar(menuBar);
		
		this.toolBar = new ToolBarEx();

		this.statusPanel = new JTextField();
		this.controlPanel = new ControlPanel();
		this.explorerPanel = new ExplorerPanel();

		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		splitPane.setRightComponent(controlPanel);
		splitPane.setLeftComponent(explorerPanel);

		this.getContentPane().add(toolBar, BorderLayout.NORTH);
		this.getContentPane().add(splitPane, BorderLayout.CENTER);
		this.getContentPane().add(statusPanel, BorderLayout.SOUTH);

		//this.actionCollection.createWorkflow();
		this.initRecentFileMenu();
	}

	public Object getEventTrigger()
	{
		return updateCaller;
	}

	public void setEventTrigger(Object updateCaller)
	{
		this.updateCaller = updateCaller;
	}

	public void setTipInfo(String status)
	{
		statusPanel.setText(status);
	}

	public void setTitle()
	{
		StringBuffer buffer = new StringBuffer();
		buffer.append(sm.getString("designer.title"));

		buffer.append(" - ");

		if (workflow_package != null)
		{
			buffer.append(((WorkflowProcess) workflow_package.getWorkflowProcesses().get(0)).getName());
		}

		if (workflow_package != null && filename != null)
		{
			buffer.append(" - ");
		}

		if (filename != null)
		{
			buffer.append("[");
			buffer.append(filename);

			if (isDirty())
			{				
				buffer.append("*");
			}

			buffer.append("]");
		}

		super.setTitle(buffer.toString());
	}

	public WorkflowPackage getDocument()
	{
		return this.workflow_package;
	}
	public XPDLPackage getXPDLDocument()
	{
		return this.xpdl_cache;
	}

	public void switchGridVisible(boolean selected)
	{
		menuBar.switchGrid(selected);
		toolBar.switchGrid(selected);
		controlPanel.setGridVisible(selected);
	}
	public void switchRulerVisible(boolean selected)
	{
		menuBar.switchRuler(selected);
		toolBar.switchRuler(selected);
		controlPanel.setRulerVisible(selected);
	}

	public ControlPanel getControlPanel()
	{
		return controlPanel;
	}
	public ExplorerPanel getExplorerPanel()
	{
		return explorerPanel;
	}

	public ActionMap getActionMap()
	{
		return actionMap;
	}

	public String getFileName()
	{
		return this.filename;
	}

	public void setFileName(String filename)
	{
		this.filename = filename;
	}

	public void loadDocument(WorkflowPackage workflowPackage)
	{
		this.workflow_package = workflowPackage;

		if (this.workflow_package == null)
		{
			this.xpdl_cache = null;
			this.setFileName(null);
		}
		else
		{
			this.xpdl_cache = new XPDLPackage(workflowPackage);
			this.xpdl_cache.initComponent();
			this.xpdl_cache.structComponent();
			this.xpdl_cache.loadComponent();
		}

		controlPanel.loadDocument();
		explorerPanel.loadDocument();

		this.setDirty(false);

		actionMap.update4Document();
	}

	public void setDirty(boolean is_dirty)
	{
		if (dirtyFlag == is_dirty)
		{
			return;
		}

		dirtyFlag = is_dirty;
		if(dirtyFlag)
		{
			actionMap.getAction("save").setEnabled(true);
		}
		else
		{
			actionMap.getAction("save").setEnabled(false);
		}
		setTitle();

	}

	public boolean isDirty()
	{
		return this.dirtyFlag;
	}

	public synchronized void selectionChanged(DefaultGraphCell graphCell, //set by  XPDLJGraphSelectionListener
	ExplorerNode treeNode, //set by  NodeExplorerSelectionListener
	boolean calledByTree)
	{
		//System.err.println("--ActionCollection--selecitionNodeType is " + selecitionNodeType + "; workflow_component is " + workflow_component+"; calledByTree is "+calledByTree);
		GOD4JFactory.getGOD4J().getActionMap().getAction("cut").setEnabled(false);
		GOD4JFactory.getGOD4J().getActionMap().getAction("copy").setEnabled(false);
		GOD4JFactory.getGOD4J().getActionMap().getAction("delete").setEnabled(false);
		GOD4JFactory.getGOD4J().getActionMap().getAction("editProperties").setEnabled(false);

		if (calledByTree)
		{
			JGraphFrame frame = GOD4JFactory.getGOD4J().getControlPanel().getSelectedJGraph();
			if (frame == null)
			{
				if (ExplorerUtilities.isActivityNode(treeNode))
				{
					WorkflowActivity act = (WorkflowActivity) treeNode.getWorkflowComponent();
					frame = GOD4JFactory.getGOD4J().getControlPanel().findJGraph(act.getWorkflowProcess().getUUID());
					GOD4JFactory.getGOD4J().getControlPanel().setSelectedJGraph(frame);
				}
				else if (ExplorerUtilities.isTransitionNode(treeNode))
				{
					WorkflowTransition trans = (WorkflowTransition) treeNode.getWorkflowComponent();
					frame = GOD4JFactory.getGOD4J().getControlPanel().findJGraph(trans.getWorkflowProcess().getUUID());
					GOD4JFactory.getGOD4J().getControlPanel().setSelectedJGraph(frame);
				}
			}

			if (frame != null)
			{
				if (ExplorerUtilities.isActivityNode(treeNode) || ExplorerUtilities.isTransitionNode(treeNode))
				{
					WorkflowComplexComponent workflow_component = treeNode.getWorkflowComponent();
					frame.getJGraph().setSelectionCell(workflow_component.getUUID());

					GOD4JFactory.getGOD4J().getActionMap().getAction("cut").setEnabled(true);
					GOD4JFactory.getGOD4J().getActionMap().getAction("copy").setEnabled(true);
					GOD4JFactory.getGOD4J().getActionMap().getAction("delete").setEnabled(true);
					GOD4JFactory.getGOD4J().getActionMap().getAction("editProperties").setEnabled(true);
				}
				else
				{
					GOD4JFactory.getGOD4J().getActionMap().getAction("editProperties").setEnabled(true);
					frame.getJGraph().clearSelection();
				}
			}
		}
		else
		{
			if (graphCell instanceof XPDLJGraphCell)
			{
				XPDLJGraphCell temp = (XPDLJGraphCell) graphCell;
				WorkflowComplexComponent comp = temp.getWorkflowComponent();
				getExplorerPanel().getNodeExplorer().setSelectionNode(comp.getUUID());

				GOD4JFactory.getGOD4J().getActionMap().getAction("cut").setEnabled(true);
				GOD4JFactory.getGOD4J().getActionMap().getAction("copy").setEnabled(true);
				GOD4JFactory.getGOD4J().getActionMap().getAction("delete").setEnabled(true);
				GOD4JFactory.getGOD4J().getActionMap().getAction("editProperties").setEnabled(true);
			}
		}
	}

	public void refreshCollections(List oldList, List newList)
	{
		List toAdd = new ArrayList();
		List toRemove = new ArrayList();
		if (oldList != null)
		{
			toRemove.addAll(oldList);
			if (newList != null)
			{
				toRemove.removeAll(newList);
			}
		}
		if (newList != null)
		{
			toAdd.addAll(newList);
			if (oldList != null)
			{
				toAdd.removeAll(oldList);
			}
		}
		addCollections(toAdd);
		removeCollections(toRemove);
	}

	public void setWorkingDirectory(File file)
	{
		if (file.isDirectory())
		{
			file = file.getParentFile();
		}
		workingDirectory = file;
	}

	public File getWorkingDirectory()
	{
		return workingDirectory;
	}

	public JMenu getRecentFilesMenu()
	{
		return recentFilesMenu;
	}

	public void addToRecentFiles(String filename)
	{
		JMenuItem mItem;
		for (int i = 0; i < recentFilesMenu.getItemCount(); ++i)
		{
			mItem = (JMenuItem) recentFilesMenu.getMenuComponent(i);
			if (filename.equals(mItem.getText().substring(2)))
			{
				recentFilesMenu.remove(i);
			}
		}
		if (recentFilesMenu.getItemCount() == 10)
		{
			recentFilesMenu.remove(10 - 1);
		}
		mItem = new JMenuItem("1 " + filename);
		mItem.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				String filename = e.getActionCommand().substring(2);
				if (Close.closeDocumentIfPossible())
				{
					Open.openDocumentIfPossible(filename);
				}
			}
		});

		recentFilesMenu.insert(mItem, 0);
		// changing mnemonics to correspond to the ordinal number of items
		for (int i = 0; i < recentFilesMenu.getItemCount(); ++i)
		{
			mItem = (JMenuItem) recentFilesMenu.getMenuComponent(i);
			String oldText = mItem.getText();
			String ordNo = String.valueOf(i + 1);
			String mnemonic = ordNo.substring(ordNo.length() - 1, ordNo.length());
			mItem.setText(mnemonic + " " + oldText.substring(2));
		}

	}

	protected void initRecentFileMenu()
	{
		this.recentFilesMenu = (JMenu) menuBar.getMenuItem("recentFiles");
		this.recentFilesMenu.setEnabled(true);

		String rfl = ToolUtils.fileToString(GOD4JConstants.GOD4J_USER_HOME + File.separator + GOD4JConstants.RFL_FILENAME);
		if (rfl != null)
		{
			for (StringTokenizer st = new StringTokenizer(rfl, "\n"); st.hasMoreTokens();)
			{
				addToRecentFiles(st.nextToken());
			}
		}
	}

	protected void addCollections(List cellsToAdd)
	{
		if (cellsToAdd == null || cellsToAdd.size() == 0)
		{
			return;
		}
		Iterator iteratorAdd = cellsToAdd.iterator();
		Object obj = null;
		while (iteratorAdd.hasNext())
		{
			obj = iteratorAdd.next();
			if (obj instanceof JGraphTransition)
			{
				JGraphTransition edge = (JGraphTransition) obj;
				WorkflowTransition transition = (WorkflowTransition) edge.getUserObject();
				transition.getWorkflowProcess().addWorkflowTransition(transition);

				GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowTransition(transition);
			}
			else if (obj instanceof JGraphActivity)
			{
				JGraphActivity cell = (JGraphActivity) obj;
				WorkflowActivity activity = (WorkflowActivity) cell.getUserObject();

				activity.getWorkflowProcess().addWorkflowActivity(activity);
				GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowActivity(activity);

				if (obj instanceof BeginActivity)
				{
					activity.getWorkflowProcess().addExtendedAttribute(
						new ExtendedAttribute(XPDLGlobals.ID_ACTIVITY_BEGIN, activity.getUUID()));
				}
				else if (obj instanceof EndActivity)
				{
					activity.getWorkflowProcess().addExtendedAttribute(
						new ExtendedAttribute(XPDLGlobals.ID_ACTIVITY_END, activity.getUUID()));
				}
			}
			else
			{
				if (obj instanceof WorkflowParameter)
				{
					GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowParameter((WorkflowParameter) obj);
				}
				else if (obj instanceof WorkflowApplication)
				{
					GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().addWorkflowApplication(
						(WorkflowApplication) obj);
				}
			}
		}
	}
	protected void removeCollections(List cellsToRemove)
	{
		if (cellsToRemove == null || cellsToRemove.size() == 0)
		{
			return;
		}
		Iterator iteratorRemove = cellsToRemove.iterator();
		Object obj = null;
		while (iteratorRemove.hasNext())
		{
			obj = iteratorRemove.next();
			if (obj instanceof JGraphTransition)
			{
				JGraphTransition edge = (JGraphTransition) obj;
				WorkflowTransition transition = (WorkflowTransition) edge.getUserObject();

				WorkflowProcess workflowProcess = transition.getWorkflowProcess();
				workflowProcess.removeWorkflowTransition(transition);
				GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().removeWorkflowTransition(transition);

				//only for GOD4J (UNDO/REDO)
				transition.setWorkflowProcess(workflowProcess);

			}
			else if (obj instanceof JGraphActivity)
			{
				JGraphActivity cell = (JGraphActivity) obj;
				WorkflowActivity activity = (WorkflowActivity) cell.getUserObject();
				WorkflowProcess workflowProcess = activity.getWorkflowProcess();
				workflowProcess.removeWorkflowActivity(activity);
				GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().removeWorkflowActivity(activity);
				//only for GOD4J (UNDO/REDO)
				activity.setWorkflowProcess(workflowProcess);

				if (obj instanceof BeginActivity)
				{
					activity.getWorkflowProcess().removeExtendedAttribute(XPDLGlobals.ID_ACTIVITY_BEGIN);
				}
				else if (obj instanceof EndActivity)
				{
					activity.getWorkflowProcess().removeExtendedAttribute(XPDLGlobals.ID_ACTIVITY_END);
				}
			}
			else
			{
				if (obj instanceof WorkflowParameter)
				{
					GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().removeWorkflowParameter((WorkflowParameter) obj);
				}
				else if (obj instanceof WorkflowApplication)
				{
					GOD4JFactory.getGOD4J().getExplorerPanel().getNodeExplorer().removeWorkflowApplication(
						(WorkflowApplication) obj);
				}
			}
		}
	}
}
