\cancel mode verify   

! dsg_checker.jnl
! Check a DSG file for valid attributes and LAS/ ERDDAP reqirements
!  * Global attribute Feature_Type
!  * Attribute cf_role attribute on the ID variable must match the feature type
!  * Attribute sample_dimension on the Rowsize variable (optional for single-feature files)
!  * The ID variable must be of string type (for ERDDAP).
!  * The time variable must be in units of "seconds since 1970-01-01" (for ERDDAP).


query/ignore $1%|<Argument 1 is the file to check%


use $1
DEFINE SYMBOL filename = $1

USE ($filename)

SAY
SAY --------- Analyzing ($filename)
SAY

LET errors = 0

! Look for Global attribute Feature_Type. 

LET attnames = ..attnames
IF `is_element_of_str_n(attnames, "featureType") gt 0` then define symbol feature_type = `..featureType`


IF `($feature_type"0|*>1) EQ 0` THEN
   SAY
   SAY **ERROR ** Global Feature_Type attribute is not found.
   SAY 
   SAY Exit
   SAY
   CANCEL DATA/ALL; CANCEL VAR/ALL; CANCEL SYMBOL/ALL
   EXIT/SCRIPT

ELSE
   SAY
   SAY --------- FeatureType is ($feature_type).
ENDIF

! Look for the cf_role attribute. It must be ($feature_type)_id.
! Check for the sample_dimension attribute.
! Find the time variable and store its units string

LET varnames = ..varnames
LET nvars = ..nvars
REPEAT/RANGE=1:`nvars`/NAME=q (\
DEFINE SYMBOL q = `q`;\
DEFINE SYMBOL vname = `varnames[i=($q)]`;\
IF `STRCMP( UPCASE("($vname)"), UPCASE("($ROWSIZE)") ) EQ 0` THEN \
 DEFINE SYMBOL rowsizevar = ($vname);\
;\
LET attnames = ($vname).attnames;\
IF `IS_ELEMENT_OF_STR_N(attnames, "cf_role") GT 0` THEN; \
  DEFINE SYMBOL cf_role = `($vname).cf_role`;\
  DEFINE SYMBOL id_var = ($vname);\
ENDIF;\
;\
IF `IS_ELEMENT_OF_STR_N(attnames, "sample_dimension") GT 0` THEN; \
  DEFINE SYMBOL sample_dimension = `($vname).sample_dimension`;\
  DEFINE SYMBOL row_var = ($vname);\
ENDIF;\
;\
IF `($time_units"0|*>1") EQ 0 AND IS_ELEMENT_OF_STR_N(attnames, "units") GT 0` THEN; \
  DEFINE SYMBOL units = `($vname).units`_aa;\
  IF `STRINDEX( UPCASE("($units)"), " SINCE " ) GT 0` THEN;\
     DEFINE SYMBOL time_var = ($vname);\
     DEFINE SYMBOL time_units = `($vname).units`;\
  ENDIF;\
ENDIF)

! If no cf_role, look for it on a coordinate variable.
IF `($cf_role"0|*>1) EQ 0` THEN

   LET coordnames = ..coordnames
   LET ncoord = ..ncoordvars

   REPEAT/RANGE=1:`ncoord`/NAME=q (\
   DEFINE SYMBOL q = `q`;\
   DEFINE SYMBOL cname = `coordnames[i=($q)]`;\
   LET attnames = (($cname)).attnames;\
   IF `IS_ELEMENT_OF_STR_N(attnames, "cf_role") GT 0` THEN; \
     DEFINE SYMBOL cf_role = `(($cname)).cf_role`;\
     DEFINE SYMBOL id_var = ($cname);\
     DEFINE SYMBOL vtype = FLOAT;\
   ENDIF)
ENDIF

! Report cf_role attribute.
IF `($cf_role"0|*>1) EQ 0` THEN
   SAY
   SAY **ERROR ** cf_role attribute is not found.
   LET errors = `errors + 1`
ELSE
   SAY
   SAY --------- cf_role attribute found on variable ($id_var).
ENDIF

! Check that the feature type and cf_role attribute describe the same feature type.

DEFINE SYMBOL feature_type_test = ($feature_type)_id

IF `STRCMP( UPCASE("($feature_type_test)"), UPCASE("($cf_role)") ) NE 0` THEN
   SAY
   SAY **ERROR ** cf_role attribute must match the feature type.
   SAY **       ** Feature_Type is ($feature_type) cf_role is ($cf_role).
   LET errors = `errors + 1`
ELSE
   SAY
   SAY --------- cf_role attribute ($cf_role) matches feature type ($feature_type).
ENDIF


! For LAS, the type of the ID variable must be String.

IF `($vtype"0|*>1") EQ 0` THEN DEFINE SYMBOL vtype = `($id_var),RETURN=dtype`
IF `($vtype"0|CHAR>1|*>0") EQ 0` THEN
   SAY
   SAY **ERROR ** The ID variable: ($id_var), must be of type string. Its type is ($vtype"Unknown").
   LET errors = `errors + 1`
ELSE
   SAY
   SAY --------- ID variable, ($id_var), is of type string.
ENDIF

! Make sure the rowSize and ID variable are on the same, non-normal grid.
IF `($rowsizevar"0|*>1") AND ($id_var"0|*>1")` THEN 

   LET instance_grid = `($id_var),RETURN=grid`
   LET rgrid = `($rowsizevar),RETURN=grid`
   IF `STRCMP("($instance_grid)", "($rgrid)") NE 0` THEN 
      SAY
      SAY **ERROR ** Grids of OD variable, ($id_var), and Rowsize variable, ($rowsizevar), do not match
      SHOW GRID ($idvar)
      SHOW GRID ($rowvar)
      LET errors = `errors + 1`
   ENDIF
ENDIF

! Check the sample_dimension attribute, matching a dimension name

IF `($sample_dimension"0|*>1") EQ 1` THEN
   LET dimnames = ..dimnames
   LET ndims = ..ndims
   REPEAT/RANGE=1:`ndims`/NAME=q (\
   DEFINE SYMBOL q = `q`;\
   DEFINE SYMBOL dname = `dimnames[i=($q)]`;\
   IF `STRCMP( UPCASE("($sample_dimension)"), UPCASE("($dname)") ) EQ 0` THEN;\
      DEFINE SYMBOL sample_dim = ($dname);\
      EXIT/LOOP;\
   ENDIF)
ENDIF

! Report on the sample_dimension attribute 

IF ($sample_dim"0|*>1") THEN
   SAY
   SAY --------- sample_dimension attribute found, ($sample_dim).
ELSE
   SAY
   SAY **NOTE  ** sample_dimension attribute not found. This is acceptable for a file containing a single feature. 
ENDIF

! Is the sample_dimension attribute on the variable named rowSize? If not, it's legal,
! but issue a note.

IF ($rowsizevar"0|*>1") THEN
   IF `($rowvar"0|*>1") AND (STRCMP( UPCASE("($rowvar)"), UPCASE("($rowsizevar)") ) NE 0)` THEN
   SAY
   SAY **NOTE  ** There is a variable named ($rowvar), but the sample_dimension attribute is on variable ($rowsizevar)
   ENDIF
ENDIF


! Look for longitude and latitude variables. 
! For ERDDAP: Are the longitudes in -180:180?

REPEAT/RANGE=1:`nvars`/NAME=q (\
DEFINE SYMBOL q = `q`;\
DEFINE SYMBOL vname = `varnames[i=($q)]`;\
leT mmvar = MINMAX(($vname));\
LET attnames = ($vname).attnames;\
IF `IS_ELEMENT_OF_STR_N(attnames, "units") GT 0` THEN;\
   LET vunits = ($vname).units;\
   IF `strlen(vunits) LE 1` THEN EXIT/CYCLE;\
   DEFINE SYMBOL vunits = `($vname),RETURN=units`;\
   IF `STRINDEX(UPCASE("($vunits)"), "NORTH") GT 0` THEN;\
      LET l1 = mmvar[i=@MIN];\
      LET l2 = mmvar[i=@MAX];\
      SAY;\
      SAY --------- Latitude variable found ... ($vname) with units ($vunits), ($vname) range `l1,prec=6`  to  `l2,prec=6`;\
   ENDIF;\
   IF `STRINDEX(UPCASE("($vunits)"), "EAST") GT 0` THEN;\
      SAY;\
      LET l1 = mmvar[i=@MIN];\
      LET l2 = mmvar[i=@MAX];\
      SAY --------- Longitude variable found ... ($vname) with units ($vunits), ($vname) range `l1,prec=6`  to  `l2,prec=6`;\
      IF `(l1 lt -180 or l2 gt 180)` then;\
      SAY **ERROR ** Longitude must be in -180:180;\
   ENDIF;\
ENDIF;\
CANCEL SYMBOL vunits;\
)


! Check for the time variable 
! For ERDDAP: units must be seconds since 1-jan-1970

IF `($time_var"0|*>1") EQ 0` THEN
   SAY  
   SAY **ERROR ** Time variable not found. Searching for units of xxx since date.
   LET errors = `errors + 1`
ELSE
   IF `STRINDEX(UPCASE("($time_units)"), "SECONDS SINCE 1970-01-01") EQ 0` THEN
      SAY  
      SAY **ERROR ** Time Units must be seconds since 1970-01-01. \
      Units on ($time_var) are ($time_units)
      LET errors = `errors+1`
   ELSE
      SAY  
      SAY --------- Time variable ($time_var) with units of ($time_units).
   ENDIF
ENDIF

SAY  
SAY 
SAY
IF `errors GT 0` THEN     
   SAY ---------   File ($filename) `errors` errors detected.
ELSE
   SAY ---------   ($filename) passed.
ENDIF
SAY  
SAY 
SAY  

CANCEL DATA/ALL; CANCEL VAR/ALL; CANCEL SYMBOL/ALL
