#!/bin/perl -w

#
# Process CLIMAT TEMP's
#
# Note: we try to deal with people who add "helpful" headers "850", etc, to each line
# Note: if such people add a "925", we scrub that line
# Note: messages which are not 5-character groups (digits and "/"'s) are rejected
# Note: decoding stops at first missing height
#
# WMC 02/98
#
# Use: clt.pl filename, OR cat filename | clt.pl
# Output: to stdout: stream of data, each "ST YYYY MM DD HH LEV# HH TT NTmiss"
# Errors: to clt.err.temps
#
# Bugs: None yet known
#       Will probably fail for interior stations
#

# Possibles:
#   DEBUG=1 - debug info
#   NODIEONSLASH=1 - don't stop on levels if H is "/" on one of them
#   XTOSLASH - convert X's into /'s
#   LEVEL=n - only output level n
$NODIEONSLASH=1;
$XTOSLASH=1;

eval "\$$1=\$2" while $ARGV[0] =~ /^(\w+)=(.*)/ && shift;

# Setup decoding array
%gs=("1" => "0Z", "2" => "12Z", "3" => "0Z & 12Z", "/" => "other");           # Code table 1400
%gh=("1" => 0, "2" => 12, "3" => 6, "/" => 18);

# Set input-terminator to end-of-message
$/="NNNN";

# Open output file
open(ERR,">>clt.err.temps") or die "Can't open error file";
print ERR "--- ",`date`;

# Loop over input
while(<>) {

# Only interested in CLIMAT TEMP messages
  next if (!/CLIMAT TEMP/);

# Debug
  if ($DEBUG) { print };

# Remove trailing NNNN
  s/NNNN$//;

# Split into multiple messages if they are indeed multiple
  @MESS=split("=");

# Decode (and output) each one
  foreach $MESS (@MESS) { decode($MESS) };

};

close(ERR);

#
# Subroutines
#

#
# Decode - decode a message
#
sub decode {
  ($_)=@_;

# Debug
  if ($DEBUG) { print };

# If people add a 925 marker, kill that line
  s/\n925 .*//;

# Allow for people putting "850 " etc into the message...
  s/\n\s{0,2}\d{2,3} / /g;

# Change all whitespace into single " "'s
  tr/\015\n 	/ /s;
  if (substr($_,-1,1) eq " ") { chop };

# Messages are sometimes grouped together. Extract the date if we're at the first such
# Note that since this is a global variable, it will survive into the next message if needed
  if (s/.*CLIMAT TEMP (\d{2})(\d{3}) //) { $MM=$1; $YYYY=1000+$2 }
# If for some reason we don't have a month, we junk this message
  if (!$MM) { 
    if ($DEBUG) { print "Junk (no month/id) <$_>\n" };
    print ERR "Junk (no month/id) <$_>\n"; return 
  };

# Check MM and YYYY a bit. Arbitrarily declare DD=1. $MM+50 is knots indicator. Set HH later
  $Kts=0;
  if ($MM>50 and $MM<63) { $MM-=50; $Kts=1 };
  if ($MM<1 or $MM>12) { print ERR "Junk (MM=$MM): $_\n"; return };
  if ($YYYY<1960 or $YYYY>1999) { 
    if ($DEBUG) { print "Junk (YYYY=$YYYY): $_\n" };
    print ERR "Junk (YYYY=$YYYY): $_\n"; return 
  };
  $DD=1;

# Convert X's into /'s if required
  if ($XTOSLASH) { s/X/\//g };

# Split rest of message up into GRouPS
  @GRPS=split(" "); return if (@GRPS+0<3);
  if (@Probs = grep !/^[\d\/]{5}$/, @GRPS) { 
    if ($DEBUG) { print "Junk ($YYYY $MM) (not 5-digit groups): [problem groups: @Probs] $_\n" };
    print ERR "Junk ($YYYY $MM) (not 5-digit groups): [problem groups: @Probs] $_\n"; return 
  };

# Extract STationid,Hours-used indicator (g),sfc(P,T,D) from first 3 groups
  ($ST,$g,$P,$T,$D) = (join("",splice(@GRPS,0,3)) =~ /(.....)(.)(...)(...)(...)/);
  if ($DEBUG) { print "$ST,$g,$P,$T,$D\n" };

#
# Sfc processing
#
# g. Set HH accordingly - 0 for 0Z, 12 for 12Z, 6 for avg(0,12) and 18 otherwise
  $gt=$gs{$g}; if (!$gt) { $gt="unknown" };
  $HH=$gh{$g}; if (!defined $HH) { $HH=$gh{"/"} };
# p0
  if ($P =~ /\//) { print ERR "Junk: no sfcp: $_\n"; return };
  if ($P<200) { $P+=1000 };
# T0
  if ($T =~ /\//) { print ERR "Junk: no sfct: $_\n"; return };
  if ($T>500) { $T=-($T-500) }; $T/=10;

#
# Levels
#
  $Hold=0; $Told=$T; $LEV=0;
# Define these here to avoid warming messages
  $rf=0; $fv=0; $fv=0, $D=0; $dv=0, $nv=0;
  while (@GRPS+0 > 3) {

# LEV just counts levels. *Should* be 850, 700, ..., but you never can tell
    $LEV++;

# Split up this level
    ($H,$nt,$T,$D,$nv,$rf,$dv,$fv) = (join("",splice(@GRPS,0,4)) =~ /(....)(..)(...)(...)(.)(..)(...)(..)/);

# Debug
    if ($DEBUG) { print "  $LEV  $H,$nt,$T,$D,$nv,$rf,$dv,$fv\n" };

# Skip rest of message if height unknown
    if ($H =~ /\// and not $NODIEONSLASH) { 
      if ($DEBUG) { print "  Ending: H is \/\n" };
      last
    };

# T may need 500 subtracting from it. Since T<-50 is quite poss, may need to do it again...
    if ($T =~ /\//) { 
      $T=999
    } else {
      if ($T>500) { $T=-($T-500) }; $T/=10;
      if ($T>$Told and $T>0) { $T-=50 }; $Told=$T;
    };

# May need to add 10,000's figure to H
    if ($H !~ /\//) { while ($H<$Hold) { $H+=10000; }; $Hold=$H };

# Output is formatted for Oracle input
    if (not $LEVEL or $LEVEL == $LEV) { print "$ST $YYYY $MM $DD $HH $LEV $H $T $nt\n" };
  };

};
