#!/usr/bin/tclsh8.5
#
# $Id: b8cf167c59118a82e57a5a11c76343b0f8d40162 $
#
package require cmdline;

set usage {dafilter [-s]};
set optlist {{s}};

## The common defaults initialization
set filters_init_file "/usr/local/libexec/nbsp/filters.init";
if {[file exists $filters_init_file] == 0} {
	puts "dafilter disabled: $filters_init_file not found.";
	return 1;
}
source $filters_init_file;
unset filters_init_file;

if {$filters_init_status == 1} {
	return 1;
}
unset filters_init_status;

## This filter is archive-aware
set initfile [file join $common(libdir) "archive.init"];
if {[file exists $initfile] == 0} {
        puts "dafilter disabled: $initfile not found.";
        return 1;
}
source $initfile;

## The initialization of this filter.
set initfile [file join $common(libdir) "dafilter.init"];
if {[file exists $initfile] == 0} {
        puts "dafilter disabled: $initfile not found.";
        return 1;
}
source $initfile;

#
# Variables of this filter
#
set dafilter(rcfiles)		[list];
set dafilter(ccbsaved)		$common(ccbsaved);
set dafilter(ccbsize)		$common(ccbsize);
set dafilter(ccbwmoawipssize) [expr $common(ccbsize) + $common(wmoawips_size)];
#
set dafilter(condition)		[list];
set dafilter(action)		[list];
#
# Default is to run as master unless "-s" is given.
set dafilter(option_s)		0;
#

# The archive variables
#
# If the archive is enabled, the next three variables are reset according
# to the current date: the wmo header or file data for archive_subdir;
# the arrival time for the inv subdir and name. In addition, we copy
# each archive(da,xxx) variable to dafilter(archive_xxx) for easy reference
# in the functions here.
#
set dafilter(archive_subdir) "";
set dafilter(archive_inv_subdir) "";
set dafilter(archive_inv_name) "";
foreach key [array names archive "da,*"] {
    set k [string range $key 3 end];
    set dafilter(archive_${k}) $archive($key);
}

# The main rc file is required
if {[file exists $dafilter(rc)] == 0} {
    log_msg "Filter disabled: $dafilter(rc) not found.";
    return 1;
}

# Build the list of rc files
set dafilter(rcfiles) [filterlib_get_rcfiles $dafilter(localrc) \
	$dafilter(localconfdirs) $dafilter(rcdir) \
	$dafilter(prerc) $dafilter(postrc)];

# Load the rules sets
source $dafilter(rc);

#
# dafilter library
#
#
# Functions to support the archive
#
proc filter_file_archive {rc_array seq fpath savedir savename} {
#
# This function is called by filter_file.
#
    upvar $rc_array rc;
    global dafilter;

    if {[is_archive_file_rule_enabled $savedir] == 0} {
	return;
    }

    filter_archive rc $seq $fpath $savedir $savename;
}

proc filter_rad_archive {rc_array seq fpath savedir savename} {

    upvar $rc_array rc;
    global dafilter;

    if {[is_archive_rad_rule_enabled $savedir] == 0} {
	return;
    }

    filter_archive rc $seq $fpath $savedir $savename;
}


proc filter_sat_archive {rc_array seq fpath savedir savename} {

    upvar $rc_array rc;
    global dafilter;

    if {[is_archive_sat_rule_enabled $savedir] == 0} {
	return;
    }

    filter_archive rc $seq $fpath $savedir $savename;
}

proc filter_archive {rc_array seq fpath savedir savename} {
#
# This function is called by filter_file.
#
    upvar $rc_array rc;
    global dafilter;

    set archive_savedir [file join $dafilter(archive_subdir) $savedir];
    set archivepath [file join $archive_savedir $savename];

    set _pwd [pwd];
    cd $dafilter(archive_datadir);

    set status [catch {
        file mkdir $archive_savedir;
	exec tar -r -f $archivepath -C [file dirname $fpath] \
	    [file tail $fpath];
    } errmsg];

    cd $_pwd;

    if {$status != 0} {
	log_msg $errmsg;
	return;
    }

    filter_register_archive_inventory rc $savedir $savename;
}

proc filter_register_archive_inventory {rc_array \
	archive_savedir archive_name} {
#
# subdir is the common subdirectory of the main archive, for example 2009/12/01
# savedir is the data directory, for example, nwx/nhc
#
    upvar $rc_array rc;
    global dafilter;

    set invpath [file join $dafilter(archive_inv_subdir) \
		       $dafilter(archive_inv_name)];

    set invdata [list];
    foreach key [list station wmoid awips wmotime seconds fbasename] {
	lappend invdata $rc($key);
    }
    lappend invdata $dafilter(archive_datadir) $dafilter(archive_subdir) \
	$archive_savedir $archive_name;

    set _pwd [pwd];
    cd $dafilter(archive_invdir);

    set status [catch {
	file mkdir $dafilter(archive_inv_subdir);
	filterlib_file_append $invpath [join $invdata ","];
    } errmsg];

    cd $_pwd;

    if {$status != 0} {
	log_msg $errmsg;
    }
}
#
# Function to support the directory listing
#
proc make_rad_dirlist {dir {level2flag 0}} {

    global dafilter;

    set rad_dirlistname "";

    if {$level2flag == 0} {
	if {$dafilter(rad_dirlist_enable) != 0} {
	    set rad_dirlistname $dafilter(rad_dirlistname);
	    set rad_dirlistlink $dafilter(rad_dirlistlink);
	    set rad_latestname $dafilter(rad_latestname);
	}
    } elseif {$dafilter(rad2_dirlist_enable) != 0} {
	set rad_dirlistname $dafilter(rad2_dirlistname);
	set rad_dirlistlink $dafilter(rad2_dirlistlink);
	set rad_latestname $dafilter(rad2_latestname);
    }

    if {$rad_dirlistname eq ""} {
	return;
    }

    set dirpath [file join $dafilter(datadir) $dir];
    set dirlistpath [file join $dirpath $rad_dirlistname];
    set dirlistlinkpath [file join $dirpath $rad_dirlistlink];
    set filelist [lsort \
	[glob -nocomplain -tails -directory $dirpath "*"]];

    # Delete the <latest>, <dirlist> file and link.
    foreach f [list $rad_dirlistname $rad_dirlistlink $rad_latestname] {
	set i [lsearch -sorted -exact $filelist $f];
	if {$i >= 0} {
	    set filelist [lreplace $filelist $i $i];
	}
    }

    # For level 2, prepend the file size to each file name in the list
    # (without the file size, grlevel2 would not pull any data)
    # Brad Holcomb <brad@w0wdx.com> 4/13/2010

    if {$level2flag != 0} {
	set oldlist $filelist;
	set filelist [list];
	foreach f $oldlist {
	    set s [file size [file join $dirpath $f]];
	    append s " " $f;
	    lappend filelist $s;
	}
    }

    set status [catch {
        set F [open $dirlistpath w 0644];
	puts $F [join $filelist "\n"];
    } errmsg];

    if {[info exists F]} {
    	close $F;
    }

    if {($status == 0) && ([file exists $dirlistlinkpath] == 0)} {
	set savedir [pwd];
	cd $dirpath;
	set status [catch {
	    exec ln -s $rad_dirlistname $rad_dirlistlink;
	} errmsg];
	cd $savedir;
    }

    if {$status != 0} {
        log_msg $errmsg;
    }
}

proc make_rad_latest {savedir savename {level2flag 0}} {

    global dafilter;

    set rad_latestname "";

    if {$level2flag == 0} {
	if {$dafilter(rad_latest_enable) != 0} {
	    set rad_latestname $dafilter(rad_latestname);
	}
    } elseif {$dafilter(rad2_latest_enable) != 0} {
	set rad_latestname $dafilter(rad2_latestname);
    }

    if {$rad_latestname eq ""} {
	return;
    }
    
    make_latest $savedir $savename $rad_latestname;
}

proc make_sat_latest {savedir savename} {

    global dafilter;

    if {$dafilter(sat_latest_enable) == 0} {
	return;
    }

    make_latest $savedir $savename $dafilter(sat_latestname);
}

proc make_latest {savedir savename latestname} {
#
# Create a link to the newest file (this is for applications like DA, IDV).
#
    global dafilter;

    set currentdir [pwd];

    set dirpath [file join $dafilter(datadir) $savedir];
    cd $dirpath;

    set latest $savename;
    set linkpath $latestname;
    if {[file exists $latest] == 0} {
 	cd $currentdir;
	return;
    }

    set status [catch {
        file delete $linkpath;
        # file link -symbolic $linkpath $latest;
	exec ln -s $latest $linkpath;
    } errmsg];

    cd $currentdir;
}
#
# Auxiliary functions to support enabling/disabling rules individually
#

proc is_rad_rule_enabled {key} {
#
# For radar the key is the subdirectory name, e.g., nexrad/nids/jua/n0r,
# or nexrad/craft/tjua for level2.
#
    global dafilter;

    set r [is_type_enabled $dafilter(rad_enable) $dafilter(rad_regex) $key];

    return $r;
}

proc is_sat_rule_enabled {key} {
#
# For sat the key is "sat/gini/<subdir>" (e.g., sat/gini/tigp01).
#
    global dafilter;

    set r [is_type_enabled $dafilter(sat_enable) $dafilter(sat_regex) $key];

    return $r;
}

proc is_file_rule_enabled {key} {
#
# For file the key is like "nwx/spc/<subdir>" (e.g., nwx/spc/stahry)
#
    global dafilter;

    set r [is_type_enabled $dafilter(file_enable) $dafilter(file_regex) $key];

    return $r;
}

proc is_grib_rule_enabled {key} {
#
# The key is the subdirectory name
#
    global dafilter;

    set r [is_type_enabled $dafilter(grib_enable) $dafilter(grib_regex) $key];

    return $r;
}

proc is_archive_rad_rule_enabled {key} {
#
# For radar the key is the subdirectory name, e.g., nexrad/nids/jua
#
    global dafilter;

    if {$dafilter(archive_enable) == 0} {
	return 0;
    }    

    set r [is_type_enabled \
	$dafilter(archive_rad_enable) $dafilter(archive_rad_regex) $key];

    return $r;
}

proc is_archive_sat_rule_enabled {key} {
#
# For sat the key is "sat/gini/<subdir>" (e.g., sat/gini/tigp01).
#
    global dafilter;

    if {$dafilter(archive_enable) == 0} {
	return 0;
    }    

    set r [is_type_enabled \
	$dafilter(archive_sat_enable) $dafilter(archive_sat_regex) $key];

    return $r;
}

proc is_archive_file_rule_enabled {key} {
#
# For file the key is like "nwx/spc/<subdir>" (e.g., nwx/spc/stahry)
#
    global dafilter;

    if {$dafilter(archive_enable) == 0} {
	return 0;
    }    

    set r [is_type_enabled \
	$dafilter(archive_file_enable) $dafilter(archive_file_regex) $key];

    return $r;
}

proc is_type_enabled {enable regex key} {
#
# The key is the subdirectory name:
#
# For file the key is like "nwx/spc/<subdir>" (e.g., nwx/spc/stahry)
# For sat the key is "sat/gini/<subdir>" (e.g., sat/gini/tigp01).
# For radar the key is the subdirectory name, e.g., nexrad/nids/jua/n0r.
#
    set r 0;

    # The "enable" variable can be set to 1 or 2.
    if {($enable != 0) && ([filterlib_uwildmat $regex $key] == 1)} {
	set r 1;
    }

    return $r;
}
proc filter_file {rc_array seq fpath savedir savename {pass_through 0}} {
#
# This function is also called from the filter_grib function, and there
# it is called with pass_through = 1 because the grib regex has already
# being checked.
#
    upvar $rc_array rc;
    global dafilter;

    if {$pass_through == 0} {
        if {[is_file_rule_enabled $savedir] == 0} {
	    return;
        }
    }

    if {$dafilter(archive_file_enable) != 2} {
	filter_file_normal $seq $fpath $savedir $savename "-a";
    }

    if {$dafilter(archive_file_enable) != 0} {
	append savename $dafilter(archive_file_namefext);
	filter_file_archive rc $seq $fpath $savedir $savename;
    }
}

proc filter_file_noappend {seq fpath savedir savename} {

    global dafilter;

    if {[is_file_rule_enabled $savedir] == 0} {
	return;
    }

    if {$dafilter(archive_file_enable) != 2} {
	filter_file_normal $seq $fpath $savedir $savename;
    }
}

proc filter_file_normal {seq fpath savedir savename {f_append ""}} {
#
# This is the ordinary method for saving the files under the "data" directory.
# This function is called by filter_file and filter_file_noappend.
#
    global dafilter;

    cd $dafilter(datadir);
    file mkdir $savedir;

#    set opts $f_append;
#    if {$dafilter(ccbsaved) == 0} {
#        append opts " -n";
#    }

    set status [catch {
	if {$f_append eq "-a"} {
	    filterlib_cspool_nbspfile $seq $fpath $savedir $savename "-a";
#	    filterlib_nbspfile $seq $fpath $savedir $savename "-a";
#           eval exec nbspfile $opts -d $savedir -o $savename $fpath $seq;
	} else {
	    filterlib_cspool_nbspfile $seq $fpath $savedir $savename;
#	    filterlib_nbspfile $seq $fpath $savedir $savename;
#           eval exec nbspfile $opts -d $savedir -o $savename $fpath $seq;
 	}
    } errmsg];

    if {$status != 0} {
	log_msg $errmsg;
    }
}
proc filter_grib {seq fpath savedir savename} {

    global dafilter;

    if {[is_grib_rule_enabled $savedir] == 0} {
	return;
    }

    if {$dafilter(archive_file_enable) != 2} {
        filter_file_normal $seq $fpath $savedir $savename "-a";	
    }
}
#
# Functions to support the inventory
#

proc filter_insert_inventory {invsubdir savedir fpathout} {
# 
# See the function with this same name in the rstfilter.lib for the meaning
# of the "savedir" argument.
#
    global dafilter;

    # The da invdir must exist
    if {[file isdirectory $dafilter(invdir)] == 0} {
	log_msg "No $dafilter(invdir)";
	return;
    }

    # The inventory files are saved in hourly subdirs within
    # digatmos/<invsubdir>. E.g.,
    # digatmos/nexrad/nids/<yyyymmddhh>/nexrad.nids.mhx.ncr
    #
    set parentdir [file join $dafilter(invdir) $invsubdir \
	[clock format [clock seconds] -format $dafilter(invformat) -gmt true]];
    file mkdir $parentdir;

    set invfile_name [join [file split $savedir] "."]
    set invfile [file join $parentdir $invfile_name];

    filterlib_file_append $invfile $fpathout;
}

proc filter_rad_insert_inventory {savedir fpathout} {

    global dafilter;

    if {$dafilter(rad_inv_enable) == 0} {
	return;
    }

    filter_insert_inventory $dafilter(radinvsubdir) $savedir $fpathout;
}

proc filter_sat_insert_inventory {savedir fpathout} {

    global dafilter;

    if {$dafilter(sat_inv_enable) == 0} {
	return;
    }

    filter_insert_inventory $dafilter(satinvsubdir) $savedir $fpathout;
}
proc dafilter_periodic {} {
#
# The hourly function to send the files to the news server.
# (Disabled if running as a worker slave.)

    global dafilter;

    if {$dafilter(option_s) == 0} {
	dafilter_nntp;
    }
}
proc filter_rad {seq fpath savedir savename {level2flag 0}} {

    global dafilter;

    if {[is_rad_rule_enabled $savedir] == 0} {
	return;
    }

    if {$dafilter(archive_rad_enable) == 2} {
	# Archive-only mode
	return;
    }

    set _pwd [pwd];

    cd $dafilter(datadir);
    file mkdir $savedir;
    set data_path [file join $savedir $savename];
    set datafpath [file join $dafilter(datadir) $data_path];

    set status [catch {
	if {$level2flag == 0} {
	    filterlib_cspool_nbspfile $seq $fpath $savedir $savename;
	    # filterlib_nbspfile $seq $fpath $savedir $savename;
	} else {
	    # level 2 files do not have a ccb, and since they do not pass
	    # through the processor they are not in the cspool cache.
	    file copy -force $fpath $datafpath;
	}
    } errmsg];

    if {$status != 0} {
	# In case the file was created
	file delete $data_path;
	log_msg $errmsg;

	return;
    }

    filter_rad_insert_inventory $savedir $datafpath;

    # Create the link to the latest
    make_rad_latest $savedir $savename $level2flag;

    # Create the directory listing
    make_rad_dirlist $savedir $level2flag;

    cd $_pwd;
}
proc filter_sat {seq fpath savedir savename {giniflag 1}} {
#
# This function optionally uncompresses the file, and renames it according
# to the way the image files are saved by the rst filter. This is done
# only for the non-polarsat ginis.
#
    global dafilter;

    if {[is_sat_rule_enabled $savedir] == 0} {
	return;
    }

    if {$dafilter(archive_sat_enable) == 2} {
	return;
    }

    set _pwd [pwd];

    # This is now (Sun Nov 29 23:34:49 AST 2009) done in the filterlib
    # through the rc variables.
    #
    # First extract the relevant information from the raw data file
    # in order to rename the data file to match the image
    # (which this filter does not produce); e.g,
    #
    # knes_tigp01.070101_1414381 (raw, compressed)
    # tigp01_20060307_0101.png   (image)
    # tigp01_20060307_0101.gini  (optionally uncompressed data)
    #
    # set output [filter_sat_info $fpath];
    # set status [lindex $output 0];
    # set datetime [lindex $output 1];

    cd $dafilter(datadir);
    file mkdir $savedir;
    set datafpath [file join $dafilter(datadir) $savedir $savename];

    set status [catch {
	if {$giniflag == 1} {
	    if {$dafilter(satuncompress) == 0} {
	        # Gini sat files do not have a ccb
	        file copy -force $fpath $datafpath;
	    } else {
	        exec nbspunz -o $datafpath $fpath;
	    }
	} else {
	    filterlib_cspool_nbspfile $seq $fpath $savedir $savename;
	}
    } errmsg];

    if {$status != 0} {
	file delete $datafpath;
	log_msg $errmsg;
	return;
    }

    filter_sat_insert_inventory $savedir $datafpath;

    # Create the link to the latest
    make_sat_latest $savedir $savename;

    cd $_pwd;
}

#
# main function
#
proc main {argc argv} {

    global dafilter;
    global errorInfo;

    cd $dafilter(datadir);

    # gets returns -1 on eof. In addition the server explicitly
    # signals the filters to quit by sending a blankline
    # (gets returns 0 in this case, and finfo is "").

    while {[gets stdin finfo] >= 0} {
	if {$finfo == ""} {
	    log_msg "Received request to quit.";
	    break;
	}

	set status [catch {process $finfo} errmsg];
	if {$status == 1} {
	    log_msg "Error processing $finfo";
	    log_msg $errmsg;
	    log_msg $errorInfo;
	}

	dafilter_periodic;
    }
}

proc process {finfo} {

    global dafilter;

    set _cmd [list filterlib_get_rcvars rc $finfo];

    # If grib is enable, extract the rc(gribxxx) parameters
    if {([info exists dafilter(grib_enable)] == 0) || \
	($dafilter(grib_enable) != 0)} {
	lappend _cmd "-dogrib";
    }

    # If rad is enable, extract the rc(radxxx) parameters
    if {([info exists dafilter(rad_enable)] == 0) || \
	($dafilter(rad_enable) != 0)} {
	lappend _cmd "-dorad";
    }

    # If sat is enable, extract the rc(satxxx) parameters
    if {([info exists dafilter(sat_enable)] == 0) || \
	($dafilter(sat_enable) != 0)} {
	lappend _cmd "-dosat";
    }

    eval ${_cmd};

    set dafilter(archive_subdir) [clock format $rc(seconds) -format \
	$dafilter(archive_subdirfmt) -gmt true];

    # If we want the inventory names to be based on the arrival time, then
    # use
    #
    # set invseconds [clock seconds];
    #
    set invseconds $rc(seconds);
    set dafilter(archive_inv_subdir) [clock format $invseconds -format \
	$dafilter(archive_inv_subdirfmt) -gmt true];
    set dafilter(archive_inv_name) [clock format $invseconds -format \
	$dafilter(archive_inv_namefmt) -gmt true];
    unset invseconds;

    # These variables are based on the time determined by the filterlib
    # The default is the wmotime, except when the data file gives a true time,
    # for example radar and sat files.
    set ymd_hm $rc(ymd_hm);
    set ymdhm $rc(ymdhm);
    set ymd_h $rc(ymd_h);
    set ymdh $rc(ymdh);
    set ymd $rc(ymd);
    set ym $rc(ym);
    set yyyy $rc(yyyy);

    set rc_status 1;

    # Evaluate the condition/action pairs, from all sets.
    set i 0;		# counts the sets
    foreach condlist $dafilter(condition) {
        set actionlist [lindex $dafilter(action) $i];
	set j 0;	# counts the rules with each set
	foreach c $condlist {
	    set a [lindex $actionlist $j];
            if {[expr $c]} {
                eval $a;
            }
	    incr j;
        }
        incr i;
    }
}

#
# main
#
array set option [::cmdline::getoptions argv $optlist $usage];
set argc [llength $argv];

# Check if invoked as a slave worker
if {$option(s) == 1} {
    set dafilter(option_s) 1;
}

filterlib_init;		# open the cpool if enabled
main $argc $argv;
filterlib_end;		# close the cpool if enabled
