#!/usr/bin/perl
#
#  buoyWriter 
#
# Program to split buoy bulletins into individual reports, then write
# them to a directory structure ~/data/raw/buoy/yyyymmdd/stn using the 
# station name as the file name. If the station name is not available then 
# the wmoId number will be used as the station name. The additional reports 
# for the hour are appended to file. 
#
#no encoding;

# process command line switches
while ($_ = $ARGV[0], /^-/) {
	 shift;
       last if /^--$/;
	     /^(-v)/ && $verbose++;
}
# process input parameters
if( $#ARGV == 1 ) {
	$datadir = $ARGV[ 0 ] ;
	$yyyymm = $ARGV[ 1 ] ;
	die "yyyymm must be 6 in length: $!\n" if( length( $yyyymm ) != 6 ) ;
	$theyear = substr( $yyyymm, 0, 4 ) ;
	$themonth = substr( $yyyymm, 4 ) ;
} else {
	die "usage: buoyWriter datatdir yyyymm < rawBuoy $!\n" ;
}

# set interrupt handler
$SIG{ 'INT' }  = 'atexit' ;
$SIG{ 'KILL' }  = 'atexit' ;
$SIG{ 'TERM' }  = 'atexit' ;
$SIG{ 'QUIT' }  = 'atexit' ;

chdir( "$datadir" ) ;

# Now begin parsing file and decoding observations breaking on cntrl C
$/ = "\cC" ;

# set select processing here from STDIN
START:
while( 1 ) {
	open( STDIN, '-' ) ;
	vec($rin,fileno(STDIN),1) = 1;
	$timeout = 1200 ; # 20 minutes
	$nfound = select( $rout = $rin, undef, undef, $timeout );
	# timed out
	if( ! $nfound ) {
		print "Shut down, time out 20 minutes\n" ;
		atexit() ;
	}
	atexit( "eof" ) if( eof( STDIN ) ) ;

	$rep_type = "" ;
	# Process each line of buoy bulletins, header first
	$_ = <STDIN> ;
	s#\cC## ;
	s#\cM##g ;
	s#\cA\n## ;
	s#\c^##g ;
	# Eat header and check bulletin times
	s#\d\d\d \n## ;
	s#\w{4}\d{1,2} \w{4} (\d{2})(\d{2})(\d{2}).*\n## ;
	$bday = $1 ;
	$bhour = $2 ;
	$bhour = "23" if( $bhour eq "24" ) ;
	$bmin = $3 ;
	next unless ( $bday && defined( $bhour ) && defined( $bmin ) ) ;
	next if( $bmin > 59 || $bhour > 23 || $bday > 31 ) ;
	# check for valid bulletin times against current time
	$cday = (gmtime())[ 3 ] ;
	$chour = (gmtime())[ 2 ] ;
	# skip bulletins over 24 hours old or in the future
	if( $bday == $cday ) {
		next if( $bhour > $chour ) ;
	} else { #  $bday != $cday, skip over day old reports
 		next if( $bday < $cday -1 ) ;
 		if( $bday > $cday ) {
			next if( $cday != 1 || $bday < 28) ;
		}
 		next if( $bhour < $chour ) ;
	}
	if( /ZZYY/ ) {
		zzyy( $_ ) ;
	} elsif( /BBXX/ ) {
		bbxx( $_ ) ;
	}
} # end while( 1 )
atexit( "eof" );
exit( 0 ) ; #should never get here

# BBXX reports for buoys and ships
sub bbxx {

( $_ ) = @_ ;

s#(BBXX)\s*\n## ;
# Separate bulletins into reports 
if( /=\n/ ) {
	s#=\s+\n#=\n#g ;
} else {
	s#\n# #g ;
}
@reports = split( /=\n/ ) ;
for ( @reports ) { # Process each report in the bulletin
	next if( /^\n/ ) ;
	s#\n# #g ;
	s#\s+# #g ;
	s#-\s*##g ;
	s#(BBXX)\s*## ;
	# decode Section 0 for buoy or ship and rdayrhour 
	if( s#^(\d{5})\s+## ) {
		$stn = "$1" ;
		$type = "BUOY"
	} elsif( s#^(SHIP|TEST)\s+## ) {
		$stn = "$1" ;
		$type = "SHIP" ;
	} else {
		s#(\w{3,7})\s+## ;
		$stn = $1 ;
		$type = "SHIP" ;
	}
	next unless( m#^(\d\d)(\d\d)# ) ;
	$rday = $1 ;
	$rhour = $2 ;
	# check for valid times
	next unless ($rday && defined( $rhour )) ;
	next if( $rhour > 23 || $rday > 31 ) ;
	# skip reports over 24 hours old
	$tmpyyyymm = $yyyymm ;
	if( $rday == $cday ) {
		next if( $rhour > $chour ) ;
	} else { #  $rday != $cday, skip over day old reports
		next if( $rday < ( $cday -1 ) ) ;
	 	if( $rday > $cday ) {
			next if( $cday != 1 || $rday < 28) ;
			# cday = 1, reset month and year
			$tmpmonth = sprintf( "%02d", $themonth -1 ) ;
			if( $tmpmonth == 0 ) {
				$tmpmonth = "12" ;
				$tmpyear = sprintf( "%04d", $theyear -1 );
			} else {
				$tmpyear = $theyear ;
			}
			$tmpyyyymm = $tmpyear .  $tmpmonth ;
		}
		next if( $rhour < $chour ) ;
	}
	$yyyymmdd = $tmpyyyymm . sprintf( "%02d", $rday ) ;
	mkdir( "$yyyymmdd", 0775 ) if( ! -e "$yyyymmdd" ) ;
	chdir( "$yyyymmdd" ) ;
	# Prepend stn, type, Z time and rep_type to report
	$_ = $stn . " $type" . " $yyyymm" . "$rday" . "$rhour" . "Z BBXX" . 
			" $stn" . " $_" ;
	open( STN, ">>$stn" ) ;
	print STN "$_\n" ;
	close STN ;
	chdir( ".." ) ;
} # end foreach report
} # end bbxx

# ZZYY reports for buoys
sub zzyy {

( $_ ) = @_ ;

# Separate bulletins into reports 
if( /=\n/ ) {
	s#=\s+\n#=\n#g ;
} else {
	s#\n# #g ;
}
@reports = split( /=\n/ ) ;
$type = "BUOY" ;

for ( @reports ) { # Process each report in the bulletin
	next if( /^\n/ ) ;
	s#\n# #g ;
	s#\s+# #g ;
	# decode Section 0 
	next unless ( m#ZZYY (\d{5}) (\d\d)(\d\d)(\d) (\d\d)(\d\d)# ) ;
	$stn = "$1" ;
	$rday = $2 ;
	$rmonth = $3 ;
	$ryear = substr( $theyear, 0, 3 ) . $4 ;
	$rhour = $5 ;
	$rmin = $6 ;
	# check for valid times
	next unless ($rday && defined( $rhour )) ;
	next if( $rhour > 23 || $rday > 31 ) ;
	# skip reports over 24 hours old
	$tmpyyyymm = $yyyymm ;
	if( $rday == $cday ) {
		next if( $rhour > $chour ) ;
	} else { #  $rday != $cday, skip over day old reports
		next if( $rday < ( $cday -1 ) ) ;
	 	if( $rday > $cday ) {
			next if( $cday != 1 || $rday < 28) ;
			# cday = 1, reset month and year
			$tmpmonth = sprintf( "%02d", $themonth -1 ) ;
			if( $tmpmonth == 0 ) {
				$tmpmonth = "12" ;
				$tmpyear = sprintf( "%04d", $theyear -1 );
			} else {
				$tmpyear = $theyear ;
			}
			$tmpyyyymm = $tmpyear .  $tmpmonth ;
		}
		next if( $rhour < $chour ) ;
	}
	# Calculate time for dir structure
	$yyyymmdd = $tmpyyyymm . sprintf( "%02d", $rday ) ;
	mkdir( "$yyyymmdd", 0775 ) if( ! -e "$yyyymmdd" ) ;
	chdir( "$yyyymmdd" ) ;
	# Prepend stn, type, Z time and rep_type to report
	$_ = $stn . " $type" . " $yyyymmdd$rhour" . "Z" . " $_" ;
	open( STN, ">>$stn" ) ;
	print STN "$_\n" ;
	close STN ;
	chdir( ".." ) ;
} # end for
} # end zzyy

# execute at exit
sub atexit
{
local( $sig ) = @_ ;

if( $sig eq "eof" ) {
	print "eof on STDIN --shutting down\n" ;
} elsif( defined( $sig )) {
	print "Caught SIG$sig --shutting down\n" ;
}
exit( 0 ) ;

} #end atexit

