/*
  * XMLGenerator
 *
 *
 * Copyright (c) 2003 Kansas State University, Laboratory for the Specification,
 * Analysis, and Transformation of Software
 *
 * This software is licensed under the SAnToS Laboratory Open Academic License.  You
 * should have received a copy of the license with the distribution.  A copy can be
 * found at:
 * http://www.cis.ksu.edu/santos/license.html
 * or you can contact the lab at:
 * SAnToS Laboratory
 * 234 Nichols Hall
 * Manhattan, KS 66506, USA
 */
package edu.ksu.cis.cadena.xmlgen;

import edu.ksu.cis.cadena.frontend.cad.analysis.DefaultASTVisitor;
import edu.ksu.cis.cadena.frontend.cad.parser.BasicEventConnection;
import edu.ksu.cis.cadena.frontend.cad.parser.Connection;
import edu.ksu.cis.cadena.frontend.cad.parser.CorrelatedEventConnection;
import edu.ksu.cis.cadena.frontend.cad.parser.DataConnection;
import edu.ksu.cis.cadena.frontend.cad.parser.InstanceDecl;
import edu.ksu.cis.cadena.frontend.cad.parser.Location;
import edu.ksu.cis.cadena.frontend.cad.parser.NormalConnection;
import edu.ksu.cis.cadena.frontend.cad.parser.Scenario;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
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;


/**
 * This class generates Boeing OEP XML files,
 * it also depends on some property files
 *
 * @version 1.0.3 8.3.2003
 * @author Sue Li
 *
 */
public class XMLGenerator extends DefaultASTVisitor {
    private static final int DATA_AVAILABLE_EVENT_TYPE = 1000000;
    private static final int CONSUMER_TYPE = 3;

    /** maps each processer name to a list of component instances*/
    private Map boardList;

    /** maps instance name to its component type name*/
    private Map instanceToBuildingBlock;

    /** the document keeps the output information*/
    private Document document;

    /** the output file writer*/
    private PrintWriter out;

    /** the root element of the document*/
    private Element root;

    /** the properties*/
    private Properties displayProperties;

    /** the basic mode, if this is true, then output XML file looks like basicsp.xml*/
    private boolean basicMode = false;

    /** the modal mode, if this is true, then output XML file looks like modalsp.xml*/
    private boolean modalMode = false;

    /** the medium mode, if this is true, then output XML file looks like basicsp.xml*/
    private boolean mediumMode = false;

    /**
     * class constructor initializes the variables
     *
     * @param xmlfile the name of generated xml file
     * @param dis the properties
     * @throws IOException
     * @pre xmlfile != null && dis != null
     */
    public XMLGenerator(String xmlfile, Properties dis) {
        assert xmlfile != null;
        assert dis != null;

        try {
            displayProperties = dis;
            boardList = new HashMap();
            instanceToBuildingBlock = new HashMap();

            File theFile = new File(xmlfile);
            out = new PrintWriter(new BufferedWriter(new FileWriter(theFile)));
            basicMode =
                displayProperties.getProperty("mode").trim().equals("basicsp");
            modalMode =
                displayProperties.getProperty("mode").trim().equals("modalsp");
            mediumMode =
                displayProperties.getProperty("mode").trim().equals("mediumsp");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    /**
     * visits Scenario
     * @groups component based on the location, which is associated with processor element in XML file,
     * and component homes, all component instances have the same home are grouped together
     * @builds the root document and sub documents
     *
     * @see edu.ksu.cis.cadena.frontend.cad.analysis.ASTVisitor#visit(Scenario, Object)
     * @see groupComponent(Scenario)
     * @see buildDOM()
     * @see buildSubDOM(String,DataManager);
     * @param node the scenario root
     * @param input a string, but not used here
     * @return null
     */
    public Object visit(Scenario node, Object input) {
        assert node != null;
        groupComponent(node);
        buildDOM();

        for (Iterator it = node.getLocationList().iterator(); it.hasNext();) {

            String board = ((Location) it.next()).toString();
            DataManager manager = (DataManager) boardList.get(board);
            buildSubDOM(board, manager);
        }

        generateXML(out);
        out.close();

        return null;
    }

    /**
     * groups component instances based on the location, the processor element in XML file,
     * and component homes, all component instances in the same location with the same home are grouped together
     * @for those instances, whose property can't be found in property, are grouped as correlators
     *
     * @see DataManager
     * @param node the scenario
     * @pre node!=null
     */
    private void groupComponent(Scenario node) {
        assert node != null;

        for (Iterator iterator = node.getLocationList().iterator();
                iterator.hasNext();) {

            String board = ((Location) iterator.next()).toString();
            boardList.put(board, new DataManager());
        }

        for (Iterator iterator = node.getInstanceList().iterator();
                iterator.hasNext();) {

            InstanceDecl instance = (InstanceDecl) iterator.next();
            DataManager componentsManager =
                (DataManager) boardList.get(instance.getLocationString());
            String in = instance.getName();
            String temp = instance.getBuildingBlock();
            String desiredProperty =
                in + "_"
                + temp.substring(temp.lastIndexOf(":") + 1, temp.length());
            String cn = displayProperties.getProperty(desiredProperty);

            if (cn != null) {
                cn = cn.trim();
            } else {
                System.err.println("Unable to find property \""
                    + desiredProperty + "\" in properties file.");

                return;
            }

            if (cn.startsWith("!")) {
                //correlator components, which should not appear in XML file
                componentsManager.correlators().put(in, instance);
            } else if (!cn.equals("EventChannel")) {
                instanceToBuildingBlock.put(in, cn);

                if (!componentsManager.homeToComponents().containsKey(cn)) {
       
                    List inList = new ArrayList();
                    inList.add(instance);
                    componentsManager.homeToComponents().put(cn, inList);
                } else {
       
                    List inList =
                        (List) componentsManager.homeToComponents().get(cn);
                    inList.add(instance);
                    componentsManager.homeToComponents().put(cn, inList);
                }
            }
        }
    }

    /**
     * generates the Document and root element, CONFIGURATION
     */
    private void buildDOM() {
       
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            document = builder.newDocument(); // Create from whole cloth
        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();
        }

        root = (Element) document.createElement("CONFIGURATION");
        document.appendChild(root);
    }

    /**
     * creates the Processor Node and starts to build its children
     *
     * @see buildProcessor(Element, DataManager)
     * @param processorName the name of the processor
     * @param manager the DataManager on this processName
     */
    private void buildSubDOM(String processorName, DataManager manager) {
        assert processorName != null;
        assert manager != null;
       
        Element processor = (Element) document.createElement("PROCESSOR");
        root.appendChild(processor);

        Element pName = (Element) document.createElement("NAME");
        pName.appendChild(document.createTextNode(processorName));
        processor.appendChild(pName);
        buildProcessor(processor, manager);
    }

    /**
     * builds Processor element,
     * includes dist_proxy, dist_master, receptacles, event_supplier, event_trigger, interval_timeout, and internal_lock
     *
     * @see writeMasterProxy(InstanceDecl, Element)
     * @see writeReceptacles(InstanceDecl,Element)
     * @see writeEventSupplier(InstanceDecl,Element)
     * @see writeEventTriggersAndTimeout(InstanceDecl,Element,DataManager)
     *
     * @param processor the Processor node
     * @param manager the DataManager on a processor
     * @return Element processor node
     */
    private Element buildProcessor(Element processor, DataManager manager) {
        assert processor != null;
        assert manager != null;
       
        for (Iterator iterator = manager.homeToComponents().keySet().iterator();
                iterator.hasNext();) {
       
            String cn = ((String) iterator.next());
            Element home = (Element) document.createElement("HOME");
            processor.appendChild(home);

            Element ht = (Element) document.createElement("HOME_TYPE");

            if (displayProperties.getProperty(cn) == null) {
                System.err.println("Unable to find property \"" + cn
                    + "\" in properties file.");
       
                return null;
            }

            String nn = displayProperties.getProperty(cn).trim();
            ht.appendChild(document.createTextNode(nn));
            home.appendChild(ht);

            Element hid = buildIDElement(nn);
            home.appendChild(hid);

            for (Iterator it =
                    ((List) manager.homeToComponents().get(cn)).iterator();
                    it.hasNext();) {
       
                InstanceDecl instance = (InstanceDecl) it.next();
                String iName = (String) instance.getName();
                Element com = (Element) document.createElement("COMPONENT");
                home.appendChild(com);

                if (displayProperties.getProperty(iName) == null) {
                    System.err.println("Unable to find property \"" + iName
                        + "\" in properties file.");
       
                    return null;
                }


                Element cid =
                    buildIDElement(displayProperties.getProperty(iName).trim());
                com.appendChild(cid);

                //write dist_proxy and dist_master
                writeMasterProxy(instance, com);

                //write receptacles
                writeReceptacles(instance, com);

                //event suppliers
                writeEventSupplier(instance, com);

                //event triggers and interval timeout
                writeEventTriggersAndTimeout(instance, com, manager);

                //correlated event triggers only for ModalSP
                for (Iterator iter = instance.getConnections().iterator();
                        iter.hasNext();) {

                    Connection c = (Connection) iter.next();

                    if (c instanceof CorrelatedEventConnection) {

                        if (iName.equals("NavDisplay") && modalMode) {
                            buildEventConsumerForNavDisplay(com);
                        } else {
                        }
                    }
                }

                //internal lock
                addInternalLock(com);
            }
        }

        return processor;
    }

    /**
     * visits DataConnection, writes receptacle element
     *
     * @see edu.ksu.cis.cadena.frontend.cad.analysis.ASTVisitor#visit(DataConnection, Object)
     * @param node the DataConnection
     * @param input the owner of this DataConnection
     *
     * @return Element if this DataConnection makes a receptacle
     * @else retun null
     */
    public Object visit(DataConnection node, Object input) {
        assert node != null;
        assert (input instanceof InstanceDecl) && (input != null);

        String iName = ((InstanceDecl) input).getName();

        if (!(iName.equals(node.getToInstance().getName()))) {

            String name = node.getToInstance().getName();
            Element rcp = (Element) document.createElement("RECEPTACLE");
            Element rhid = (Element) document.createElement("HOME_ID");
            String rcn = ((String) instanceToBuildingBlock.get(name)).trim();

            if (displayProperties.getProperty(rcn) == null) {
                System.err.println("Unable to find property \"" + rcn
                    + "\" in properties file.");

                return null;
            }

            rcn = displayProperties.getProperty(rcn).trim();

            Element rhidid = buildIDElement(rcn);
            rhid.appendChild(rhidid);
            rcp.appendChild(rhid);

            if (displayProperties.getProperty(name) == null) {
                System.err.println("Unable to find property \"" + name
                    + "\" in properties file.");

                return null;
            }

            //component_id node
            Element rcid = (Element) document.createElement("COMPONENT_ID");
            Element rcidid =
                buildIDElement(displayProperties.getProperty(name).trim());
            rcid.appendChild(rcidid);
            rcp.appendChild(rcid);

            return rcp;
        }

        return null;
    }

    /**
     * visits BasicEventConnection, writes event_supplier element
     *
     * @see edu.ksu.cis.cadena.frontend.cad.analysis.ASTVisitor#visit(BasicEventConnection, Object)
     * @param node the BasicEventConnection
     * @param input the owner of this BasicEventConnection
     * @return Element if this BasicEventConnection makes an event_supplier
     * @else retun null
     */
    public Object visit(BasicEventConnection node, Object input) {
        assert node != null;
        assert (input instanceof InstanceDecl) && (input != null);

        String iName = ((InstanceDecl) input).getName();

        if (iName.equals(node.getFromInstance().getName())) {
            
            Element es = (Element) document.createElement("EVENT_SUPPLIER");
            Element eset = (Element) document.createElement("EVENT_SET");
            es.appendChild(eset);

            Element event = (Element) document.createElement("EVENT");
            event.appendChild(document.createComment(node.getType()));

            Element et = (Element) document.createElement("EVENT_TYPE");
            event.appendChild(et);
            et.appendChild(document.createTextNode(Integer.toString(
                        DATA_AVAILABLE_EVENT_TYPE)));
            eset.appendChild(event);

            return es;
        }

        return null;
    }

    /**
     * visits CorrelatedEventConnection
     *
     * @see edu.ksu.cis.cadena.frontend.cad.analysis.ASTVisitor#visit(BasicEventConnection, Object)
     * @param node the CorrelatedEventConnection
     * @param input the owner of this connection
     * @return Element if this CorrelatedEventConnection is a consumer
     * @else return null
     */
    public Object visit(CorrelatedEventConnection node, Object input) {
        assert node != null;
        assert (input instanceof InstanceDecl) && (input != null);
        
        if (node.isIncoming()) {
        
            Element es = (Element) document.createElement("EVENT_SUPPLIER");
            Element eset = (Element) document.createElement("EVENT_SET");
            es.appendChild(eset);

            Element event = (Element) document.createElement("EVENT");
            event.appendChild(document.createComment(node.getType()));

            Element et = (Element) document.createElement("EVENT_TYPE");
            event.appendChild(et);
            et.appendChild(document.createTextNode(Integer.toString(
                        DATA_AVAILABLE_EVENT_TYPE)));
            eset.appendChild(event);

            return es;
        }

        return null;
    }

    /**
     * writes dist_master or dist_proxy element if some connections are made though "ReplicateService"
     *
     * @see writeProxyConnection(List,Element,String)
     * @see writeMasterConnection(List,Element,String)
     * @param instance the Component instance
     * @param com the node where the master and proxy are added
     */
    private void writeMasterProxy(InstanceDecl instance, Element com) {
        assert instance != null;
        assert com != null;

        List proxyConnection = new ArrayList();
        List masterConnection = new ArrayList();
        String iName = (String) instance.getName();

        for (Iterator iter = instance.getConnections().iterator();
                iter.hasNext();) {

            Connection c = (Connection) iter.next();

            if (c.hasThrough()
                    && c.getThrough().trim().equals("ReplicateService")) {

                if (iName.equals(((NormalConnection) c).getFromInstance()
                                      .getName())) {

                    if (((NormalConnection) c).getFromRole() == Connection.MASTER) {
                        masterConnection.add(c);
                    } else {
                        proxyConnection.add(c);
                    }
                } else {

                    if (((NormalConnection) c).getFromRole() == Connection.MASTER) {
                        proxyConnection.add(c);
                    } else {
                        masterConnection.add(c);
                    }
                }
            }
        }

        if (proxyConnection.size() != 0) {
            writeProxyConnection(proxyConnection, com, iName);
        }

        if (masterConnection.size() != 0) {
            writeMasterConnection(masterConnection, com, iName);
        }
    }

    /**
     * builds the receptacle element
     *
     * @see apply(DataConnection, Object)
     * @param instance the component instance
     * @param com the node where the receptacle is added
     */
    private void writeReceptacles(InstanceDecl instance, Element com) {
        assert instance != null;
        assert com != null;
    
        for (Iterator iter = instance.getConnections().iterator();
                iter.hasNext();) {
    
            Connection c = (Connection) iter.next();
            boolean pureDataConnection =
                (!c.hasThrough())
                || (!c.getThrough().trim().equals("ReplicateService"));

            if (c instanceof DataConnection && pureDataConnection) {
    
                Element receptacle =
                    (Element) ((DataConnection) c).apply(this, instance);

                if (receptacle != null) {
                    com.appendChild(receptacle);
                }
            }
        }
    }

    /**
     * builds the event supplier element
     *
     * @see apply(BasicEventConnection, Object)
     * @see apply(CorrelatedEventConnection, Object)
     * @param instance the component instance
     * @param com the node where the event supplier element is added
     */
    private void writeEventSupplier(InstanceDecl instance, Element com) {
        assert instance != null;
        assert com != null;
    
        boolean skip = false;

        for (Iterator iter = instance.getConnections().iterator();
                iter.hasNext();) {
    
            Connection c = (Connection) iter.next();
            boolean pureBasicEventConnection =
                (!c.hasThrough())
                || (!c.getThrough().trim().equals("ReplicateService"));

            if (c instanceof BasicEventConnection && pureBasicEventConnection) {
    
                Element supplier = (Element) c.apply(this, instance);

                if (supplier != null) {
                    com.appendChild(supplier);
                    skip = true;
                }
            }

            if (skip) {
                 break;
            }
        }

        if (!skip) {
    
            for (Iterator iter = instance.getConnections().iterator();
                    iter.hasNext();) {
    
                Connection c = (Connection) iter.next();

                if (c instanceof CorrelatedEventConnection) {
    
                    Element supplier = (Element) c.apply(this, instance);

                    if (supplier != null) {
                        com.appendChild(supplier);
                        skip = true;
                    }
                }

                if (skip) {
                    break;
                }
            }
        }
    }

    /**
     * builds the EventTrigger and TimeOut elements
     * @if this instance connects to a correlator, then builds the event_trigger for a CorrelatedEventConnection
     * and sets the value of EVENT_CORRELATION true
     * @else group the connection by basic event or timeout event, and builds the basic event trigger and interlval_timeout
     *
     * @see buildEventConsumerForCorrelation(InstanceDecl, Element)
     * @see buildBasicEventConsumer(List,Element)
     *
     * @param instance the component instance
     * @param com the node where the EventTrigger and TimeOut is added
     * @param manager the DataManager of this component instance
     */
    private void writeEventTriggersAndTimeout(InstanceDecl instance,
        Element com, DataManager manager) {
        assert instance != null;
        assert com != null;
        assert manager != null;
   
        List basicList = new ArrayList();
        List timeOutList = new ArrayList();

        for (Iterator iter = instance.getConnections().iterator();
                iter.hasNext();) {
         
            Connection c = (Connection) iter.next();

            if (c instanceof BasicEventConnection) {
              
                String syn; //synginazation

                if (((BasicEventConnection) c).isSynchronously()) {
                    syn = "1"; //ERM_EVENT
                } else {
                    syn = "3"; //FULL_EVENT
                }

               String fromName =
                    ((BasicEventConnection) c).getFromInstance().getName();

                if (displayProperties.getProperty(fromName) == null) {
                    System.err.println("Unable to find property \"" + fromName
                        + "\" in properties file.");

                    return;
                }

                if ((displayProperties.getProperty(fromName).startsWith("!"))
                        && !fromName.equals("EventChannel")) { //this instance is a correlator, not a normal one

                    InstanceDecl decl =
                        (InstanceDecl) (manager.correlators()).get(fromName);
                    Element eventCon =
                        (Element) document.createElement("EVENT_TRIGGER");
                    Element eset =
                        (Element) document.createElement("EVENT_SET");
                    eventCon.appendChild(eset);

                    for (Iterator deit = decl.getConnections().iterator();
                            deit.hasNext();) {
                       
                        Connection con = (Connection) deit.next();

                        if (fromName.equals(((BasicEventConnection) con).getToInstance()
                                                 .getName())) {
                            buildEventConsumerForCorrelation(((BasicEventConnection) con)
                                .getFromInstance(), eset);
                        }
                    }

                    
                    Element evec =
                        (Element) document.createElement("EVENT_CORRELATION");
                    evec.appendChild(document.createTextNode("TRUE"));
                    eventCon.appendChild(evec);

                    if (syn.equals("3")) {
                        eventCon.appendChild(document.createComment(
                                "FULL CHANNEL"));
                    } else {
                        eventCon.appendChild(document.createComment(
                                "ERM CHANNEL"));
                    }

                   
                    Element cont =
                        (Element) document.createElement("CONSUMER_TYPE");
                    cont.appendChild(document.createTextNode(Integer.toString(
                                CONSUMER_TYPE)));
                    eventCon.appendChild(cont);
                    com.appendChild(eventCon);
                } else if (!(((String) instance.getName()).equals(
                            ((BasicEventConnection) c).getFromInstance()
                                 .getName()))) {
                 
                    String type =
                        ((BasicEventConnection) c).getFromInstance()
                         .getBuildingBlock();
                    type =
                        type.substring(type.lastIndexOf(":") + 1, type.length());

                    if (!type.equals("EventChannel")) {
                        basicList.add(c);
                    } else {
                        timeOutList.add(c);
                    }
                }
            }
        }

        if (basicList.size() != 0) {
            buildBasicEventConsumer(basicList, com);
        }

        //interval timeout
        for (Iterator iter = timeOutList.iterator(); iter.hasNext();) {

            BasicEventConnection act = (BasicEventConnection) iter.next();
            Element internalTm =
                (Element) document.createElement("INTERVAL_TIMEOUT");
            int freq = act.getRate();
            internalTm.appendChild(document.createTextNode(Integer.toString(
                        1000000 / freq)));
            com.appendChild(internalTm);
        }
    }

    /**
     * builds the event consumer element for CorrelatedEventConnection
     * @param ce the component instance
     * @param com the node where this event consumer is added
     */
    private void buildEventConsumerForCorrelation(InstanceDecl ce, Element com) {
        assert ce != null;
        assert com != null;

        Element event = (Element) document.createElement("EVENT");
        Element cid = buildIDElement(((InstanceDecl) ce).getName().toUpperCase());    /**** This is the bug place ****/
        event.appendChild(cid);
        event.appendChild(document.createComment("DATA AVAILABLE"));

        Element et = (Element) document.createElement("EVENT_TYPE");
        et.appendChild(document.createTextNode(Integer.toString(
                    DATA_AVAILABLE_EVENT_TYPE)));
        event.appendChild(et);
        com.appendChild(event);
    }

    /**
     * writes the internal_lock node
     * @param com the node where the internal lock element is added
     */
    private void addInternalLock(Element com) {
        assert com != null;

        Element internalLock =
            (Element) document.createElement("INTERNAL_LOCK");
        Element lockType = (Element) document.createElement("LOCK_TYPE");
        lockType.appendChild(document.createTextNode("2"));
        internalLock.appendChild(lockType);
        com.appendChild(internalLock);
    }

    /**
     * builds the proxy node for the proxy connections
     * @param proxy the list of the proxy connections
     * @param com the node where the proxies added
     * @param instanceName the name of the instance of the proxy connections
     */
    private void writeProxyConnection(List proxy, Element com,
        String instanceName) {
        assert (proxy != null) && (proxy.size() > 0);
        assert com != null;
        assert instanceName != null;

        for (Iterator iter = proxy.iterator(); iter.hasNext();) {

            NormalConnection c = (NormalConnection) iter.next();
            String masterName = c.getFromInstance().getName();

            if (instanceName.equals(c.getFromInstance().getName())) {
                masterName = c.getToInstance().getName();
            }


            Element distProxy = (Element) document.createElement("DIST_PROXY");
            Element masterID = (Element) document.createElement("MASTER_ID");
            Element id = (Element) document.createElement("ID");
            Element name = (Element) document.createElement("NAME");

            if (displayProperties.getProperty(masterName) == null) {
                System.err.println("Unable to find property \"" + masterName
                    + "\" in properties file.");

                return;
            }

            name.appendChild(document.createTextNode(displayProperties.getProperty(
                        masterName).trim()));
            id.appendChild(name);
            masterID.appendChild(id);
            distProxy.appendChild(masterID);

            Element replication =
                (Element) document.createElement("REPLICATION");
            Element dynamic = (Element) document.createElement("DYNAMIC");
            dynamic.appendChild(document.createTextNode("1"));
            replication.appendChild(dynamic);
            distProxy.appendChild(replication);

            Element distWrite = (Element) document.createElement("DIST_WRITE");
            distProxy.appendChild(distWrite);
            com.appendChild(distProxy);
        }
    }

    /**
     * builds the master node for the master connections
     * @param master the list of the master connections
     * @param com the node where the masters added
     * @param instanceName the name of the instance of the master connections
     */
    private void writeMasterConnection(List master, Element com,
        String instanceName) {
        assert (master != null) && (master.size() > 0);
        assert com != null;
        assert instanceName != null;

        for (Iterator iter = master.iterator(); iter.hasNext();) {

            NormalConnection c = (NormalConnection) iter.next();
            Element distMaster =
                (Element) document.createElement("DIST_MASTER");
            Element replication =
                (Element) document.createElement("REPLICATION");
            Element dynamic = (Element) document.createElement("DYNAMIC");
            dynamic.appendChild(document.createTextNode("1"));

            Element eventSet = (Element) document.createElement("EVENT_SET");
            Element event = (Element) document.createElement("EVENT");
            Element eventType = (Element) document.createElement("EVENT_TYPE");
            eventType.appendChild(document.createTextNode("1000000"));
            event.appendChild(document.createComment("ERM CONSUMER")); //?????
            event.appendChild(eventType);
            eventSet.appendChild(event);
            replication.appendChild(dynamic);
            replication.appendChild(eventSet);
            distMaster.appendChild(replication);

            Element distWrite = (Element) document.createElement("DIST_WRITE");
            distMaster.appendChild(distWrite);
            com.appendChild(distMaster);
        }
    }

    /**
     * builds the event_trigger for a list of basicEventConnection
     * @sets the value of EVENT_CORRELATION false
     *
     * @param ce list of BasicEventConnections
     * @param com the node where the event consumer is added
     */
    private void buildBasicEventConsumer(List ce, Element com) {
        assert (ce != null) && (ce.size() > 0);
        assert com != null;

        Element eventCon = (Element) document.createElement("EVENT_TRIGGER");
        Element eset = (Element) document.createElement("EVENT_SET");
        eventCon.appendChild(eset);

        String syn = "";

        for (Iterator oit = ce.iterator(); oit.hasNext();) {

            Object act = oit.next();
            InstanceDecl ins = ((BasicEventConnection) act).getFromInstance();
            buildEventConsumerForBasicEvent(ins, eset,
                ((BasicEventConnection) act));

            if (((BasicEventConnection) act).isSynchronously()) {
                syn = "1"; //ERM_EVENT
            } else {
                syn = "3"; //FULL_EVENT
            }
        }

        if (!basicMode) { //basicsp scenario does not have this node

            Element eventPortImpl =
                (Element) document.createElement("EVENT_PORT_IMPL");

            if (syn.equals("3")) {
                eventCon.appendChild(document.createComment("FULL CHANNEL"));
                eventPortImpl.appendChild(document.createTextNode("FULL_EVENT"));
            } else {
                eventCon.appendChild(document.createComment("ERM CHANNEL"));
                eventPortImpl.appendChild(document.createTextNode("ERM_EVENT"));
            }

            eventCon.appendChild(eventPortImpl);
        }


        Element evec = (Element) document.createElement("EVENT_CORRELATION");
        evec.appendChild(document.createTextNode("FALSE"));
        eventCon.appendChild(evec);
        com.appendChild(eventCon);
    }

    /**
     * builds the inter part of event consumer for BasicEventConnecions
     * @param ce the component instance
     * @param com the node where the EventConsumer element is added
     * @param connection the connection for the event consumer
     */
    private void buildEventConsumerForBasicEvent(InstanceDecl ce, Element com,
        Connection connection) {
        assert ce != null;
        assert com != null;
        assert connection != null;

        Element event = (Element) document.createElement("EVENT");
        event.appendChild(document.createComment(connection.getType()));

        Element et = (Element) document.createElement("EVENT_TYPE");
        et.appendChild(document.createTextNode(Integer.toString(
                    DATA_AVAILABLE_EVENT_TYPE)));
        event.appendChild(et);

        if (displayProperties.getProperty(((InstanceDecl) ce).getName()) == null) {
            System.err.println("Unable to find property \""
                + ((InstanceDecl) ce).getName() + "\" in properties file.");

            return;
        }

        Element cid =
            buildIDElementSupplier(displayProperties.getProperty(
                    ((InstanceDecl) ce).getName()).trim());
        event.appendChild(cid);
        com.appendChild(event);
    }

    /*private void buildCorrelatedEventConsumer(List corr, Element com){
          }*/

    /**
     * builds the ID element, includes Name node
     * @param name the name of component instance
     * @return the DOM element node of id
     */
    private Element buildIDElement(String name) {
        assert name != null;

        Element id = (Element) document.createElement("ID");
        Element nm = (Element) document.createElement("NAME");
        nm.appendChild(document.createTextNode(name));
        id.appendChild(nm);

        return id;
    }

    /**
     * builds supplier_id element, includes ID and Name nodes
     *
     * @param name the name of the supplier
     * @return Element supplier_id Element
     * @pre name != null
     * @post supplierID != null
     */
    private Element buildIDElementSupplier(String name) {
        assert name != null;
        assert !name.equals("");

        Element supplierID = (Element) document.createElement("SUPPLIER_ID");
        Element id = (Element) document.createElement("ID");
        Element nm = (Element) document.createElement("NAME");
        nm.appendChild(document.createTextNode(name));
        id.appendChild(nm);
        supplierID.appendChild(id);
        assert supplierID != null;

        return supplierID;
    }

    /**
          * translates the document into XML file
          *
          * @throws TransformerConfigurationException
          * @throws TransformerException
          *
          * @param out the output file
          */
    private void generateXML(PrintWriter out) {
        assert out != null;

        TransformerFactory tFactory = TransformerFactory.newInstance();

        try {
            Transformer transformer = tFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");

            //set the output indent true	
            DOMSource source = new DOMSource(document);
            StreamResult result = new StreamResult(out);
            transformer.transform(source, result);
        } catch (TransformerConfigurationException tce) {
            System.out.println("* Transformer Factory error");
            System.out.println("* " + tce.getMessage());

            // Use the contained exception, if any	
            Throwable x = tce;

            if (tce.getException() != null) {
                x = tce.getException();
            }

            x.printStackTrace();
        } catch (TransformerException te) {
            // Error generated by the parser	
            System.out.println("* Transformation error");
            System.out.println("  " + te.getMessage());

            // Use the contained exception, if any	
            Throwable x = te;

            if (te.getException() != null) {
                x = te.getException();
            }

            x.printStackTrace();
        }
    }

    /**
     * builds the event consumer part for NavDisplay component of ModalSP scenario,
     * because not all correlation information is available in scenario file,
     * hard code is used
     * @param com the node where the to be generated elemenet is added on
     */
    private void buildEventConsumerForNavDisplay(Element com) {
        assert com != null;

        Element correlation1 =
            (Element) document.createElement("EVENT_CORRELATION");
        correlation1.appendChild(document.createTextNode("TRUE"));

        Element eventPortImpl =
            (Element) document.createElement("EVENT_PORT_IMPL");
        eventPortImpl.appendChild(document.createTextNode("FULL_EVENT"));

        Element correlation =
            (Element) document.createElement("EVENT_CORRELATION");
        correlation.appendChild(document.createTextNode("TRUE"));

        Element eventPort = (Element) document.createElement("EVENT_PORT_IMPL");
        eventPort.appendChild(document.createTextNode("FULL_EVENT"));

        Element eventCon1 = (Element) document.createElement("EVENT_TRIGGER");
        com.appendChild(eventCon1);

        Element eset1 = (Element) document.createElement("EVENT_SET");
        eventCon1.appendChild(eset1);

        Element event1 = (Element) document.createElement("EVENT");
        eset1.appendChild(event1);
        event1.appendChild(document.createComment("DATA AVAILABLE"));

        Element et1 = (Element) document.createElement("EVENT_TYPE");
        et1.appendChild(document.createTextNode(Integer.toString(
                    DATA_AVAILABLE_EVENT_TYPE)));
        event1.appendChild(et1);

        Element id1 = buildIDElementSupplier("AIRFRAME");
        event1.appendChild(id1);

        Element event11 = (Element) document.createElement("EVENT");
        eset1.appendChild(event11);
        event11.appendChild(document.createComment("DATA AVAILABLE"));

        Element et11 = (Element) document.createElement("EVENT_TYPE");
        et11.appendChild(document.createTextNode(Integer.toString(
                    DATA_AVAILABLE_EVENT_TYPE)));
        event11.appendChild(et11);

        Element id11 = buildIDElementSupplier("NAV_STEERING");
        event11.appendChild(id11);
        eventCon1.appendChild(document.createComment("FULL CHANNEL"));
        eventCon1.appendChild(eventPortImpl);
        eventCon1.appendChild(correlation1);

        Element eventCon2 = (Element) document.createElement("EVENT_TRIGGER");
        com.appendChild(eventCon2);

        Element eset2 = (Element) document.createElement("EVENT_SET");
        eventCon2.appendChild(eset2);

        Element event2 = (Element) document.createElement("EVENT");
        eset2.appendChild(event2);
        event2.appendChild(document.createComment("DATA AVAILABLE"));

        Element et2 = (Element) document.createElement("EVENT_TYPE");
        et2.appendChild(document.createTextNode(Integer.toString(
                    DATA_AVAILABLE_EVENT_TYPE)));
        event2.appendChild(et2);

        Element id2 = buildIDElementSupplier("AIRFRAME");
        event2.appendChild(id2);

        Element event22 = (Element) document.createElement("EVENT");
        eset2.appendChild(event22);
        event22.appendChild(document.createComment("DATA AVAILABLE"));

        Element et22 = (Element) document.createElement("EVENT_TYPE");
        et22.appendChild(document.createTextNode(Integer.toString(
                    DATA_AVAILABLE_EVENT_TYPE)));
        event22.appendChild(et22);

        Element id22 = buildIDElementSupplier("TACTICAL_STEERING");
        event22.appendChild(id22);
        eventCon2.appendChild(document.createComment("FULL CHANNEL"));
        eventCon2.appendChild(eventPort);
        eventCon2.appendChild(correlation);
    }
}


syntax highlighted by Code2HTML, v. 0.9.1