#!/usr/bin/perl -w
# 
#  (c) 2002-2003 Newisys, Inc.  All rights reserved.
# 
# $Header: Viewer.pl, 6, 4/7/05 1:45:14 PM CDT, Jenny Cornell$
#
use strict;
use warnings;
use diagnostics;

######################################################################
#
# EventViewer
# -----------
# The Event Viewer (EV) is a facility that provides for viewing log 
# files created by the Event Manager.  This application knows how to
# parse event logs that contain XML documents conforming to the emEvent
# schema.  The emEvent schema provides for both smEvent and notice
# objects.
#
# The algorithm used is to suck in an emEvent document at a time and
# recognize it as either an smEvent or a notice.  Each document is
# placed in the appropriate array for its type (smEvent or notice) and
# then once the entire event log file is processed, each array element
# is processed individually and the row data is displayed.
#
######################################################################

use Getopt::Long;
use Carp;

sub _showSMEvents($);
sub _showNotices($);
sub main($);
main($_);

#
# This routine displays each entry of the array specified assuming that they are smEvent
# records.
#
sub _showSMEvents($)
{
    my $records = shift;

    if (scalar(@{$records}) == 0) {
        return;
    }

    my ($time, $id, $count, $type, $subtype, $component, $severity, $text);

    print "\n\n";
    print STDOUT "---------------------------------\n";
    print STDOUT "             Events              \n";
    print STDOUT "---------------------------------\n";
    print STDOUT sprintf("%-16s\t%-6s\t%-5s\t%-9s\t%-12s\t%-25s\t%-17s\t%s\n", "Latest Time", "Evt ID", "Count", "Component", "Type", "Sub-type", "Severity", "Message");
    print STDOUT sprintf("%-16s\t%-6s\t%-5s\t%-9s\t%-12s\t%-25s\t%-17s\t%s\n", "-----------", "------", "-----", "---------", "----", "--------", "--------", "-------");
    foreach my $emEvent (@{$records}) {
        next unless ($emEvent =~ /<smEventHeader>/);
	if ($emEvent =~ /<lastUpdateTime>(.*?)<\/lastUpdateTime>/) {
	    $time = $1;
	}
	if ($emEvent =~ /<eventID>(.*?)<\/eventID>/) {
	    $id = $1;
	}
	if ($emEvent =~ /<eventCount>(.*?)<\/eventCount>/) {
	    $count = $1;
	}
	if ($emEvent =~ /<smEventType>(.*?)<\/smEventType>/) {
	    $type = $1;
	    if ($type =~ /<(.*?)>(.*?)<\/(.*?)>/) {
	        $type = $1;
		$subtype = $2;
	    }
	}
	if ($emEvent =~ /<componentID>(.*?)<\/componentID>/) {
	    $component = $1;
	}
	if ($emEvent =~ /<smEventSeverity>(.*?)<\/smEventSeverity>/) {
	    $severity = $1;
	    if ($severity =~ /<(.*?)\/>/) {
	        $severity = $1;
	    }
	}
	if ($emEvent =~ /<message>(.*?)<\/message>/) {
	    $text = $1;
	    if ($emEvent =~ /<messageText>(.*?)<\/messageText>/) {
	        $text = $1;
	    }
	}
        print STDOUT sprintf("%-16s\t%-6s\t%-5s\t%-9s\t%-12s\t%-25s\t%-17s\t%s\n", $time, $id, $count, $component, $type, $subtype, $severity, $text);
    }
}

#
# This routine displays each entry of the array specified assuming that they are notice
# records.
#
sub _showNotices($)
{
    my $records = shift;

    if (scalar(@{$records}) == 0) {
        return;
    }

    my ($time, $source, $type, $subtype, $msg);

    print "\n\n";
    print STDOUT "---------------------------------\n";
    print STDOUT "             Notices             \n";
    print STDOUT "---------------------------------\n";
    print STDOUT sprintf("%-17s\t%-20s\t%-12s\t%-25s\t%s\n", "Creation Time", "Source Name", "Type", "Sub-type", "Message");
    print STDOUT sprintf("%-17s\t%-20s\t%-12s\t%-25s\t%s\n", "-------------", "-----------", "----", "--------", "-------");
    foreach my $emEvent (@{$records}) {
        next unless ($emEvent =~ /<noticeHeader>/);
	if ($emEvent =~ /<creationTime>(.*?)<\/creationTime>/) {
	    $time = $1;
	}
	if ($emEvent =~ /<sourceName>(.*?)<\/sourceName>/) {
	    $source = $1;
	}
	if ($emEvent =~ /<noticeType>(.*?)<\/noticeType>/) {
	    $type = $1;
	    if ($type =~ /<(.*?)>(.*?)<\/(.*?)>/) {
	        $type = $1;
		$subtype = $2;
	    }
	}
	if ($emEvent =~ /<message>(.*?)<\/message>/) {
	    $msg = $1;
	    if ($emEvent =~ /<messageText>(.*?)<\/messageText>/) {
	        $msg = $1;
	    }
	}
        print STDOUT sprintf("%-17s\t%-20s\t%-12s\t%-25s\t%s\n", $time, $source, $type, $subtype, $msg);
    }
}

sub main($)
{
    my $infile = undef;
    GetOptions('file=s' => \$infile);

    unless (defined($infile)) {
        print STDOUT "usage: $0 --file\n";
        return;
    }

    unless (-e $infile && -r _) {
        print STDOUT "$0: file $infile does not exist or is not readable\n";
        return;
    }

    # edit the file for necessary \n to parse correctly
    open(OLD, "< $infile");
    open(NEW, "> ${infile}.tmp");
    my $useFile = "new";
    while(<OLD>) {
        # for unclearedEvents we need a \n before the emEvent
        if (/<unclearedEvents>/) {

            # when ready to parse, use the temp file
            $useFile = "tmp";

            my @emEvents = split /<emEvent>/ ;

            # do not want to print <emEvent> with first record
            my $firstTime = 1;

            # go through each record and print a \n
            foreach my $ref (@emEvents) {
              if ( $firstTime == 1 ) {
                  $firstTime = 2;
                  print NEW "RECORD $ref\n";
              }
              else {
                  print NEW "RECORD <emEvent>$ref\n";
              }
            }
        }
        else {
            print NEW $_;
        }
    }
    close(OLD);
    close(NEW);

    if ( $useFile =~ m/tmp/ ) {
        $infile = "${infile}.tmp";
    }
    else {
        # this file is now un-neccessary
        unlink "${infile}.tmp";
    }

    open(LOGFILE, "<$infile");
    my (@smEventRecords, @noticeRecords, @illegalRecords);
    my ($eventRecord, $continuation);
    while (<LOGFILE>) {
        chomp;
	if (/<smEventHeader>/) {
	    $eventRecord = $_;
	    while ($eventRecord !~ /<\/emEvent>/) {
	        $continuation = <LOGFILE>;
		chomp($continuation);
		$eventRecord .= $continuation;
	    }
            push(@smEventRecords, $eventRecord);
	} elsif (/<noticeHeader>/) {
	    $eventRecord = $_;
	    while ($eventRecord !~ /<\/emEvent>/) {
	        $continuation = <LOGFILE>;
		chomp($continuation);
		$eventRecord .= $continuation;
	    }
            push(@noticeRecords, $eventRecord);
	} elsif (/<emEvent>/) {
	    $eventRecord = $_;
	    while ($eventRecord !~ /<\/emEvent>/) {
	        $continuation = <LOGFILE>;
		chomp($continuation);
		$eventRecord .= $continuation;
	    }
            push(@illegalRecords, $eventRecord);
	} else {
            push(@illegalRecords, $_);
	}
    }
    close(LOGFILE);

    # remove temp file if used
    if ( $useFile =~ m/tmp/ ) {
        unlink $infile;
    }

    _showSMEvents(\@smEventRecords);
    _showNotices(\@noticeRecords);
}

