class NSWTopo::ESRIHdr

def initialize(path_or_object, *args)

def initialize(path_or_object, *args)
  @header = case path_or_object
  when Pathname then path_or_object.sub_ext(".hdr").each_line.map(&:upcase).map(&:split).to_h
  when ESRIHdr then path_or_object.header.dup
  end
  @format = case @header.values_at "PIXELTYPE", "NBITS", "BYTEORDER"
  when %w[SIGNEDINT 8 I]    then "c*"
  when %w[SIGNEDINT 8 M]    then "c*"
  when %w[SIGNEDINT 16 I]   then "s<*"
  when %w[SIGNEDINT 16 M]   then "s>*"
  when %w[SIGNEDINT 32 I]   then "l<*"
  when %w[SIGNEDINT 32 M]   then "l>*"
  when %w[UNSIGNEDINT 8 I]  then "C*"
  when %w[UNSIGNEDINT 8 M]  then "C*"
  when %w[UNSIGNEDINT 16 I] then "S<*"
  when %w[UNSIGNEDINT 16 M] then "S>*"
  when %w[UNSIGNEDINT 32 I] then "L<*"
  when %w[UNSIGNEDINT 32 M] then "L>*"
  when %w[FLOAT 32 I]       then "e*"
  when %w[FLOAT 32 M]       then "g*"
  end
  @nodata = case path_or_object
  when Pathname
    case @header.values_at "PIXELTYPE", "NBITS"
    when %w[SIGNEDINT 8]    then args.take(1).pack("c").unpack("c").first
    when %w[UNSIGNEDINT 8]  then args.take(1).pack("C").unpack("C").first
    when %w[SIGNEDINT 16]   then args.take(1).pack("s").unpack("s").first
    when %w[UNSIGNEDINT 16] then args.take(1).pack("S").unpack("S").first
    when %w[SIGNEDINT 32]   then args.take(1).pack("l").unpack("l").first
    when %w[UNSIGNEDINT 32] then args.take(1).pack("L").unpack("L").first
    when %w[FLOAT 32]       then args.first
    else abort @header.inspect
    end if args.any?
  when ESRIHdr then path_or_object.nodata
  end
  @values = case path_or_object
  when Pathname
    data = []
    path_or_object.sub_ext(".bil").open("rb") do |file|
      while !file.eof?
        data += file.read(32*1024*1024).unpack(@format).map do |value|
          value == @nodata ? nil : value
        end
      end
    end
    data
  when ESRIHdr then args[0]
  end
end

def ncols

def ncols
  @ncols ||= @header["NCOLS"].to_i
end

def nrows

def nrows
  @nrows ||= @header["NROWS"].to_i
end

def rows

def rows
  @values.each_slice ncols
end

def write(path)

def write(path)
  @header.map do |pair|
    "%-#{@header.keys.map(&:length).max}s  %s\n" % pair
  end.join('').tap do |text|
    path.sub_ext(".hdr").write text
  end
  @values.map do |value|
    value || @nodata
  end.pack(@format).tap do |data|
    path.sub_ext(".bil").binwrite data
  end
end