/*******************************************************************************
 * Copyright (c) 2003 Hyades project.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;

import org.eclipse.hyades.logging.events.cbe.CommonBaseEvent;
import org.eclipse.hyades.logging.events.cbe.ReportSituation;
import org.eclipse.hyades.logging.events.cbe.Situation;
import org.eclipse.hyades.logging.events.cbe.ComponentIdentification;
import org.eclipse.hyades.logging.parsers.LogParserException;
import org.eclipse.hyades.logging.parsers.Parser;

/**
 * A simple parser created to illustrate how one can create their own
 * parsers for a given log file.
 */
public class MyParser extends Parser {

    /* The version of the software used to generate the log file */
    private String productVersion = null;

    /* The release (eg. Alpha, Beta, etc..) of the software used to generate the log file */
    private String productRelease = null;

    /* The source ID (which is simply the concatenation of the release and the version of the 
       software used to generate the log file) */
    private String sourceID = null;

    /* The following field holds the creationTime of the previous log record */
    //NOTE:  MUST be initialized to an empty string (e.g. ""):
    private String previousCreationTime = "";

    /* Store the message count */
    private int messageCounter = 0;

    /* Keys for the product version & the product release */
    private final static String PRODUCT_VERSION_KEY = "PRODUCT_VERSION";
    private final static String PRODUCT_RELEASE_KEY = "PRODUCT_RELEASE";

    /* The following method is invoked right after the user clicks on the 'finish' button in the 
     * import wizard page. This method sets the appropriate fields based on the user's input */
    public void setUserInput(Hashtable table) throws LogParserException {

        /* The following line of code sets file_path to the path that has been chosen by the user */
        super.setUserInput(table);

        /* Store the product version and the product release */
        productVersion = ((String) (table.get(PRODUCT_VERSION_KEY)));
        productRelease = ((String) (table.get(PRODUCT_RELEASE_KEY)));

        /* Create the sourceID */
        if (productRelease != null) {

            if (productVersion != null) {
                sourceID = productRelease.concat(" ").concat(productVersion);
            }
            else {
                sourceID = productRelease;
            }
        }
    }

    /**
     * The following method is invoked right after setUserInput(Hashtable) in order 
     * to parse the log file.  Parses each log record and produces a Common Base 
     * Event (CBE) object that is returned as a member of a CBE array.
     *
     * @return ICommonBaseEvent[] array of CBE's representing parsed records.  
     * @exception LogParserException thrown if the parser is unable to parse the log
     */
    public CommonBaseEvent[] parseNext() throws LogParserException {

        CommonBaseEvent[] temp = null;

        arrayIndex = 0;

        /* Attempting to parse the log file */
        try {

            //Iterate all the lines (e.g. until EOF/null line) within the file:
            while ((curLine = readLine()) != null) {

                //Trim leading/trailing whitespace from the current line:
                curLine = curLine.trim();

                /* Go to the next line if the current line does not begin with "##" */
                if ((curLine.length() > 0) && (curLine.charAt(0) == '#') && (curLine.charAt(1) == '#')) {

                    //(Re)initialize the CBE:
                    reinitializeCBE();

                    int lessThanIndex = curLine.indexOf('<');
                    int greaterThanIndex = curLine.indexOf('>', lessThanIndex);

                    /* Find the severity of the log record */
                    String severity = curLine.substring((lessThanIndex + 1), greaterThanIndex).trim();

                    if (severity.equals("Information"))
                        messages[arrayIndex].setSeverity(((short) (10)));
                    else if (severity.equals("Error"))
                        messages[arrayIndex].setSeverity(((short) (50)));
                    else if (severity.equals("Warning"))
                        messages[arrayIndex].setSeverity(((short) (30)));

                    lessThanIndex = curLine.indexOf('<', greaterThanIndex);
                    greaterThanIndex = curLine.indexOf('>', lessThanIndex);

                    /* Find the creation time of the log record */
                    String creationTime = findCreationTime(lessThanIndex, greaterThanIndex);
                    messages[arrayIndex].setCreationTime(creationTime);

                    /* Find the message count and the unique ID of the log record */
                    if (previousCreationTime.equals(creationTime)) {
                        messages[arrayIndex].setSequenceNumber(((short) (messageCounter++)));
                    }
                    else {
                        messageCounter = 0;
                        previousCreationTime = creationTime;
                    }

                    /* Find the text body of the log record */
                    messages[arrayIndex].setMsg(curLine.substring(greaterThanIndex + 1).trim());

                    arrayIndex++;

                    if (arrayIndex == MessageArraySize) {

                        arrayIndex = 0;
                        recordCount++;

                        return messages;
                    }

                    recordCount++;
                }
            }

            //If we are not logging the message then null the array elements that weren't set on this call
            if (arrayIndex == 0) {
                temp = null;
            }
            else {

                for (int i = arrayIndex; i < MessageArraySize; i++) {
                    messages[i] = null;
                }
                temp = messages;
            }

        }
        catch (Throwable throwable) {
            throw new LogParserException("Error parsing log.");
        }

        //Throw an exception if no valid log records are parsed/logged:
        if (recordCount == 0) {
            throw new LogParserException("No records were found!");
        }

        return temp;
    }

    private void reinitializeCBE() {

        //(Re)initialize the CBE:
        messages[arrayIndex].init();

        //Create the CBE's source component ID, set various properties and add to the CBE:
        ComponentIdentification sourceComponentID = eventFactory.createComponentIdentification();
        sourceComponentID.setExecutionEnvironment("Java");
        sourceComponentID.setComponent("HyadesExamples");
        sourceComponentID.setSubComponent("MyParser");
        sourceComponentID.setComponentIdType("Application");
        sourceComponentID.setComponentType("HyadesLoggingSamples");
        sourceComponentID.setLocation(localHostId);
        sourceComponentID.setLocationType(localHostIdFormat);

        messages[arrayIndex].setSourceComponentId(sourceComponentID);

        //Create the CBE's situation and set various properties:
        Situation cbeSituation = eventFactory.createSituation();

        //Unknown situation therefore use the generic:
        //Initialize the CBE's situation type, set various properties and add to the situation:
        ReportSituation cbeReportSituation = eventFactory.createReportSituation();
        cbeReportSituation.setReasoningScope("INTERNAL");
        cbeReportSituation.setReportCategory("LOG");

        cbeSituation.setCategoryName("ReportSituation");
        cbeSituation.setSituationType(cbeReportSituation);

        messages[arrayIndex].setSituation(cbeSituation);
    }

    /* Store the creation time in the desirable format */
    private String findCreationTime(int startIndex, int stopIndex) {

        if ((curLine.charAt(startIndex) == '<') && (curLine.charAt(stopIndex) == '>')) {

            /* This is the format found in the log file */
            SimpleDateFormat dateFormat = new SimpleDateFormat("MM.d.yy.kk.mm.ss");
            Date date = dateFormat.parse(curLine.substring((startIndex + 1), stopIndex), new ParsePosition(0));

            /* This is the desirable format that we would like creation time to be in
             * (The creation time has to be in this format) */
            dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            StringBuffer creationTime = new StringBuffer(dateFormat.format(date));
            creationTime.replace(10, 11, "T");
            creationTime.append(".000000");

            return (creationTime.toString().trim());
        }

        return null;
    }

    /* Returns the name of this parser */
    public String getName() {
        return "Simple Parser";
    }

    /* Returns the version of this parser */
    public String getVersion() {
        return "V1.0";
    }
}
