#!/usr/bin/env ruby
#
# gpv2nc
# Copyright (C) by GFD-Dennou Club, 2002.  All rights reserved.

def usage
   return <<-EOS

   #{$0}: Converts GPV files into a NetCDF file

   Usage:
      % #{$0} [-ihd] gpv_files.. [-o output_file]

      -o output_file : output file name (if omitted, determined internally)
      -h : help (to show this message)
      -d : debug mode (does extra printing)
      -i : shows info on the input file (does not dump a file, but creates
           a temporarlly file -- if you do not have a write permission of the
           current directory, specify one you have it by the envronmental
           variable TMPDIR. Example: % export TMPDIR=/tmp).
   EOS
end
#############################################################
require 'numru/gpv/bugaifile.rb'
require "getopts"
include NumRu

if( getopts('ihd',"o:gpv.nc") && ! $OPT_h )
   ofilename = $OPT_o
   show_info = $OPT_i
   $DEBUG = $OPT_d
else
   raise usage
end

outfmt = 'netcdf'

GPVID = %w(institution source grid basetime average)
gpvid = Hash::new
planetype = nil

plane = []
validtime = []
xlist = []
ylist = []
elems = []

ARGV.each { |fnam|
    fp = BugaiFile::new(fnam, "r")
    fp.each { |rec|
        bull = rec.decode
        raise "currently only DGRB is supported" unless bull.is_a? DGRB
        bull.each { |sec|
            raise "currently only DGRB/GPV is supported" \
		unless sec.is_a? DGRB::StdSection
	    if planetype.nil? then
		print "prescanning ...\n"; $defout.flush
		GPVID.each {|k| gpvid[k] = sec.send(k) }
		planetype = sec.planetype
	    else
		GPVID.each {|k|
		    raise "#{k} mismatch (#{gpvid[k]} != #{sec.send(k)})" \
			if not gpvid[k] == sec.send(k)
		}
		raise "planetype mismatch (#{planetype}, #{sec.planetype})" \
		    unless planetype.compatible? sec.planetype
	    end
	    plane = (plane.push sec.plane1).uniq
	    validtime = (validtime + sec.validtime_list).uniq
	    xlist = (xlist + sec.xlist).uniq
	    ylist = (ylist + sec.ylist).uniq
            elems = (elems.push sec.format.to_i).uniq
        }
    }
    fp.close
}

p "plane list", plane if $DEBUG
p "fcst time list", validtime if $DEBUG
p "i grid number", xlist if $DEBUG
p "j grid number", ylist if $DEBUG
p "element list", elems if $DEBUG

if outfmt == 'netcdf' then

    require 'numru/netcdf'
    if (show_info)
        output = NumRu::NetCDF::create_tmp
    else
        output = NumRu::NetCDF::create(ofilename)
        print "file created ...\n"; $defout.flush
    end

    dimx = output.def_dim('lon', xlist.size)
    dimy = output.def_dim('lat', ylist.size)
    dimz = output.def_dim('p', plane.size) if not plane.first.nil?
    dimt = output.def_dim('time', validtime.size)

    output.def_var('lon', "sfloat", [dimx])
    output.def_var('lat', "sfloat", [dimy])
    output.def_var('p', "sfloat", [dimz]) if not plane.first.nil?
    output.def_var('time', "sfloat", [dimt])

    elems.each { |ie|
        e = DGRB::Parameter::new(ie)
        varname = e.altname
        if ! (plane.first.nil?)
            output.def_var(varname, "sfloat", [dimx, dimy, dimz, dimt])
	else
            output.def_var(varname, "sfloat", [dimx, dimy, dimt])
	end
        output.var(varname).put_att('long_name', e.alttitle)
        output.var(varname).put_att('units', e.units)
    }   

    output.enddef

    output.var('lon').put gpvid['grid'].lon_list xlist
    output.var('lat').put gpvid['grid'].lat_list ylist
    if not plane.first.nil?
        output.var('p').put plane
    end
    output.var('time').put(validtime.collect(){|e| e.to_i })

    if (show_info)
        output.close
        p output.path if $DEBUG
        print `ncdump -c #{output.path}`
        exit
    end

    ARGV.each { |fnam|
	fp = BugaiFile::new(fnam, "r")
	fp.each { |rec|
	    bull = rec.decode
	    raise "currently only DGRB is supported" unless bull.is_a? DGRB
	    bull.each { |sec|
		vlist = sec.validtime_list
                ip = plane.index sec.plane1
		iv = validtime.index vlist.first
		ix = xlist.index sec.xlist.first
		iy = ylist.index sec.ylist.first
                nv = sec.format.altname
                kx = xlist.index sec.xlist.last
                ky = ylist.index sec.ylist.last
		kv = validtime.index vlist.last
		if (vlist.size > 1) then
		    sv = (kv - iv) / (vlist.size - 1)
		else
		    sv = 1
		end
		#p [iv, ip, iy, ix]
		# "->", kv, ip, ky, kx, "nv", \
		#    ">>", sv, ":", sec.get_vals.size ]
	        if ! (plane.first.nil?)
	            output.var(nv).put(sec.get_vals, \
		        "start" => [ix, iy, ip, iv], \
                        "end" => [kx, ky, ip, kv],
		        "stride" => [1, 1, 1, sv])
		else
	            output.var(nv).put(sec.get_vals, \
		        "start" => [ix, iy, iv], \
                        "end" => [kx, ky, kv],
		        "stride" => [1, 1, sv])
		end
            }
        }
    }

    output.close

end
