/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package scriptbuilder.structures;

import java.util.Random;
import java.util.Stack;
import java.util.TreeMap;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import scriptbuilder.structures.events.*;
import scriptbuilder.structures.units.Unit;

/**
 * Script Handler class for the ScriptBuilder. Adapted from the TMCSim script
 * handler written by Matthew Cechini.
 *
 * @author Bryan McGuffin
 * @version 2017/07/03
 */
public class MyScriptHandler extends DefaultHandler
{

    /**
     * Error Logger.
     */
    private Logger myScriptLogger = Logger.getLogger("scriptbuilder.structures");

    /**
     * The script which XML entities will be entered into.
     */
    private SimulationScript script;

    /**
     * Map containing all parsed values. Keys = XML Element. Values = parsed
     * character data from XML file.
     */
    private TreeMap<ELEMENT, String> pcData;

    /**
     * Current element that we're in.
     */
    private ELEMENT currentElement;

    /**
     * Ordering of elements that we're within.
     */
    private Stack<ELEMENT> docPosition;

    /**
     * Map containing all parsed Incidents. Keys = Incident Log Number. Values =
     * Incident object.
     */
    private TreeMap<Integer, ScriptIncident> incidentMap;

    /**
     * Map containing all Units. Keys = Unit number. Values = Unit object.
     */
    private TreeMap<String, Unit> unitMap;

    /**
     * Map containing all parsed script events. Keys = XML file level. Values =
     * Event object.
     */
    private TreeMap<ELEMENT, I_ScriptEvent> eventMap;

    /**
     * Buffer used to hold parsed tag content.
     */
    private StringBuffer parsedValue = new StringBuffer();

    /**
     * *************************************************
     * ~~~~~~~~Element attribute data.~~~~~~~~
     * **************************************************
     */
    /**
     * Log number for the current ScriptEvent being parsed.
     */
    private Integer incidentLogNumber = 0;

    /**
     * File path for the current audio file.
     */
    private String audioPath = "";

    /**
     * Length in seconds of the current audio file.
     */
    private Integer audioLength = 0;

    /**
     * Category name for the current cardfile.
     */
    private String cardfileCategory = "";

    /**
     * File path for the current CHP radio file.
     */
    private String CHPRadiofile = "";

    /**
     * ID number for the current CMS data.
     */
    private String CMSID = "";

    /**
     * Type for the current CMS data.
     */
    private String CMSType = "";

    /**
     * Role played by the instructor for the current dialog line.
     */
    private String InstructorRole = "";

    /**
     * Role played by the speaker for the current dialog line.
     */
    private String LineRole = "";

    /**
     * ID number for the current location info.
     */
    private String LocationInfoID = "";

    /**
     * ID number for the current unit.
     */
    private String NewUnitNum = "";

    /**
     * ID number for the current Paramics data.
     */
    private String ParamicsID = "";

    /**
     * Title of the script.
     */
    private String TMCTitle = "";

    /**
     * Beat for the current Tow data.
     */
    private String TowBeat = "";

    /**
     * Company name for the current Tow data.
     */
    private String TowCompany = "";

    /**
     * Confirmation phone number for the current Tow data.
     */
    private String TowConfNum = "";

    /**
     * Public telephone number for the current Tow data.
     */
    private String TowPubNum = "";

    /**
     * True/false value for whether the current unit is active.
     */
    private String UnitActive = "";

    /**
     * True/false value for whether the current unit is the primary unit.
     */
    private String UnitPrimary = "";

    /**
     * Status of the current unit.
     */
    private String UnitStatus = "";

    /**
     * ID number for the current unit.
     */
    private String UnitNum = "";

    /**
     * Street address of the current witness.
     */
    private String WitnessAddress = "";

    /**
     * Name of the current witness.
     */
    private String WitnessName = "";

    /**
     * Phone number of the current witness.
     */
    private String WitnessNum = "";

    /**
     * If true, the current CAD event is not empty.
     */
    private boolean foundSubEvents = false;

    /**
     * The most recent element which contains dialog or other sub-elements.
     */
    private I_ScriptEvent trackedEvent = null;

    /**
     * Incident description for the current ScriptEvent being parsed.
     */
    private String currentIncidentDesc = "";

    /**
     * Name of the current incident.
     */
    private String currentIncName = "";

    /**
     * Time index value (in seconds) for the current ScriptEvent being parsed.
     */
    private long currentEventTime = 0;

    /**
     * Number of levels deep we are. Used for debugging.
     */
    private int sublevels = 0;

    /**
     * The incident we are currently editing.
     */
    private ScriptIncident currInc = null;

    private CadData cad = null;

    /**
     * Constructor. Initializes incident map.
     */
    public MyScriptHandler(SimulationScript s)
    {
        script = s;
        incidentMap = new TreeMap<Integer, ScriptIncident>();
        eventMap = new TreeMap<ELEMENT, I_ScriptEvent>();
        unitMap = new TreeMap<String, Unit>();
        pcData = new TreeMap<ELEMENT, String>();
        docPosition = new Stack<ELEMENT>();
    }

    /**
     * Get the list of incidents that have been parsed from the script file.
     *
     * @returns Vector of Incident objects.
     */
    public Vector<ScriptIncident> getIncidents()
    {
        return new Vector<ScriptIncident>(incidentMap.values());
    }

    /**
     * Get the list of units that have been parsed from the script file.
     *
     * @returns Vector of Unit objects.
     */
    public Vector<Unit> getUnits()
    {
        return new Vector<Unit>(unitMap.values());
    }

    /**
     * SAX Handler method. Clear incident map and reset the error flag.
     */
    @Override
    public void startDocument()
    {
        //System.out.println("STUB: Start the document");

    }

    /**
     * Clear all existing events, thereby resetting the script.
     */
    public void reset()
    {
        incidentMap.clear();
        System.out.println("STUB: Restart the document");
    }

    /**
     * SAX Handler method. Executes at the beginning of each XML element.
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes)
    {

        docPosition.push(ELEMENT.byName(qName));

        try
        {
            if (qName.equals(ELEMENT.ACTIVITY_LOG_EVALUATION.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.ACTIVITY_LOG_EVAL_EVENT));
                trackedEvent = eventMap.get(docPosition.peek());
            }
            else if (qName.equals(ELEMENT.ATMS_EVALUATION.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.ATMS_EVAL_EVENT));
                trackedEvent = eventMap.get(docPosition.peek());
            }
            else if (qName.equals(ELEMENT.AUDIO.tag))
            {
                foundSubEvents = true;
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.AUDIO_EVENT));
                try
                {
                    audioLength = Integer.parseInt(attributes.getValue("Length"));
                    audioPath = attributes.getValue("Path");
                }
                catch (Exception e)
                {
                    audioLength = 0;
                    audioPath = "";
                }
            }
            else if (qName.equals(ELEMENT.CARDFILE.tag))
            {
                try
                {
                    cardfileCategory = attributes.getValue("Category");
                }
                catch (Exception e)
                {
                    cardfileCategory = "";
                }
            }
            else if (qName.equals(ELEMENT.CAD_EVALUATION.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.CAD_EVAL_EVENT));
                trackedEvent = eventMap.get(docPosition.peek());
            }
            else if (qName.equals(ELEMENT.CAD_INCIDENT_EVENT.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.CAD_EVENT));
            }
            else if (qName.equals(ELEMENT.CCTV_INFO.tag))
            {
                foundSubEvents = true;
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.CCTV_EVENT));
            }
            else if (qName.equals(ELEMENT.CHP_RADIO.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.CHP_RADIO_EVENT));
                trackedEvent = eventMap.get(docPosition.peek());
                try
                {
                    CHPRadiofile = attributes.getValue("RadioFile");
                }
                catch (Exception e)
                {
                    CHPRadiofile = "";
                }
            }
            else if (qName.equals(ELEMENT.CMS_EVALUATION.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.CMS_EVAL_EVENT));
                trackedEvent = eventMap.get(docPosition.peek());
                try
                {
                    CMSID = attributes.getValue("cmsID");
                    CMSType = attributes.getValue("type");
                }
                catch (Exception e)
                {
                    CMSID = "";
                    CMSType = "";
                }
            }
            else if (qName.equals(ELEMENT.FACILITATOR_EVALUATION.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.FACILITATOR_EVAL_EVENT));
                trackedEvent = eventMap.get(docPosition.peek());
            }
            else if (qName.equals(ELEMENT.INSTRUCTOR.tag))
            {
                try
                {
                    InstructorRole = attributes.getValue("Role");
                }
                catch (Exception e)
                {
                    System.out.println("SERIOUS PARSING ERROR IN \'Role\'");
                    InstructorRole = "";
                }
            }
            else if (qName.equals(ELEMENT.LINE.tag))
            {
                try
                {
                    LineRole = attributes.getValue("Role");
                }
                catch (Exception e)
                {
                    LineRole = "";
                }
            }
            else if (qName.equals(ELEMENT.LOCATION_INFO.tag))
            {
                try
                {
                    LocationInfoID = attributes.getValue("ID");
                }
                catch (Exception e)
                {
                    LocationInfoID = "";
                }
            }
            else if (qName.equals(ELEMENT.MAINTENANCE_RADIO.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.MAINTENANCE_RADIO_EVENT));
            }
            else if (qName.equals(ELEMENT.NEW_UNIT.tag))
            {
                try
                {
                    NewUnitNum = attributes.getValue("UnitNum");
                }
                catch (Exception e)
                {
                    NewUnitNum = "";
                }
            }
            else if (qName.equals(ELEMENT.PARAMICS.tag))
            {
                foundSubEvents = true;
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.PARAMICS_EVENT));
                trackedEvent = eventMap.get(docPosition.peek());
                try
                {
                    ParamicsID = attributes.getValue("LocationID");
                }
                catch (Exception e)
                {
                    ParamicsID = "";
                }
            }
            else if (qName.equals(ELEMENT.RADIO_EVALUATION.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.RADIO_EVAL_EVENT));
                trackedEvent = eventMap.get(docPosition.peek());
            }
            else if (qName.equals(ELEMENT.SCRIPT_EVENT.tag))
            {
                cad = new CadData();
            }

            else if (qName.equals(ELEMENT.TMC_SCRIPT.tag))
            {
                try
                {
                    TMCTitle = attributes.getValue("title");
                }
                catch (Exception e)
                {
                    TMCTitle = "";
                }
                script.title = TMCTitle;

            }
            else if (qName.equals(ELEMENT.TMT_RADIO.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.TMT_RADIO_EVENT));
            }
            else if (qName.equals(ELEMENT.TOW.tag))
            {
                foundSubEvents = true;
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.TOW_EVENT));
                try
                {
                    TowBeat = attributes.getValue("Beat");
                    TowCompany = attributes.getValue("Company");
                    TowConfNum = attributes.getValue("ConfNum");
                    TowPubNum = attributes.getValue("PubNum");
                }
                catch (Exception e)
                {
                    TowBeat = "";
                    TowCompany = "";
                    TowConfNum = "";
                    TowPubNum = "";
                }
            }
            else if (qName.equals(ELEMENT.TELEPHONE.tag))
            {
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.TELEPHONE_EVENT));
                trackedEvent = eventMap.get(docPosition.peek());
            }
            else if (qName.equals(ELEMENT.UNIT.tag))
            {
                foundSubEvents = true;
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.UNIT_EVENT));
                try
                {
                    UnitActive = attributes.getValue("Active");
                    UnitPrimary = attributes.getValue("Primary");
                    UnitStatus = attributes.getValue("Status");
                    UnitNum = attributes.getValue("UnitNum");
                }
                catch (Exception e)
                {
                    UnitActive = "";
                    UnitPrimary = "";
                    UnitStatus = "";
                    UnitNum = "0-0";
                }
            }
            else if (qName.equals(ELEMENT.WITNESS.tag))
            {
                foundSubEvents = true;
                eventMap.put(docPosition.peek(), ScriptEvent.factoryByType(ScriptEvent.ScriptEventType.WITNESS_EVENT));
                try
                {
                    WitnessAddress = attributes.getValue("Address");
                    WitnessName = attributes.getValue("Name");
                    WitnessNum = attributes.getValue("PhoneNum");
                }
                catch (Exception e)
                {
                    WitnessAddress = "";
                    WitnessName = "";
                    WitnessNum = "";
                }
            }
            else if (qName.equals(ELEMENT.INCIDENT.tag))
            {
                try
                {
                    incidentLogNumber = Integer.parseInt(attributes.getValue(
                            "LogNum"));
                }
                catch (Exception e)
                {
                    myScriptLogger.logp(Level.SEVERE, "ScriptHandler", "startElement",
                            "Invalid LogNumber " + attributes.getValue(
                                    "LogNum"), e);
                    incidentLogNumber = 0;
                }
            }
            else if (qName.equals(ELEMENT.UNIT.tag))
            {
                try
                {
                    UnitNum = attributes.getValue("UnitNum");
                }
                catch (Exception e)
                {
                    myScriptLogger.logp(Level.SEVERE, "ScriptHandler", "startElement",
                            "Invalid Unit Number " + attributes.getValue(
                                    "UnitNum"), e);
                    UnitNum = "0-0";
                }
            }
        }
        catch (Exception e)
        {
            myScriptLogger.logp(Level.SEVERE, "ScriptHandler", "startElement",
                    "Exception in starting element <" + qName + ">.", e);
        }
    }

    /**
     * SAX Handler method. Append read characters to local buffer.
     */
    @Override
    public void characters(char[] ch, int start, int length)
    {
        String str = new String(ch, start, length).trim();
        str = str.replace("\t ", "");
        str = str.replace("\t", "");
        str = str.replace("\n ", "\n");

        parsedValue.append(str);
        if (pcData.get(docPosition.peek()) == null || pcData.get(docPosition.peek()).equals(""))
        {
            pcData.put(docPosition.peek(), str);
        }
        else
        {
            pcData.put(docPosition.peek(), "" + (pcData.get(docPosition.peek())
                    + "\n" + str));
        }
    }

    /**
     * SAX Handler method. Executes at the close of each XML element.
     */
    @Override
    public void endElement(String uri, String localName, String qName)
    {
        currentElement = docPosition.pop();
        I_ScriptEvent newEvent = null;
        try
        {
            if (currentElement == ELEMENT.ATMS_EVALUATION)
            {
                newEvent = eventMap.remove(currentElement);

                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.ACTIVITY_LOG_EVALUATION)
            {
                newEvent = eventMap.remove(currentElement);

                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.AGY && docPosition.peek() == ELEMENT.GENERAL)
            {
                cad.Agy = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.ADDRESS && docPosition.peek() == ELEMENT.LOCATION)
            {
                cad.Location_Address = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.AREA && docPosition.peek() == ELEMENT.LOCATION)
            {
                cad.Location_Area = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.BEAT && docPosition.peek() == ELEMENT.LOCATION)
            {
                cad.Location_Beat = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.CITY && docPosition.peek() == ELEMENT.LOCATION)
            {
                cad.Location_City = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.EMS && docPosition.peek() == ELEMENT.LOCATION)
            {
                cad.Location_Ems = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.FIRE && docPosition.peek() == ELEMENT.LOCATION)
            {
                cad.Location_Fire = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.LAW && docPosition.peek() == ELEMENT.LOCATION)
            {
                cad.Location_Law = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.LOC && docPosition.peek() == ELEMENT.LOCATION)
            {
                cad.Location_Loc = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.Type && docPosition.peek() == ELEMENT.HEADER_INFO)
            {
                cad.Header_Type = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.Beat && docPosition.peek() == ELEMENT.HEADER_INFO)
            {
                cad.Header_Beat = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.TruncLoc && docPosition.peek() == ELEMENT.HEADER_INFO)
            {
                cad.Header_TruncLoc = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.FullLoc && docPosition.peek() == ELEMENT.HEADER_INFO)
            {
                cad.Header_FullLoc = pcData.remove(currentElement);
            }

            else if (currentElement == ELEMENT.AUDIO)
            {
                newEvent = eventMap.remove(currentElement);
                ((AudioEvent) newEvent).audioLength = audioLength;
                ((AudioEvent) newEvent).audioPath = audioPath;
                ((AudioEvent) newEvent).length = audioLength;
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.CAD_EVALUATION)
            {
                newEvent = eventMap.remove(currentElement);

                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.CAD_INCIDENT_EVENT)
            {
                newEvent = eventMap.remove(currentElement);
                ((CADEvent) newEvent).detail = pcData.remove(ELEMENT.DETAIL);
                ((CADEvent) newEvent).hasSubEvents = foundSubEvents;
                if (null != ((CADEvent) newEvent).detail)
                {
                    if (!(((CADEvent) newEvent).detail.equals("")))
                    {
                        currInc.addNewEvent(newEvent, (int) currentEventTime);
                    }
                }
                foundSubEvents = false;
            }
            else if (currentElement == ELEMENT.CCTV_INFO)
            {
                newEvent = eventMap.remove(currentElement);
                ((CCTVEvent) newEvent).message = pcData.remove(ELEMENT.CCTV_INFO);
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.CHP_RADIO)
            {
                newEvent = eventMap.remove(currentElement);
                ((CHPRadioEvent) newEvent).radioFile = CHPRadiofile;
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }

            else if (currentElement == ELEMENT.CMS_EVALUATION)
            {
                newEvent = eventMap.remove(currentElement);
                ((CMSEvaluationEvent) newEvent).cmsID = CMSID;
                ((CMSEvaluationEvent) newEvent).cmsType = CMSType;
                if (pcData.get(ELEMENT.LOCATION) != null)
                {
                    ((CMSEvaluationEvent) newEvent).location = pcData.remove(ELEMENT.LOCATION);
                }

                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.CMS_LINE)
            {
                if (trackedEvent instanceof CMSEvaluationEvent)
                {
                    ((CMSEvaluationEvent) trackedEvent).message.add(pcData.remove(ELEMENT.CMS_LINE));
                }
            }
            else if (currentElement == ELEMENT.EXPECTED_ACTION)
            {
                if (trackedEvent instanceof I_EvaluationEvent)
                {
                    ((I_EvaluationEvent) trackedEvent).addAction(pcData.remove(ELEMENT.EXPECTED_ACTION));
                }
            }
            else if (currentElement == ELEMENT.FACILITATOR_EVALUATION)
            {
                newEvent = eventMap.remove(currentElement);

                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.INSTRUCTOR)
            {
                if (trackedEvent instanceof TelephoneEvent)
                {
                    ((TelephoneEvent) trackedEvent).lines.add(pcData.remove(ELEMENT.INSTRUCTOR));
                    ((TelephoneEvent) trackedEvent).roles.add(InstructorRole);
                }
            }
            else if (currentElement == ELEMENT.Lane_number)
            {
                if (trackedEvent instanceof ParamicsEvent)
                {
                    ((ParamicsEvent) trackedEvent).laneNums.add(Integer.parseInt(pcData.remove(ELEMENT.Lane_number)));
                }
            }
            else if (currentElement == ELEMENT.LINE)
            {
                if (trackedEvent instanceof CHPRadioEvent)
                {
                    ((CHPRadioEvent) trackedEvent).lines.add(pcData.remove(ELEMENT.LINE));
                    ((CHPRadioEvent) trackedEvent).roles.add(LineRole);
                }
            }
            else if (currentElement == ELEMENT.LOCATION_INFO)
            {
                Location_Info locInfo = new Location_Info();
                
                locInfo.Location_ID = LocationInfoID;
                locInfo.Direction = pcData.remove(ELEMENT.Direction);
                locInfo.Location_type = pcData.remove(ELEMENT.Location_type);
                locInfo.Route = pcData.remove(ELEMENT.Route);
                locInfo.Postmile = pcData.remove(ELEMENT.Postmile);
                cad.locInfo.add(locInfo);                
            }
            else if (currentElement == ELEMENT.MAINTENANCE_RADIO)
            {
                newEvent = eventMap.remove(currentElement);
                ((MaintenanceRadioEvent) newEvent).message = pcData.remove(ELEMENT.MAINTENANCE_RADIO);
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.MASTER_INC_NUM)
            {
                cad.Master_Inc_Num = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.PARAMICS)
            {
                newEvent = eventMap.remove(currentElement);
                ((ParamicsEvent) newEvent).locationID = ParamicsID;

                if (pcData.get(ELEMENT.Status) != null)
                {
                    ((ParamicsEvent) newEvent).status = pcData.remove(ELEMENT.Status);
                }
                if (pcData.get(ELEMENT.Incident_type) != null)
                {
                    ((ParamicsEvent) newEvent).type = pcData.remove(ELEMENT.Incident_type);
                }
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.RADIO_EVALUATION)
            {
                newEvent = eventMap.remove(currentElement);

                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.SCRIPT_EVENT)
            {
                currInc.insertCadData(currentEventTime, cad);
            }
            else if (currentElement == ELEMENT.STUDENT)
            {
                if (trackedEvent instanceof TelephoneEvent)
                {
                    ((TelephoneEvent) trackedEvent).lines.add(pcData.remove(ELEMENT.STUDENT));
                    ((TelephoneEvent) trackedEvent).roles.add("Student");
                }
            }
            else if (currentElement == ELEMENT.TEXT && docPosition.peek() == ELEMENT.GENERAL_INFO)
            {
                currInc.description = pcData.remove(ELEMENT.TEXT);
                cad.General_Text = currInc.description;
            }
            else if (currentElement == ELEMENT.TITLE && docPosition.peek() == ELEMENT.GENERAL_INFO)
            {
                cad.General_Title = pcData.remove(ELEMENT.TITLE);
            }
            else if (currentElement == ELEMENT.TMT_RADIO)
            {
                newEvent = eventMap.remove(currentElement);
                ((TMTRadioEvent) newEvent).message = pcData.remove(ELEMENT.TMT_RADIO);
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.TELEPHONE)
            {
                newEvent = eventMap.remove(currentElement);
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.TOW)
            {
                newEvent = eventMap.remove(currentElement);
                ((TowEvent) newEvent).towBeat = TowBeat;
                ((TowEvent) newEvent).towCompany = TowCompany;
                ((TowEvent) newEvent).towConfNum = TowConfNum;
                ((TowEvent) newEvent).towPubNum = TowPubNum;
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.TYPE && docPosition.peek() == ELEMENT.ADDITIONAL_INFO)
            {
                cad.Info_Type = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.TYPE_CODE && docPosition.peek() == ELEMENT.ADDITIONAL_INFO)
            {
                cad.Info_Type_Code = pcData.remove(currentElement);
            }
            else if (currentElement == ELEMENT.UNIT)
            {
                newEvent = eventMap.remove(currentElement);
                ((UnitEvent) newEvent).unitActive = UnitActive;
                ((UnitEvent) newEvent).unitPrimary = UnitPrimary;
                ((UnitEvent) newEvent).unitStatus = UnitStatus;
                ((UnitEvent) newEvent).unitNum = UnitNum;
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }
            else if (currentElement == ELEMENT.WITNESS)
            {
                newEvent = eventMap.remove(currentElement);
                ((WitnessEvent) newEvent).witnessAddress = WitnessAddress;
                ((WitnessEvent) newEvent).witnessName = WitnessName;
                ((WitnessEvent) newEvent).witnessNum = WitnessNum;
                currInc.addNewEvent(newEvent, (int) currentEventTime);
            }

            else if (currentElement == ELEMENT.INCIDENT)
            {
                currentIncName = parsedValue.toString();

                if (incidentMap.get(incidentLogNumber) == null)
                {
                    incidentMap.put(incidentLogNumber,
                            new ScriptIncident(SimulationScript.incidentColors[Math.abs(new Random().nextInt()) % SimulationScript.incidentColors.length],
                                    incidentLogNumber, currentIncName, currentIncidentDesc,
                                    script, (int) currentEventTime));
                }
                currInc = incidentMap.get(incidentLogNumber);

            }
            else if (currentElement == ELEMENT.NEW_UNIT)
            {
                if (unitMap.get(NewUnitNum) == null)
                {
                    Unit unit = new Unit();
                    unit.UnitNum = NewUnitNum;
                    if (pcData.containsKey(ELEMENT.AGY))
                    {
                        unit.Agy = pcData.remove(ELEMENT.AGY);
                    }
                    if (pcData.containsKey(ELEMENT.ALIAS))
                    {
                        unit.Alias = pcData.remove(ELEMENT.ALIAS);
                    }
                    if (pcData.containsKey(ELEMENT.AREA))
                    {
                        unit.Area = pcData.remove(ELEMENT.AREA);
                    }
                    if (pcData.containsKey(ELEMENT.BADGE_NUM))
                    {
                        unit.Badge_Num = pcData.remove(ELEMENT.BADGE_NUM);
                    }
                    if (pcData.containsKey(ELEMENT.CURR_LOC))
                    {
                        unit.Curr_Loc = pcData.remove(ELEMENT.CURR_LOC);
                    }
                    if (pcData.containsKey(ELEMENT.DESTINATION))
                    {
                        unit.Destination = pcData.remove(ELEMENT.DESTINATION);
                    }
                    if (pcData.containsKey(ELEMENT.ID))
                    {
                        unit.ID = pcData.remove(ELEMENT.ID);
                    }
                    if (pcData.containsKey(ELEMENT.MASTER_INC_NUM))
                    {
                        unit.Master_Inc_Num = pcData.remove(ELEMENT.MASTER_INC_NUM);
                    }
                    if (pcData.containsKey(ELEMENT.MISC_INFO))
                    {
                        unit.Misc_Info = pcData.remove(ELEMENT.MISC_INFO);
                    }
                    if (pcData.containsKey(ELEMENT.OOS))
                    {
                        unit.OOS = pcData.remove(ELEMENT.OOS);
                    }
                    if (pcData.containsKey(ELEMENT.OFFICE))
                    {
                        unit.Office = pcData.remove(ELEMENT.OFFICE);
                    }
                    if (pcData.containsKey(ELEMENT.OFFICER))
                    {
                        unit.Officer = pcData.remove(ELEMENT.OFFICER);
                    }
                    if (pcData.containsKey(ELEMENT.P))
                    {
                        unit.P = pcData.remove(ELEMENT.P);
                    }
                    if (pcData.containsKey(ELEMENT.PRIMARY))
                    {
                        unit.Primary = pcData.remove(ELEMENT.PRIMARY);
                    }
                    if (pcData.containsKey(ELEMENT.STACK))
                    {
                        unit.Stack = pcData.remove(ELEMENT.STACK);
                    }
                    if (pcData.containsKey(ELEMENT.STATUS))
                    {
                        unit.Status = pcData.remove(ELEMENT.STATUS);
                    }
                    if (pcData.containsKey(ELEMENT.TIMER))
                    {
                        unit.Timer = pcData.remove(ELEMENT.TIMER);
                    }
                    unitMap.put(NewUnitNum, unit);
                }
            }
            else if (qName.equals(ELEMENT.TIME_INDEX.tag))
            {
                currentEventTime = timeBytesToSeconds(parsedValue.toString().trim());
            }

            parsedValue.setLength(0);
            eventMap.put(currentElement, null);
        }
        catch (Exception e)
        {
            myScriptLogger.logp(Level.SEVERE, "ScriptHandler", "endElement",
                    "Exception in ending element <" + qName + ">.", e);
        }
        /*
         String t = "";
         sublevels--;
         for (int i = 0; i < sublevels; i++)
         {
         t += "\t";
         }
         System.out.println(t + "End of element " + qName);*/

    }

    /**
     * SAX Handler method. End the document and close it out.
     */
    @Override
    public void endDocument()
    {
        //System.out.println("STUB: End the document");
    }

    /**
     * Sax Handler method. Log normal errors.
     */
    @Override
    public void error(SAXParseException e)
    {
        myScriptLogger.logp(Level.SEVERE, "ScriptHandler", "error",
                "SAX Parsing error.", e);
    }

    /**
     * SAX Handler method. Log fatal errors.
     */
    @Override
    public void fatalError(SAXParseException e)
    {
        myScriptLogger.logp(Level.SEVERE, "ScriptHandler", "fatalError",
                "SAX Parsing fatal error.", e);
    }

    /**
     * SAX Handler method. Log warnings.
     */
    @Override
    public void warning(SAXParseException e)
    {
        myScriptLogger.logp(Level.SEVERE, "ScriptHandler", "warning",
                "SAX Parsing warning.", e);
    }

    /**
     * Private method to convert a time object from format HH:MM:SS to a long
     * value of the corresponding number of seconds.
     *
     * @param time String time representation of format HH:MM:SS
     * @return long Number of seconds
     * @throws StringIndexOutOfBoundsException if the input parameter is not
     * valid
     */
    private long timeBytesToSeconds(String time)
            throws StringIndexOutOfBoundsException
    {
        long seconds = 0;

        seconds = ((long) Character.digit(time.charAt(0), 10) * 36000
                + Character.digit(time.charAt(1), 10) * 3600
                + Character.digit(time.charAt(3), 10) * 600
                + Character.digit(time.charAt(4), 10) * 60
                + Character.digit(time.charAt(6), 10) * 10
                + Character.digit(time.charAt(7), 10));

        return seconds;
    }
}
