// File: ActionOpen.java
// Classes: ActionOpen
// Author: Kedar Patankar

package edu.neu.ccs.demeter.tools.apstudio.graphedit;

import edu.neu.ccs.demeter.Ident;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.awt.FileDialog;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Vector;
import java.util.Enumeration;


/**
 * Action to open a file and reading the object description it holds, creating
 * the correponding graph structutre. */

public class ActionOpen extends Action
{
	private Document _document;
	private int _idd=0;
	private String _folderName,_fileName;
	public ActionOpen(Editor editor) {super(editor);}
	public String name() { return "Open file with input Object"; }
	public void doIt()
	{
		FileDialog fd = new FileDialog(_editor, "Select Input File", FileDialog.LOAD);
		fd.setDirectory(_editor.getReadDir());
		fd.setFile("*.cd");
		fd.setVisible(true);
		_fileName = fd.getFile();
		if (_fileName == null) {return;}
		_folderName = fd.getDirectory();
		_editor.setReadDir(_folderName);
		String s = _folderName + _fileName;

		if(_fileName.endsWith(".gcd"))
		{
			String title = "File read error";
			String message = "\".gcd\" files are system files which should not be opened directly";
			ActionShowMessage asm= new ActionShowMessage(_editor,title,message);
			asm.doIt();
			return;
		}
		if(_fileName.endsWith(".apcd"))
		{
			String title = "File read error";
			String message = "\".apcd\" files should not be opened directly";
			ActionShowMessage asm= new ActionShowMessage(_editor,title,message);
			asm.doIt();
			return;
		}

		if(_editor.isPresent(s))
		{
			Action act = new ActionRevert(_editor,s,this);
			act.doIt();
			return;
		}
		goAheadandOpen();
	}

	public void goAheadandOpen()
	{
		String fileName = _folderName + _fileName;

		FileInputStream in=null;
		UGraph _graph=null;

		String trialFile = fileName + ".gcd";
		boolean foundSystemCopy = true;
		try {in = new FileInputStream(trialFile);} 
		catch (FileNotFoundException de){foundSystemCopy = false;}
		
		boolean goodSystemCopy = true;
		if(foundSystemCopy)
		{
			_editor.setMessage("System copy of class dictionay found. "+
				"Opening the system copy.");
			try 
			{
				_graph = UGraph.parse(in);
				in.close();
			}catch (Exception fe){ goodSystemCopy = false;}
		}
		else
			goodSystemCopy = false;

		if(goodSystemCopy)
			_editor.setMessage("Finished building class graph");
				
		if(!foundSystemCopy || !goodSystemCopy)
		{
			_editor.setMessage("System copy of the class dictionary was either corrupt or not found. "+
				"Building system image of the class dictionary.");

			try {in = new FileInputStream(fileName);} 
			catch (FileNotFoundException de){return ;}
			Program p;
			try 
			{
				p = Program.parse(in);
				in.close();
			}catch (Exception fe)
			{
				String title = "File format error";
				String message = "The file could be corrupt or outdated. Please check version";
				ActionShowMessage asm= new ActionShowMessage(_editor,title,message);
				asm.doIt();
				return;
			}
			_editor.setMessage("Finished reading file "+fileName);
// check if the class dictionary has interfaces and/or extension of base classes
			try{
				p.check_classparents();
			}catch(UnsupportedSyntaxException use)
			{
				String title = "Unsupported Syntax";
				String message = use.getMessage();
				ActionShowMessage asm= new ActionShowMessage(_editor,title,message);
				asm.doIt();
				return;
			}

			try{
			_graph = p.print_edges();}
			catch(ParameterisationException e)
			{
				_editor.setMessage("Class dictionary has parameterized classes. Cannot open it.");
				e.printStackTrace();
				return;
			}
			catch(UnsupportedSyntaxException use)
			{
				String title = "Error";
				String message = use.getMessage();
				ActionShowMessage asm= new ActionShowMessage(_editor,title,message);
				asm.doIt();
				return;
			}
			catch(Exception e)
			{
				_editor.setMessage("Error occured during building class graph");
				e.printStackTrace();
				return;
			}
			_editor.setMessage("Finished building class graph.");
		}

		_document=new Document(_editor);
		_document.setDocName(fileName);
		_editor.attach(fileName,_document); // This causes the scroll panel to be laid
		_editor.setCurrentMenuString(fileName);

/* Traverse trough the graph and read all the infromation required for
   drawing the vertices on the screen*/

		VertexContainer vc = _graph.GetAllVertices();
//		System.out.println("Finished traversing the vertex list");
		if(!addConstructionVertices(vc)){_editor.detach(fileName,_document);return;}
		if(!addAlternationVertices(vc)){_editor.detach(fileName,_document);return;}

/* Traverse trough the graph and read all the infromation required for
   drawing the edges on the screen */

		EdgeContainer ec = _graph.GetAllEdges();
		if(!addConstructionEdges(ec)){_editor.detach(fileName,_document);return;}
		if(!addAlternationEdges(ec)){_editor.detach(fileName,_document);return;}
// Add the preamble and package stuff
		_document.set_preamble(_graph.get_preamble());
		_document.set_pkg(_graph.get_pkg());
/* After adding all the elements to view and the net list draw them */
		_document.cdNeedsSaving(false);
		_document.setId(_idd); // sets the current maximum integer id used up.
	}

	private boolean addConstructionVertices(VertexContainer VC)
	{							 
		Vector construction_vertices = VC.get_construction();
		return buildAndaddVertices(construction_vertices,"edu.neu.ccs.demeter.tools.apstudio.graphedit.UConstVertex");
	}

	private boolean addAlternationVertices(VertexContainer VC)
	{
		Vector alternation_vertices = VC.get_alternation();
		return buildAndaddVertices(alternation_vertices,"edu.neu.ccs.demeter.tools.apstudio.graphedit.UAltVertex");
	}
	
	private boolean buildAndaddVertices(Vector v,String className)
	{
		UVertex newNode;
		Class _nodeClass;
		String _nodeClassName=className;
		Enumeration elm = v.elements();
		try { _nodeClass = Class.forName(_nodeClassName); }
		catch (java.lang.ClassNotFoundException ignore) 
		{
			System.out.println("Class " + _nodeClassName + " could not be found!");
			return false; 
		}
		while (elm.hasMoreElements())
		{
			try { newNode = (UVertex) _nodeClass.newInstance();	}
			catch (java.lang.IllegalAccessException ignore) { return false; }
			catch (java.lang.InstantiationException ignore) { return false; }
			
			VertexInfo vf=(VertexInfo)elm .nextElement();
			int id=vf.get_id().get_id().intValue();
			_idd=Math.max(_idd,id);
			newNode.initialize(vf,_document,vf.get_id());
			newNode.set_vertexname(new UVertexName(new Ident(vf.get_name())));
			if(newNode instanceof UConstVertex)
			{
				String before = vf.get_before();
				String after = vf.get_after();
				((UConstVertex)newNode).set_beforeSyntax(before);
				((UConstVertex)newNode).set_afterSyntax(after);
			}
			((UConstOrAltVertex)newNode).set_parse(new YaParse()); 
			// Always parse method generated ScopeIdentifierList is null meaning package level by default
			_document.add(newNode.get_Perspective());
		}
		return true;
	}
	
	private boolean addConstructionEdges(EdgeContainer EC)
	{
		Vector construction_edges = EC.get_construction();
		return buildAndaddEdges(construction_edges);
	}
	private boolean addAlternationEdges(EdgeContainer EC)
	{
		Vector alternation_edges = EC.get_alternation();
		return buildAndaddEdges(alternation_edges);
	}
	private boolean buildAndaddEdges(Vector v)
	{
		Enumeration elm=v.elements();

		while (elm.hasMoreElements())
		{
			EdgeInfo edgeinfo= (EdgeInfo)elm.nextElement();

	  /** Extracting the information from EdgeInfo */

	  
			int id=edgeinfo.get_id().get_id().intValue();
			_idd=Math.max(_idd,id);
			UID from=edgeinfo.get_from();
			UID to=edgeinfo.get_to();
			String edge_name= edgeinfo.get_name();
			String cardinality = edgeinfo.get_card();


	  /** Get the source and destination vertices so that their height and width can
	  be obtained */
	  
			Perspective sourcePerspective= (Perspective)_document.pick(from);
			Perspective destPerspective= (Perspective)_document.pick(to);
	  
			if(sourcePerspective==null) { System.out.println("sors null");return false;}
			if(destPerspective==null) { System.out.println("dest null");return false;}

			UVertex startNode= (UVertex)sourcePerspective.owner();
			UVertex destNode= (UVertex)destPerspective.owner();
			
			if(startNode==null){ System.out.println("start Node is null");return false;}
			if(destNode==null){ System.out.println("dst Node is null"); return false;}

			UEdge newArc;
			ArcPerspective ap;

			if(edge_name==null && cardinality==null)
			{
				newArc=new UAltEdge();
				newArc.set_eid(edgeinfo.get_id());
//				newArc.connect(startNode, destNode);
				newArc.connectAlternation(startNode, destNode);
				Point p = edgeinfo.get_bendpoint();
				if(p==null)
					ap= new ArcPerspective(newArc,_document);
				else
					ap= new ArcPerspective(newArc,_document,p);
			}
			else
			{
				newArc=new UConstEdge();
				newArc.set_eid(edgeinfo.get_id());
				newArc.connect(startNode, destNode);
				if(edge_name==null)
					((UConstEdge)newArc).set_edgename(null);
				else
					((UConstEdge)newArc).set_edgename(new UEdgeName(new Ident(edge_name)));
				String before = edgeinfo.get_beforeSyntax();
				((UConstEdge)newArc).set_beforeSyntax(before);
				String after = edgeinfo.get_afterSyntax();
				((UConstEdge)newArc).set_afterSyntax(after);
				Point p = edgeinfo.get_bendpoint();
				if(p==null)
					ap= new ArcPerspective(newArc,edge_name,cardinality,_document);
				else
					ap= new ArcPerspective(newArc,edge_name,cardinality,_document,p);
// check if self edge
				if(startNode==destNode)
					ap = new ArcPerspective(newArc,edge_name,cardinality,_document,
					new Point(sourcePerspective.get_dimensions().x + sourcePerspective.center().x, 
					sourcePerspective.center().y));
			}
	  
			_document.add(ap);
		}
		return true;
	}
	
	public void undoIt() {}

} /* end class ActionOpen */

