#!/usr/local/bin/ruby
# -*- coding: utf-8 -*-
#
# Shin-ya Murakami 2005,2012 <murashin@gfd-dennou.org>
#
# validate NOAA/CMDL raw data format
#
# 以下のような行で構成されるファイルが
# 正しくフォーマットされているかチェックする.
#
# <2235912>z0000.y000.x9F4.w000.v000.u000.t000.s000.r000.q3+86B8.p3+6133.o3+EF0A.n3+75D6.m3+8E96.l3+2E0A.k0000.
#
# 数字が書いてある箇所は任意の16進数がはいる. 長さは固定.
# .の後の英字1文字は変わらない. +の位置は+か-が入る. <>は変更無し. 
# zの後の数字とkの後の数字は一致.(まだ考慮していない)

#エラーが3つ以上ある行は, 3つ目以降エラー表示を抑制する.

require "getoptlong"        # for option_parse

CHKFRMT_VERSION = "0.1"

#frmt:見本の形式
#line: データ1行分(改行文字は含まない)
#nlines:データの先頭からの位置(単位:行)
def check(frmt, line, nlines)
  nerrors = 0
  return if line.size == 9  # <2235912>のようなものだけの行は無視.
  return if line.size == 0  # 空白行も無視
  frmt.size.times do |i|
    frmtchar = frmt[i].chr
    if line[i].nil?
      $invalid = true
      if $OPT_warn
        print "warning: unexpected termination at l.#{nlines}\n"
      end
      return
    end
    char = line[i].chr
    if frmtchar == '@'
      if not '0123456789abcdef'.include? char.downcase
        $invalid = true
        nerrors += 1
        errmsg = "error: #{char} should be hex number at l.#{nlines},#{i}\n"
        superrprint(errmsg, nerrors)
      end
    elsif frmtchar == '+'
      if (char != '+' && char != '-')
        $invalid = true
        nerrors += 1
        errmsg = "error: #{char} should be + or - at l.#{nlines},#{i}\n"
        superrprint(errmsg, nerrors)
      end
    elsif frmtchar != char
      $invalid = true
      nerrors += 1
      errmsg = "error: #{char} should be #{frmtchar} at l.#{nlines},#{i}\n"
      superrprint(errmsg, nerrors)
    end
  end
end

#err: エラーメッセージ文字列
#n: エラーメッセージ出力回数
def superrprint(err, n)
  trv = $maxerror
  if n > trv
    nil
  elsif n < trv
    print err
  elsif n == trv
    print "the following error messages about this line are suppresed.\n"
  end
end

parser = GetoptLong.new
parser.set_options(
    ['--maxerror', '-m', GetoptLong::REQUIRED_ARGUMENT],
    ['--warn', '-w', GetoptLong::NO_ARGUMENT],
    ['--skip', '-s', GetoptLong::REQUIRED_ARGUMENT],
    ['--help', '-h', GetoptLong::NO_ARGUMENT],
    ['--version', '-v', GetoptLong::NO_ARGUMENT])


begin
  parser.each_option do |name, arg|
    eval "$OPT_#{name.sub(/^--/, '').gsub(/-/, '_')} = '#{arg}'"
  end
rescue
  exit(1)
end

file = ARGV[0]
$maxerror = 3 #1行あたりのエラー表示最大回数

$maxerror = $OPT_maxerror if $OPT_maxerror

headers = '7' # default
headers = $OPT_skip if $OPT_skip
headers = headers.to_i # nil.to_i => 0なので, ここで数字に変換.

$invalid = false

p file, file.nil?

if $OPT_help or file.nil?
  print "usage: chkfrmt.rb file [options]\n"
  print "options:\n"
  print "  -m, --maxerror n     set max error outputs in a line\n"
  print "  -s, --skip n         skip first n lines (default:n=7)\n"
  print "  -w, --warn           warn unexpected termination in each line\n"
  print "  -v, --version        print version\n"
  exit
end

if $OPT_version
  print "chkfrmt.rb version #{CHKFRMT_VERSION}\n"
  exit
end

#----
frmt = "<@@@@@@@>z@@@@.y@@@.x@@@.w@@@.v@@@.u@@@.t@@@.s@@@.r@@@.q@+@@@@.p@+@@@@.o@+@@@@.n@+@@@@.m@+@@@@.l@+@@@@.k@@@@."

data = File.new(file, 'r')
headers.times {|i| data.gets}
nlines = headers 

while (line = data.gets)
  nlines = nlines + 1
#  print "proseccing #{nlines}\n"
  check(frmt, line.chomp, nlines)
end

data.close
print "format is ok\n" if !$invalid


