#!/usr/bin/ruby
=begin
= ԃCu nwpl/nwptime
=end

module NWPL

=begin
== class NWPL::NwpTimeSpan
ԊԊu\NXB
NwpTime gĉZs߂ɎgB
=end

class NwpTimeSpan

    def initialize (factor, units = "MIN")
	@min = @mon = 0
	case factor
	when Array
	    @min, @mon = factor
	    return
	end
	case units
	when 'MIN', 'MINUTE'
	    @min = factor
	when 'HOUR'
	    @min = factor * 60
	when 'DAY'
	    @min = factor * 60 * 24
	when 'WEEK'
	    @min = factor * 60 * 24 * 7
	when 'MON', 'MONTH'
	    @mon = 1
	else
	    raise NwpTime::FmtError, "Bad time units #{units}"
	end
    end

    MIN = NwpTimeSpan::new([1, 0])
    HOUR = NwpTimeSpan::new([60, 0])
    DAY = NwpTimeSpan::new([1440, 0])
    MON = NwpTimeSpan::new([0, 1])

    attr_reader :min, :mon

    def to_s
        if @mon.zero? and @min % 1440 == 0
  	    "#{@min / 1440} DAY"
        elsif @mon.zero? and @min % 60 == 0
  	    "#{@min / 60} HOUR"
        elsif @mon.zero? then
  	    "#{@min} MIN"
        elsif @min.zero? then
  	    "#{@mon} MON"
	else
	    "(#{@min} MIN + #{@mon} MON)"
	end
    end

    def * other
        # other = other.to_i if other.is_a? String and /^\d+$/.match other
        self.class.new([@min * other, @mon * other])
    rescue TypeError => e
	if other.is_a? String and /^\d+$/.match other then
	    STDERR.print "Warning #{$0}: (other=#{other.inspect})\n\t",
		e.backtrace.join("\n\t"), "\n" if $DEBUG
	    other = other.to_i
	    retry
	end
	raise e
    end

    def / other
        self.class.new([@min / other, @mon / other])
    rescue TypeError => e
	if other.is_a? String and /^\d+$/.match other then
	    STDERR.print "Warning #{$0}: (other=#{other.inspect})\n\t",
		e.backtrace.join("\n\t"), "\n" if $DEBUG
	    other = other.to_i
	    retry
	end
	raise e
    end

    def -@
        self.class.new([-@min, -@mon])
    end

    def + other
	case other
	when NwpTimeSpan
	    self.class.new([@min + other.min, @mon + other.mon])
	when NwpTime
	    other + self
	when Numeric
	    self.class.new([@min + other, @mon])
	end
    end

    def - other
	case other
	when NwpTimeSpan
	    self.class.new([@min - other.min, @mon - other.mon])
	when NwpTime
	    other + -self
	when Numeric
	    self.class.new([@min - other, @mon])
	end
    end

end

class NwpTime

=begin
== class NWPL::NwpTime
l\pB
Comparable CN[hĂB
== ŋN肤O
FmtError  StandardError ̌p
=end

    class FmtError < StandardError
    end

    include Comparable

=begin
=== 萔
--- UNDEF
    閧 Integer lŁA\zɕs莞\߂ɗpB
=end

    UNDEF = 1
    UNIX_ERA = 88_885_440

=begin
=== NX\bh
--- new time, quiet = false
    ɉēK؂Ȏ\zB
    * Time IuWFNgȂ΂̂܂ܕϊ
    * Numeric IuWFNgȂ 1801N1100 (? vmF)
      ̒ʎZƂ݂Ȃ to_i Ǝ
    * String IuWFNgȂ ISO `Ƃ݂ȂĎB
      ܂sȂꍇ FmtError 𓊂B
       quiet ^ɂꍇ͓ȒlԂ;
       oob? ɂmFłB
    * ȊǑ^̏ꍇ TypeError
=end

    def initialize arg, quiet = false
        case arg
	when Time
	    @min = arg.tv_sec / 60 + UNIX_ERA
	when Numeric
	    @min = arg.to_i
	when String
	    if (m = /^(\d+)-(\d+)-(\d+)[-Tt](\d\d)(\d*)/.match(arg)) then
		t = Time::utc(m[1], m[2], m[3], m[4], m[5])
		@min = t.tv_sec / 60 + UNIX_ERA
	    elsif (m = /^(\d+)-(\d+)-(\d+)[-Tt](\d)/.match(arg)) then
		t = Time::utc(m[1], m[2], m[3], m[4])
		@min = t.tv_sec / 60 + UNIX_ERA
	    elsif (m = /^(\d+)-(\d+)-(\d+)[-Tt](\d+):(\d+)/.match(arg)) then
		t = Time::utc(m[1], m[2], m[3], m[4], m[5])
		@min = t.tv_sec / 60 + UNIX_ERA
	    elsif (m = /^(\d+)-(\d+)-(\d+)/.match(arg)) then
		t = Time::utc(m[1], m[2], m[3])
		@min = t.tv_sec / 60 + UNIX_ERA
	    elsif (m = /^min(\d+)/.match(arg)) then
		@min = m[1].to_i
            else
		if quiet then
		    @min = nil
		    return
		end
		fail FmtError, "malformatted time #{arg}"
	    end
	else
	    raise(TypeError, arg.inspect)
	end
    end

=begin
--- self::gettime (timecard = 'TIMECARD')
    t@C timecard ̐l\^CJ[hJA
    ǂ݂Ƃ NwpTime \zB
    Ƃ肠 Time::utc oRŎĂ̂ŁA܂̂▢͈ȂB
=end

    def self::gettime(timecard = 'TIMECARD')
	fp = File::open(timecard, "r")
	a = fp.readline.strip.split(/\s+/)
	fp.close
	self::new(Time::utc(*a))
    end

=begin
=== CX^X\bh
--- to_i
    ʎZԂ
--- undef?
    UNDEF l̏ꍇ^
--- unix
    UNIX ̒ʎZbԂB\łȂ͈͂ł̓I[o[t[B
--- time
    unix  Time IuWFNgĕԂB
=end

    def to_i; @min.to_i; end

    def undef?; @min.nil? or @min == UNDEF; end

    def oob?; @min.nil?; end

    def unix; (@min - UNIX_ERA) * 60; end

    def time; Time::at((@min - UNIX_ERA) * 60).utc; end

=begin
--- year
--- mon
--- mday
--- wday
--- hour
--- min
    Time NXƓl̈ӖB
    ƂA܂̂Ƃ Time oRĎĂ̂ŁA
    ͈̔͂łȂB
=end

    def year;  unix.year;  end
    def mon;  unix.mon;  end
    def mday;  unix.mday;  end
    def wday;  unix.wday;  end
    def hour;  unix.hour;  end
    def min;  unix.min;  end

=begin
--- to_s
    pandora W̏ (ISO) sB܂̂ƂAtime \bh
    IɎgpĂ̂ŁAUNIX \łȂ͈͂̎ɂĂ
    ONB
=end

    def to_s
	return sprintf('min%d', @min) if @min < 10
	time.strftime '%Y-%m-%dt%H%M'
    end

=begin
--- narrow
    NuSDaS Iɗpt@Ĉ߂̏sB
=end

    def narrow
	time.strftime '%Y%m%d%H%M'
    end

=begin
--- time <=> other
    召rsB
    Comparable ɂAEsEbetween? g悤ɂȂB
=end

    def <=> (other)
	case other
	when Time
	    return unix <=> other
	when Numeric
	    return @min
	when NwpTime
	    return @min <=> other.to_i
	else
	    fail "NwpTime <=> #{other.type} (#{other.inspect})"
	end
    end

=begin
--- time - other
    ̌ZsB
    NwpTime ɕϊ^ NwpTimeSpan ԂB
    NwpTimeSpan  NwpTime ԂB
    Numeric  NwpTimeSpan::new(((|other|))) ̂ƓB
--- time + other
    ̉ZsB
    ʂɒĂ͌ZƓlB
=end

    def - (other)
        case other
        when Time, String
	     NwpTimeSpan::new(self.to_i - NwpTime::new(other).to_i)    
        when NwpTime
	     NwpTimeSpan::new(self.to_i - other.to_i)    
        when Numeric
	     NwpTime::new(self.to_i - other)    
        when NwpTimeSpan
	     raise if not other.mon.zero?
	     NwpTime::new(self.to_i - other.min) 
	else
	     raise ArgumentError, other.inspect
        end
    end

    def + (other)
        case other
        when Time, String
	     NwpTimeSpan::new(self.to_i + NwpTime::new(other).to_i)    
        when Numeric
	     NwpTime::new(self.to_i + other)    
        when NwpTimeSpan
	     raise if not other.mon.zero?
	     NwpTime::new(self.to_i + other.min) 
	else
	     raise ArgumentError, other.inspect
        end
    end

=begin
=== foOpNX\bh
--- self::debug
    R}hCׂĂɂāANwpTime \z to_s  p B
=end

    def self::debug
	ARGV.each do |arg|
	    p NwpTime::new(arg).to_s
	end
    end

end

end
# $Id: nwptime-rb.rb,v 1.3 2002/09/10 01:29:07 suuchi43 Exp $
=begin
= class Nusdas::NusDecode

DATA L^ GPV 𓾂邽߂̃fR[hB
=end

module Nusdas
class NusDecode

    begin
        require 'narray'
	NARRAY = true
    rescue LoadError
	NARRAY = false
    end

=begin
== NX\bh
--- self::new nx, ny, pack, miss, payload
    f[^L^̊iq̑傫 ((|nx|)), ((|ny|)),
    k@ ((|pack|)), l\@ ((|miss|)),
    k+f[^ ((|payload|)) pč\zB
=end

    def initialize nx, ny, pack, miss, payload
	@nx, @ny, @pack, @miss, @payload = nx, ny, pack, miss, payload
    end

=begin
== CX^X\bh
=== \z
--- nx
    ꎟ̊iq
--- ny
    񎟌̊iq
--- pack
    k@
--- miss
    l̕\@
--- payload
    kꂽ񂻂̂
=end

    attr_reader :nx, :ny, :pack, :miss, :payload

=begin
=== lɊւ͌
=end

=begin
--- miss_offset
    ((<miss>))  ((<payload>)) ̌lɊւ闓̃oCg߂B
=end

    def miss_offset
	case @miss
	when 'NONE' then 0
	# elemwidth q
	when 'UDVF' then elemwidth()
	when 'MASK' then @payload.unpack('N').first
	else raise
	end
    end

=begin
--- pbody
    ((<payload>))  ((<miss_offset>)) oCg菜́B
    ̐擪͈kłB
=end

    def pbody 
	@payload[miss_offset .. -1]
    end

=begin
=== kɊւ͌
--- elemwidth
    kꂽ1vfoCg
--- pack_offset
    ((<pack>))  ((<payload>)) ̈kɊւoCg߂B
--- body
    ((<payload>))  ((<miss_offset>))  ((<pack_offset>)) ̍v
    擪̃oCg菜́B
    ͔z񂻂̂̂łB
=end

    def elemwidth;  PACKINFO[@pack][0];  end
    def pack_offset;  PACKINFO[@pack][2];  end

    def body 
	ofs = miss_offset + pack_offset
	@payload[ofs .. -1]
    end

=begin
--- unpack_nt
    ŏ ((<body>)) fR[h邽߂ɗp NArray ^CvR[hB
    cOȂANArray ɂ 16bit, 32bit ̕ȂȂ̂ŁA
    dȂɕtŕ\邱ƂɂȂ̂ɒӁB
--- sgnfix_nt
    킹邽߂ɗp NArray ^CvR[hB
    킹svȏꍇ nil
--- sgnfix_ofs
    킹ɕlɉZItZbg
--- scale_nt
    XP[ϊ邽߂ɗp NArray ^CvR[hB
    ϊȂĂ悢ꍇ nil ԂB
=end

    def unpack_nt;  NAINFO[ PACKINFO[@pack][1] ]; end
    def sgnfix_ofs;  2 ** (elemwidth * 8);  end

    def sgnfix_nt
	abstype = PACKINFO[@pack][3]
	return nil if abstype.nil?
	NAINFO[abstype]
    end

    def scale_nt
	abstype = PACKINFO[@pack][4]
	return nil if abstype.nil?
	NAINFO[abstype]
    end

=begin
--- ary_raw (typecode = nil)
    ((|body|))  ((<unpack_nt>)) ^ (((|nx|)), ((|ny|))) 
    NArray zɕϊB
    ̂BXP[ῗĂȂB
    * ((|typecode|)) w肵ꍇ͂̌^ɕϊB
      sK؂Ȍ^łɕϊ̂ŒӁB
    * oO: RLE k̏ꍇ ArgumentError ɂȂB̑ΏKv
=end

    def ary_raw (typecode = nil)
	if typecode.nil? then
	    NArray::to_na(body, unpack_nt, @nx, @ny).ntoh
	else
	    a = NArray::to_na(body, unpack_nt, @nx, @ny).ntoh
	    b = NArray::new(typecode, @nx, @ny)
	    b[] = a
	    b
	end
    end

=begin
--- ary_sgnfix (typecode = nil)
    ((<ary_raw>)) ƓA̕𐳂B
    * ̓Iɂ ((<pack>))  '2UPC', '4UPC' ̏ꍇłA܂NȂB
    * ((|typecode|))  NArray::FLOAT ̏ꍇ FLOAT ^vB
      łȂ '2UPC' ̏ꍇ SFLOAT ^vB
    * ϊsvȏꍇ ((<ary_raw>))  ((|typecode|)) 
      ̂܂ܓ`B
=end

    def ary_sgnfix (typecode = nil)
	if (nt = sgnfix_nt).nil? then
	    return ary_raw(typecode)
	end
	nt = NArray::FLOAT if (typecode == NArray::FLOAT)
	b = ary_raw(nt)
	c = NArray::new(nt, @nx, @ny)
	c[] = b < 0
	b + c * sgnfix_ofs
    end

=begin
--- packinfo
    XP[k̏ꍇ͍ŒlƃXP[ȂzԂB
    Ak̏ꍇ̓rbgAkőlA̐ȂzԂB
    łȂꍇ nil ԂB
=end

    def packinfo
	case @pack
	when '1PAC', '2PAC', '2UPC'
	    pbody.unpack('g2')
	when '4PAC', '4UPC'
	    pbody.unpack('G2')
	when 'RLEN'
	    pbody.unpack('N3')
	else
	    nil
	end
    end

=begin
--- ary_scale (typecode = nil)
    ((<ary_sgnfix>)) ƓB
    AXP[ksĂAWJB
    * ̏ꍇAI FLOAT B
      ItZbgƒPxł͌N邱ƂB
    * ((<pack>))  'N1I2' ̏ꍇ SFLOAT  0.1 {B
       ((|typecode|))  FLOAT ̏ꍇ FLOAT ƂBB
    * XP[svȏꍇ ((<ary_raw>))  ((|typecode|)) 
      ̂܂ܓ`B
=end

    def ary_scale (typecode = nil)
	if not (snt = scale_nt).nil? then
	    base, amp = packinfo
	    a = ary_sgnfix(NArray::FLOAT) * amp
	    a + base
	elsif @pack == 'N1I2'
	    snt = (typecode == NArray::FLOAT) ? NArray::FLOAT : NArray::SFLOAT
	    ary_sgnfix(snt) * 0.1
	else
	    ary_sgnfix(typecode)
	end
    end

=begin
--- array (typecode = nil)
    ((<ary_scale>)) ƓBA((|typecode|)) ɂϊ
    IɍsB
=end

    def array (typecode = nil)
	a = ary_scale(typecode)
        if (typecode.nil? or a.typecode == typecode) then
	    a
	else
	    b = NArray::new(typecode, @nx, @ny)
	    b[] = a
	    b
	end
    end

=begin
== 萔
--- PACKINFO
    ʏĝł͂ȂBk`KvȏɊւ𓾂\B
--- NAINFO
    ʏĝł͂ȂB
    PACKINFO ̒ۓIȌ^ NArray  ^R[h𓾂\B
    ̗̕LĂ̂ňʖړIɂ͕sKB
=end

    PACKINFO = {
	#  elemwidth unpack	packofs	signfix	scalefix
	'1PAC' => [1, 'byte',	8,	nil,	'sfloat'],
	'2PAC' => [2, 'sint',	8,	nil,	'sfloat'],
	'2UPC' => [2, 'usint',	8,	'sfloat', 'sfloat'],
	'4PAC' => [4, 'lint',	8,	nil,	'float'],
	'4UPC' => [4, 'ulint',	8,	'float', 'sfloat'],
	'I1  ' => [1, 'byte',	0],
	'I2  ' => [2, 'sint',	0],
	'N1I2' => [2, 'sint',	0,	nil,	'sfloat'],
	'I4  ' => [4, 'lint',	0],
	'R4  ' => [4, 'sfloat',	0],
	'R8  ' => [8, 'float',	0],
	'RLEN' => [1, 'byte',	12]
    }

    NAINFO = {
	'byte'		=> NArray::BYTE,
	'sint'		=> NArray::SINT,
	'usint'		=> NArray::SINT,
	'lint'		=> NArray::LINT,
	'ulint'		=> NArray::LINT,
	'sfloat'	=> NArray::SFLOAT,
	'float'		=> NArray::FLOAT
    }

end
end
# $Id: nusdecode.rb,v 1.3 2002/08/01 10:38:27 suuchi43 Exp $
#!/usr/bin/ruby
# vi: set ts=8 sw=4:


=begin
= nusdas/nusrecord.rb
R[hɊւNXQB
* ((<class Nusdas::NusRecord>))  ܂݂͂Ă
* ((<"class Nusdas::NusRecordNUSD">))
* ((<class Nusdas::NusRecordCNTL>))
* ((<class Nusdas::NusRecordINDX>))
* ((<class Nusdas::NusRecordDATA>))
=end

module Nusdas

class NusRecordNUSD

=begin
== class Nusdas::NusRecordNUSD
NUSD R[h̃fR[h
--- self::new string
    oCg񂩂烌R[h\
--- to_s
    fobOp\
=end

    def initialize val
	fragm = val[0..79];
	@source, = fragm.unpack('80a');
	fragm = val[80..99];
	@version, @t, @nrec, @ninfo, @nsubc = fragm.unpack("NNNNN")
    end

    def to_s
	sprintf("source '%s' ver %d Nrec %d Ninfo %d Nsubc %d", \
	    @source, @version, @nrec, @ninfo, @nsubc)
    end
    
end

class NusRecordCNTL

=begin
== class Nusdas::NusRecordCNTL
ǗR[hɊւfR[h
--- self::new string
    oCg񂩂烌R[h\
=end

    def initialize val
	@body = val
	@n_member = @body.unpack('x36N')[0]
	@n_valid = @body.unpack('x40N')[0]
	@n_plane = @body.unpack('x44N')[0]
	@n_element = @body.unpack('x48N')[0]
    end

=begin
=== E\
--- type1
--- type2
--- type3
--- nustype
    sIhȂB
--- basetime
    ((<NWPL::NwpTime|URL:../nwpl/nwptime.html>)) IuWFNgԂB
--- n_member
--- n_valid
--- n_plane
--- n_element
=end

    def type1; @body.unpack('a8')[0]; end
    def type2; @body.unpack('x8a4')[0]; end
    def type3; @body.unpack('x12a4')[0]; end
    def nustype; sprintf('%s.%s.%s', type1, type2, type3); end
    def basetime; NWPL::NwpTime::new(@body.unpack('x28N')[0]); end
    def tunit; @body.unpack('x32a4')[0]; end
    def n_member; @n_member; end
    def n_valid; @n_valid; end
    def n_plane; @n_plane; end
    def n_element; @n_element; end

=begin
--- member
    o̔z
=end

    def member
	ofs = 156
	wid = 4 * @n_member
	block = @body[ofs, wid]
	block.unpack('a4' * @n_member)
    end

=begin
--- validtime1
--- validtime2
    ((<NWPL::NwpTime|URL:../nwpl/nwptime.html>)) IuWFNg̔z񂪕ԂB
=end

    def validtime1
	ofs = 156 + 4 * @n_member
	wid = 4 * @n_valid
	block = @body[ofs, wid]
	r = []
	block.unpack('N*').each do |x|
	    r << NWPL::NwpTime.new(x)
	end
	return r
    end

    def validtime2
	ofs = 156 + 4 * (@n_member + @n_valid)
	wid = 4 * @n_valid
	block = @body[ofs, wid]
	r = []
	block.unpack('N*').each do |x|
	    r << NWPL::NwpTime.new(x)
	end
	return r
    end

    def validtime
	ofs1 = 156 + 4 * @n_member
	ofs2 = 156 + 4 * (@n_member + @n_valid)
	wid = 4 * @n_valid
	block1 = @body[ofs1, wid].unpack('N*')
	block2 = @body[ofs2, wid].unpack('N*')
	return (0 ... @n_valid).collect { |i|
	    if (block2[i] == NWPL::NwpTime::UNDEF) then
	         NWPL::NwpTime.new(block1[i])
	    else
	         [NWPL::NwpTime.new(block1[i]), NWPL::NwpTime.new(block2[i])]
	    end
	}
    end

    def plane1
	ofs = 156 + 4 * (@n_member + @n_valid * 2)
	wid = 6 * @n_plane
	block = @body[ofs, wid]
	block.unpack('a6' * @n_plane)
    end

    def plane2
	ofs = 156 + 4 * (@n_member + @n_valid * 2) + 6 * @n_plane
	wid = 6 * @n_plane
	block = @body[ofs, wid]
	block.unpack('a6' * @n_plane)
    end

    def plane
	ofs1 = 156 + 4 * (@n_member + @n_valid * 2)
	ofs2 = 156 + 4 * (@n_member + @n_valid * 2) + 6 * @n_plane
	wid = 6 * @n_plane
	block1 = @body[ofs1, wid].unpack('a6' * @n_plane)
	block2 = @body[ofs2, wid].unpack('a6' * @n_plane)
	return (0 ... @n_plane).collect { |i|
	    if (block1[i] == block2[i]) then
	         block1[i].strip
	    else
	         block1[i].strip + "," + block2[i].strip
	    end
	}
    end

    def element
	ofs = 156 + 4 * (@n_member + @n_valid * 2) + 6 * 2 * @n_plane
	wid = 6 * @n_element
	block = @body[ofs, wid]
	block.unpack('a6' * @n_element).collect{ |s| s.strip }
    end

=begin
=== WIg
--- proj
--- grid
--- basetpoint
--- baseloc
--- gridsize
--- projparam
--- repres
=end

    def proj; @body.unpack('x52a4')[0]; end
    def grid; @body.unpack('x56N2'); end
    def basepoint; @body.unpack('x64g2'); end
    def baseloc; @body.unpack('x72g2'); end
    def gridsize; @body.unpack('x80g2'); end
    def projparm; @body.unpack('x88g8'); end
    def repres; @body.unpack('x120a4'); end

=begin
=== foO
--- to_s
=end

    def to_s
	sp = ' '
	qsp = "' '"
	return (<<EOF).chop
	IDEN type '#{nustype}' basetime #{basetime}
	PROJ '#{proj}' #{projparm.join(sp)} base #{baseloc.join(sp)}
	GRID #{grid.join(sp)} size #{gridsize.join(sp)} \
base #{basepoint.join(sp)} time '#{repres}'
	MEMBER #{n_member}
	'#{member.join qsp}'
	VALID #{n_valid} '#{tunit}'
	#{validtime1.join sp}
	#{validtime2.join sp}
	PLANE #{n_plane}
	'#{plane.join qsp}'
	'#{plane2.join qsp}'
	ELEMENT #{n_element}
	'#{element.join qsp}'
EOF
    end

end

class NusRecordINDX

=begin
== class Nusdas::NusRecordINDX
INDX R[h̃fR[h
=== NX\bh
--- self::new string
=end

    def initialize val
	@val = val.unpack("N*")
    end

=begin
--- self::ofs_str (ofs)
    l ((|ofs|)) 6̏\Zi\LBA-1 ̏ꍇɌ "-1" ƂB
=end

    def self::ofs_str(ofs)
	if (ofs == 0xffffffff) then "    -1" else sprintf('%6x', ofs) end
    end

=begin
=== CX^X\bh
--- val
    l̔zԂB
=end

    def value; @val; end

=begin
--- to_s
    foO
=end

    def to_s
	r = ""
	i = 0
	@val.each do |x|
	    if ((i += 1) == 10) then
	        r = r + "\n " + self.class.ofs_str(x)
		i = 0
	    else
	        r = r + " " + self.class.ofs_str(x)
	    end
	end
	r;
    end

end

class NusRecordDATA

=begin
== class Nusdas::NusRecordDATA
DATA R[h̃fR[hB
=== NX\bh
--- self::new string
    oCg񂩂\z
=end

    def initialize val
	@member, @valid1, @valid2, @plane1, @plane2, @element, \
	    @nx, @ny, @pack, @miss \
	    = val.unpack('a4N2a6a6a6x2N2a4a4');
	@valid1 = NWPL::NwpTime::new(@valid1)
	@valid2 = NWPL::NwpTime::new(@valid2)
	@payload = val[48 .. -1]
    end

=begin
=== CX^X\bh
==== wb_
--- member
--- validtime1
--- validtime2
--- plane1
--- plane2
--- element
--- nx
--- ny
--- nustype
--- miss
=end

    attr_reader(:valid1, :valid2, :plane1, :plane2)
    attr_reader(:nx, :ny, :pack, :miss)

    def element; @element.strip; end
    def member; @member == "    " ? "none" : @member; end

    def validtime
	if @valid2.undef? then
	    @valid1
	else
	    [@valid1, @valid2]
	end
    end

    def validtime_str
	validtime.to_a.join(',')
    end

    def plane
	if @plane1 == @plane2 then
	    @plane1.strip
	else
	    @plane1.strip + "," + @plane2.strip
	end
    end

    def payload
	NusDecode::new @nx, @ny, @pack, @miss, @payload
    end

=begin
==== foO
--- to_s
=end

    def to_s
	sprintf("[%s/%s/%s/%s] %d %d %s %s", \
            member, validtime_str, plane, element, @nx, @ny, @pack, @miss)
    end
    
end


class NusRecord

=begin
== class Nusdas::NusRecord
=end

=begin
=== NX\bh
--- self::new (head, body)
    R[h̐擪 12 oCg(ׂẴR[hɋʂ) ((|head|)) 
    c ((|body|)) ^č\zB
    ((<Nusdas::NusRecStream|URL:nusrecstream.html>)) ̓sɂB
=end

    def initialize(_head, _body)
	@recl, @record_type, @contentlen, @rectime = _head.unpack('Na4NN')
	@body = _body
	@contentlen -= 12
    end

=begin
=== CX^X\bh
--- body
    \z̃oCg ((|body|)) ̂
--- recl
    L^̒łByC[h̒ + 16 ł邩ǂ
    ۏ؂̌ł͂Ȃ
--- record_type
    "NUSD", "CNTL", "INDX", "DATA" ̂ꂩ̕B
--- rectime
--- contentlen
    yC[h̒łAL^擪ɏĂl 12 Ȃ
=end

    def body; @body; end
    def recl; @recl; end
    def record_type; @record_type; end
    def rectime; NWPL::NwpTime::new(Time::at(@rectime)); end
    def contentlen; @contentlen; end

=begin
--- payload
    yC[h߂Ĉȉ̂ǂꂩ̃NX\zĕԂB
    * ((<"class Nusdas::NusRecordNUSD">))
    * ((<class Nusdas::NusRecordCNTL>))
    * ((<class Nusdas::NusRecordINDX>))
    * ((<class Nusdas::NusRecordDATA>))
--- record
    payload ̓`
=end

    def payload
	if (@record_type == 'NUSD') then
	    NusRecordNUSD.new(@body)
	elsif (@record_type == 'CNTL') then
	    NusRecordCNTL.new(@body)
	elsif (@record_type == 'INDX') then
	    NusRecordINDX.new(@body)
	elsif (@record_type == 'DATA') then
	    NusRecordDATA.new(@body)
	else
	    nil
	end
    end
    alias record payload

=begin
--- to_s
    foOpo
	sprintf("record %4s %6d [%s]", record_type, contentlen, rectime.to_s)
=end

    def to_s
	sprintf("record %4s %6d [%s]", record_type, contentlen, rectime.to_s)
    end

=begin
--- inspect
    foOpóB
    to_s ɉApayload.to_s \ȂB
=end

    def inspect
	if ((p = payload) != nil) then
	    return to_s + "\n" + p.to_s
	else
	    return to_s
	end
    end

end
end
# $Id: nusrecord.rb,v 1.13 2002/08/01 10:38:27 suuchi43 Exp $

=begin
= class Nusdas::NusRecStream

((<ruby gݍ݂ File|URL:http://www.ruby-lang.org/ja/man-1.6/?cmd=view;name=File>)) pĂB

܂̂ƂAǂݎ肾B
=end

module Nusdas
class NusRecStream < File

=begin
== ŔO
:FmtError
  IOError p
=end

    class FmtError < IOError
    end

=begin
== NX\bh
--- self::new (file, mode = "r", perm = 0666)
    PɃt@CJłȂA binmode ɂB
=end

    def initialize (file, mode = "r", perm = 0666)
        super
        binmode
	@tell_backspace = nil
    end

    attr_reader :tell_backspace

=begin
--- self::open (file, mode = "r", perm = 0666)
    PɃt@CJłȂA binmode ɂB
=end

    def self::open(filename, mode = "r", perm = 0666)
        r = super
        r.binmode
    end

=begin
== CX^X\bh
--- get_record_str
    1R[hǂށBԋpl̓wb_ƃyC[hȂ2vfzB
    t@CGhɗĂ nil ԂB
    * R[h̍\͈ȉ̒ʂB
      T^I FORTRAN ȂҐt@CƂ肾ႤB
      L^͋L^g܂ނ FORTRAN ͓ǂ߂ȂB
      * wb_
        * L^: 32rbg (PʃoCg)
        * L^: 4oCg
        * L^L: 32rbg
        * XV: 32rbgAunix time ̕ԋpl
      * yC[h
        (yC[h̒ (L^ - 20) oCgł邪A
        ̂LȂ̂ (L^L - 12) )
      * L^
--- get_record
    1R[hǂ ((<NusRecord|URL:nusrecord.html>)) \zĕԂB
    t@CGhɗĂ nil ԂB
    G[ ((<FmtError>)) ԂB
    * ((**)) ŕ NUSDAS_WRITE ꂽꍇA
       DATA R[h݂邱ƂɂȂB
      ̏ꍇAINDX R[hɎwĂ̂LłB
      L DATA R[hQƂꍇ
      ((<Nusdas::NusFile|URL:nusfile.html>)) gƁB
=end

    def get_record_str()
        # wb_
	@tell_backspace = self.tell
        head = read(16)
	return nil if head.nil?
	raise FmtError, "too short record" if head.length < 16

        # yC[h
        recl = head.unpack("N").first
	vrecl = head.unpack("x8N").first - 12
        payload = self.read(recl - 20)[0, vrecl]
	if payload.nil? or payload.length < (recl - 20) then
	    raise FmtError, "too short record: missing payload"
	end

        # L^̊mF (wb_̋L^ƂĂ邩)
        tail = read(4)
        if tail.nil? or tail.length < 4 then
            raise(FmtError, "malformed record: missing tail")
        end
        tailed = tail.unpack('N').first
        if (tailed != recl) then
            raise(FmtError, "record length mismatch #{tailed} #{r.size}")
        end
        return [head, payload]
    end

    def get_record()
        head, payload = get_record_str()
	return nil if head.nil?
	return NusRecord.new(head, payload)
    end

=begin
== foOp\bh
--- self::debug
    R}hC̃t@Cɂ get_record Ă݂B
=end

    def self::debug
        for filename in ARGV
            input = NusRecStream::open(filename)
            while 1
                itell = input.tell
                r = input.get_record
                break if (r == nil)
                print "#{sprintf '%04x', itell} #{r.inspect}\n"
            end
            input.close
        end
    end

end
end
# $Id: nusrecstream.rb,v 1.14 2003/02/10 07:57:08 suuchi43 Exp $

=begin
= class Nusdas::NusFile
((<NusRecStream|URL:nusrecstream.html>)) pĂB
=end

module Nusdas

class NusFile < NusRecStream

=begin
== ̗O
--- Nusdas::NusFile::FmtError < StandardError
=end

    class FmtError < StandardError
    end

=begin
== NX\bh
--- self::new (filename, mode = "r", perm = 0666)
    ʎĝł͂ȂB
    P NuSDaS t@CJB
    File::open ƓlA؂̃R[hǂ܂ȂB
=end

    def initialize (filename, mode = "r", perm = 0666)
	super
	@filename = @nusd = @cntl = @indx = nil
	self
    end

    def setup filename, nusd, cntl, indx
	@filename, @nusd, @cntl, @indx = filename, nusd, cntl, indx
    end

=begin
--- self::open (filename)
    t@CJANUSD, CNTL, INDX R[hǂŃZbgAbvB
=end

    def self::open(filename)
	r = self::new(filename)
	begin
	    nusd = r.get_record
	    fail FmtError, 'NUSD not found' if nusd === nil
	end until nusd.record_type == 'NUSD'
	begin
	    cntl = r.get_record
	    fail FmtError, 'CNTL not found' if cntl === nil
	end until cntl.record_type == 'CNTL'
	begin
	    indx = r.get_record
	    fail FmtError, 'INDX not found' if indx === nil
	end until indx.record_type == 'INDX'
        r.setup(filename, nusd, cntl, indx)
	return r
    end

=begin
== CX^X\bh
=end

=begin
=== ǗR[h
--- nustype
--- basetime
--- member
--- validtime1
--- validtime2
--- n_member
--- n_valid
--- n_plane
--- n_element
=end

    def nustype; @cntl.record.nustype; end
    def basetime; @cntl.record.basetime; end
    def member; @cntl.record.member; end
    def validtime1; @cntl.record.validtime1; end
    def validtime2; @cntl.record.validtime2; end
    def validtime; @cntl.record.validtime; end
    def plane; @cntl.record.plane; end
    def element; @cntl.record.element; end
    def n_member; @cntl.record.n_member; end
    def n_valid; @cntl.record.n_valid; end
    def n_plane; @cntl.record.n_plane; end
    def n_element; @cntl.record.n_element; end

=begin
=== ̑
--- read_record (im, iv, ip, ie)
    oԍ im, \񎞊Ԕԍ iv, ʔԍ ip, vfԍ ie
    Ŏw肳郌R[h֒ڃV[NēǂݎB
=end

    def read_record(im, iu, ip, ie)
	im = member.index im if im.is_a? String
	raise "member not found" if im.nil?
	iu = validtime.index iu if iu.is_a? NWPL::NwpTime
	raise "validtime not found" if iu.nil?
	ip = plane.index ip if ip.is_a? String
	raise "plane not found" if ip.nil?
	ie = element.index ie if ie.is_a? String
	raise "element not found" if ie.nil?
	ofs = ((im * n_valid + iu) * n_plane + ip) * n_element + ie
	ofs = @indx.record.value[ofs]
	# L^R[hɂ͂Ȃ 0  -1  
	return nil if ofs == 0xffffffff or ofs == 0
	seek(ofs, IO::SEEK_SET)
	get_record
    end

=begin
--- each_index { |im, iv, ip, ie| ... }
    oԍ im, \񎞊Ԕԍ iv, ʔԍ ip, vfԍ ie
    ̂肤lׂĂɂāAINDX R[h𒲂ׂĒlĂ
    Ƃ yield B
=end

    def each_index
	v = @indx.record.value
	v.each_index { |i|
	    next if v[i] == 0xffffffff or v[i] == 0
	    im = i
	    ie = im % n_element;  im /= n_element
	    ip = im % n_plane;  im /= n_plane
	    iv = im % n_valid;  im /= n_valid
	    yield  im, iv, ip, ie
	}
    end

=begin
--- list (nuspath)
    ((<Nusdas::NusPath|URL:nuspath.html>)) ((|nuspath|)) 
    w肳鉽炩̎ɂĈꗗ쐬B
    ʂ String ̔złB
=end

    def list_member(longp)
	mlist = []
	each_index { |im, iv, ip, ie| mlist << im }
	(@cntl.record.member.indices(*mlist.uniq)).collect {|m|
	    if (/^\s*$/.match m) then "none" else m end
	}
    end

    def list_validtime(nuspath, longp)
	im_given = @cntl.record.member.index nuspath.member
	vlist = []
	each_index { |im, iv, ip, ie|
	    next unless im == im_given
	    vlist << iv
	}
	@cntl.record.validtime.indices(*vlist.uniq)
    end

    def list_plane(nuspath, longp)
	im_given = @cntl.record.member.index nuspath.member
	iv_given = @cntl.record.validtime.index nuspath.validtime
	plist = []
	each_index { |im, iv, ip, ie|
	    next unless im == im_given
	    next unless iv == iv_given
	    plist << ip
	}
	@cntl.record.plane.indices(*plist.uniq)
    end

    def list_element(nuspath, longp)
	im_given = @cntl.record.member.index nuspath.member
	iv_given = @cntl.record.validtime.index nuspath.validtime
	ip_given = @cntl.record.plane.index nuspath.plane
	elist = []
	each_index { |im, iv, ip, ie|
	    next unless im == im_given
            next unless iv == iv_given
            next unless ip == ip_given
	    elist << ie
	}
	@cntl.record.element.indices(*elist.uniq)
    end

    def list (nuspath, longp)
	return list_member(longp) if nuspath.member.nil?
	return list_validtime(nuspath, longp) if nuspath.validtime.nil?
	return list_plane(nuspath, longp) if nuspath.plane.nil?
	return list_element(nuspath, longp) if nuspath.element.nil?
	[]
    end

=begin
=== fobO
--- to_s
    fobOóB
--- self::debug
    R}hCŎw肳t@CJăfobOo͂B
=end

    def to_s
	return (<<EOF)
file=#{@filename}
nusd=#{@nusd.to_s}
cntl=#{@cntl.to_s}
  type=#{nustype} base=#{basetime}
  member=#{member.join('/')}
  valid1=#{validtime1.join('/')}
  valid2=#{validtime2.join('/')}
indx=#{@indx.to_s}
EOF
    end

    def self::debug
	f = open(ARGV[0])
	print f
	m = f.member
	u = f.validtime1
	v = f.validtime2
	nplane = f.n_plane
	nelem = f.n_element
	m.each_with_index do |member, im|
            u.each_with_index do |valid1, iu|
	        valid2 = v[iu]
	        print "#{im} #{iu} #{member} #{valid1} #{valid2}\n";
		for ip in 0 .. nplane - 1
		    for ie in 0 .. nelem - 1
			r = f.read_record(im, iu, ip, ie)
			next if r == nil
			print "#{r.payload}\n"
			fail FmtError if r.payload.member != member
			fail FmtError if r.payload.validtime1 != valid1
			fail FmtError if r.payload.validtime2 != valid2
		    end
		end
	    end
	end
    end

end

end
# $Id: nusfile.rb,v 1.13 2002/08/01 10:38:27 suuchi43 Exp $
=begin
= iqn̓ɊւNXQ
* ((<class NWPL::Angle>))
* ((<class NWPL::LonLat>))
* ((<class NWPL::Projection>))
* ((<class NWPL::GridSystem>))
* ((<class NWPL::GridSlice>))

NWPL::Base60 ̓[hȂƂɂȂB
=end

module NWPL

=begin
== class NWPL::Angle
Z\iB
KvɂAA邢͓k̕𑮐ƂĎƂłB
--- self::new string, dir = 0
    Z\i񂠂邢͐l (fVbpPʂƂ݂Ȃ) ((|string|)) 
    l\zB
    ̏ꍇA󂯓l
    /^[+-]?(\d+:)*\d+(\.\d+)[NEWS]?$/i ł̂ŁA
    萔邢(ŵȂ)\gB
    W ܂ S uƕl E ܂ N ɕϊB
     ((|dir|))  ((|string|)) ̖Ȃ
    ((|string|)) l̏ꍇɎgpA?N ܂ ?E ̐lB
--- self::deg n, dir = 0
    \zAxpPʁB
--- self::min n, dir = 0
    \zApPʁB
--- to_i
    BfVbpPʁB
--- to_f
    Ato_i.to_f łB
--- deg
    xpPʂ̎B
--- dms
    Z\iWJčŌɕ\lA
    s4vf̐̔z񂪕ԂB
--- to_s
    xb̕\L
--- dir
    0 (ʖ`), ?N (k), ?E () łB
--- dircode
    nil, "N" ܂ "E"
=end

    class Angle

	def initialize val, dir = 0
	    if val.is_a? Numeric
		@to_i = val.to_i
		@dir = dir
		return
	    elsif val.is_a? self.class
		@to_i, @dir = val.to_i, val.dir
	    else
		raise(ArgumentError, val.inspect) unless \
		 /^([-+]?)(\d*)(:(\d+)(:(\d+))?)?(\.\d+)?([NEWS]?)$/i.match val
		#  1      2    3 4    5 6        7       8
		# l̉
		sign = $1
		d = $2.to_i
		m = $4.to_i
		s = $6.to_i
		if $7 then
		    if $6 then
			s += $7.to_f
		    elsif $4 then
			m += $7.to_f
		    else
			d += $7.to_f
		    end
		end
		@dir = $8[0].to_i
		@to_i = Integer((s + 60 * (m + 60 * d)) * 10)  
		@to_i = -@to_i if sign == "-"
	    end
	    # ftHg
	    if @dir.zero?
	       @dir = dir.to_i
	    end
	    # K
            case @dir
	    when ?W, ?w
		@to_i = -@to_i
		@dir = ?E
	    when ?S, ?s
		@to_i = -@to_i
		@dir = ?N
	    when ?n
		@dir = ?N
	    when ?e
		@dir = ?E
	    when ?N, ?E, 0
	    else
		raise "bad dir = #{@dir}"
	    end
	end

	def self::deg(val, dir = 0)
	    if val.is_a? Numeric then
	    	self::new(val * 36_000, dir)
	    else
	    	self::new(val, dir)
	    end
	end

	def self::min(val, dir = 0)
	    if val.is_a? Numeric then
	    	self::new(val * 600, dir)
	    else
	    	self::new(val, dir)
	    end
	end

        attr_reader(:dir, :to_i)

	def to_f; @to_i.to_f; end
	def dircode; @dir.zero? ? "" : @dir.chr; end

	def dir= val
            case @dir
	    when ?n, ?N
		@dir = ?N
	    when ?e, ?E
		@dir = ?E
	    end
	    self
	end

	def deg
	    @to_i / 36000.0
	end

	def dms
	    h = @to_i
	    if (h < 0) then
		sign = -1
		h *= -1
	    else
		sign = 1
	    end
	    if (h % 10).zero?
		s = (h % 600) / 10
	    else
		s = h % 600 / 10.0
	    end
	    h /= 600
	    m = h % 60
	    h /= 60
	    [h, m, s, sign]
	end

	def to_s
	    h, m, s, sign = self.dms
	    format('%s%d:%02d:%s%s', (sign < 0 ? '-' : ''), h, m, s, dircode)
	end

	def - other
	    case other
	    when Float
		self.class.new(to_f - other, @dir)
	    when Numeric, self.class
		self.class.new(@to_i - other.to_i, @dir)
	    else raise(TypeError, other.to_s)
	    end
	end

	def == other
	    to_i == other.to_i
	end

	def + other
	    case other
	    when Float
		self.class.new(to_f + other, @dir)
	    when Numeric, self.class
		self.class.new(@to_i + other.to_i, @dir)
	    else raise(TypeError, other.to_s)
	    end
	end

	def has_dir?
	    @dir != 0
	end

	def * other
	    case other
	    when Numeric then self.class.new(@to_i * other, @dir)
	    else raise(TypeError, other.to_s)
	    end
	end

	def / other
	    case other
	    when Integer then self.class.new(@to_i / other.to_i, @dir)
	    when Numeric then self.class.new(@to_i / other.to_f, @dir)
	    when self.class 
		self.class.new(@to_i / other.to_i, @dir + other.dir)
	    else raise(TypeError, other.to_s)
	    end
	end

    end

=begin
== class NWPL::LonLat
oܓxɂn_𓯒肷邽߂̂́B
=end

    class LonLat

=begin
--- self::new lon, lat
    ((|lon|)), ((|lat|)) ͓xPʂ̐lA"30.0N", "140:30:25.9N" ̂悤ɁA
    (x)܂̓R؂(xEEb̕)
     E, N, W, S (ȗ) ́B
=end

        def initialize lon, lat
	    @lon = Angle::deg(lon, ?E)
	    @lat = Angle::deg(lat, ?N)
	    @lat, @lon = @lon, @lat if @lat.dir == ?E && @lon.dir == ?N
	    raise 'lat is longitude' if @lat.dir == ?E
	    raise 'lon is latitude' if @lon.dir == ?N
        end
	attr_accessor(:lon, :lat)

=begin
--- self == other
    ʒuƂēꍇ^ɂȂB
=end

	def == other
	    (self - other) == [0, 0]
	end

=begin
--- to_a
    oxAܓxȂzB
--- to_s
    "(140.0E, 30.0N)" ̂悤ɕ񉻂
=end

	def to_a;  [@lon.deg, @lat.deg];  end
        def to_s;  "(#{@lon}, #{@lat})";  end

=begin
--- self - other
    oܓx̍2vf̔zŕԂB
=end

	def - other
	    raise ArgumentError unless other.is_a? LonLat
	    [@lon.to_i - other.lon.to_i, @lat.to_i - other.lat.to_i]
	end

    end

=begin
== class NWPL::Projection
e@̓s߂̂́B
=end

    class Projection

=begin
--- self::new pjcode, params = nil
    e@\ ((|pjcode|)) ƕWoܐ ((|params|)) 
    (NWPL::LonLat ̔z񂪊҂) 瓊e@𓯒肷
    \zB
    ̃NXł͓e@̂͒PɕƂĕێ邾ł邪A
    NuSDaS \ɂȂ̂ ArgumentError ƂȂB
=end
=begin RT
pjcode, Ӗ, params ̗pr
LL, ܓxox,	gpȂ
LM, xgp~,	
PS, |[[XeI,	
GS, KEXiq,	
MR, Jg,	
YP, ܓx-C,	
XP, ox-C,	
FG, free grid,	
OL, Ύxgp~,	
RD, [_[,	
ST, Xe[V,	
XX, s,	
=end

	def initialize pjcode, params = []
	    @pjcode, @params = pjcode, params
	    raise(ArgumentError, "unknown projection #{pjcode}") \
		unless /^(LL|LM|PS|GS|MR|YP|XP|FG|OL|RD|ST|XX)$/.match pjcode
	end
	attr_reader(:pjcode, :params)

=begin
--- direct?
    esȂꍇAȂ킿AܓxoxW̏ꍇɐ^ƂȂB
=end

        def direct?;  @pjcode == 'LL';  end

=begin
--- self == other
    Kv񂪂ׂēƂ^ƂȂB
=end

	def == other
	    return false unless other.is_a? Projection
	    (self.pjcode == other.pjcode and self.params == other.params)
	end

	def to_s
	    if (@params.empty?) then
	        "proj(#{@pjcode})"
	    else
		"proj(#{@pjcode}, #{@params.join(', ')})"
	    end
	end

    end

=begin
== class NWPL::GridSystem
iqԍňoܓx𓾂邽߂ɕKvȊiqzuǗB
=end


    class GridSystem

=begin
--- self::new proj, basepoint, ofs, gridsize
    e@ ((|proj|)) ɂĒn_ ((|basepoint|)) (((<class NWPL::LonLat>)))
    e_iqԍ ((|ofs|)) (l2̔z) Ƃ
    iqԊu ((|gridsize|)) (l2̔z) ̊iqn\zB
    iqԊu proj.direct? ̎͌oܓxƉ߂AłȂꍇ
    Ɖ߂B
=end

        def initialize proj, basepoint, ofs, gridsize
	    @proj = proj
	    raise ArgumentError unless proj.is_a? Projection
	    @basepoint = basepoint
	    raise ArgumentError unless basepoint.is_a? LonLat
	    @ofs = ofs
	    (0..1).each {|i| raise ArgumentError unless @ofs[i].is_a? Numeric }
	    if @proj.direct? then
	        @gridsize = [NWPL::Angle::deg(gridsize[0], ?E), 
		     NWPL::Angle::deg(gridsize[1], ?N)]
	    else
	        @gridsize = gridsize.collect { |dx| dx.to_f }
	    end
	end
	attr_reader(:proj, :ofs, :gridsize, :basepoint)

=begin
--- dup
    basepoint, ofs  ((<canon!>)) ɔ dup B
=end

        def dup2
	    @basepoint = @basepoint.dup
	    @ofs = @ofs.dup
	    self
	end

	def dup
	    super.dup2
	end

=begin
--- slide! (other)
    self >>= other ̔jI
--- self >> other
    n_ ((|other|)) iqB   
    ofs l other ̕Ɣ΂ɓB
    basepoint l邩邩 gridsize ̕ɂB
    proj.direct? łȂꍇ͗O𓊂B
--- canon!
--- canon
    iqԊuoܓx̏ꍇ 0 <= ofs[((|i|))] < 1 (((|i|)) = 0, 1)
    ƂȂ悤ɐKsB
=end

        def slide! other
	    if @proj.direct? then
		x, y = other
		@ofs[0] -= x
		@ofs[1] -= y
		@basepoint.lon -= x * @gridsize[0]
		@basepoint.lat -= y * @gridsize[1]
	        self
	    else
		raise "slide is not allowed"
	    end
	end

	def >> other;  dup.slide!(other);  end
	def << other;  dup.slide!([-other[0], -other[1]]);  end

	def mod
	    [(@basepoint.lon.to_f / @gridsize[0]).to_i,
	     (@basepoint.lat.to_f / @gridsize[1]).to_i]
	end

        def canon!
	    if @proj.direct? then
		x, y = mod
		@ofs[0] -= x
		@ofs[1] -= y
		@basepoint.lon -= @gridsize[0] * x
		@basepoint.lat -= @gridsize[1] * y
	    end
	    self
	end

	def canon;  dup.canon!;  end

=begin
--- self == other
    ܂: KsƂőSp^vꍇ^ԂB
=end

	def == other
	    return false unless other.is_a? GridSystem
	    return false unless self.proj == other.proj
	    cs = self.canon
	    co = other.canon
	    (cs.gridsize == co.gridsize &&
	     cs.basepoint == co.basepoint &&
	     cs.ofs == co.ofs)
	end

=begin
--- self === other
    Vtg: A
    canon  gridsize  basepoint A
    Ȃ ofs ̍ɂȂĂꍇ^
=end

        def === other
	    return false unless other.is_a? GridSystem
	    return false if (self.proj != other.proj)
	    return false if (self.gridsize != other.gridsize)
	    cs = self.canon
	    co = other.canon
	    return false unless (cs.basepoint - co.basepoint == [0, 0])
	    fs = cs.ofs
	    fo = co.ofs
	    [(fs[0] - fo[0]) % 1.0, (fs[1] - fo[1]) % 1.0] == [0, 0] 
	end

=begin
--- add_ofs!(other)
    self += other ̔jI
--- self + other
    ofs l ((|other|)) ₷B((|other|)) ͐l2̔zB
    Ɠn_ViqnŎw߂̊iqԍ
    ((|other|)) ̐B
    덷 (self + other).canon  self.canon + other Ƃ͓B
=end

	def add_ofs! other
	    iofs, jofs = other
	    @ofs[0] += iofs
	    @ofs[1] += jofs
	    self
	end

	def + other
	    dup.add_ofs!(other)
	end

=begin
--- self * other
    gridsize  ((|other|)) {B
    ((|other|)) ͐l2̔złB
    (self * other).canon  self.canon * other Ƃ͌ʂقȂB
=end

	def * other
	    ifac, jfac = other
            newgridsize = [@gridsize[0] * ifac, @gridsize[1] * jfac]
	    self.class::new(@proj, @basepoint, @ofs, newgridsize)
	end

=begin
--- self / other
    iqԊuZB
    ((|other|)) ͐l(܂Angle)2̔z񂩁AGridSystem.
    O҂ GridSystem ԂA҂͐l2̔zԂB
=end

	def / other
	    if other.is_a? Array then
		idiv, jdiv = other
		newgridsize = [@gridsize[0] / idiv, @gridsize[1] / jdiv]
		self.class::new(@proj, @basepoint, @ofs, newgridsize)
	    elsif other.is_a? self.class
		ogs = other.gridsize
		[@gridsize[0] / ogs[0], @gridsize[1] / ogs[1]]
	    else
		raise TypeError
	    end
	end

=begin
--- self - other
    ofs ̍Ƃē 2 vf̔zԂB
    B + (A - B)  A ƂȂ悤Ɍ߂ĂB
    ((|self|)) === ((|other|)) Ȃꍇ͗O𓊂B
=end

	def - other
	    raise TypeError unless other.is_a? GridSystem
	    raise ArgumentError if (self.proj != other.proj)
	    raise ArgumentError if (self.gridsize != other.gridsize)
	    cs = self.canon
	    co = other.canon
	    raise ArgumentError unless (cs.basepoint - co.basepoint == [0, 0])
	    fs = cs.ofs
	    fo = co.ofs
	    [fs[0] - fo[0], fs[1] - fo[1]] 
	end

=begin
--- ij2lonlat(i, j)
    Yiqnɂ (((|i|)), ((|j|))) Ԋiq̌oܓx𓾂B
    ݂̂ƂoܓxWłȂB
=end

        def ij2lonlat(i, j)
	    raise "LL expected" unless @proj.direct?
	    lon = @basepoint.lon + @gridsize[0] * (i - @ofs[0])
	    lat = @basepoint.lat + @gridsize[1] * (j - @ofs[1])
 	    LonLat::new(lon, lat)
        end

=begin
--- lonlat2ij lonlat
    ^ꂽʒu (((<class NWPL::LonLat>)) IuWFNg) 
    Yiqnɂiqԍ𐮐2̔zŕԂB
    ݂̂ƂoܓxWłȂB
=end

        def lonlat2ij(ll)
	    raise "LL expected" unless @proj.direct?
	    i = (ll.lon - @basepoint.lon) / @gridsize[0] + @ofs[0]
	    j = (ll.lat - @basepoint.lat) / @gridsize[1] + @ofs[1]
 	    [i.to_i, j.to_i]
        end

	def to_s
	    "GridSystem(#{proj}, dx=[" +
	    @gridsize[0].to_s + ", " + 
	    @gridsize[1].to_s + "], " + 
	    "ofs=#{ofs.inspect}, base=#{basepoint})"
	end

    end

=begin
== class NWPL::GridSlice
錈܂iqn ((<class NWPL::GridSystem>)) ̏ł
肳ꂽiq͈ (iqԊuł̊Ԉ) ǗB
=end

    class GridSlice

=begin
--- self::new gridsystem, start, count, stride
    iqn ((|gridsystem|)) (((<class NWPL::GridSystem>))) 
    iqԍl ((|start|)),
    iq ((|count|)),
    iqԊu ((|stride|)) gč\zB
    ((|start|)), ((|count|)), ((|stride|)) ͐2̔zB
    iqłȂŏIiqԍ^Ă
    ((|count|)) vẐʓ|ȏꍇ͂Ƃ肠
    ((|count|))  nil ɂĂāA
     ((<finish=>)) Őݒ肷邱ƂłB
=end

	def initialize gridsystem, start, count = nil, stride = [1, 1]
	    ae = ArgumentError
	    @gridsystem = gridsystem
	    raise ae unless @gridsystem.is_a? GridSystem
	    @start, @count, @stride = start, count, stride
	    raise ae unless @start.is_a? Array and @start.size == 2
	    raise ae unless (@count.is_a? Array and @count.size == 2 or \
		@count.nil?)
	    raise ae unless @stride.is_a? Array and @stride.size == 2
	end
	attr_reader(:gridsystem, :start, :count, :stride)

	def finish
	    [@start[0] + @count[0] * @stride[0],
	     @start[1] + @count[1] * @stride[1]]
	end

	def finish= val
	     @count = [(val[0] - @start[0]) / @stride[0] + 1,
		(val[1] - @start[1]) / @stride[1] + 1]
	end

	def params;  @start + @count + @stride;  end

=begin
--- params
    start + count + stride ƓB
--- self == other
    ܂B
=end

	def == other
	    return false unless other.is_a? GridSlice
	    return false unless self.gridsystem == other.gridsystem
	    return self.params == other.params
	end

        def to_s
	    "GridSlice(#{@gridsystem}, start=#{start.join(',')}, " \
		+ "count=#{count.join(',')}, stride=#{stride.join(',')})"
	end

=begin
--- dup
    iqn dup B
=end

	def dup2;  @gridsystem = @gridsystem.dup;  self;  end
	def dup;  super.dup2;  end

=begin
--- canon!
--- canon
    iqn𐳋KB
    K͊iqԍƒn_̊֌Wς̂ł͂Ȃ̂ŁA
    ((|start|)), ((|count|)), ((|stride|)) ̒l͕ωȂB
=end

        def canon!
	    @gridsystem.canon!
	    self
	end

	def canon;  dup.canon!;  end

    end

end
=begin
= class Nusdas::NusPath

XbV (/) ؂̕pXeoB
͈ȉׂ̂ĂT|[gB

* /((|type|))/((|base|))/((|member|))/((|valid1|))/((|plane1|))/((|element|)) (`1) 
* /((|type|))/((|base|))/((|member|))/((|valid1|)),((|valid2|))/((|plane1|)),((|plane2|))/((|element|)) (`2)
* /((|type|))/((|base|))/((|member|))/((|valid1|))/((|valid2|))/((|plane1|))/((|plane2|))/((|element|)) (`)

E̎ȗ邱ƂłAȗ̂ nil ƂȂB

=end

module Nusdas
class NusPath

=begin
== O
--- FmtError
=end

    class FmtError < StandardError; end

=begin
== NX\bh
--- new string
    \zB
    `ƃ`̋ʂ͑4 (XbVŋ؂0琔n߂) 
    ((<NWPL::NwpTime|URL:../nwpl/nwptime.html>)) Ƃ݂Ȃꍇ
    `ƂAłȂꍇ̓`ƂB
=end

    def initialize (string)
        path = string.sub(/^\/*/, "").sub(/\/+$/, "").split(/\//)
	if path[4].nil? then
	    @old = false
	else
	    # ܂ƎvĂ݂
	    @valid2 = NWPL::NwpTime::new(path[4], true)
	    @old = !@valid2.oob?
	end
	@nustype = path[0]
	@basetime = (path[1] ? NWPL::NwpTime::new(path[1]) : nil)
	@member = path[2]
	if @old then
	    @valid1 = (path[3] ? NWPL::NwpTime::new(path[3]) : nil)
	    @plane1 = path[5]
	    @plane2 = path[6]
	    @element = path[7]
	    raise "path #{string} too deep" if path[8]
	else
	    if path[3] then
		v = path[3].split(/,/)
		@valid1 = NWPL::NwpTime::new(v.first)
		@valid2 = v[1] ? NWPL::NwpTime::new(v[1]) : nil
	    else
		@valid1 = @valid2 = nil
	    end
	    if path[4] then
	    	@plane1, @plane2 = path[4].split(/,/)
		@plane2 = @plane1 if @plane2.nil?
	    else
	    	@plane1 = @plane2 = nil
	    end
	    @element = path[5]
	    raise "path #{string} too deep" if path[6]
	end
	@member = "    " if @member == "none"
    end

=begin
== CX^X\bh
=== pX\vf
--- nustype
    sIh؂̕Ԃ
--- basetime
     ((<NWPL::NwpTime|URL:../nwpl/nwptime.html>)) ŕԂ
--- member
    O̕ԂB󔒃ȍꍇ "    " ԂB
--- member_str
    O̕ԂB󔒃ȍꍇ "none" ԂB
--- validtime
    Ώێ ((<NWPL::NwpTime|URL:../nwpl/nwptime.html>)) ŕԂ
    PƎ̏ꍇ NwpTime ̂́A
    Ԃ̏ꍇ NwpTime 2vf Array ƂȂB
--- validtime_str
    񉻂Ώێ
--- valid1
--- valid2
    PƑΏێ̏ꍇ valid2.undef? ^ɂȂB
    `ŕsSȃpX̂Ƃ nil ɂȂ
--- plane
    ʂ\ԂB
    ʊԂ̏ꍇ̓R}؂B
--- plane1
--- plane2
    PƖʂ̏ꍇ plane1 ƓɂȂB
    `ŕsSȃpX̂Ƃ nil ɂȂ
--- element
    vfԂ
--- old
    KĩpXō\zꂽꍇ^
=end

    attr_reader(:nustype, :basetime, :valid1, :valid2, :member)
    attr_reader(:plane1, :plane2, :element, :old)

    def member_str
	if (@member == "    ") then "none" else @member end
    end

    def validtime
	if (@valid2.nil? or @valid2.undef?) then
	    @valid1
	else
	    [@valid1, @valid2]
	end
    end

    def validtime= vt
	case vt
	when NWPL::NwpTime then
	    @valid1 = vt
	else
	    raise ArgumentError
	end
    end

    def validtime_str
	validtime.to_a.join(',')
    end

    def plane
	if @plane2.nil?
	    nil
	elsif @plane2 == @plane1 then
	    @plane1
	else
	    @plane1 + "," + @plane2
	end
    end

=begin
=== Xg擾
--- list (longp, schema = false)
    {Iɂ́Aŏ nil ɂȂĂ̂񋓂B
    Aŏ nil  basetime ɂȂĂ鎞ɌA
    nustype ^LN^܂łƂ nustype 񋓂B
    schema ^ɂȂĂꍇ͒`t@C̏񂾂
    񋓂쐬B
    longp ̌ʂ͂Ƃ肠̂ƂȂB
=end

    def glob_nustype type, longp
	search = Regexp::quote(type)
	search.gsub!(/\\\*/, '.*')
	search.gsub!(/\\\?/, '.')
	search = Regexp::new "^#{search}$"
	ret = []
	Nusdas::each_def do |deffile|
	    next unless search.match deffile.nustype
	    if longp then
		ret.push deffile.nustype + "\t" + deffile.to_s
	    else
		ret.push deffile.nustype
	    end
	end
	return ret
    end

    def list (longp, schema = false)
	return glob_nustype('*', longp) if nustype.nil?
	return glob_nustype(nustype, longp) \
	    if basetime.nil? and /[?*]/.match nustype
        if (schema) then
	    Nusdas::find_def(nustype).list_schema(self, longp)
	else
	    Nusdas::find_def(nustype).list_real(self, longp)
	end
    end

=begin
=== foOp
--- to_s
    `̕ԂB
=end

    def to_s
	[@nustype, @basetime, member_str, validtime_str, plane, @element].compact.join('/')
    end

end
end
# $Id: nuspath.rb,v 1.11 2002/08/01 10:38:27 suuchi43 Exp $
require "find"

=begin
= class Nusdas::NusDef ƓNX
=end

module Nusdas

class NusDef

    KEYWORDS = %w(nusdas path filename creator type1 type2 type3 member
	memberlist basetime validtime validtime1 validtime2 plane
	plane1 element elementmap size basepoint distance standard
	others value packing missing information subcntl forcedlen)
    IS_KEYWORD = Hash::new
    KEYWORDS.each { |k|
	IS_KEYWORD[k] = true
    }

    PATH_TEMPLATE = {
	 'nwp_path_s' => '/_3d_name',
	 'nwp_path_vm' => '/_3d_name',
	 'nwp_path_m' => '/_3d_name/_member',
	 'nwp_path_bs' => '/_3d_name/_basetime',
    }

    class SyntaxError < StandardError; end
    class TodoError < StandardError; end
    class IncompletePathError < StandardError; end

=begin
== class Nusdas::NusDef::ElementMap
=end

    class ElementMap

=begin
=== NX\bh
--- self::new stmt, npl, nvt
    elementmap  ((|stmt|)), ʂ̐ ((|npl|)), Ώێ̐ ((|nvt|))
    ^č\zB
=end

	def initialize stmt, npl, nvt
	    stmt.shift
	    @elname = stmt.shift
	    @elclass = stmt.shift.to_i
	    case @elclass
	    when 0
		@elmap = nil
	    when 1
		@elmap = stmt
	    when 2
		@elmap = Array::new(nvt)
		ip = 0
		until (count = stmt.shift).nil? do
		     sliced = stmt.slice!(0, npl)
		     count.to_i.times do
		         @elmap[ip] = sliced
			 ip += 1
		     end
		end
	    end
	end

=begin
=== CX^X\bh
--- to_s
--- elname
    vfԂ
=end

	def to_s; @elname; end
	def elname; @elname; end

=begin
--- allowed? (ip, iv = nil, im = nil)
    iqԍ (ip, iv, im)@̊iq邩ۂԂB
=end

	def allowed? (ip, iv = nil, im = nil)
	    case @elclass
	    when 0
		true
	    when 1
		@elmap[ip] == "1"
	    when 2
		if (iv.nil?) then
		    @elmap.each do |ivslice|
			next if ivslice.nil?
			return true if ivslice[ip] == "1"
		    end
		    return false
		else
		    @elmap[iv][ip] == "1"
		end
	    else
		fail("unimplemented elementmap class = #{@elclass}")
	    end
	end

    end

=begin
== class Nusdas::NusDef

=== NX\bh

--- self::new filename, rootdir
    t@C ((|filename|)) ƃiX_X[g ((|rootdir|))
    w肵č\zB
=end

    def parse_vt1 inout, unit
	return nil unless (/^IN|OUT$/i =~ inout)
	@vt_infile = (/^IN$/i =~ inout)
	return nil unless (/^MIN|HOUR|DAY|PEN|MON|WEEK|JUN$/i =~ unit)
	@vt_unit = unit
    end
    private :parse_vt1

    def decode stmt
	case stmt.first
	when "type1"
	    @type1 = stmt[1, 3].pack('A4A2A2')
	when "type2"
	    @type2 = stmt[1, 2].pack('A2A2')
	when "type3"
	    @type3 = stmt[1, 1].pack('A4')
	when "validtime"
	    @vt_size = Integer(stmt[1])
	    parse_vt1(stmt[2], stmt[3]) || parse_vt1(stmt[3], stmt[2]) ||
		raise(SyntaxError, "<#{stmt.join(' ')}>")
        when "validtime1"
	    @vt1_style = stmt[1].upcase
	    if (@vt1_style == 'ARITHMETIC') then
		@vt1 = Array::new;
		0.upto(@vt_size.to_i - 1) do |iv|
		    @vt1.push(Integer(stmt[2]) + Integer(stmt[3]) * iv)
		end
	    elsif (@vt1_style == 'ALL_LIST') then
		fail(SyntaxError, "validtime1 before validtime") \
		    unless @vt_size
                @vt1 = stmt[2, @vt_size].collect{|x| x.to_i}
	    else
		fail SyntaxError, 'after validtime1'
	    end
        when "validtime2"
            @vt2 = stmt
	when "plane"
	    @pl_size = Integer(stmt[1])
	when "plane1"
	    fail(SyntaxError, "plane1 before plane") \
		unless @pl_size
	    @pl1 = stmt[1, @pl_size]
	when "plane2"
	    fail(SyntaxError, "plane2 before plane") \
		unless @pl_size
	    @pl2 = stmt[1, @pl_size]
	when "element"
	    @el_size = Integer(stmt[1])
	when "elementmap"
	    @el.push(ElementMap::new(stmt, @pl_size, @vt_size))
	when "path"
	    if stmt[1] == 'relative_path'
		@path = stmt[2]
            else
		@path = PATH_TEMPLATE[stmt[1]]
		@filename = '_validtime'
	    end
	when "filename"
	    @filename = stmt[1]
	when "member"
	    @me_size = stmt[1].to_i
	    @me_infile = /in/i.match stmt[2]
        when "size"
            @size = [stmt[1].to_i, stmt[2].to_i]
        when "basepoint"
            @basegrid = [stmt[1].to_f, stmt[2].to_f]
            @basepoint = NWPL::LonLat::new(stmt[3], stmt[4])
	when "distance"
	    @distance = [stmt[1].to_f, stmt[2].to_f]
	when "packing"
	    @packing = stmt[1].strip
	when "standard"
	    @standard = [NWPL::LonLat::new(stmt[1], stmt[2]),
		NWPL::LonLat::new(stmt[3], stmt[4])]
	when "others"
	    @others = [NWPL::LonLat::new(stmt[1], stmt[2]),
		NWPL::LonLat::new(stmt[3], stmt[4])]
	when "memberlist"
	    @member = stmt[1, @me_size]
	else
	    STDERR.print "NusDef: #{stmt.join(' ')} not supported\n"
	end
    end
    private :decode

    def initialize filename, rootdir
	@deffile = filename
	@rootdir = rootdir
	@type1 = @type2 = @type3 = nil
	@vt_size = @vt_infile = @vt_unit = @vt1_style = @vt1 = @vt2 = nil
	@pl_size = @pl1 = @pl2 = @el_size = @me_size = @me_infile = nil
	@member = ["none"]
	@path = '/_model/_attribute/_space/_time/_name'
	@filename = '_basetime'
        @size = @basegrid = @basepoint = nil
	@standard = @others = []
        @packing = "2PAC"
	@el = Array::new
	fail Errno::ENOENT, "#{filename} not a file" \
            unless File::file? filename
        input = open(filename, "r")
	a = Array::new
	begin
	    input.each_line do |line|
		w = line.gsub(/#.*/, '').split
		next if w.empty?
		if IS_KEYWORD[w.first.downcase] then
		    a.push w
		elsif (a.size > 0) then
		    a[a.size - 1].concat w
		else
		    a.push w
		end
	    end
	ensure
	    input.close
	end
	a.each do |stmt|
	    decode stmt
	end
    end

=begin
=== 
--- vt_unit
    Ώێ̒P
--- vt_infile
    Ώێɂăt@C邩ۂ
--- vt_size
    Ώێ̐
--- vt1
    Ώێ1 ̔z
--- vt2
    Ώێ2 ̔zA` nil
--- pl_size
    ʂ̐
--- pl1
    1 ̔z
--- pl2
    2 ̔zA` nil
--- el
    Gg}bv̔z
--- el_size
    vf̐
--- nustype
    ʕ
--- deffile
    `t@C̃pX
--- rootdir
    iX_X[gfBNg̃pX
--- path
    `t@C path Ō܂ĂApXev[g
--- filename
    `t@C filename Ō܂At@Cev[g
--- basegrid
--- basepoint
--- size
--- packing
--- distance
--- standard
--- others
=end

    attr_reader(:type1, :type2, :type3)
    attr_reader(:vt_unit, :vt_infile, :vt_size, :vt1, :vt2)
    attr_reader(:pl_size, :pl1, :pl2, :el, :el_size)
    def nustype; sprintf('%8s.%4s.%4s', @type1, @type2, @type3); end
    attr_reader(:deffile, :rootdir, :path, :filename)
    attr_reader(:basegrid, :basepoint, :size, :packing, :distance)
    attr_reader(:standard, :others)

=begin
=== CX^X\bh
--- elname
    vf̔zԂ
=end

    def elname
	@el.collect {|e| e.elname }
    end

=begin
--- el_allowed? (ie, ip, iv = nil, im = nil)
    vf ((|ie|)), ʂ̏ ((|ip|)) ȂтɕKvȂ
    Ώێ̏ ((|iv|)), ȍ ((|im|))
    w肵āAGg}bvŋeĂ邩ۂԂB
=end

    def el_allowed? (ie, ip, iv = nil, im = nil)
	@el[ie].allowed?(ip, iv, im)
    end

=begin
--- nusfilename (basetime, member = nil, validtime = nil, strip = nil)
    ((|basetime|)), ((|member|)), ((|validtime|)) Ō܂t@CԂB
     nil ^ƁAsł邱ƂwB
    t@CsƂȂꍇAftHgł IncompletePathError ƂȂB
    ((|strip|))  true łꍇ͕s̃t@C
    ; ̓fBNgT̋N_ƂĎgB
    ((|strip|))  false łꍇ͐K\ƂȂB
=end

    def nusfilename (basetime, member = nil, validtime = nil, strip = nil) 
	fnam = [@rootdir, @path, @filename].join('/')
	fnam = Regexp.quote(fnam) if strip == false
	fnam.sub!(/_model/i, @type1[0, 4])
	fnam.sub!(/_2d/i, @type1[4, 2])
	fnam.sub!(/_3d/i, @type1[6, 2])
	fnam.sub!(/_space/i, @type1[4, 4])
	fnam.sub!(/_attribute/i, @type2[0, 2])
	fnam.sub!(/_time/i, @type2[2, 2])
	fnam.sub!(/_name/i, @type3)
	if (basetime.nil?) then
	    fnam.sub!(/_basetime/i, '\d{12}')
	else
	    fnam.sub!(/_basetime/i, basetime.narrow)
	end
	if (member.nil?) then
	    fnam.sub!(/_member.*/i, '\w{4}')
	else
	    fnam.sub!(/_member/i, member.to_s)
	end
	if (validtime.nil?) then
	    fnam.sub!(/_validtime.*/i, '\d{12}')
	else
	    fnam.sub!(/_validtime/i, validtime.narrow)
	end
	fnam.gsub!(/\s/, '_')
	if strip != false then
	    segms = fnam.split(/\//)
	    while /\\(d\{12\}|w\{4\})/.match(segms.last)
		segms.pop
		raise IncompletePathError if strip.nil?
	    end
	    segms.join('/')
	else
	    fnam
	end
    end

=begin
--- to_s
    Ƃ肠A`t@C̃pXԂ܂ǁA
    ܂肠ĂɂȂłB
=end

    def to_s; @deffile; end

=begin
--- validlist (basetime)
    w肳ꂽ ((|basetime|)) ɑ΂đΏێ (\񎞊Ԃł͂Ȃ)
    ̃XgԂB
=end

    def validlist(basetime)
	tu = NWPL::NwpTimeSpan::new(1, vt_unit)
	if vt2.nil? then
	    vt1.collect { |f| basetime + tu * f }
	else
	    (0 ... vt1.size).collect { |i|
		a = basetime + tu * vt1[i]
		b = basetime + tu * vt2[i]
		"#{a},#{b}"
	    }
	end
    end

=begin
--- planelist
    ʂ̃XgԂB2ꍇ̓R}؁B
=end

    def planelist
	if pl2.nil? then
	    pl1
	else
	    (0 ... pl1.size).collect { |i| "#{pl1[i]},#{pl2[i]}" }
	end
    end

=begin
--- pvmindex (plane, validtime, member, basetime)
    ʔԍ ip, Ώێԍ iv, oԍ im ߂ĔzɂĕԂB
=end

    def pvmindex(p, v, m, b)
	[planelist.index(p), validlist(b).index(v), @member.index(m)]
    end

=begin
--- elemlist(ip, iv, im)
    ʔԍ ip, Ώێԍ iv, oԍ im ɂ
    vf̃XgԂB
--- elemlist(nuspath)
    NusPath Ŏw肳ꂽ member, validtime, plane ɂ
    vf̃XgԂB
=end

    def elemlist (ip, iv = nil, im = nil)
	if ip.is_a? NusPath
	    return elemlist(*pvmindex(ip.plane, ip.validtime, ip.member, \
		ip.basetime))
	end
	ans = []
	@el.each {|e|
	    ans.push e.elname if e.allowed?(ip, iv, im)
	}
	return ans
    end

=begin
--- find_rec (nuspath)
=end

    def find_rec (np)
        fp = NusFile::open(nusfilename(np.basetime, np.member, np.validtime))
	r = fp.read_record(np.member, np.validtime, np.plane, np.element)
	fp.close
	return r
    end

=begin
--- each_file { |filename| ... }
    `t@Cwt@C ((|filename|))
    (iX_X[gn܂tpX)
    ЂƂЂƂT yield B
=end

    def each_file
	pattern = Regexp::new(nusfilename(nil, nil, nil, false))
        Find::find(nusfilename(nil, nil, nil, true)) { |fnam|
	    next if not pattern.match fnam
	    next if File::directory? fnam
	    yield fnam
	}
    end

=begin
--- list_basetime (long)
    `t@Cɑ΂̃Xg
=end

    def list_basetime (long)
	ans = []
	each_file { |fnam|
	    fp = NusFile::open(fnam)
	    ans.push fp.basetime.to_s
	    fp.close
	}
	ans.sort.uniq
    end

=begin
--- list_schema (nuspath, long)
    ((<Nusdas::NusPath|URL:nuspath.html>)) ((|nuspath|)) 
    w肳鉽炩̎ɂĈꗗ쐬B
    ʂ String ̔złB
    `t@CQƂĈꗗ쐬邽ߍA
    ܂܂ĂȂpXꗗɊ܂܂B
    Abasetime ̈ꗗ͎̂QƂčsB
=end

    def list_schema (nuspath, long)
	return list_basetime (long) if nuspath.basetime.nil?
	return @member if nuspath.member.nil?
	# { elementmap QƂ̕Kv邩
	return validlist(nuspath.basetime) if nuspath.validtime.nil?
	# { elementmap QƂ̕Kv邩
	return planelist if nuspath.plane.nil?
	return elemlist(nuspath) if nuspath.element.nil?
	[]
    end

=begin
--- list_real (nuspath, long)
    ((<Nusdas::NusPath|URL:nuspath.html>)) ((|nuspath|)) 
    w肳鉽炩̎ɂĈꗗ쐬B
    ʂ String ̔złB
    `t@Cł͂ȂAt@CQƂĎ݂pXvf
    悤ƂB
=end

    def list_real (nuspath, long)
	return list_basetime(long) if nuspath.basetime.nil?
	ans = []
	each_file { |fnam|
	    fp = NusFile::open(fnam)
	    next if fp.basetime != nuspath.basetime
	    list = fp.list(nuspath, long)
	    ans.push(*list) if not list.empty?
	    fp.close
	}
	ans.uniq
    end

=begin
--- proj
    e@ ((<class NWPL::Projection|URL:../nwpl/gridsystem.html>)) 
    \zĕԂB
--- gridsystem
    iqn ((<class NWPL::GridSystem|URL:../nwpl/gridsystem.html>)) 
    \zĕԂB
=end

    def proj
	params = standard + others
	NWPL::Projection::new(@type1[4, 2], params)
    end

    def gridsystem
	ofs = [@basegrid[0], @basegrid[1]]
	gridsize = [@distance[0], -@distance[1]]
	NWPL::GridSystem::new(proj, @basepoint, ofs, gridsize)
    end

end
end
# $Id: nusdef.rb,v 1.21 2003/01/16 02:16:44 suuchi43 Exp $

=begin
= class Nusdas::NusRoot
=end

module Nusdas
class NusRoot

=begin
== NX\bh
--- self::new dirname
    fBNg ((|dirname|)) w肵č\zB
    ̂Ȃ (({nusdas_def})) ƂfBNgȂ΂ȂȂB
=end

    def initialize dirname
	@root = dirname
	@defdir = File.join(dirname, 'nusdas_def')
	fail Errno::ENOTDIR, "#{dirname}: 'nusdas_def' not found" \
	    unless File::directory? @defdir
    end

    def to_s; @root; end

=begin
== CX^X\bh
--- each_def { |deffile| ... }
    `t@CׂĂɂ ((<NusDef|URL:nusdef.html>)) 
    \z yield B
=end

    def each_def
	dir = Dir::new(@defdir)
	begin
	    dir.each do |file|
		next unless /\.def$/ =~ file
		yield NusDef::new(File.join(@defdir, file), @root)
	    end
        ensure
	    dir.close
        end
    end

=begin
--- deffile_list
    `t@CׂĂɂ ((<NusDef|URL:nusdef.html>)) 
    \zĔzɓĕԂB
=end

    def deffile_list
	dir = Dir::new(@defdir)
        list = Array::new
	begin
	    dir.each do |file|
		next unless /\.def$/ =~ file
		list.push NusDef::new(File.join(@defdir, file), @root)
	    end
        ensure
	    dir.close
        end
        return list
    end

=begin
--- find_def type
    w肵 ((|type|)) 
    `t@C ((<NusDef|URL:nusdef.html>)) ԂB
    ݂Ȃ nil
=end

    def find_def type
	d = deffile_list
	d.each do |deffile|
	    return deffile if deffile.nustype == type
	end
	nil
    end

=begin
--- has? type
    w肵 ((|type|)) 
    `t@C邩ۂ
=end

    def has? type
	d = deffile_list
	d.each do |deffile|
	    return true if deffile.nustype == type
	end
	false
    end

end
end
# $Id: nusroot.rb,v 1.7 2002/08/01 10:38:28 suuchi43 Exp $

=begin
= module Nusdas

NuSDaS ƂʖgB

=end

module Nusdas

=begin
== O
=== NusDefNotFound
w肵 type ɑ΂`t@C݂ȂB
=end

    class NusDefNotFound < StandardError
    end

    class NusRecNotFound < StandardError
    end

=begin
== NX\bh
--- self::root_path (nn)
    0 ȏ 99 ȉ̐l ((|nn|)) ɑ΂ăiX_X[g
    pX𒲂ׂĕԂB
    ϐ ((*NUSDAS*))((|nn|)) ΂̒lA
    Ȃ΃JgfBNg̃fBNg ((*NUSDAS*))((|nn|))
    pB
=end

    def self::root_path(nn)
	nusdas_nn = sprintf('NUSDAS%02d', nn)
	if (e = ENV[nusdas_nn]) then
	    return e if File::directory?(e)
	end
	return nusdas_nn if File::directory?(nusdas_nn)
	nil
    end

=begin
--- self::each_root { |root| ... }
    0  99 ܂ŏԂ ((<Nusdas::NusRoot|URL:nusdas/nusroot.html>)) 
    \z yield B
=end

    def self::each_root
	0.upto 99 do |nn|
	    path = root_path(nn)
	    next if path.nil?
	    yield NusRoot.new(path)
	end
    end

=begin
--- self::find_root (type)
    f[^ ((|type|)) LiX_X[gԂB
    ݂Ȃ nil ԂB
=end

    def self::find_root(type)
	each_root do |root|
	    return root if root.has?(type)
	end
	return nil
    end

=begin
--- self::find_def (type)
    f[^ ((|type|)) L
    `t@C ((<Nusdas::NusDef|URL:nusdas/nusdef.html>))
    \zĕԂB
    `t@C݂Ȃꍇ NusDefNotFound 𓊂B
=end

    FIND_DEF = Hash::new

    def self::find_def(type)
	return FIND_DEF[type] if FIND_DEF[type]
	r = find_root(type)
	raise(NusDefNotFound, "type = #{type}") if r.nil?
	FIND_DEF[type] = r.find_def(type)
    end

=begin
--- self::each_def { |deffile| ... }
    ׂẴiX_X[ĝׂĂ
    `t@C ((<Nusdas::NusDef|URL:nusdas/nusdef.html>))
    \z yield B
=end

    def self::each_def
	each_root do |root|
	    root.each_def do |deffile|
		yield deffile
	    end
	end
    end

=begin
--- self::read path
    pXŎw肳ꂽʃf[^ǂݎ
=end

    def self::read path
        if NusPath === path
 	    np = path
        else
	    np = NusPath::new(path)
	end
	r = find_def(np.nustype).find_rec(np)
        raise(NusRecNotFound, "#{path} not found") if r.nil?
	r.payload.payload
    end

=begin
--- self::read_a path
    pXŎw肳ꂽʃf[^ǂݎāANArray \ẑԂB
    LbVB
=end

    ARR = Hash::new

    def self::read_a(path)
	key = path.to_s
	return ARR[key] if ARR[key]
	ARR[key] = self::read(path).array
    end

=begin
--- self::meta path
    pXŎw肳ꂽʃf[^Ɋւtǂݎ
    ()
=end

=begin
--- self::plel_to_dgrb (plane, elem)
    NuSDaS ̖ ((|plane|)) Ɨvf ((|elem|)) A
    iʕ񎮂 [ʂ̌`AʁAvf] ȂzĕԂB
=end

    def self::plel_to_dgrb(plane, elem)
	e = Elem[elem]
	return nil if e.nil?
	levStyle = e['DGRB-LEV']
	if (levStyle.nil?) then
	    levStyle = 100
	    levStyle = 1 if (plane == 'SURF' || plane == 'ECTOP')
	end
	if (levStyle == 100 || levStyle == 170)
	    if (plane == 'sea') then
		lev = 0
            elsif (plane == 'TROPO') then
                levStyle = 7
                lev = 0
            elsif (plane == 'MXWIND') then
                levStyle = 6
                lev = 0
            elsif (plane == 'CBTOP') then
                levStyle = 3
                lev = 0
	    elsif (plane[0, 1] == 'F') then
		lev = Fl[plane]
	    else
		lev = plane.to_i
		if (lev.to_s != plane)
		    return nil
		end
	    end
	else
	    lev = 0
	end
	return e['DGRB'], levStyle, lev
    end

    Elem = Hash::new
    Elem['PSEA'] = { 'DGRB' => 1, 'DGRB-LEV' => 102 }
    Elem['P'] = { 'DGRB' => 1 }
    Elem['TRPP'] = { 'DGRB' => 1  ,'DGRB-LEV' => 7 }
    Elem['T'] = { 'DGRB' => 4 }
    Elem['STDT'] = { 'DGRB' => 7 }
    Elem['TTD'] = { 'DGRB' => 11 }
    Elem['Q'] = { 'DGRB' => 12 }
    Elem['RH'] = { 'DGRB' => 13 }
    Elem['STDPS'] = { 'DGRB' => 16 }
    Elem['WindD'] = { 'DGRB' => 20 }
    Elem['WindS'] = { 'DGRB' => 21 }
    Elem['U'] = { 'DGRB' => 23 }
    Elem['V'] = { 'DGRB' => 24 }
    Elem['PSI'] = { 'DGRB' => 29 }
    Elem['VOR'] = { 'DGRB' => 30 }
    Elem['DIV'] = { 'DGRB' => 34 }
    Elem['CHI'] = { 'DGRB' => 39 }
    Elem['OMG'] = { 'DGRB' => 42 }
    Elem['TPW'] = { 'DGRB' => 47 }
    Elem['RRC'] = { 'DGRB' => 48 }
    Elem['RAIN'] = { 'DGRB' => 50 }
    Elem['SnowD'] = { 'DGRB' => 51 }
    Elem['RRL'] = { 'DGRB' => 55 }
    Elem['SST'] = { 'DGRB' => 61 }
    Elem['Z'] = { 'DGRB' => 102 }
    Elem['STDZ'] = { 'DGRB' => 105 }
    Elem['CLA'] = { 'DGRB' => 150 }
    Elem['RR3'] = { 'DGRB' => 201 }
    Elem['RR60LV'] = { 'DGRB' => 202 }
    Elem['HIGHLV'] = { 'DGRB' => 203 }
    Elem['POP6'] = { 'DGRB' => 215 }
    Elem['MRR6'] = { 'DGRB' => 216 }
    Elem['ROCA'] = { 'DGRB' => 219 }
    Elem['MRR3'] = { 'DGRB' => 222 }
    Elem['CLH'] = { 'DGRB' => 225 }
    Elem['WCAT'] = { 'DGRB' => 229 }
    Elem['TANKLV'] = { 'DGRB' => 234, 'DGRB-LEV' => 170 }
    Elem['TURB'] = { 'DGRB' => 236 }
    Elem['CSIG'] = { 'DGRB' => 237 }
    Elem['PI10LV'] = { 'DGRB' => 253, 'DGRB-LEV' => 1 }
    Elem['ORDER'] = { 'DGRB' => 254, 'DGRB-LEV' => 170 }

    Fl = Hash::new
    Fl['F010'] = 977 
    Fl['F030'] = 908 
    Fl['F050'] = 843 
    Fl['F070'] = 782
    Fl['F090'] = 724
    Fl['F110'] = 670 
    Fl['F130'] = 619 
    Fl['F150'] = 572 
    Fl['F170'] = 527 
    Fl['F190'] = 485
    Fl['F210'] = 446 
    Fl['F230'] = 410 
    Fl['F250'] = 376 
    Fl['F270'] = 344 
    Fl['F290'] = 315
    Fl['F310'] = 287 
    Fl['F330'] = 262 
    Fl['F350'] = 238 
    Fl['F370'] = 217 
    Fl['F390'] = 197
    Fl['F410'] = 179 
    Fl['F430'] = 162 
    Fl['F450'] = 147 
    Fl['F470'] = 134 
    Fl['F490'] = 122
    Fl['F510'] = 110 
    Fl['F530'] = 100 
    Fl['F550'] = 91 
    Fl['F570'] = 83 
    Fl['F590'] = 75 

end

NuSDaS = Nusdas
# $Id: nusdas.rb,v 1.23 2003/02/10 10:57:30 suuchi39 Exp $

module Nusdas
    class NusDef
    	def replace(str)
	    raise unless /^(\w+)\.(\w+)\.(\w+)$/ =~ nustype
	    model = $1[0..3]
	    co2d = $1[4..5]
	    co3d = $1[6..7]
	    attr = $2[0..1]
	    time = $2[2..3]
	    name = $3
	    r = str.dup
	    r.gsub!(/_model/, model)
	    r.gsub!(/_2d/i, co2d)
	    r.gsub!(/_3d/i, co3d)
	    r.gsub!(/_space/, co2d + co3d)
	    r.gsub!(/_attribute/, attr)
	    r.gsub!(/_time/, time)
	    r.gsub!(/_name/, name)
	    r
	end
    	def path_replaced
	    replace("#{path}/#{filename}")
	end
    end
end

class PathChange

    def self::help
	print <<EOF
#{$0}: restructure NuSDaS datasets directory structure

usage:
	#{$0} [-dc] conversion [ conversion ... ]

conversion:
	[member=MMMM] nrd1 def1 nrd2 def2

options:
	-d --debug	DEBUG mode
	-c --clobber	removes or overwrites existing files

EOF
	exit 0
   end

    def initialize(nrd1, def1, nrd2, def2)
	@nrd1, @nrd2 = nrd1, nrd2
	dset1 = Nusdas::NusDef::new("#{nrd1}/nusdas_def/#{def1}.def", nrd1)
	dset2 = Nusdas::NusDef::new("#{nrd2}/nusdas_def/#{def2}.def", nrd2)
	raise "nustype mismatch (#{dset1.nustype} != #{dset2.nustype})" \
	    if dset1.nustype != dset2.nustype
	p [nrd1, def1, nrd2, def2] if $DEBUG
	@p1 = dset1.path_replaced.split(/\/+/).reject{|a| /^\.?$/ =~ a}
	@p2 = dset2.path_replaced
	@link = {}
	@mkdir = {}
    end

    BVM = Regexp::new('_((base|valid)time|member)')

    def search(nrd1, p1, p2)
	if p1.empty?
	    raise "undefined #{$&}: #{p2}" if BVM =~ p2
	    raise "duplicated link: #{nrd1}, #{@link[p2]} --> #{p2}" \
	        if @link[p2]
	    @link[p2] = nrd1
	    return
	end
	print "search #{nrd1}\n"
	if BVM =~ p1.first
	    pat = p1.first.dup
	    pat.gsub!(/\W/, '\\\&')
	    keyword = []
	    pat.gsub!(BVM) do |str|
		keyword.push str
		str == '_member' ? '(\w{4})' : '(\d{12})'
	    end
	    rpat = Regexp::new("^#{pat}$")
	    dir = Dir::open(nrd1)
	    files = dir.collect
	    p [nrd1, p1, rpat] if $DEBUG
	    for file in files
		match = rpat.match(file)
		next unless match
		p [file, keyword, match[1..-1]] if $DEBUG
		myp2 = p2.dup
		1.upto(match.size - 1) do |i|
		    myp2.sub!(keyword[i-1], match[i])
		end
	        search("#{nrd1}/#{file}", p1[1..-1], myp2)
	    end
	else
	    raise unless File::exist?(dn = "#{nrd1}/#{p1.first}")
	    search(dn, p1[1..-1], p2)
	end
    end

    def mkdir_parent to
        parent = to.sub(%r|/+[^/]+/*$|, '')
	print "mkdir #{to}\n"
	return if @mkdir[parent]
	return @mkdir[parent] = true if File::directory? parent
	mkdir_parent(parent)
	Dir::mkdir parent
	@mkdir[parent] = true
    end

    def set_writable to
	return unless $OPT_clobber
        parent = to.sub(%r|/+[^/]+/*$|, '')
	print "chmod u+w #{to}\n"
	omode = File::stat(parent).mode
	File::chmod(omode | 0200, parent)
    end

    def link(from, to)
        mkdir_parent to
	print "ln #{from} #{to}\n"
	begin
	    File::link(from, to)
        rescue Errno::EEXIST
	    STDERR.print "#{to}: existent target removed\n"
	    print " ... existent target removed\n"
	    File::unlink(to) if $OPT_clobber
	    File::link(from, to)
	rescue Errno::EACCES
	    set_writable(to)
	    File::link(from, to)
	rescue Errno::EXDEV
	    raise unless $OPT_clobber
	    STDERR.print "#{to}: ln fails, and will try copying\n"
	    print " ... ln fails, and will try copying\n"
	    require 'ftools'
	    File::copy(from, to)
	end
    end

    def kick
	search(@nrd1, @p1, @p2)
	for to, from in @link
	    link from, "#@nrd2/#{to}"
	end
    end

    def member=(str)
        return if str.nil?
        str = [str].pack('A4').gsub(/ /, '_')
	@p2.gsub!(/_member/, str)
    end

    def self::main
        require 'getopts'
	getopts('dwc', *%w(clobber debug verbose))
	$DEBUG = true if $OPT_d or $OPT_debug
	$VERBOSE = true if $OPT_w or $OPT_verbose
	$OPT_clobber = true if $OPT_c
	help if (ARGV.size == 0)
	member = nil
	while not ARGV.empty?
	    if /^member=/ =~ ARGV.first
		member = $'
		ARGV.shift
	    end
	    nrd1 = ARGV.shift
	    def1 = ARGV.shift
	    nrd2 = ARGV.shift
	    def2 = ARGV.shift
	    help if def2.nil?
	    conv = self.new(nrd1, def1, nrd2, def2)
	    conv.member = member if member
	    conv.kick
	end
    rescue => e
        STDERR.print e.message, "\n"
        print e.message, "\n"
        help
    end

end


PathChange.main
exit 0

