package pipe.dataLayer;

// Collections
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Observable;
import java.util.Random;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import pipe.gui.CreateGui;

/**
 * <b>DataLayer</b> - Encapsulates entire Petri-Net, also contains functions to perform calculations
 *
 * @see <p><a href="..\PNMLSchema\index.html">PNML  -  Petri-Net XMLSchema (stNet.xsd)</a>
 * @see </p><p><a href="uml\DataLayer.png">DataLayer UML</a></p>
 * @version 1.0
 * @author James D Bloom
 */
public class DataLayer extends Observable implements pipe.gui.Constants{

  private static Random randomNumber = new Random(); // Random number generator

  /** PNML File Name */
  private String pnmlName = null;

  /** List containing all the Place objects in the Petri-Net */
  private ArrayList placesArray = null;
  /** ArrayList containing all the Transition objects in the Petri-Net */
  private ArrayList transitionsArray = null;
  /** ArrayList containing all the Arc objects in the Petri-Net */
  private ArrayList arcsArray = null;
  /** ArrayList containing all the Token objects in the Petri-Net */
  private ArrayList tokensArray = null;
  /** ArrayList containing all the Arrow objects in the Petri-Net */
  private ArrayList arrowsArray = null;

  /** ArrayList for net-level label objects (as opposed to element-level labels).*/
  private ArrayList labelsArray = null;

  /** An ArrayList used to point to either the Arc, Place or Transition ArrayLists when these ArrayLists are being update */
  private ArrayList changeArrayList = null;

  /** Initial Markup Matrix */
  private int[] initialMarkupMatrix = null;
  /** Initial Markup Matrix */
  private int[] currentMarkupMatrix = null;
  /** Markup Matrix Storage used during animation */
  private int[] markupMatrixAnimationStorage = null;

  /** Markup Matrix Storage */
  private Object[] markupStore = {null, null, null, null, null, null, null, null, null, null};
  /** Markup Matrix Storage Position */
  private int position = 0;

  /** Markup Storage Array */
  private PNMatrix markupHistoryMatrix = null;
  /** Foward Incidence Matrix */
  private PNMatrix fowardsIncidenceMatrix = null;
  /** Backward Incidence Matrix */
  private PNMatrix backwardsIncidenceMatrix = null;
  /** Incidence Matrix */
  private PNMatrix incidenceMatrix = null;

  /** X-Axis Scale Value */
  private final int DISPLAY_SCALE_FACTORX = 7; // Scale factors for loading other Petri-Nets (not yet implemented)
  /** Y-Axis Scale Value */
  private final int DISPLAY_SCALE_FACTORY = 7; // Scale factors for loading other Petri-Nets (not yet implemented)
  /** X-Axis Shift Value */
  private final int DISPLAY_SHIFT_FACTORX = 270; // Scale factors for loading other Petri-Nets (not yet implemented)
  /** Y-Axis Shift Value */
  private final int DISPLAY_SHIFT_FACTORY = 120; // Scale factors for loading other Petri-Nets (not yet implemented)

  /** Hashtable which maps PlaceTransitionObjects to their list of connected arcs */
  private Hashtable arcsMap = null;

  /**
   * Create Petri-Net object from PNML file with URI pnmlFileName
   *
   *
   * @param pnmlFileName Name of PNML File
   */
  public DataLayer(String pnmlFileName) {
    initializeMatrixes();
    try {
      loadPNML(pnmlFileName);
    } catch (IOException e) {
      System.err.println("IOException thrown in dataLayer(String pnmlFileName) : dataLayer Class : dataLayer Package");
      e.printStackTrace(System.err);
    } catch (SAXException e) {
      System.err.println("SAXException thrown in dataLayer(String pnmlFileName) : dataLayer Class : dataLayer Package");
      e.printStackTrace(System.err);
    } catch (TransformerException e) {
      System.err.println("TransformerException thrown in dataLayer(String pnmlFileName) : dataLayer Class : dataLayer Package");
      e.printStackTrace(System.err);
    } catch (ParserConfigurationException e) {
      System.err.println("ParserConfigurationException thrown in dataLayer(String pnmlFileName) : dataLayer Class : dataLayer Package");
      e.printStackTrace(System.err);
    }
  }

  /**
   * Create Petri-Net object from pnmlFile
   *
   * @param pnmlFile PNML File
   */
  public DataLayer(File pnmlFile) {
      this(pnmlFile.getAbsolutePath());
  }

  /**
   * Create empty Petri-Net object
   */
  public DataLayer() {
    initializeMatrixes();
  }

  /**
   * Initialize Arrays
   */
  private void initializeMatrixes() {
    placesArray = new ArrayList();
    transitionsArray = new ArrayList();
    arcsArray = new ArrayList();
    tokensArray = new ArrayList();
    arrowsArray = new ArrayList();
    labelsArray = new ArrayList();
    initialMarkupMatrix = null;
    fowardsIncidenceMatrix = null;
    backwardsIncidenceMatrix = null;
    incidenceMatrix = null;

    // may as well do the hashtable here as well
    arcsMap = new Hashtable();
  }

  /**
   * Function populates the arcsMap hashtable enabling easier cross referencing of places, transitions and the arcs connected to them.
   *
   */
  public void setArcConnectionMap() {
    // map (PTO, arcslist)


    // get all the PlaceTransitionObjects
    ArrayList allPTO = new ArrayList(placesArray);
    allPTO.addAll(transitionsArray);

    Iterator pto;
    Iterator arcs;
    PlaceTransitionObject current ;

    pto = allPTO.iterator();
    while (pto.hasNext()) {
      current = (PlaceTransitionObject)pto.next();
      // make an entry for each pto in our mapping structure
      arcsMap.put(current,new ArrayList());
    }

    arcs = arcsArray.iterator();
    Arc currentArc;
    PlaceTransitionObject source;
    PlaceTransitionObject target;
    ArrayList arcslist = null;


    // iterate over the arcs, getting the source and destination ptos and adding the arc to their lists
    while (arcs.hasNext()) {
      currentArc = (Arc)arcs.next();
      source = currentArc.getSource();
      target = currentArc.getTarget();


      // get the list of arcs attached to the source and target and add the arc to them
      try {
        ((ArrayList)arcsMap.get(source)).add(currentArc);
      } catch (NullPointerException ne1) {
//        System.out.println("Populating arcsMap: " + ne1.toString());
      }

      try {
        ((ArrayList)arcsMap.get(target)).add(currentArc);
      } catch (NullPointerException ne2) {
//        System.out.println("Populating arcsMap: " + ne2.toString());
      }



    }

  }


 /**
  * Remove first Place that has an id equal to idInput
  *
  * @param idInput id of Place object to remove from Petri-Net
  */
  public void removePlace(String idInput) {
    for(int i = 0 ; i < placesArray.size(); i++)
      if(idInput.equals(((Place)placesArray.get(i)).getId())) {
    placesArray.remove(i);
    setChanged();
      }
  }

  /**
   * Remove first Transition that has an id equal to idInput
   *
   * @param idInput id of Transition object to remove from Petri-Net
   */
  public void removeTransition(String idInput) {
    for(int i = 0 ; i < transitionsArray.size(); i++)
      if(idInput.equals(((Transition)transitionsArray.get(i)).getId())) {
    transitionsArray.remove(i);
    setChanged();
      }
  }

  /**
   * Remove first Arc that has an id equal to idInput
   *
   * @param idInput id of Arc object to remove from Petri-Net
   */
  public void removeArc(String idInput) {

    for(int i = 0 ; i < arcsArray.size(); i++)
      if(idInput.equals(((Arc)arcsArray.get(i)).getId())) {
    arcsArray.remove(i);
    setChanged();
      }
  }


  /**
   * Add placeInput to the back of the Place ArrayList
   * All observers are notified of this change (Model-View Architecture)
   *
   * @param placeInput Place Object to add
   */
  public void addPlace(Place placeInput) {
    boolean unique = true;
    if(placeInput != null) {
      if(placeInput.getId() != null && placeInput.getId().length() > 0) {
        for(int i = 0 ; i < placesArray.size() ; i++) {
          if(placeInput.getId().equals(((Place)placesArray.get(i)).getId())) {
            unique = false;
          }
        }
      } else {
        String id = null;
        if(placesArray != null && placesArray.size() > 0) {
          int no = placesArray.size();
          //          id = "P" + no;
          do {
            // System.out.println("in while loop");
            for(int i = 0 ; i < placesArray.size() ; i++) {
              id = "P" + no;
              if(placesArray.get(i) != null) {
                if(id.equals(((Place)placesArray.get(i)).getId())) {
                  // System.out.println("testing id: " + id);
                  unique = false;
                  no++;
                } else {
                  unique = true;
                }
              }
            }
          } while(!unique);
        } else {
          id = "P0";
        }

        if(id != null) {
          placeInput.setId(id);
        } else {
          placeInput.setId("error");
        }
      }
      placesArray.add(placeInput);
      setChanged();
      // notifyObservers(placeInput.getBounds());
      notifyObservers(placeInput);
    }
  }

  /**
   * Add placeInput to the back of the Place ArrayList
   * All observers are notified of this change (Model-View Architecture)
   *
   * @param placeInput Place Object to add
   */
  public void addAnnotation(AnnotationNote labelInput) {
  	boolean unique = true;
  	labelsArray.add(labelInput);
  	setChanged();
	notifyObservers(labelInput);
  	}
 
 
  /**
   * Add transitionInput to back of the Transition ArrayList
   * All observers are notified of this change (Model-View Architecture)
   *
   * @param transitionInput Transition Object to add
   */
  public void addTransition(Transition transitionInput) {
    boolean unique = true;
    if(transitionInput != null) {
      if(transitionInput.getId() != null && transitionInput.getId().length() > 0) {
        for(int i = 0 ; i < transitionsArray.size() ; i++) {
          if(transitionInput.getId().equals(((Transition)transitionsArray.get(i)).getId())) {
            unique = false;
          }
        }
      } else {
        String id = null;
        if(transitionsArray != null && transitionsArray.size() > 0) {
          int no = transitionsArray.size();
          do {
            // System.out.println("transition while loop");
            for(int i = 0 ; i < transitionsArray.size() ; i++) {
              id = "T" + no;
              if(transitionsArray.get(i) != null) {
                if(id.equals(((Transition)transitionsArray.get(i)).getId())) {
                  unique = false;
                  no++;
                } else {
                  unique = true;
                }
              }
            }
          } while(!unique);
        } else {
          id = "T0";
        }

        if(id != null) {
          transitionInput.setId(id);
        } else {
          transitionInput.setId("error");
        }
      }
      transitionsArray.add(transitionInput);
      setChanged();
      //    notifyObservers(transitionInput.getBounds());
      notifyObservers(transitionInput);
    }
  }

  /**
   * Add arcInput to back of the Arc ArrayList
   * All observers are notified of this change (Model-View Architecture)
   *
   * @param arcInput Arc Object to add
   */
  public void addArc(Arc arcInput) {
    boolean unique = true;
    if(arcInput != null) {
      if(arcInput.getId() != null && arcInput.getId().length() > 0) {
        for(int i = 0 ; i < arcsArray.size() ; i++) {
          if(arcInput.getId().equals(((Arc)arcsArray.get(i)).getId())) {
            unique = false;
          }
        }
      } else {
        String id = null;
        if(arcsArray != null && arcsArray.size() > 0) {
          int no = arcsArray.size();
          do {
            for(int i = 0 ; i < arcsArray.size() ; i++) {
              id = "A" + no;
              if(arcsArray.get(i) != null) {
                if(id.equals(((Arc)arcsArray.get(i)).getId())) {
                  unique = false;
                  no++;
                } else {
                  unique = true;
                }
              }
            }
          } while(!unique);
        } else {
          id = "A0";
        }

        if(id != null) {
          arcInput.setId(id);
        } else {
          arcInput.setId("error");
        }
      }
      arcsArray.add(arcInput);
      addArcToArcsMap(arcInput);

      setChanged();
      //notifyObservers(arcInput.getBounds());
      notifyObservers(arcInput);
    }
  }


  /** Update the arcsMap hashtable to reflect the new arc
   * @param arcInput New Arc
   * */
  private void addArcToArcsMap(Arc arcInput) {
    // now we want to add the arc to the list of arcs for it's source and target
    PlaceTransitionObject source = arcInput.getSource();
    PlaceTransitionObject target = arcInput.getTarget();
    ArrayList newList = null;


    if (source != null) {
// Pete: Place/Transitions now always moveable
//      source.setMovable(false);
      if (arcsMap.get(source)!=null) {
//        System.out.println("adding arc to existing list");
        ((ArrayList)arcsMap.get(source)).add(arcInput);
      } else {
//        System.out.println("creating new arc list");
        newList = new ArrayList();
        newList.add(arcInput);
        arcsMap.put(source,newList);
      }
    }

    if (target != null) {
// Pete: Place/Transitions now always moveable
//      target.setMovable(false);
      if (arcsMap.get(target)!=null) {
//        System.out.println("adding arc to existing list2");
        ((ArrayList)arcsMap.get(target)).add(arcInput);
      } else {
//        System.out.println("creating new arc list2");
        newList = new ArrayList();
        newList.add(arcInput);
        arcsMap.put(target,newList);
      }
    }

//    System.out.println("arcsMap size: " + arcsMap.size());

  }

  /**
   * Add tokenInput to the back of the Token ArrayList
   * All observers are notified of this change.
   *
   * @param tokenInput Token Object to add
   */
  public void addToken(Token tokenInput) {
    tokensArray.add(tokenInput);
    setChanged();
    // notifyObservers(tokenInput.getBounds());
    notifyObservers(tokenInput);
  }

// Pete: Removed ArrowLabel class
//  public void addArrow(ArrowLabel arrowInput) {
//    arrowsArray.add(arrowInput);
//    setChanged();
//    notifyObservers(arrowInput);
//  }

  /**
   * Add any PetriNetObject - the object will be added to the appropriate list.
   * If the object passed in isn't a Transition, Place or Arc nothing will happen.
   * All observers are notified of this change.
   * @param pnObject The PetriNetObject to be added.
   */

  public void addPetriNetObject(PetriNetObject pnObject) {

    if (setPetriNetObjectArrayList(pnObject)) {


      if (pnObject instanceof Arc) {
        addArcToArcsMap((Arc)pnObject);
        addArc((Arc)pnObject);
      } else if (pnObject instanceof Place) {
        addPlace((Place)pnObject);
      } else if (pnObject instanceof Transition) {
        addTransition((Transition)pnObject);
      } else if (pnObject instanceof AnnotationNote) {
      	labelsArray.add(pnObject);
      }	else { // arrows, other labels.
        changeArrayList.add(pnObject);
        setChanged();
        notifyObservers(pnObject);
      }

    }
    // we reset to null so that the wrong ArrayList can't get added to
    changeArrayList = null;
  }
//######################################################################################
  /**
   * Removes the specified object from the appropriate ArrayList of objects.
   * All observers are notified of this change.
   * @param pnObject The PetriNetObject to be removed.
   */

  public void removePetriNetObject(PetriNetObject pnObject){
    boolean didSomething = false;
    ArrayList attachedArcs = null;
    Iterator i = null;

    //System.out.println("removing: " + pnObject.getClass().getName());

    if (setPetriNetObjectArrayList(pnObject)) {
      didSomething = changeArrayList.remove(pnObject);


      // we want to remove all attached arcs also
      if (pnObject instanceof PlaceTransitionObject) {

        if ( (ArrayList)arcsMap.get(pnObject) != null) {

          // get the list of attached arcs for the object we are removing
          attachedArcs = ((ArrayList)arcsMap.get(pnObject));

          // remove the object we are removing from the arcsMap
          Arc removeArc;
          PlaceTransitionObject attached;

          // iterate over all the attached arcs, removing them all
          while(!attachedArcs.isEmpty()) {
            removeArc = (Arc)attachedArcs.get(0);
//            removePetriNetObject(removeArc);
            removeArc.delete();

          }
          arcsMap.remove(pnObject);
        }
      } else if (pnObject instanceof Arc) {

        // get source and target of the arc
        PlaceTransitionObject attached = ((Arc)pnObject).getSource();

          if (attached != null) {
            ArrayList a=(ArrayList)arcsMap.get(attached);
            if(a!=null)a.remove(pnObject);
          	attached.removeFromArc((Arc)pnObject);
          	if (attached instanceof Transition)
          		((Transition)attached).removeArcCompareObject((Arc)pnObject);
          	//attached.updateConnected(); ? causing null pointer exceptions
          }

          attached = ((Arc)pnObject).getTarget();

          if (attached != null) {
          	((ArrayList)arcsMap.get(attached)).remove(pnObject);
          	attached.removeToArc((Arc)pnObject);
          	if (attached instanceof Transition)
          		((Transition)attached).removeArcCompareObject((Arc)pnObject);
          	attached.updateConnected();
          }
      }      
      
      if (didSomething) {
        setChanged();
        // notifyObservers(pnObject.getBounds());
        notifyObservers(pnObject);
      }
    }
    // we reset to null so that the wrong ArrayList can't get added to
    changeArrayList = null;
  }
//######################################################################################
    /* Returns an iterator for the transitions array.  Used by Animator.class to set all
       enabled transitions to highlighted */
  public Iterator returnTransitions(){
//    System.out.println("returnTransitionsIterator called");
    return transitionsArray.iterator();
  }
//######################################################################################
  /**
   * Sets an internal ArrayList according to the class of the object passed in.
   * @param pnObject The pnObject in question.
   * @return Returns True if the pnObject is of type Place, Transition or Arc
   */
  private boolean setPetriNetObjectArrayList(PetriNetObject pnObject) {

    // determine appropriate ArrayList
    if (pnObject instanceof Transition) {
      changeArrayList = transitionsArray;
      return true;
    } else if (pnObject instanceof Place){
      changeArrayList = placesArray;
      return true;
    } else if (pnObject instanceof Arc) {
      changeArrayList = arcsArray;
      return true;
    } else if(pnObject instanceof Token){
      changeArrayList = tokensArray;
      return true;
    } else if(pnObject instanceof AnnotationNote) {
      changeArrayList = labelsArray;
      return true;

    }



    return false;
  }


  /**
   *
   * Set the Foward Incidence Matrix
   *
   * @param fowardIncidenceInput Foward Incidence Matrix object
   */
    /* public void setFowardIncidenceMatrix(int[][] fowardIncidenceInput) {
    int i = 0;
    int j = 0;
    Integer intergerInput = null;
    for( ; i < fowardIncidenceInput.length ; i++) {
      fowardsIncidenceMatrix.add(i, new ArrayList(fowardIncidenceInput[i].length));
      for( ; j < fowardIncidenceInput[i].length ; j++) {
        intergerInput = new Integer(fowardIncidenceInput[i][j]);
        fowardsIncidenceMatrix.add(j, intergerInput);
      }
    }
    }*/

   /**
    * Set the Backward Incidence Matrix
    *
    * @param backwardsIncidenceInput Backward Incidence Matrix object
    */

   /**
    * Returns an iterator of all PetriNetObjects - the order of these cannot be guaranteed.
    * @return An iterator of all PetriNetObjects
    */
  public Iterator getPetriNetObjects(){
    ArrayList all = new ArrayList(placesArray);
    all.addAll(transitionsArray);
    all.addAll(arcsArray);
    all.addAll(tokensArray);
    all.addAll (labelsArray);
    all.addAll(arrowsArray);

    return all.iterator();
  }



  /**
   * Set the Foward Incidence Matrix
   *
   * @param fowardIncidenceInput Foward Incidence Matrix object
   */
  public void setFowardIncidenceMatrix(int[][] fowardIncidenceInput) {
    fowardsIncidenceMatrix = new PNMatrix(fowardIncidenceInput);
  }

  /**
   * Set the Backward Incidence Matrix
   *
   * @param backwardsIncidenceInput Backward Incidence Matrix object
   */

  public void setBackwardsIncidenceMatrix(int[][] backwardsIncidenceInput) {
    backwardsIncidenceMatrix = new PNMatrix(backwardsIncidenceInput);
  }

  /**
   * Set the Incidence Matrix
   *
   * @param incidenceInput Backward Incidence Matrix object
   */
  public void setIncidenceMatrix(int[][] incidenceInput) {
    incidenceMatrix = new PNMatrix(incidenceInput);
  }

  /**
   * Set the Initial Markup Matrix
   *
   * @param markupInput Initial Markup Matrix object
   */
  public void setInitalMarkupMatrix(int[][] markupInput) {
    /*
    int i = 0;
    int j = 0;
    Integer intergerInput = null;
    for( ; i < markupInput.length ; i++) {
      fowardsIncidenceMatrix.add(i, new ArrayList(markupInput[i].length));
      for( ; j < markupInput[i].length ; j++) {
        intergerInput = new Integer(markupInput[i][j]);
        fowardsIncidenceMatrix.add(j, intergerInput);
      }
    }
    */
  }

  /**
   * Save the Petri-Net
   *
   * @param filename URI location to save file
   * @throws ParserConfigurationException
   * @throws DOMException
   * @throws TransformerConfigurationException
   * @throws TransformerException
   */
  public void savePNML(String filename) 
      throws NullPointerException, IOException, ParserConfigurationException, DOMException, TransformerConfigurationException, TransformerException {
     savePNML(new File(filename));	
  }

  /**
   * Save the Petri-Net
   *
   * @param filename URI location to save file
   * @throws ParserConfigurationException
   * @throws DOMException
   * @throws TransformerConfigurationException
   * @throws TransformerException
   */
  
  public void savePNML(File file)
      throws NullPointerException, IOException, ParserConfigurationException, DOMException, TransformerConfigurationException, TransformerException {

    // Error checking
    if(file == null) throw new NullPointerException("Null file in savePNML");
/*    
    System.out.println("=======================================");
    System.out.println("dataLayer SAVING FILE=\"" + file.getCanonicalPath() + "\"");
    System.out.println("=======================================");
*/
    Document pnDOM = null;
    int i;
    StreamSource xsltSource = null;
    Transformer transformer = null;
    try {
      // Build a Petri Net XML Document
      DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = builderFactory.newDocumentBuilder();
      pnDOM = builder.newDocument();

      Element PNML = pnDOM.createElement("pnml"); // PNML Top Level Element
      pnDOM.appendChild(PNML);
     
      Attr pnmlAttr = pnDOM.createAttribute("xmlns"); // PNML "xmlns" Attribute
      pnmlAttr.setValue("http://www.informatik.hu-berlin.de/top/pnml/ptNetb");
      PNML.setAttributeNode(pnmlAttr);
      	
      Element NET = pnDOM.createElement("net"); // Net Element
      PNML.appendChild(NET);
      Attr netAttrId = pnDOM.createAttribute("id"); // Net "id" Attribute
      netAttrId.setValue("Net-One");
      NET.setAttributeNode(netAttrId);

      Attr netAttrType = pnDOM.createAttribute("type"); // Net "type" Attribute
      netAttrType.setValue("P/T net");
      NET.setAttributeNode(netAttrType);
      Place[] places = getPlaces();
      for(i = 0 ; i < places.length ; i++) {
        NET.appendChild(createPlaceElement(places[i], pnDOM));
      }
      places = null;
      AnnotationNote[] labels = getLabels();
      if (labels.length>0) {
	      for (i = 0; i <labels.length; i++) {
	      	NET.appendChild(createAnnotationNoteElement(labels[i], pnDOM));
	      }
	      labels = null;
      }
      
      Transition[] transitions = getTransitions();
      for(i = 0 ; i < transitions.length ; i++) {
        NET.appendChild(createTransitionElement(transitions[i], pnDOM));
      }
      transitions = null;
      Arc[] arcs = getArcs();
      for(i = 0 ; i < arcs.length ; i++) {
      	Element newArc = createArcElement(arcs[i],pnDOM);
      	
        int arcPoints = arcs[i].getArcPath().getArcPathDetails().length;
        String[][] point = arcs[i].getArcPath().getArcPathDetails();
        for (int j = 0; j < arcPoints; j++){
        	newArc.appendChild(createArcPoint(point[j][0],point[j][1],point[j][2],pnDOM,j));
        }
        NET.appendChild(newArc);
        //newArc = null;
      }
      arcs = null;
     

      pnDOM.normalize();
      // Create Transformer with XSL Source File
      xsltSource = new StreamSource(CreateGui.appPath+"xslt"+System.getProperty("file.separator")+"GeneratePNML.xsl");
      
      transformer = TransformerFactory.newInstance().newTransformer(xsltSource);
      // Write file and do XSLT transformation to generate correct PNML
      File outputObjectArrayList = file;//new File(filename); // Output for XSLT Transformation
      DOMSource source = new DOMSource(pnDOM);
      StreamResult result = new StreamResult(outputObjectArrayList);
      transformer.transform(source, result);

    } catch (ParserConfigurationException e) {
//      System.out.println("=====================================================================================");
      System.out.println("ParserConfigurationException thrown in savePNML() : dataLayer Class : dataLayer Package: filename=\"" + file.getCanonicalPath() + "\" xslt=\"" + xsltSource.getSystemId() + "\" transformer=\"" + transformer.getURIResolver() + "\"");
//      System.out.println("=====================================================================================");
//      e.printStackTrace(System.err);
    } catch (DOMException e) {
//      System.out.println("=====================================================================");
      System.out.println("DOMException thrown in savePNML() : dataLayer Class : dataLayer Package: filename=\"" + file.getCanonicalPath() + "\" xslt=\"" + xsltSource.getSystemId() + "\" transformer=\"" + transformer.getURIResolver() + "\"");
//      System.out.println("=====================================================================");
//      e.printStackTrace(System.err);
    } catch (TransformerConfigurationException e) {
//      System.out.println("==========================================================================================");
      System.out.println("TransformerConfigurationException thrown in savePNML() : dataLayer Class : dataLayer Package: filename=\"" + file.getCanonicalPath() + "\" xslt=\"" + xsltSource.getSystemId() + "\" transformer=\"" + transformer.getURIResolver() + "\"");
//      System.out.println("==========================================================================================");
//      e.printStackTrace(System.err);
    } catch (TransformerException e) {
//      System.out.println("=============================================================================");
      System.out.println("TransformerException thrown in savePNML() : dataLayer Class : dataLayer Package: filename=\"" + file.getCanonicalPath() + "\" xslt=\"" + xsltSource.getSystemId() + "\" transformer=\"" + transformer.getURIResolver() + "\"" + e);
//      System.out.println("=============================================================================");
//      e.printStackTrace(System.err);
    }
  }

  /**
   * Load PNML file
   *
   * @param filename URI location of PNML
   * @throws IOException
   * @throws SAXException
   * @throws TransformerException
   * @throws ParserConfigurationException
   */
  public void loadPNML(String filename)
      throws IOException, SAXException, TransformerException, ParserConfigurationException {
//    System.out.println("========================================================");
//    System.out.println("dataLayer Loading filename=\"" + filename + "\"");
//    System.out.println("========================================================");

    emptyPNML();
    Element element = null;
    Node node = null;
    NodeList nodeList = null;
    int noOfObjects = 0;
    Document document = null;
    File outputObjectArrayList;
    
    try {
      // Create Transformer with XSL Source File
      StreamSource xsltSource = new StreamSource(CreateGui.appPath+"xslt"+System.getProperty("file.separator")+"GenerateObjectList.xsl");
      Transformer transformer = TransformerFactory.newInstance().newTransformer(xsltSource);
      // TRY TO DO ALL IN MEMORT TO REDUCE READ-WRITE DELAYS
      outputObjectArrayList = new File(System.getProperty("java.io.tmpdir")+System.getProperty("file.separator")+"ObjectList.xml"); // Output for XSLT Transformation
      outputObjectArrayList.deleteOnExit();
      StreamSource source = new StreamSource(filename);
      StreamResult result = new StreamResult(outputObjectArrayList);
      transformer.transform(source, result);

      // Get DOM for transformed document
      document = getDOM(outputObjectArrayList);
      nodeList = document.getDocumentElement().getChildNodes();
      CreateGui.getApp().setMode(CREATING);				// Notifies used to indicate new instances.
      
      for(int i = 0 ; i < nodeList.getLength() ; i++) {
        node = nodeList.item(i);

        if(node instanceof Element) {
          element = (Element)node;
          if ("labels".equals(element.getNodeName())){
          	addAnnotation(createAnnotation(element));
          }
          else if("place".equals(element.getNodeName()))
            addPlace(createPlace(element));
          else if ("transition".equals(element.getNodeName())){
            addTransition(createTransition(element));
          }
          else if ("arc".equals(element.getNodeName())) {
            Arc a=createArc(element);
            addArc(a);
            a.addWeightLabelToContainer();
          }
        }
      }
      
      CreateGui.getApp().restoreMode();

      pnmlName = filename;
//    } catch (IOException e) {
//      System.out.println("IOException thrown in loadPNML(String filename) : dataLayer Class : dataLayer Package");
//      e.printStackTrace(System.err);
//    } catch (SAXException e) {
//      System.out.println("SAXException thrown in loadPNML(String filename) : dataLayer Class : dataLayer Package");
//      e.printStackTrace(System.err);
//    } catch (TransformerException e) {
//      System.out.println("TransformerException thrown in loadPNML(String filename) : dataLayer Class : dataLayer Package");
//      e.printStackTrace(System.err);
//    } catch (ParserConfigurationException e) {
//      System.out.println("ParserConfigurationException thrown in loadPNML(String filename) : dataLayer Class : dataLayer Package");
//      e.printStackTrace(System.err);
// Maxim - make it throw out any exception it gets to the caller. Debugging message left in for now.
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    
    // Delete transformed file
    if(outputObjectArrayList!=null) outputObjectArrayList.delete();
  }

  /**
   * Creates a Place object from a Place DOM Element
   *
   * @param inputPlaceElement Input Place DOM Element
   * @return Place Object
   */
  private Place createPlace(Element inputPlaceElement){
    double positionXInput = 0;
    double positionYInput = 0;
    String idInput = null;
    String nameInput = null;
    double nameOffsetYInput = 0;
    double nameOffsetXInput = 0;
    int initialMarkingInput = 0;
    double markingOffsetXInput = 0;
    double markingOffsetYInput = 0;

    String positionXTempStorage = inputPlaceElement.getAttribute("positionX");
    String positionYTempStorage = inputPlaceElement.getAttribute("positionY");
    String idTempStorage = inputPlaceElement.getAttribute("id");
    String nameTempStorage = inputPlaceElement.getAttribute("name");
    String nameOffsetYTempStorage = inputPlaceElement.getAttribute("nameOffsetX");
    String nameOffsetXTempStorage = inputPlaceElement.getAttribute("nameOffsetY");
    String initialMarkingTempStorage = inputPlaceElement.getAttribute("initialMarking");
    String markingOffsetXTempStorage = inputPlaceElement.getAttribute("markingOffsetX");
    String markingOffsetYTempStorage = inputPlaceElement.getAttribute("markingOffsetY");

    if (positionXTempStorage.length() > 0)
      positionXInput = Double.valueOf(positionXTempStorage).doubleValue()*(false ? DISPLAY_SCALE_FACTORX : 1)+(false ? DISPLAY_SHIFT_FACTORX : 1);
    if (positionYTempStorage.length() > 0)
      positionYInput = Double.valueOf(positionYTempStorage).doubleValue()*(false ? DISPLAY_SCALE_FACTORY : 1)+(false ? DISPLAY_SHIFT_FACTORY : 1);

    if (idTempStorage.length() > 0)
      idInput = idTempStorage;
    else if (nameTempStorage.length() > 0)
      idInput = nameTempStorage;

    if (nameTempStorage.length() > 0)
      nameInput = nameTempStorage;
    else if (idTempStorage.length() > 0)
      nameInput = idTempStorage;

    if (nameOffsetYTempStorage.length() > 0)
      nameOffsetXInput = Double.valueOf(nameOffsetYTempStorage).doubleValue();
    if (nameOffsetXTempStorage.length() > 0)
      nameOffsetYInput = Double.valueOf(nameOffsetXTempStorage).doubleValue();
    if (initialMarkingTempStorage.length() > 0)
      initialMarkingInput = Integer.valueOf(initialMarkingTempStorage).intValue();
    if (markingOffsetXTempStorage.length() > 0)
      markingOffsetXInput = Double.valueOf(markingOffsetXTempStorage).doubleValue();
    if (markingOffsetYTempStorage.length() > 0)
      markingOffsetYInput = Double.valueOf(markingOffsetYTempStorage).doubleValue();
    // Pete: Removed colour properties

    positionXInput+=PLACE_TRANSITION_HEIGHT/2-1;
    positionYInput+=PLACE_TRANSITION_HEIGHT/2-1;
    
    return new Place(positionXInput, positionYInput, idInput, nameInput, nameOffsetXInput, nameOffsetYInput, initialMarkingInput, markingOffsetXInput, markingOffsetYInput);
  }

  /**
   * Creates a Label object from a Label DOM Element
   *
   * @param inputLabelElement Input Label DOM Element
   * @return Label Object
   */
  private AnnotationNote createAnnotation(Element inputLabelElement){
  	int positionXInput = 0;
  	int positionYInput = 0;
  	int widthInput = 0;
  	int heightInput = 0;
  	String text = null;
  	boolean borderInput = true;

  	String positionXTempStorage = inputLabelElement.getAttribute("xPosition");
  	String positionYTempStorage = inputLabelElement.getAttribute("yPosition");
  	String widthTemp = inputLabelElement.getAttribute("w");
  	String heightTemp = inputLabelElement.getAttribute("h");
  	String textTempStorage = inputLabelElement.getAttribute("txt");
  	String borderTemp = inputLabelElement.getAttribute("border");
  	
  	if (positionXTempStorage.length() > 0)
  		positionXInput = Integer.valueOf(positionXTempStorage).intValue()*(false ? DISPLAY_SCALE_FACTORX : 1)+(false ? DISPLAY_SHIFT_FACTORX : 1);
  	if (positionYTempStorage.length() > 0)
  		positionYInput = Integer.valueOf(positionYTempStorage).intValue()*(false ? DISPLAY_SCALE_FACTORX : 1)+(false ? DISPLAY_SHIFT_FACTORX : 1);
  	if (widthTemp.length() > 0)
  		widthInput = Integer.valueOf(widthTemp).intValue()*(false ? DISPLAY_SCALE_FACTORY : 1)+(false ? DISPLAY_SHIFT_FACTORY : 1);
  	if (heightTemp.length() > 0)
  		heightInput = Integer.valueOf(heightTemp).intValue()*(false ? DISPLAY_SCALE_FACTORY : 1)+(false ? DISPLAY_SHIFT_FACTORY : 1);
  	if (borderTemp.length()>0)
  		borderInput = Boolean.valueOf(borderTemp).booleanValue();
  	else borderInput = true;
  	if (textTempStorage.length() > 0)
  		text = textTempStorage;
  	else text = "";
  	
  	return new AnnotationNote(text, (int)positionXInput, (int)positionYInput, (int)widthInput, (int)heightInput, borderInput);
  }
  
  
  /**
   * Creates a Transition object from a Transition DOM Element
   *
   * @param inputTransitionElement Input Transition DOM Element
   * @return Transition Object
   */
  private Transition createTransition(Element inputTransitionElement){
    double positionXInput = 0;
    double positionYInput = 0;
    String idInput = null;
    String nameInput = null;
    double nameOffsetYInput = 0;
    double nameOffsetXInput = 0;
    double rate = 1.0;
    boolean timedTransition;
    int angle = 0;
    String positionXTempStorage = inputTransitionElement.getAttribute("positionX");
    String positionYTempStorage = inputTransitionElement.getAttribute("positionY");
    String idTempStorage = inputTransitionElement.getAttribute("id");
    String nameTempStorage = inputTransitionElement.getAttribute("name");
    String nameOffsetYTempStorage = inputTransitionElement.getAttribute("nameOffsetX");
    String nameOffsetXTempStorage = inputTransitionElement.getAttribute("nameOffsetY");
    String nameRate = inputTransitionElement.getAttribute("rate");
    String nameTimed = inputTransitionElement.getAttribute("timed");
    String nameAngle = inputTransitionElement.getAttribute("angle");
    if (nameTimed.length() == 0)
    	timedTransition = false;
    else if (nameTimed.length()== 5)
    	timedTransition = false;
    else
    	timedTransition = true;
    if (positionXTempStorage.length() > 0)
      positionXInput = Double.valueOf(positionXTempStorage).doubleValue()*(false ? DISPLAY_SCALE_FACTORX : 1)+(false ? DISPLAY_SHIFT_FACTORX : 1);
    if (positionYTempStorage.length() > 0)
      positionYInput = Double.valueOf(positionYTempStorage).doubleValue()*(false ? DISPLAY_SCALE_FACTORY : 1)+(false ? DISPLAY_SHIFT_FACTORY : 1);
    if (idTempStorage.length() > 0)
      idInput = idTempStorage;
    else if (nameTempStorage.length() > 0)
      idInput = nameTempStorage;
   
    if (nameTempStorage.length() > 0)
      nameInput = nameTempStorage;
    else if (idTempStorage.length() > 0)
      nameInput = idTempStorage;
   
    if (nameOffsetXTempStorage.length() > 0)
      nameOffsetXInput = Double.valueOf(nameOffsetXTempStorage).doubleValue();
   
    if (nameOffsetYTempStorage.length() > 0)
      nameOffsetYInput = Double.valueOf(nameOffsetYTempStorage).doubleValue();
   
    if (nameRate.length()== 0)
    	{	
    	 	nameRate = "1.0";
    	}
    if (nameRate != "1.0"){
    	rate = Double.valueOf(nameRate).doubleValue();}
    else 
    	rate = 1.0;

    if (nameAngle.length()>0)
    	angle = Integer.valueOf(nameAngle).intValue();
    // Pete: Removed colour properties
    positionXInput+=PLACE_TRANSITION_HEIGHT/2-1;
    positionYInput+=PLACE_TRANSITION_HEIGHT/2-1;
    return new Transition(positionXInput, positionYInput,  idInput,  nameInput,  nameOffsetXInput, nameOffsetYInput, rate , timedTransition, angle);
  }

  /**
   * Creates a Arc object from a Arc DOM Element
   *
   * @param inputArcElement Input Arc DOM Element
   * @return Arc Object
   */
  private Arc createArc(Element inputArcElement){
    String idInput = null;
    String sourceInput = null;
    String targetInput = null;
    int weightInput = 1;
    double inscriptionOffsetXInput = 0;
    double inscriptionOffsetYInput = 0;
    double startX = 0;
    double startY = 0;
    double endX = 0;
    double endY = 0;
    
    
    sourceInput = inputArcElement.getAttribute("source");
    targetInput = inputArcElement.getAttribute("target");
    String idTempStorage = inputArcElement.getAttribute("id");
    String sourceTempStorage = inputArcElement.getAttribute("source");
    String targetTempStorage = inputArcElement.getAttribute("target");
    String inscriptionTempStorage = inputArcElement.getAttribute("inscription");
//    String inscriptionOffsetXTempStorage = inputArcElement.getAttribute("inscriptionOffsetX");
//    String inscriptionOffsetYTempStorage = inputArcElement.getAttribute("inscriptionOffsetY");


    if (idTempStorage.length() > 0)
      idInput = idTempStorage;
    if (sourceTempStorage.length() > 0)
      sourceInput = sourceTempStorage;
    if (targetTempStorage.length() > 0)
      targetInput = targetTempStorage;
    if (inscriptionTempStorage.length() > 0)
      weightInput = Integer.valueOf((inputArcElement.getAttribute("inscription") != null ? inputArcElement.getAttribute("inscription") : "1")).intValue();
//    if (inscriptionOffsetXTempStorage.length() > 0)
//      inscriptionOffsetXInput = Double.valueOf(inputArcElement.getAttribute("inscriptionOffsetX")).doubleValue();
//    if (inscriptionOffsetYTempStorage.length() > 0)
//     inscriptionOffsetYInput = Double.valueOf(inputArcElement.getAttribute("inscriptionOffsetY")).doubleValue();


    if (sourceInput.length() > 0) {
      if (getPlaceTransitionObject(sourceInput) != null) {
//        System.out.println("PNMLDATA: sourceInput is not null");
        startX = getPlaceTransitionObject(sourceInput).getPositionX();
        startX += getPlaceTransitionObject(sourceInput).centreOffsetLeft();
        startY = getPlaceTransitionObject(sourceInput).getPositionY();
        startY += getPlaceTransitionObject(sourceInput).centreOffsetTop();
      }
    }
    if (targetInput.length() > 0) {
      if (getPlaceTransitionObject(targetInput) != null) {
//        System.out.println("PNMLDATA: targetInput is not null");
        endX = getPlaceTransitionObject(targetInput).getPositionX();
        endY = getPlaceTransitionObject(targetInput).getPositionY();
      }
    }
    
    PlaceTransitionObject sourceIn = getPlaceTransitionObject(sourceInput);
    PlaceTransitionObject targetIn = getPlaceTransitionObject(targetInput);
    
    int aStartx;
    int aStarty;
    int aEndx;
    int aEndy;
    aStartx = sourceIn.getX();
    aStarty = sourceIn.getY();
    // add the insets and offset
    aStartx += sourceIn.centreOffsetLeft();
    aStarty += sourceIn.centreOffsetTop();
    
    aEndx = targetIn.getX();
    aEndy = targetIn.getY();
    aEndx += targetIn.centreOffsetLeft();
    aEndy += targetIn.centreOffsetTop();
    
    double _startx = aStartx;
    double _starty = aStarty;
    double _endx = aEndx;
    double _endy = aEndy;
    //TODO
    Arc tempArc = new Arc(_startx, _starty, _endx, _endy, sourceIn, targetIn, weightInput, idInput, Color.BLACK);
   
    getPlaceTransitionObject(sourceInput).addConnectFrom(tempArc);
    getPlaceTransitionObject(targetInput).addConnectTo(tempArc);
    
//**********************************************************************************
//The following section attempts to load and display arcpath details****************
//    ArcPath tempArcPath = tempArc.getArcPath();
    
    
    float arcPointX = 0;
    float arcPointY = 0;
    boolean arcPointType = false;
    String arcTempX = null;
    String arcTempY = null;
    String arcTempType = null;
    Node node = null;
    NodeList nodelist = null;
    nodelist = inputArcElement.getChildNodes();
    if (nodelist.getLength()>0) {
    	tempArc.getArcPath().purgePathPoints();
	    for (int i = 1; i < nodelist.getLength()-1; i++) {
	    	node = nodelist.item(i);
	    	if(node instanceof Element) {
		    	Element element = (Element)node;
		    	if ("arcpath".equals(element.getNodeName())){
		    		arcTempX = element.getAttribute("x");
		    		arcTempY = element.getAttribute("y");
		    		arcTempType = element.getAttribute("arcPointType");
		    		arcPointX = Float.valueOf(arcTempX).floatValue();
		    		arcPointY = Float.valueOf(arcTempY).floatValue();
            arcPointX+=ARC_CONTROL_POINT_CONSTANT+1;
            arcPointY+=ARC_CONTROL_POINT_CONSTANT+1;
		    		arcPointType = Boolean.valueOf(arcTempType).booleanValue();
		    		tempArc.getArcPath().addPoint(arcPointX,arcPointY,arcPointType);
		    		
		    	}
		    }
    	}
    }

//Arc path creation ends here***************************************************************    
//******************************************************************************************
    return tempArc;
  }

  /**
   * Creates a Place Element for a PNML Petri-Net DOM
   *
   * @param inputPlace Input Place
   * @param document Any DOM to enable creation of Elements and Attributes
   * @return Place Element for a PNML Petri-Net DOM
   */
  private Element createPlaceElement(Place inputPlace, Document document){

    Element placeElement = null;

    if(document != null) {
      placeElement = document.createElement("place");
    }

    if(inputPlace != null ) {
      Integer attrValue = null;
      Double positionXInput = inputPlace.getPositionXObject();
      Double positionYInput = inputPlace.getPositionYObject();
      String idInput = inputPlace.getId();
      String nameInput = inputPlace.getName();
//      Double nameOffsetYInput = inputPlace.getNameOffsetXObject();
//      Double nameOffsetXInput = inputPlace.getNameOffsetXObject();
      Integer initialMarkingInput = inputPlace.getCurrentMarkingObject();
      Double markingOffsetXInput = inputPlace.getMarkingOffsetXObject();
      Double markingOffsetYInput = inputPlace.getMarkingOffsetYObject();

      placeElement.setAttribute("positionX", (positionXInput != null ? String.valueOf(positionXInput) : ""));
      placeElement.setAttribute("positionY", (positionYInput != null ? String.valueOf(positionYInput) : ""));
      placeElement.setAttribute("name", (nameInput != null ? nameInput : (idInput != null && idInput.length() > 0? idInput : "")));
      placeElement.setAttribute("id", (idInput != null ? idInput : "error"));
//      placeElement.setAttribute("nameOffsetX", (nameOffsetXInput != null ? String.valueOf(nameOffsetXInput) : ""));
//      placeElement.setAttribute("nameOffsetY", (nameOffsetYInput != null ? String.valueOf(nameOffsetYInput) : ""));
      placeElement.setAttribute("initialMarking", (initialMarkingInput != null ? String.valueOf(initialMarkingInput) : "0"));
      placeElement.setAttribute("markingOffsetX", (markingOffsetXInput != null ? String.valueOf(markingOffsetXInput) : ""));
      placeElement.setAttribute("markingOffsetY", (markingOffsetYInput != null ? String.valueOf(markingOffsetYInput) : ""));

    }
    return placeElement;
  }

  /**
   * Creates a Place Element for a PNML Petri-Net DOM
   *
   * @param inputPlace Input Place
   * @param document Any DOM to enable creation of Elements and Attributes
   * @return Place Element for a PNML Petri-Net DOM
   */
  private Element createAnnotationNoteElement(AnnotationNote inputLabel, Document document){

  	Element labelElement = null;
  	if(document != null) {
  		labelElement = document.createElement("labels");
  	}

  	if(inputLabel != null ) {
  		int positionXInput = inputLabel.getX();
  		int positionYInput = inputLabel.getY();
  		int widthInput = inputLabel.getNoteWidth();
  		int heightInput = inputLabel.getNoteHeight();
  		String nameInput = inputLabel.getNoteText();
  		boolean borderInput = inputLabel.isShowingBorder();
  		
  		labelElement.setAttribute("positionX", (positionXInput >= 0.0 ? String.valueOf(positionXInput) : ""));
  		labelElement.setAttribute("positionY", (positionYInput >= 0.0 ? String.valueOf(positionYInput) : ""));
  		labelElement.setAttribute("width", (widthInput>=0.0? String.valueOf(widthInput):""));
  		labelElement.setAttribute("height", (heightInput>=0.0? String.valueOf(heightInput):""));
  		labelElement.setAttribute("border",String.valueOf(borderInput));
  		labelElement.setAttribute("text", (nameInput != null ? nameInput : ""));
  	}
  	
  	return labelElement;
  }
  
  
  /**
   * Creates a Transition Element for a PNML Petri-Net DOM
   *
   * @param inputTransition Input Transition
   * @param document Any DOM to enable creation of Elements and Attributes
   * @return Transition Element for a PNML Petri-Net DOM
   */
  private Element createTransitionElement(Transition inputTransition, Document document){
    Element transitionElement = null;

    if(document != null) {
      transitionElement = document.createElement("transition");
    }

    if(inputTransition != null ) {
      Integer attrValue = null;
      Double positionXInput = inputTransition.getPositionXObject();
      Double positionYInput = inputTransition.getPositionYObject();
      String idInput = inputTransition.getId();
      String nameInput = inputTransition.getName();
      double aRate = inputTransition.getRate();
      boolean timedTrans = inputTransition.getTimed();
      int orientation = inputTransition.getAngle();

      transitionElement.setAttribute("positionX", (positionXInput != null ? String.valueOf(positionXInput) : ""));
      transitionElement.setAttribute("positionY", (positionYInput != null ? String.valueOf(positionYInput) : ""));
      transitionElement.setAttribute("name", (nameInput != null ? nameInput : (idInput != null && idInput.length() > 0? idInput : "")));
      transitionElement.setAttribute("id", (idInput != null ? idInput : "error"));
      transitionElement.setAttribute("rate", (aRate != 1 ? String.valueOf(aRate):"1.0"));
      transitionElement.setAttribute("timed", String.valueOf(timedTrans));
      transitionElement.setAttribute("angle", String.valueOf(orientation));
    }

    return transitionElement;
  }

  /**
   * Creates a Arc Element for a PNML Petri-Net DOM
   *
   * @param inputArc Input Arc
   * @param document Any DOM to enable creation of Elements and Attributes
   * @return Arc Element for a PNML Petri-Net DOM
   */
  private Element createArcElement(Arc inputArc, Document document){
    Element arcElement = null;

    if(document != null) {
      arcElement = document.createElement("arc");
    }

    if(inputArc != null ) {
      Integer attrValue = null;
      double positionXInputD = (int)inputArc.getStartPositionX();
      Double positionXInput = new Double (positionXInputD);
      double positionYInputD = (int)inputArc.getStartPositionY();
      Double positionYInput = new Double (positionXInputD);
      String idInput = inputArc.getId();
      String sourceInput = inputArc.getSource().getId();
      String targetInput = inputArc.getTarget().getId();
      int inscriptionInput = (inputArc != null ? inputArc.getWeight() : 1);
//      Double inscriptionPositionXInput = inputArc.getInscriptionOffsetXObject();
//      Double inscriptionPositionYInput = inputArc.getInscriptionOffsetYObject();
      arcElement.setAttribute("id", (idInput != null ? idInput : "error"));
      arcElement.setAttribute("source", (sourceInput != null ? sourceInput : ""));
      arcElement.setAttribute("target", (targetInput != null ? targetInput : ""));
      arcElement.setAttribute("inscription", Integer.toString(inscriptionInput));
//      arcElement.setAttribute("inscriptionOffsetX", (inscriptionPositionXInput != null ? String.valueOf(inscriptionPositionXInput) : ""));
//      arcElement.setAttribute("inscriptionOffsetY", (inscriptionPositionYInput != null ? String.valueOf(inscriptionPositionYInput) : ""));
      

    }
    return arcElement;
  }
  
  private Element createArcPoint(String x, String y, String type, Document document, int id) {
  	Element arcPoint = null;
  	if (document != null) {
  		arcPoint = document.createElement("arcpath");
  	}
  	String pointId = String.valueOf(id);
  	if (pointId.length() < 3)
  		pointId = "0" + pointId;
  	if (pointId.length() < 3)
  		pointId = "0" + pointId; 	
  	arcPoint.setAttribute("id", pointId);
  	arcPoint.setAttribute("xCoord", x);
  	arcPoint.setAttribute("yCoord", y);
  	arcPoint.setAttribute("arcPointType", type);
  	
  	return arcPoint;
  }

  /**
   * Creates all Petri-Net Matrixes from current Petri-Net
   *
   */
  private void createMatrixes(){
    createFowardIncidenceMatrix();
    createBackwardsIncidenceMatrix();
    createIncidenceMatrix();
    createInitialMarkupMatrix();
    createCurrentMarkupMatrix();
  }

  /**
   * Creates Foward Incidence Matrix from current Petri-Net
   *
   */
  private void createFowardIncidenceMatrix(){//m
    int placeNo = 0, transitionNo = 0;
    int placeSize = placesArray.size();
    int transitionSize = transitionsArray.size();

    Arc arc = null;
    Place place = null;
    Transition transition = null;

    fowardsIncidenceMatrix = new PNMatrix(placeSize, transitionSize);

    fowardsIncidenceMatrix.setToZero();

    for(int i = 0 ; i < arcsArray.size() ; i++) {
      arc = (Arc)arcsArray.get(i);
      if(arc != null) {
        PetriNetObject pnObject = arc.getTarget();
        if(pnObject != null){
          if(pnObject instanceof Place) {
            place = (Place)pnObject;
            pnObject = arc.getSource();
            if(pnObject != null){
              if(pnObject instanceof Transition){
                transition = (Transition)pnObject;
                transitionNo = getListPosition(transition);
                placeNo = getListPosition(place);
                fowardsIncidenceMatrix.set(placeNo, transitionNo, arc.getWeight());
              }
            }
          }
        }
      }
    }
  }

  /**
   * Creates Backwards Incidence Matrix from current Petri-Net
   *
   */
  private void createBackwardsIncidenceMatrix(){//Matthew
    int placeNo = 0, transitionNo = 0;
    int placeSize = placesArray.size();
    int transitionSize = transitionsArray.size();

    Arc arc = null;
    Place place = null;
    Transition transition = null;

    backwardsIncidenceMatrix = new PNMatrix(placeSize, transitionSize);

    backwardsIncidenceMatrix.setToZero();

    for(int i = 0 ; i < arcsArray.size() ; i++) {
      arc = (Arc)arcsArray.get(i);
      if(arc != null) {
        PetriNetObject pnObject = arc.getSource();
        if(pnObject != null){
          if(pnObject instanceof Place) {
            place = (Place)pnObject;
            pnObject = arc.getTarget();
            if(pnObject != null){
              if(pnObject instanceof Transition){
                transition = (Transition)pnObject;
                transitionNo = getListPosition(transition);
                placeNo = getListPosition(place);
                backwardsIncidenceMatrix.set(placeNo, transitionNo, arc.getWeight());
              }
            }
          }
        }
      }
    }
  }

  /**
   * Creates Incidence Matrix from current Petri-Net
   *
   */
  private void createIncidenceMatrix(){
    createFowardIncidenceMatrix();
    createBackwardsIncidenceMatrix();
    incidenceMatrix = new PNMatrix(fowardsIncidenceMatrix.getArrayCopy());   
    incidenceMatrix = incidenceMatrix.minus(backwardsIncidenceMatrix);
  }

  /**
   * Creates Initial Markup Matrix from current Petri-Net
   *
   */
  private void createInitialMarkupMatrix(){
    int placeNo = 0;
    int placeSize = placesArray.size();
    initialMarkupMatrix = new int[placeSize];
    for( ; placeNo < placeSize ; placeNo++)
      initialMarkupMatrix[placeNo] = ((Place)placesArray.get(placeNo)).getInitialMarking();
  }

  /**
   * Creates Initial Markup Matrix from current Petri-Net
   *
   */
  private void createCurrentMarkupMatrix(){
    int placeNo = 0;
    int placeSize = placesArray.size();
    currentMarkupMatrix = new int[placeSize];
    for( ; placeNo < placeSize ; placeNo++)
      currentMarkupMatrix[placeNo] = ((Place)placesArray.get(placeNo)).getCurrentMarking();
  }

  /**
   * Stores Initial Markup Matrix from current Petri-Net Markup
   *
   */
  public void storeInitialMarking(){
    createMatrixes();
    int placeNo = 0;
    int placeSize = placesArray.size();
    initialMarkupMatrix = new int[placeSize];
    for( ; placeNo < placeSize ; placeNo++)
      initialMarkupMatrix[placeNo] = ((Place)placesArray.get(placeNo)).getCurrentMarking();
  }

  /**
   * Restores Initial Markup Matrix to current Petri-Net Markup
   *
   */
  public void restoreInitialMarking(){
    createMatrixes();
    int placeNo = 0;
    int placeSize = placesArray.size();
    for( ; placeNo < placeSize ; placeNo++) {
      Place place = ((Place)placesArray.get(placeNo));
      if(place != null) {
        place.setCurrentMarking(initialMarkupMatrix[placeNo]);
        setChanged();
        notifyObservers(place);
      }
    }
  }

  /**
   * Stores Current Markup
   *
   */
  public void storeState(){
    int placeNo = 0;
    int placeSize = placesArray.size();
    markupMatrixAnimationStorage = new int[placeSize];
    for( ; placeNo < placeSize ; placeNo++)
      markupMatrixAnimationStorage[placeNo] = ((Place)placesArray.get(placeNo)).getCurrentMarking();
  }

  /**
   * Restores To previous Stored Markup
   */
  public void restoreState(){
    if(markupMatrixAnimationStorage != null) {
      int placeNo = 0;
      int placeSize = placesArray.size();
      for( ; placeNo < placeSize ; placeNo++) {
        Place place = ((Place)placesArray.get(placeNo));
        if(place != null) {
          place.setCurrentMarking(markupMatrixAnimationStorage[placeNo]);
          setChanged();
          notifyObservers(place);
        }
      }
    }
  }

  /**
   * Fire a specified transition, no affect if transtions not enabled
   * @param transition Reference of specifiec Transition
   */
  public void fireTransition(Transition transition) {
    if(transition != null) {
      setEnabledTransitions();
      if(transition.isEnabled() && placesArray != null){
        int transitionNo = transitionsArray.indexOf(transition);
        for(int placeNo = 0 ; placeNo < placesArray.size() ; placeNo++) {
          ((Place)placesArray.get(placeNo)).setCurrentMarking((currentMarkupMatrix[placeNo] + incidenceMatrix.get(placeNo, transitionNo)));
        }
      }
    }
  }

  /**
   * Fire a specified transition, no affect if transtions not enabled
   * @param transitionNo Position of Transition in internal ArrayList
   */
  private void fireTransition(int transitionNo) {
    setEnabledTransitions();
    if(((Transition)transitionsArray.get(transitionNo)).isEnabled() && placesArray != null){
      for(int placeNo = 0 ; placeNo < placesArray.size() ; placeNo++) {
        ((Place)placesArray.get(placeNo)).setCurrentMarking((currentMarkupMatrix[placeNo] + incidenceMatrix.get(placeNo, transitionNo)));
      }
    }
  }

  /**
   * Fire a random transition, takes rate (probability) of Transitions into account
   */
  public Transition fireRandomTransition() {
    Transition result=null;
    setEnabledTransitions();
//    int transitionsSize = transitionsArray.size()*transitionsArray.size()*transitionsArray.size();
    int randomTransition = 0;
    int transitionNo = 0;
    double rate = 0;
    ArrayList enabledTransitions = new ArrayList();

    for(transitionNo = 0 ; transitionNo < transitionsArray.size() ; transitionNo++) {
      if(((Transition)transitionsArray.get(transitionNo)).isEnabled()) {
        rate = ((Transition)transitionsArray.get(transitionNo)).getRate();
        for(int i = 0 ; i < rate ; i++ ) {
          enabledTransitions.add(new Integer(transitionNo));
        }
      }
    }
    randomTransition = randomNumber.nextInt((enabledTransitions.size() > 0 ? enabledTransitions.size() : 1 ));
    if(randomTransition < enabledTransitions.size()) {
      if(enabledTransitions.get(randomTransition) != null) {
        int n=((Integer)enabledTransitions.get(randomTransition)).intValue();
        result=(Transition)(transitionsArray.get(n));
        fireTransition(n);
      }
    }
    resetEnabledTransitions();
    return result;
  }

  public void fireTransitionBackwards(Transition transition) {
    if(transition != null) {
      setEnabledTransitionsBackwards();
      if(transition.isEnabled() && placesArray != null){
        int transitionNo = transitionsArray.indexOf(transition);
        for(int placeNo = 0 ; placeNo < placesArray.size() ; placeNo++) {
          ((Place)placesArray.get(placeNo)).setCurrentMarking((currentMarkupMatrix[placeNo] - incidenceMatrix.get(placeNo, transitionNo)));
        }
      }
    }
  }

  private void fireTransitionBackwards(int transitionNo) {
    setEnabledTransitionsBackwards();
    if(((Transition)transitionsArray.get(transitionNo)).isEnabled() && placesArray != null){
      for(int placeNo = 0 ; placeNo < placesArray.size() ; placeNo++) {
        ((Place)placesArray.get(placeNo)).setCurrentMarking((currentMarkupMatrix[placeNo] - incidenceMatrix.get(placeNo, transitionNo)));
      }
    }
  }

  public void fireRandomTransitionBackwards() {
    setEnabledTransitionsBackwards();
    int transitionsSize = transitionsArray.size()*transitionsArray.size()*transitionsArray.size();
    int randonTransition = 0;
    do {
      randonTransition = randomNumber.nextInt(transitionsArray.size());
      transitionsSize--;
      if(transitionsSize <= 0) break;
    } while(!((Transition)transitionsArray.get(randonTransition)).isEnabled());
    fireTransitionBackwards(randonTransition);
//    System.out.println("Random Fired Transition Backwards" + ((Transition)transitionsArray.get(randonTransition)).getId());
  }

  /**
   * Determines whether all transitions are enabled and sets
   * the correct value of the enabled boolean
   */
  public void setEnabledTransitions() {
    createMatrixes();
    if(transitionsArray != null && placesArray != null) {
      for(int transitionNo = 0 ; transitionNo < transitionsArray.size() ; transitionNo++) {
        Transition transition = (Transition)transitionsArray.get(transitionNo);
        if(transition != null) {
          int test = placesArray.size();
          for(int placeNo = 0 ; placeNo < placesArray.size() ; placeNo++) {
            if(backwardsIncidenceMatrix.get(placeNo, transitionNo) <= currentMarkupMatrix[placeNo]) {
              test--;
            }
          }
          if(test <= 0) {
            transition.setEnabled(true);
            setChanged();
            notifyObservers(transition);
          } else {
            transition.setEnabled(false);
            setChanged();
            notifyObservers(transition);
          }
        }
      }
    }
  }

  public void resetEnabledTransitions() {
    createMatrixes();
    if(transitionsArray != null && placesArray != null) {
      for(int transitionNo = 0 ; transitionNo < transitionsArray.size() ; transitionNo++) {
        Transition transition = (Transition)transitionsArray.get(transitionNo);
        if(transition != null) {
          int test = placesArray.size();
          for(int placeNo = 0 ; placeNo < placesArray.size() ; placeNo++) {
            if(backwardsIncidenceMatrix.get(placeNo, transitionNo) <= currentMarkupMatrix[placeNo]) {
              test--;
            }
          }
          if(test <= 0) {
            transition.setEnabled(false);
          } else {
            transition.setEnabled(false);
          }
          setChanged();
          notifyObservers(transition);
        }
      }
    }
  }

  /**
   * Determines whether all transitions are enabled and sets
   * the correct value of the enabled boolean
   */
  public void setEnabledTransitionsBackwards() {
    createMatrixes();
    if(transitionsArray != null && placesArray != null) {
      for(int transitionNo = 0 ; transitionNo < transitionsArray.size() ; transitionNo++) {
        Transition transition = (Transition)transitionsArray.get(transitionNo);
        if(transition != null) {
          int test = placesArray.size();
          for(int placeNo = 0 ; placeNo < placesArray.size() ; placeNo++) {
            if(fowardsIncidenceMatrix.get(placeNo, transitionNo) <= currentMarkupMatrix[placeNo]) {
              test--;
            }
          }
          if(test <= 0) {
            transition.setEnabled(true);
          } else {
            transition.setEnabled(false);
          }
          setChanged();
          notifyObservers(transition);
        }
      }
    }
  }

  /**
   * Empty all attributes, turn into empty Petri-Net
   */
  public void emptyPNML() {
    pnmlName = null;
    placesArray = null;
    transitionsArray = null;
    arcsArray = null;
    tokensArray = null;
    labelsArray = null;
    arrowsArray = null;
    changeArrayList = null;
    initialMarkupMatrix = null;
    markupHistoryMatrix = null;
    fowardsIncidenceMatrix = null;
    backwardsIncidenceMatrix = null;
    incidenceMatrix = null;
    arcsMap = null;
    initializeMatrixes();
  }

  /**
   * Get position of Petri-Net Object in ArrayList of given Petri-Net Object's type
   *
   * @param pnObject PlaceTransitionObject to get the position of
   * @return Position (-1 if not present) of Petri-Net Object in ArrayList of given Petri-Net Object's type
   */
  public int getListPosition(PetriNetObject pnObject){
    if (setPetriNetObjectArrayList(pnObject))
      return changeArrayList.indexOf(pnObject);
    else
      return -1;
  }

  /**
   * Get an List of all the Place objects in the Petri-Net
   *
   * @return An List of all the Place objects
   */
  public Place[] getPlaces() {
    Place[] returnArray = new Place[placesArray.size()];

    for(int i = 0 ; i < placesArray.size() ; i++)
      returnArray[i] = (Place)placesArray.get(i);

    return returnArray;
  }

  /**
   * Get a List of all the net-level NameLabel objects in the Petri-Net
   *
   * @return A List of all the net-level (as opposed to element-specific) label objects
   */
  public AnnotationNote[] getLabels() {
  	AnnotationNote[] returnArray = new AnnotationNote[labelsArray.size()];

  	for(int i = 0 ; i < labelsArray.size() ; i++)
  		returnArray[i] = (AnnotationNote)labelsArray.get(i);

  	return returnArray;
  }
  /**
   * Get an List of all the Transition objects in the Petri-Net
   *
   * @return An List of all the Transition objects
   */
  public Transition[] getTransitions() {
//    setEnabledTransitions();
    Transition[] returnArray = new Transition[transitionsArray.size()];

    for(int i = 0 ; i < transitionsArray.size() ; i++)
      returnArray[i] = (Transition)transitionsArray.get(i);

    return returnArray;
  }

  /**
   * Get an List of all the Arcs objects in the Petri-Net
   *
   * @return An List of all the Arc objects
   */
  public Arc[] getArcs() {
    Arc[] returnArray = new Arc[arcsArray.size()];

    for(int i = 0 ; i < arcsArray.size() ; i++)
      returnArray[i] = (Arc)arcsArray.get(i);

    return returnArray;
  }

  /**
   * Return the Transition called transitionName from the Petri-Net
   *
   * @param transitionName Name of Transition object to return
   * @return The first Transition object found with a name equal to transitionName
   */
  public Transition getTransition(String transitionName) {
    Transition returnTransition = null;

    if(transitionsArray != null) {
      if(transitionName != null) {
        for(int i = 0 ; i < transitionsArray.size(); i++) {
          if(transitionName.equalsIgnoreCase(((Transition)transitionsArray.get(i)).getId())) {
            returnTransition = (Transition)transitionsArray.get(i);
          }
        }
      }
    }

    return returnTransition;
  }


  /**
   * Return the Transition called transitionName from the Petri-Net
   *
   * @param transitionNo No of Transition object to return
   * @return The Transition object
   */
  public Transition getTransition(int transitionNo) {
    Transition returnTransition = null;

    if(transitionsArray != null) {
      if(transitionNo < transitionsArray.size()) {
        returnTransition = (Transition)transitionsArray.get(transitionNo);
      }
    }

    return returnTransition;
  }

  /**
   * Return the Place called placeName from the Petri-Net
   *
   * @param placeName Name of Place object to return
   * @return The first Place object found with a name equal to placeName
   */
  public Place getPlace(String placeName) {
    Place returnPlace = null;

    if(placesArray != null) {
      if(placeName != null) {
        for(int i = 0 ; i < placesArray.size(); i++) {
          if(placeName.equalsIgnoreCase(((Place)placesArray.get(i)).getId())) {
            returnPlace = (Place)placesArray.get(i);
          }
        }
      }
    }

    return returnPlace;
  }

  /**
   * Return the Place called placeName from the Petri-Net
   *
   * @param placeNo No of Place object to return
   * @return The Place object
   */
  public Place getPlace(int placeNo) {
    Place returnPlace = null;

    if(placesArray != null) {
      if(placeNo < placesArray.size()) {
        returnPlace = (Place)placesArray.get(placeNo);
      }
    }

    return returnPlace;
  }

  /**
   * Return the Arc called arcName from the Petri-Net
   *
   * @param arcName Name of Arc object to return
   * @return The first Arc object found with a name equal to arcName
   */
  public Arc getArc(String arcName) {
    Arc returnArc = null;


    if(arcsArray != null) {
      if(arcsArray != null) {
        for(int i = 0 ; i < arcsArray.size(); i++) {
          if(arcName.equalsIgnoreCase(((Arc)arcsArray.get(i)).getId())) {
            returnArc = (Arc)arcsArray.get(i);
          }
        }
      }
    }

    return returnArc;
  }

  /**
   * Return the Arc called arcName from the Petri-Net
   *
   * @param arcName Name of Arc object to return
   * @return The first Arc object found with a name equal to arcName
   */
  public Arc getArcWithSource(PetriNetObject arcName) {
    Arc returnArc = null;

    if(arcsArray != null) {
      for(int i = 0 ; i < arcsArray.size(); i++) {
        if(arcsArray.get(i) != null) {
          Arc arc = (Arc)arcsArray.get(i);
          if(arc.getTarget() != null) {
            if(arcName.equals(arc.getSource())) {
              returnArc = arc;
            }
          }
        }
      }
    }

    return returnArc;
  }

  /**
   * Return the Arc called arcName from the Petri-Net
   *
   * @param arcName Name of Arc object to return
   * @return The first Arc object found with a name equal to arcName
   */
  public Arc getArcWithTarget(PetriNetObject arcName) {
    Arc returnArc = null;

    if(arcsArray != null) {
      for(int i = 0 ; i < arcsArray.size(); i++) {
        if(arcsArray.get(i) != null) {
          Arc arc = (Arc)arcsArray.get(i);
          if(arc.getTarget() != null) {
            if(arcName.equals(arc.getTarget())) {
              returnArc = arc;
            }
          }
        }
      }
    }

    return returnArc;
  }

  /**
   * Return the PlaceTransitionObject called ptoName from the Petri-Net
   *
   * @param ptoId Id of PlaceTransitionObject object to return
   * @return The first Arc PlaceTransitionObject found with a name equal to ptoName
   */
  public PlaceTransitionObject getPlaceTransitionObject(String ptoId) {

    if (ptoId != null) {
      if (getPlace(ptoId) != null)
        return getPlace(ptoId);
      else if (getTransition(ptoId) != null)
        return getTransition(ptoId);
    }

    return null;
  }

  /**
   * Return the Foward Incidence Matrix for the Petri-Net
   *
   * @return The Foward Incidence Matrix for the Petri-Net
   */
  public int[][] getForwardsIncidenceMatrix() {
    createFowardIncidenceMatrix();
    return (fowardsIncidenceMatrix != null ? fowardsIncidenceMatrix.getArrayCopy() : null);
  }

  /**
   * Return the Backward Incidence Matrix for the Petri-Net
   *
   * @return The Backward Incidence Matrix for the Petri-Net
   */
  public int[][] getBackwardsIncidenceMatrix() {
    createBackwardsIncidenceMatrix();
    return (backwardsIncidenceMatrix != null ? backwardsIncidenceMatrix.getArrayCopy() : null);
  }

  /**
   * Return the Incidence Matrix for the Petri-Net
   *
   * @return The Incidence Matrix for the Petri-Net
   */
  public int[][] getIncidenceMatrix() {
    createIncidenceMatrix();
    return (incidenceMatrix != null ? incidenceMatrix.getArrayCopy() : null);
  }

  /**
   * Return the Initial Markup Matrix for the Petri-Net
   *
   * @return The Initial Markup Matrix for the Petri-Net
   */
  public int[] getInitialMarkupMatrix() {
    createInitialMarkupMatrix();
    return initialMarkupMatrix;
  }

  /**
   * Return the Initial Markup Matrix for the Petri-Net
   *
   * @return The Initial Markup Matrix for the Petri-Net
   */
  public int[] getCurrentMarkupMatrix() {
    createCurrentMarkupMatrix();
    return currentMarkupMatrix;
  }

  /**
   * Return a DOM for the PNML file at URI pnmlFileName
   *
   * @param pnmlFileName URI of PNML file
   * @return A DOM for the PNML file pnmlFileName
   * @throws ParserConfigurationException
   * @throws IOException
   * @throws SAXException
   */
  public Document getDOM(String pnmlFileName)
      throws ParserConfigurationException, IOException, SAXException{

    Document document = null;

    try {

      DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
      documentBuilderFactory.setIgnoringElementContentWhitespace(true);
      // POSSIBLY ADD VALIDATING
      // documentBuilderFactory.setValidating(true);
      DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
      document = documentBuilder.parse(pnmlFileName);

    } catch (ParserConfigurationException e) {
      System.err.println("javax.xml.parsers.ParserConfigurationException thrown in getDom(String pnmlFileName) : dataLayer Class : dataLayer Package");
    }
    catch (IOException e) {
      System.err.println("ERROR: File may not be present or have the correct attributes");
      System.err.println("java.io.IOException thrown in getDom(String pnmlFileName) : dataLayer Class : dataLayer Package");
    }
    catch (SAXException e) {
      System.err.println("org.xml.sax.SAXException thrown in getDom(String pnmlFileName) : dataLayer Class : dataLayer Package");
   }

    return document;
  }

  /**
   * Return a DOM for the PNML File pnmlFile
   *
   * @param pnmlFile File Object for PNML of Petri-Net
   * @return A DOM for the File Object for PNML of Petri-Net
   * @throws ParserConfigurationException
   * @throws IOException
   * @throws SAXException
   */
  public Document getDOM(File pnmlFile)
      throws ParserConfigurationException, IOException, SAXException{

    Document document = null;

    try {

      DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
      documentBuilderFactory.setIgnoringElementContentWhitespace(true);
      // POSSIBLY ADD VALIDATING
      // documentBuilderFactory.setValidating(true);
      DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
      document = documentBuilder.parse(pnmlFile);

    } catch (ParserConfigurationException e) {
      System.err.println("javax.xml.parsers.ParserConfigurationException thrown in getDom(String pnmlFileName) : dataLayer Class : dataLayer Package");
    }
    catch (IOException e) {
      System.err.println("ERROR: File may not be present or have the correct attributes");
      System.err.println("java.io.IOException thrown in getDom(String pnmlFileName) : dataLayer Class : dataLayer Package" + e);
    }
    catch (SAXException e) {
      System.err.println("org.xml.sax.SAXException thrown in getDom(String pnmlFileName) : dataLayer Class : dataLayer Package" + e);
      System.err.println("Workaround: delete the xmlns attribute from the PNML root node.  Probably not ideal, to be fixed when time allows.");
      
     
    }

    return document;
  }

  /**
   * Return a DOM for the Petri-Net
   *
   * @return A DOM for the Petri-Net
   * @throws ParserConfigurationException
   * @throws IOException
   * @throws SAXException
   */
  public Document getDOM()
      throws ParserConfigurationException, IOException, SAXException{
    return getDOM(pnmlName);
  }

  /**
   *
   * Return a URI for the PNML file for the Petri-Net
   *
   * @return A DOM for the Petri-Net
   */
  public String getURI() {
    return pnmlName;
  }

  /** prints out a brief representation of the dataLayer object */
  public void print() {
    System.out.println("No of Places = " + placesArray.size() + "\"");
    System.out.println("No of Transitions = " + transitionsArray.size() + "\"");
    System.out.println("No of Arcs = " + arcsArray.size() + "\"");
    System.out.println("No of Labels = " + labelsArray.size() + "\" (Model View Controller Design Pattern)");
  }  
}

