/*
 * Created on Aug 10, 2003
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package APStudio.editors;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.EventObject;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.KeyHandler;
import org.eclipse.gef.KeyStroke;
import org.eclipse.gef.dnd.TemplateTransferDragSourceListener;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.CopyTemplateAction;
import org.eclipse.gef.ui.actions.DirectEditAction;
import org.eclipse.gef.ui.actions.GEFActionConstants;
import org.eclipse.gef.ui.parts.GraphicalEditorWithPalette;
import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler;
import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
import org.eclipse.gef.ui.stackview.CommandStackInspectorPage;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.part.FileEditorInput;

import APStudio.APContextMenuProvider;
import APStudio.APStudioPlugin;
import APStudio.ResourceMgtUtils;
import APStudio.dnd.APTemplateTransferDropTargetListener;
import APStudio.dnd.TextTransferDropTargetListener;
import APStudio.editparts.GraphicalPartFactory;
import APStudio.models.ClassGraphModel;
/**
 * @author rajags
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class CDiagramEditor extends GraphicalEditorWithPalette {

	private boolean savePreviouslyNeeded = false;
	private PaletteRoot root;
	private ClassGraphModel _classgraphModel = new ClassGraphModel();
	private ResourceTracker resourceListener = new ResourceTracker();
	private KeyHandler sharedKeyHandler;
	public CDiagramEditor() {
		setEditDomain(new DefaultEditDomain(this));
	}	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.ui.parts.GraphicalEditorWithPalette#getPaletteRoot()
	 */
	protected PaletteRoot getPaletteRoot() {
		if( root == null ){
			root = APStudioPlugin.createPalette();
		}
		return root;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.ui.parts.GraphicalEditor#initializeGraphicalViewer()
	 */
	protected void initializeGraphicalViewer() {
		getGraphicalViewer().setContents(getClassGraphModel());
		getGraphicalViewer().addDropTargetListener(
				new APTemplateTransferDropTargetListener(getGraphicalViewer()));
		getGraphicalViewer().addDropTargetListener(
				new TextTransferDropTargetListener(getGraphicalViewer(), TextTransfer.getInstance()));
	}

	protected void initializePaletteViewer() {
		super.initializePaletteViewer();
		getPaletteViewer().addDragSourceListener(
			new TemplateTransferDragSourceListener(getPaletteViewer()));
		APStudioPlugin.getDefault().getPreferenceStore().setDefault(
					"Palette Size", 130);
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
	 */
	public void doSave(IProgressMonitor monitor) {
		try {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			createOutputStream(out);
			IFile file = ((IFileEditorInput)getEditorInput()).getFile();
			file.setContents(new ByteArrayInputStream(out.toByteArray()), 
							true, false, monitor);
			out.close();
			getCommandStack().markSaveLocation();
		} 
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.ISaveablePart#doSaveAs()
	 */
	public void doSaveAs() {
		performSaveAs();
	}
	
	/**
	 * 
	 * @return
	 */
	protected boolean performSaveAs() {
		SaveAsDialog dialog= new SaveAsDialog(getSite().getWorkbenchWindow().getShell());
		dialog.setOriginalFile(((IFileEditorInput)getEditorInput()).getFile());
		dialog.open();
		IPath path= dialog.getResult();
	
		if (path == null)
			return false;
	
		IWorkspace workspace= ResourcesPlugin.getWorkspace();
		final IFile file= workspace.getRoot().getFile(path);
	
		WorkspaceModifyOperation op= new WorkspaceModifyOperation() {
			public void execute(final IProgressMonitor monitor) throws CoreException {
				try {
					ByteArrayOutputStream out = new ByteArrayOutputStream();
					createOutputStream(out);
					file.create(new ByteArrayInputStream(out.toByteArray()), true, monitor);
					out.close();
				} 
				catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
	
		try {
			new ProgressMonitorDialog(getSite().getWorkbenchWindow().getShell()).run(false, true, op);
			setInput(new FileEditorInput((IFile)file));
			getCommandStack().markSaveLocation();
		} 
		catch (Exception e) {
			e.printStackTrace();
		} 
		return true;
	}

	protected void closeEditor(boolean save) {
		getSite().getPage().closeEditor(CDiagramEditor.this, save);
		ResourceMgtUtils.removeTemporaryFolder(APStudioPlugin.getCurrentProject());
	}
	protected void createActions() {
		super.createActions();
		ActionRegistry registry = getActionRegistry();
		IAction action;
	
		action = new CopyTemplateAction(this);
		registry.registerAction(action);

		action = new DirectEditAction(this);
		registry.registerAction(action);
		getSelectionActions().add(action.getId());

	}

	public Object getAdapter(Class type){
		if (type == CommandStackInspectorPage.class)
			return new CommandStackInspectorPage(getCommandStack());


		return super.getAdapter(type);
	}

	public void commandStackChanged(EventObject event) {
		if (isDirty()){
			if (!savePreviouslyNeeded()) {
				setSavePreviouslyNeeded(true);
				firePropertyChange(IEditorPart.PROP_DIRTY);
			}
		}
		else {
			setSavePreviouslyNeeded(false);
			firePropertyChange(IEditorPart.PROP_DIRTY);
		}
		super.commandStackChanged(event);
	}

	protected void configureGraphicalViewer() {
		super.configureGraphicalViewer();
		ScrollingGraphicalViewer viewer = (ScrollingGraphicalViewer)getGraphicalViewer();

		ScalableFreeformRootEditPart root = new ScalableFreeformRootEditPart();

//		IAction zoomIn = new ZoomInAction(root.getZoomManager());
//		IAction zoomOut = new ZoomOutAction(root.getZoomManager());
//		getActionRegistry().registerAction(zoomIn);
//		getActionRegistry().registerAction(zoomOut);
//		getSite().getKeyBindingService().registerAction(zoomIn);
//		getSite().getKeyBindingService().registerAction(zoomOut);

		viewer.setRootEditPart(root);

		viewer.setEditPartFactory(new GraphicalPartFactory());
		ContextMenuProvider provider = new APContextMenuProvider(viewer, getActionRegistry());
		viewer.setContextMenu(provider);
		getSite().registerContextMenu("APStudio.editors.contextmenu", //$NON-NLS-1$
			provider, viewer);
		viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer)
			.setParent(getCommonKeyHandler()));
	}

	/**
	 * Returns the KeyHandler with common bindings for both the Outline and Graphical Views.
	 * For example, delete is a common action.
	 */
	protected KeyHandler getCommonKeyHandler(){
		if (sharedKeyHandler == null){
			sharedKeyHandler = new KeyHandler();
			sharedKeyHandler.put(
				KeyStroke.getPressed(SWT.DEL, 127, 0),
				getActionRegistry().getAction(GEFActionConstants.DELETE));
			sharedKeyHandler.put(
				KeyStroke.getPressed(SWT.F2, 0),
				getActionRegistry().getAction(GEFActionConstants.DIRECT_EDIT));
		}
		return sharedKeyHandler;
	}
	
	protected void configurePaletteViewer() {
		super.configurePaletteViewer();
//		PaletteViewer viewer = (PaletteViewer)getPaletteViewer();
//		ContextMenuProvider provider = new PaletteContextMenuProvider(viewer);
//		getPaletteViewer().setContextMenu(provider);
//		viewer.setCustomizer(new LogicPaletteCustomizer());
	}
		
	protected void createOutputStream(OutputStream os)throws IOException {
		ObjectOutputStream out = new ObjectOutputStream(os);
		out.writeObject(getClassGraphModel());
		out.close();	
	}

	public void dispose() {
		//CopyTemplateAction copy = (CopyTemplateAction)getActionRegistry().getAction(GEFActionConstants.COPY);
		//getPaletteViewer().removeSelectionChangedListener(copy);
		//getSite().getWorkbenchWindow().getPartService().removePartListener(partListener);
		//partListener = null;
		((FileEditorInput)getEditorInput()).getFile().getWorkspace().removeResourceChangeListener(resourceListener);
		super.dispose();
	}

	protected ClassGraphModel getClassGraphModel() {
		return _classgraphModel;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.ui.IEditorPart#gotoMarker(org.eclipse.core.resources.IMarker)
	 */
	public void gotoMarker(IMarker marker) {

	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.ISaveablePart#isDirty()
	 */
	public boolean isDirty() {
		return isSaveOnCloseNeeded();
	}
	
	/**
	 * 
	 */
	public boolean isSaveOnCloseNeeded() {
		return getCommandStack().isDirty();
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
	 */
	public boolean isSaveAsAllowed() {
		return true;
	}
	
	private boolean savePreviouslyNeeded() {
		return savePreviouslyNeeded;
	}

	public void setInput(IEditorInput input) {
		superSetInput(input);

		IFile file = ((IFileEditorInput)input).getFile();
		try {
			InputStream is = file.getContents(false);
//			ObjectInputStream ois = new ObjectInputStream(is);
//			setClassGraphModel((ClassGraphModel)ois.readObject());
//			ois.close();
		}
		catch (Exception e) {
			//This is just an example.  All exceptions caught here.
			e.printStackTrace();
		}
	}

	public void setClassGraphModel(ClassGraphModel diagram) {
		_classgraphModel = diagram;
	}

	private void setSavePreviouslyNeeded(boolean value) {
		savePreviouslyNeeded = value;
	}

	protected void superSetInput(IEditorInput input) {
		// The workspace never changes for an editor.  So, removing and re-adding the 
		// resourceListener is not necessary.  But it is being done here for the sake
		// of proper implementation.  Plus, the resourceListener needs to be added 
		// to the workspace the first time around.
		if(getEditorInput() != null) {
			IFile file = ((FileEditorInput)getEditorInput()).getFile();
			file.getWorkspace().removeResourceChangeListener(resourceListener);
		}
	
		super.setInput(input);
	
		if(getEditorInput() != null) {
			IFile file = ((FileEditorInput)getEditorInput()).getFile();
			file.getWorkspace().addResourceChangeListener(resourceListener);
			setTitle(file.getName());
		}
	}
		
//	This class listens to changes to the file system in the workspace, and 
//	makes changes accordingly.
//	1) An open, saved file gets deleted -> close the editor
//	2) An open file gets renamed or moved -> change the editor's input accordingly	
 class ResourceTracker
	 implements IResourceChangeListener, IResourceDeltaVisitor
 {
	 public void resourceChanged(IResourceChangeEvent event) {
		 IResourceDelta delta = event.getDelta();
		 try {
			 if (delta != null)
				 delta.accept(this);
		 } 
		 catch (CoreException exception) {
			 // What should be done here?
		 }
	 }	
	 public boolean visit(IResourceDelta delta) { 
		 if (delta == null || !delta.getResource().equals(((FileEditorInput)getEditorInput()).getFile()))
			 return true;
			
		 if (delta.getKind() == IResourceDelta.REMOVED) {
			 if ((IResourceDelta.MOVED_TO & delta.getFlags()) == 0) { // if the file was deleted
				 // NOTE: The case where an open, unsaved file is deleted is being handled by the 
				 // PartListener added to the Workbench in the initialize() method.
				 if (!isDirty()) 
					 closeEditor(false); 
			 } 
			 else { // else if it was moved or renamed
				 final IFile newFile = ResourcesPlugin.getWorkspace().getRoot().getFile(delta.getMovedToPath());
				 Display display = getSite().getShell().getDisplay();
				 display.asyncExec(new Runnable() {
					 public void run() {
						 superSetInput(new FileEditorInput(newFile));
					 }
				 });
			 }
		 }			
		 return false; 
	 }
 }
}
