package Grid;
#<copyright>
# ----------------------------------------------------------
# Sun Proprietary/Confidential Code
# Copyright 2001, Sun Microsystems, Inc. All rights reserved.
# ----------------------------------------------------------
#</copyright>

use strict;
use System;
#use TO;
use Util;
use Report;

use vars qw ($SERVICE @GRIDIDX $ERROR $EGRID $CODES %GRIDHASH %INC %GRIDNOHASH);

sub setCode {
  my($class, $egrid) = @_;
  $egrid =~ s/AlarmEvent/ValueChangeEvent/;
  $egrid =~ s/ /_/g;
  $EGRID = $egrid;
}

#  Grid->setSign(+, - , P, M, X)

sub setSign {
  my($class, $sign) = @_;
  return if (!$EGRID);
  my($cat, $type, $caption) = split(/\./, $EGRID, 3);
  return if ($type =~ /[\+\-]/);
  $sign = "-" if ($sign eq "M" || $sign eq "X");
  $sign = "+" if ($sign eq "P");
  $EGRID = "$cat.$type$sign.$caption";
}


sub getCode {
  my($class) = @_;
  return $EGRID;
}


sub getNo {
  my($class, $egrid) = @_;
  $class->readCodes();
  $egrid = $EGRID if (!$egrid);
  my($t1, $t2, $c1) = split(/\./, $egrid, 3);
  $c1 = "enclosure" if (!$c1);
  return ($CODES->{TYPE}{$t1}||"ERR_$t1") . "." .
        ($CODES->{EVENT}{$t2}||"ERR_$t2") . "." .
         ($CODES->{COMP}{$c1}||"ERR_$c1");
}


sub readCodes {
  my($class) = @_;
  my $F = System->get_home() . "/System/EGrid/GridCodes";
  return if $CODES;
  my($l);
  if (open(O, $F)) {
    while ($l = <O>) {
     chop($l);
     my ($t, $pos, $e) = split(/\t/, $l);
     $CODES->{$t}{$e} = $pos + 0;
    }
    close(O);
  }
  $class->loadServices();
}

sub loadServices {
  my($class) = @_;
  my($l);
  return if ($SERVICE) ;
  $SERVICE = {};
  my $F2 = System->get_home() . "/System/EGrid/service.list";
  if (open(O, $F2)) {
    while ($l = <O>) {
      chop($l);
      next if (substr($l,0,1) eq "#");
      my ($t, $e) = split(/\s*=\s*/, $l, 2);
      $SERVICE->{$t} = $e if ($t);
    }
    close(O);
  }
}

sub readService {
  my($class, $id) = @_;
  return $SERVICE->{$id};
}

  
sub get_sev_image {
  my($class, $sev) = @_;
  my $im;
  my $L = Labels->read();
  return $L->{"sev$sev"};
}

sub get_sev_image0 {
  my($class, $sev) = @_;
  my $im;
  if ($sev == 1) {
    $im = "<img src=/gif/al_alert.gif width=13 alt=\"Warning\">";
  } elsif ($sev == 2) {
    $im = "<img src=/gif/al_crit.gif width=13 alt=\"Error\"> ";
  } elsif ($sev == 3) {
    $im = "<img src=/gif/al_down.gif width=13 alt=\"Error/Critical\">";
  }
  return $im;
}

sub format72 {
  my($ev) = @_;

  foreach my $e ('info','cause','action') {
    $ev->{$e}   = &format72_($ev->{$e}) if ($ev->{$e});
  }
}

sub format72_ {
  my($s) = @_;
  my ($out, $len ,$wc);
  $s =~ s/\n/ <NL> /g;
  my @W = split(/\s+/, $s);
  foreach my $w (@W) {
     if ($w eq "<NL>" || ($len + length($w)) > 72) {
       $out .= "\n"; $wc++; 
       $w = "" if ($w eq "<NL>");
       $len = 0;
     }
     $out .= $w . " ";
     $len += length($w);
  }
  return $out;
}


#  from type/component

sub getInfoString {
  my($class, $type, $comp, $code, $asObject) = @_;
  my $LB = Labels->read("Provider")->section('email');
  my @C  = ($LB->{info}, $LB->{cause}, $LB->{action});

  my $ev = $class->getInfo($type, $comp, {code => $code});
  my $s;
  my $cnt = 0;
  my %F;
  &format72($ev);
  foreach my $k ('info', 'cause', 'action') {
     if ($ev->{$k}) {
       $F{$k} = $ev->{$k};
       my $v = "  " . $F{$k};
       chomp($v);
       $v =~ s/\n/\n  /g;
       $s .= "\n" . $C[$cnt] . ":\n$v";
     }
     $cnt++;
  }
  if (wantarray) {
    return($F{info}, $F{cause}, $F{action}, $ev->{code});
  } elsif ($asObject) {
    return $ev;
  } else {
    return $s;
  }
}

sub format {
  my($class, $ev) = @_;
  my @SEV = ('Information','Warning','Error','Critical');
  my $ac = "Actionable" if ($ev->{actionable});

  my $v =<<EOF;
EventCode : $ev->{code}
EventType : $ev->{type}
Severity  : $SEV[$ev->{severity}] $ac

----Sample Description---
$ev->{desc}
----Information----------
$ev->{info}
----Probable Cause-------
$ev->{cause}
----Recommended Action---
$ev->{action}
EOF
    return $v;
}


sub toReport0 {
  my($class) = @_;
  my $filelist = $class->readFiles();
  my $out  = "StorADE 2.2 Event Grid Short Listing\n";
  $out .= "Event/Description                        Code        Severity Actionable\n";
  $out .= "---------------------------------------- ----------- -------- ------------------------------------- \n";
  my @SEV = ('Normal','Warning','Error','Down');
  foreach my $f (sort @$filelist) {
    my $events = Grid->read($f);
    foreach my $event (sort keys %$events) {
       my $v = $events->{$event};
       my $tt = $v->{type};
       $tt .= ".$v->{comp}" if ($v->{comp});
       my $no = $v->{code};
       my $act = $v->{actionable} ? "Yes" : "No";
       my $sev = $SEV[$v->{severity}];
       $out .= sprintf("%-40.40s %-12.12s %-8.8s %-4.4s\n      %s\n", 
              $tt,
              $v->{code},
              $sev,
              $act,
              $v->{desc}, 
               );

    }
  }
  return $out;
}

sub toTab {
  my($class) = @_;
  my $filelist = $class->readFiles();
  my $out ;
  my @SEV = ('Information','Warning','Error','Critical');

  foreach my $f (sort @$filelist) {
     my $events = Grid->read($f);
     foreach my $event (sort keys %$events) {
       my $v = $events->{$event};
       my $tt = $v->{type};
       $tt .= ".$v->{comp}" if ($v->{comp});
       my $no = $v->{code};
       $out .= "$tt\t$no\t";
       my $sev = $SEV[$v->{severity}];
       my $act = $v->{actionable} ? "action": "no-action";
       $out .= "$sev\t$act\t"; 

       foreach my $el ('desc','info','cause','action') {
          my $val = $v->{$el};
          chomp($val);
          $val =~ s/\n/ /g;
          $out .= "$val\t";
       }
       $out .= "\n";
    }
  }
  return $out;
}

sub toXML {
  my($class) = @_;
  my $filelist = $class->readFiles();
  my $out  = "<?xml version=\"1.0\"?>\n<grid>\n";

  foreach my $f (sort @$filelist) {
     my $events = Grid->read($f);
     foreach my $event (sort keys %$events) {
       my $v = $events->{$event};
       my $tt = $v->{type};
       $tt .= ".$v->{comp}" if ($v->{comp});
       my $no = $v->{code};
       $out .= "  <event code=\"$tt\" no=\"$no\">\n";
       foreach my $el ('pattern','severity','actionable') {
          $out .= "    <$el>$v->{$el}</$el>\n";
       }
       foreach my $el ('desc','info','cause','action') {
          my $val = $v->{$el};
          chomp($val);
          $val =~ s/\n/\n /g;
          my $nl = index($val, "\n") > 0 ? "\n    " : "";
          $out .= "    <$el>$val$nl</$el>\n";
       }
       $out .= "  </event>\n";
    }
  }
  $out .= "</grid>\n";
  return $out;
}

sub find_type_category {
  my($type) = @_;
  if ($Report::ISSWITCH{$type} ) {
     return "switch";
  } elsif ($type eq "host" || $type eq "sp") {
     return "host";
  } else {
     return "storage";
  }
}

sub readFiles {
  my($class) = @_;
  my(@list);
  my $F = System->get_home() . "/System/EGrid";
  opendir(O, $F);
  my @files = readdir(O); closedir(O);
  foreach my $f (@files) {
     if ($f =~ /\.grid$/) {
        push(@list, $f);
     }
  }
  return \@list;
}

sub readIndex {
  my($class) = @_;
  my($l);
  $class->readCodes();
  my $DIR = System->get_home() . "/System/EGrid";
  if ($#GRIDIDX < 0) {
    if (open(O, "$DIR/Grid.idx")) {
      while ($l = <O>) {
        chop($l);
        my @a = split(/ \| /, $l);
        my $code = $a[0];
        $code .= ".$a[1]" if ($a[1]);
        $GRIDHASH{$code} = $a[2];

        my($t1, $t2, $c1) = split(/\./, $code, 3);
        $c1 = "enclosure" if (!$c1);
        $GRIDNOHASH{"$CODES->{TYPE}{$t1}.$CODES->{EVENT}{$t2}.$CODES->{COMP}{$c1}"}
              = $code;
        push(@GRIDIDX, $l);
      }
      close(O);
    } else {
      return undef;
    }
  }
}


# grap  all section of the Grid for this event
sub getInfo {
  my($class, $type, $comp, $arg) = @_;

  if ($arg->{gridno}) {
     $class->readIndex();
     $arg->{code} = $GRIDNOHASH{$arg->{gridno}};
  } 
  my $code = $arg->{code};
  my $locale = $arg->{locale};

  my $ev = $class->getInfo_($type, $comp, $code, $locale);
  return $ev if ($ev);

  my($c1, $t1) = split(/\./, $type, 2);
  if ($c1 ne "host" && $t1 =~ /LogEvent/) {
     $ev = $class->getInfo_("host.$t1", $comp, $code, $locale);
  }
  return $ev if($ev);

# I18N RFE 5087138 fall back solution. If cannot find the entry in the localized file, 
# try it in English one again.

  if($locale && $locale ne "en" && !$ev) {

    $locale = "";
    
    $ev = $class->getInfo_($type, $comp, $code, $locale);
    return $ev if ($ev);
    
    ($c1, $t1) = split(/\./, $type, 2);
    if ($c1 ne "host" && $t1 =~ /LogEvent/) {
      $ev = $class->getInfo_("host.$t1", $comp, $code, $locale);
    }
    
    return $ev if ($ev);
  }
  return {};
}

sub getInfo_ {
  my($class, $type, $comp, $code, $locale) = @_;

  $class->readIndex();

  my ($type1, $comp1, $file1, $found, $pat, $san_type1, $san_type2, $foundR);
  my ($foundS, $foundSR, $foundAny);
  my($st_type1, $st_type2);

  if (substr($type, 0,4) eq "san.") {
     ($san_type1, $san_type2) = split(/\|/, $comp);
     $st_type1 = &find_type_category($san_type1);
     $st_type2 = &find_type_category($san_type2);

  # HAS A CODE ALREADY, USE IT
  } elsif ($code && $GRIDHASH{$code}) {
     my $file = $GRIDHASH{$code};
     my($t1, $e1, $c1) = split(/\./, $code, 3);
     return $class->readEvent($file, "$t1.$e1", $c1, $locale);

  } elsif ($code && $GRIDHASH{"$code.enclosure"}) {
     my $file = $GRIDHASH{"$code.enclosure"};
     my($t1, $e1, $c1) = split(/\./, "$code.enclosure", 3);
     return $class->readEvent($file, "$t1.$e1", $c1, $locale);
  }
  
  foreach my $l (@GRIDIDX) {
      ($type1, $comp1, $file1, $pat) = split(/ \| /, $l);
      if ($san_type1) {  # link | link events
         next if ($type1 ne $type);
         my ($s_type1, $s_type2) = split(/\|/, $comp1);
         if ($s_type1 eq $san_type1 && ($s_type2 eq $san_type2) ) {
            $found = [$file1, $type1, $comp1];
            last;
         } elsif ($s_type1 eq $san_type2 && ($s_type2 eq $san_type1) ) {
            $foundR = [$file1, $type1, $comp1];
         } elsif ($s_type1 eq $st_type1 && ($s_type2 eq $st_type2) ) {
            $foundS = [$file1, $type1, $comp1];
         } elsif ($s_type1 eq $st_type2 && ($s_type2 eq $st_type1) ) {
            $foundSR = [$file1, $type1, $comp1];
         } elsif ($s_type1 eq "Any" && ($s_type2 eq "Any") ) {
            $foundAny = [$file1, $type1, $comp1];
         }
         
      } else {
        $pat =~ s/\t//g;
        my $t = $type1;
        chop($t) if (index("+-", substr($t,-1)) >= 0);
        if ($type eq $t) {
           if ($pat) {
             $found = [$file1, $type1, $comp1] if ($comp =~ /$pat/);
           } elsif ($comp1 && $comp1 ne "enclosure") {
             $found = [$file1, $type1, $comp1] if ($comp eq $comp1);
           } else {
              $found = [$file1, $type1, $comp1];
           }
           last if ($found);
        }
      }
  }
  my $el;
  if ($found) {
    $el = $class->readEvent($found->[0], $found->[1], $found->[2], $locale);
  } elsif ($foundS) {
    $el = $class->readEvent($foundS->[0], $foundS->[1], $foundS->[2], $locale);
  } elsif ($foundR) {
    $el = $class->readEvent($foundR->[0], $foundR->[1], $foundR->[2], $locale);
  } elsif ($foundSR) {
    $el = $class->readEvent($foundSR->[0], $foundSR->[1], $foundSR->[2], $locale);
  } elsif ($foundAny) {
    $el = $class->readEvent($foundAny->[0], $foundAny->[1], $foundAny->[2], $locale);
  }
  return $el;

}

sub write {
  my($h, $file,  $arg) = @_;
  $ERROR = undef;
  my $langOnly = $arg->{langOnly};
  my $LANG = "/Lang" if (index($file, "/") > 0);

  if (open(W, ">" . System->get_home() . "$LANG/System/EGrid/$file")) {
    print W "######################\n";
    print W "# $file\n";
    print W "######################\n\n";

    foreach my $event (sort keys %$h) {
       my $v = $h->{$event};
       my $tt = $v->{type};
       $tt .= ".$v->{comp}" if ($v->{comp});
       print W "type=$tt\n";
       #print W "comp=$v->{comp}\n" if ($v->{comp});
       print W "code=$v->{code}\n" if ($v->{code});
       if (!$langOnly) {
          print W "pattern=$v->{pattern}\n" if ($v->{pattern});
          print W "severity=$v->{severity}\n";
          print W "actionable=$v->{actionable}\n";
       }
       foreach my $k ('desc', 'info', 'cause', 'action') {
          my $desc = $v->{$k};
          next if (!$desc);
          $desc =~ s/\n/\n'/g;
          $desc =~ s/
//g;
          $desc = substr($desc,0,-2) if (substr($desc,-2) eq "\n'");
          print W "$k=$desc\n";
       }
       print W "\n\n";
    }
    close(W);

  } else {
    $ERROR = "Cannot  write to $file: $!";
    return undef;
  }
}

sub sync {
  my($class, $v1, $v2, $mark) = @_;

  foreach my  $el (keys %$v1) {
       if (exists $v2->{$el}) {
          $v1->{$el}{desc} = $v2->{$el}{desc};
          $v1->{$el}{info} = $v2->{$el}{info};
          $v1->{$el}{cause} = $v2->{$el}{cause};
          $v1->{$el}{action} = $v2->{$el}{action};
       } else {
          $v1->{$el}{desc}  .= $mark;
       }
  } 
  return $v1;
}


# $T3G = Grid->read('t3.grid', {codeOrder => 1} );

sub read {
  my($class, $file, $arg) = @_;
  my $renv = System->get_renv();
  my $ruser = System->get_ruser();
  my $byCode = $arg->{codeOrder};
  my $locale = $arg->{locale};
  
  my $D     = System->get_home() . "/Lang/System/EGrid";
  my $lfile = "$locale/$file";

  if (-f  "$D/$lfile") {
     return $class->read_($lfile, $byCode);
  } else {
     return $class->read_($file, $byCode);
  }
}

# INCLUDE and INCLUDE_
# change a .grid file by processing the <include> sections
#
sub include {
  my($class, $file) = @_;
  my(@NEW, $l, $x);
  open(O2, $file);
  my @LINES = <O2>;
  close(O2);
  $x = 0;
  while ($x <= $#LINES) {
    if ($LINES[$x] =~ /^<include ([\w\.]+)\s*(.*)>/) {
       my $file = $1; 
       my @args = split(/\s+/, " $2");
       push(@NEW, $LINES[$x]);
       while ($x <= $#LINES && $LINES[$x] !~ /^<\/include>/) {
          $x++;
       }
       push(@NEW, $class->include_($file, @args));
       push(@NEW, "</include>\n");
    } else {
       push(@NEW, $LINES[$x]);
    }
    $x++;
  }
  close(O2);
  if (open(O2, ">$file")) {
    print O2 join("", @NEW);
    close(O2);
  }
}


sub include_ {
  my($class, $file, @args) = @_;

  my($f, $section) = split(/\./, $file, 2);
  my $f2 = System->get_home() . "/System/EGrid/$f.include";
  my $conf;
  if (! exists $INC{$f2}) {
    my ($l2);
    if (open(O2, $f2)) {
      my (%inc);
      my $section = "ALL";
      while ($l2 = <O2>) {
         if (substr($l2,0,1) eq "[") {
            $l2 =~ /\[(\w+)\]/;
            $section = $1;
         } else {
            $inc{$section} .= $l2;
         }
      }
      close(O2);
      $conf = $INC{$f2} = \%inc;
    } else {
      print "ERROR: cannot open file $f2: $! \n";
    }
  } else {
    $conf = $INC{$f2};
  }
  $section = "ALL" if (!$section);
  if (!exists $conf->{$section}) {
     print "ERROR: Cannot find section '$section' in file $f2! \n";
  }
  my $text = $conf->{$section};
  $text =~ s/\n+$/\n/;
  $text =~ s/\$(\d+)/$args[$1]/eg;
  return $text;
}

  

sub read_ {
  my($class, $file, $byCode) = @_;
  my %H;
  my($which, $which_name, $l, $el);
  $ERROR = undef;
  my $LANG = "/Lang" if (index($file, "/") > 0);

  my $file = System->get_home() . "$LANG/System/EGrid/$file";

  if (open(O, $file)) {
    while ($l = <O>) {
       next if (substr($l,0,3) eq "<in" || substr($l,0,4) eq "</in");
       if ($l =~ /^type=(.*)/) {
          my $t1 = $1;
          if ($el->{type}) {
              my $comp = $el->{comp} || "enclosure";
              my $k = $byCode ? $el->{code} : "$el->{type}.$comp";
              $H{$k} = $el;
              $el = {};
              $which = 0;
          }
          my @t1 = split(/\./, $t1, 3);
          $el->{type} = "$t1[0].$t1[1]";
          $el->{comp} = $t1[2];

       #} elsif ($l =~ /^comp=(.*)/) {
       #   $el->{comp} = $1;

       } elsif ($l =~ /^code=(.*)/) {
          $el->{code} = $1;

       } elsif ($l =~ /^fault=(.*)/) {
          $el->{fault} = $1;

       } elsif ($l =~ /^severity=(.*)/) {
          $el->{severity} = $1;

       } elsif ($l =~ /^service=(.*)/) {
          my $v1 = $1;
          $el->{service} = $SERVICE->{$v1} || $v1;

       } elsif ($l =~ /^actionable=(.*)/) {
          $el->{actionable} = $1;

       } elsif ($l =~ /^pattern=(.*)/) {
          $el->{pattern} = $1;

       } elsif ($l =~ /^desc=/) {
          $el->{desc} = substr($l,5);
          $which = 3;

       } elsif ($l =~ /^info(\w*)=/) {
	  $which_name = $1;
	  my $ix0 = index($l,"=");
          $el->{"info$which_name"} .= substr($l,$ix0+1);
          $which = 1;

       } elsif ($l =~ /^cause(\w*)=/) {
	  $which_name = $1;
	  my $ix0 = index($l,"=");
          $el->{"cause$which_name"} .= substr($l,$ix0+1);
          $which = 4;

       } elsif ($l =~ /^action(\w*)=/) {  # action, action_sys, action_se, action_6320 ..
	  $which_name = $1;
	  my $ix0 = index($l,"=");
          $el->{"action$which_name"} .= substr($l,$ix0+1);
          $which = 2;

       } elsif (substr($l,0,1) eq "'") {
          if ($which == 3) {
            $el->{desc} .= substr($l,1) ;

          } elsif ($which == 4) {
            $el->{"cause$which_name"} .= substr($l,1) ;

          } elsif ($which == 1) {
            $el->{"info$which_name"} .= substr($l,1) ;

          } elsif ($which == 2) {
            $el->{"action$which_name"} .= substr($l,1);
          }
       }
     }
     close(O);
     my $comp = $el->{comp} || "enclosure";
     my $k = $byCode ? $el->{code} : "$el->{type}.$comp";
     $H{$k} = $el;
   } else {
     $ERROR = "Cannot read $file";
     return undef;
   }
   delete($H{"ZZ.enclosure"});

#  FIX THE ACTION, CAUSE FOR SYSTEMS
# 
   my $renv  = System->get_renv();
   my $model = $renv->{solution_model};
   my $se    = $renv->{solution};

   foreach my $k (keys %H) {
      my $e = $H{$k};
      foreach my $tag ('action','cause') {
        if (exists $e->{"${tag}_$model"}) {
	   $e->{$tag} = $e->{"${tag}_$model"};
        } elsif (exists $e->{"${tag}_$se"}) {
	   $e->{$tag} = $e->{"${tag}_$se"};
        } elsif ($se ne "N" && exists $e->{"${tag}_sys"}) {
	   $e->{$tag} = $e->{"${tag}_sys"};
	}
      }
   }
   my $H = \%H;
   bless($H, 'Grid');
}
  
sub list {
  my($class, $arg) = @_;
  my(@G, @S, $l);
  my $byCode = $arg->{codeOrder};
  my $path = $arg->{gridcodes_path} || "/net/storade.central/export/depot/CVS/Events/GridCodes";
  if ($byCode) {
     open(O, $path);
     while ($l = <O>) {
        chop($l);
        if ($l =~ /^TYPE/) {
           my @x = split(/\t/, $l);
           $G[$x[1]+0] = "$x[2].grid";
        }
     }
     close(O);
     return \@G;
  }
  opendir(O, System->get_home() . "/System/EGrid");
  while ($l = readdir(O)) {
     next if ($l !~ /.grid$/);
     push(@G, $l);
  }
  closedir(O);
  return \@G;
}
    
  
sub updateEvent {
  my($class, $file, $type, $comp, $info, $cause, $action) = @_;

  my $h = Grid->read($file);
  #foreach my $k (keys %$h) {print "read=$k<br>"}
  my $e = $h->{"$type.$comp"};
  if ($e) {
    $e->{info} = $info     if (defined($info));
    $e->{cause} = $cause   if (defined($cause));
    $e->{action} = $action if (defined($action));
    $h->write( $file);

  } else {
    $ERROR = "Cannot find $type.$comp";
    return undef;
  }
}

sub readEvent {
  my($grid, $file, $type, $comp, $locale) = @_;

  $type = Util->rtrim($type);
  $comp = Util->rtrim($comp);


  my $h = Grid->read($file, {locale => $locale});
  my $ev = $h->{"$type.$comp"};

  #&format72($ev);

  return $ev;
}

####
# create a link to GUI::EventLog to display the event

sub links {
  my($class, $el, $scriptdone, $Hash) = @_;
  my $out;
  my $renv = System->get_renv();
  my $G = Labels->read();

  if ($renv->{window} eq "N") {
     return "<a href=\"$Http::WEBPROC?GO=GUI::EventLog::info&event=$el\&MAINWIN=1\">$G->{advisor}</a>";
  }

  if (! $$scriptdone) {
    $out = "
  <script>
   function info2(a) {
     var b = '$Http::WEBPROC?GO=GUI::EventLog::info&event=' + a;
     var O = window.open(b,'linfo','menubar=yes,resizable=yes,scrollbars=yes,width=600,height=700');
     O.focus();
   }
   </script>
   ";
   $$scriptdone= 1;
  }
  my $t;
  if ($Hash && $Hash->{Service}) {
    $t = $G->{advisor_service};
  } else {
    $t = $G->{advisor};
  }
  $out .= "<a href=\"javascript:info2('$el')\">$t</a>";

  return $out;

# NOT USED

  my ( $H, $event);
  if ($Hash) {
    $H = $Hash;
  } else {
    $event = State->readEvent($el);
    $H     = State->eventHash($event->[4]);
  }
  my $code     = $H->{GridCode};
  my $ev       = Grid->getInfo(undef, undef, {code => $code});

  my($service);
  if ($ev->{service}) {
    $out .= " | <a href=$Http::WEBPROC?GO=Service::Advisor::help&SVC_PAGE=$ev->{service}>Service</a>";
  }
  return $out;
}

1;
