#!/usr/bin/ruby

###########################################################
#
#
#
#
###########################################################

require 'optparse'

PROGRAM_NAME = "igmconvert"
@option_hash = {}

#
# コマンドラインオプションを解析する. 
#
def analize_CmdLineOpt()
  OptionParser.new{|opt|
    opt.on('-h') {|v| @option_hash[:h] = v}       
    opt.on('-N 2:2') {|v| @option_hash[:gp_interval] = v}
    opt.on('-T 0:0:1') {|v| @option_hash[:ip_time] = v}   
    opt.on('-F [u,v,h]') {|v| @option_hash[:fields_name] = v } # オプション引数 任意（[]で囲むと任意となる）
    
    opt.parse!(ARGV)
  }

  #ARGV.each {|arg| puts "#{arg}"}
  return ARGV[0], ARGV[1]
end 

#
# glevel の取得
#
def get_glevel(input_fname)
  
  # NetCDF ファイルを ncdump -h に通して, グローバル変数として定義されている glevel の箇所を
  # grep と sed を使って抜き出す. 
  gleveltmp = `ncdump -h #{input_fname} | grep :glevel | sed -e 's/[^0-9]//g'`  
  return gleveltmp.chomp!()
  
end

#
# 鉛直レベル数 の取得
#
def get_VerticalLevelNum(input_fname)
  
  # NetCDF ファイルを ncdump -h に通して, グローバル変数として定義されている nMesh3_layers の箇所を
  # grep と sed を使って抜き出す. 
  
  cmdstr = "ncdump -h #{input_fname} | grep 'nMesh3_layers = ' | sed -e 's/nMesh3_layers = //g'| sed -e 's/;//g'"
  verticalLvNum = `#{cmdstr}`  
#  p verticalLvNum.strip()
  
  return verticalLvNum.strip()
  
end

def split_range1(range)

  if /(.*):(.*)/ =~ range
    if $1 == ""
      min = nil
    else
      min = $1.to_f
    end
    if $2 == ""
      max = nil
    else
      max = $2.to_f
    end
  elsif range == nil
    min = max = nil
  else
    raise "invalid range: variable subset specification error. split range with ':'\n\n"
  end
  
  return min, max
end

def split_range2(range)

  if /(.*):(.*):(.*)/ =~ range
    if $1 == ""
      min = nil
    else
      min = $1.to_f
    end
    if $2 == ""
      max = nil
    else
      max = $2.to_f
    end
    if $3 == ""
     interval = nil
    else
      interval = $3.to_f
    end
  elsif range == nil
    min = max = interval=nil
  elsif /(.*):(.*)/ =~ range
    min, max = split_range1(range)
    interval == nil
  else
    raise "invalid range: variable subset specification error. split range with ':'\n\n"
  end
  
  return min, max, interval
end

def divide_fieldNameList(input_fname, fieldNameList)
  
  field2DList = []
  field3DList = []
  field2D_StrList=""
  field3D_StrList=""
        
  fields = fieldNameList.split(",")
  
  fields.each{|field|
    cmdstr = "ncdump -h #{input_fname} | grep '#{field}('"
    fieldDimInfo = `#{cmdstr}`
    
    if fieldDimInfo.length == 0
      puts "Undefined field name '#{field}' in NetCDF file '#{input_fname}' !!"
      exit(1)
    elsif fieldDimInfo.index("nMesh3_layers") == nil
      field2DList << field
    else
      field3DList << field
    end
  }

  if field2DList.size() != 0   
    field2DList.each{|field|
      field2D_StrList << "#{field},"
    }
    field2D_StrList[field2D_StrList.length()-1,1] = ""
  end
  
  if field3DList.size() != 0 
    field3DList.each{|field|
      field3D_StrList << "#{field},"
     }
    field3D_StrList[field3D_StrList.length()-1,1] = ""
  end
  
#  p field2DList
#  p field3DList
#  p field2D_StrList
#  p field3D_StrList
  
  return field2D_StrList, field3D_StrList
end

def auto_select_gpinterval(glevel)
  case glevel
  when 4 then
    return "73,37"   # 5 度間隔
  when 5 then
    return "145,73"  # 2.5 度間隔
  when 6 then
    return "145,73"  # 2.5 度間隔
  when 7 then
    return "289,145" # 1.25 度間隔
  when 8 then
    return "289,145" # 1.25 度間隔
  end
end

#
# help を表示する. 
#
def show_help
  puts '= igmconvert3D'
  puts "* 'igmconvert3D is a frontend ruby script for igmconvert. "
  puts "  * By using this script, the user can reduce the parmeters required to run igmconvert(native fortran program)."
  puts '* Usage:'
  puts
  puts "  $igmconvert3D inputfile outputfile -F 'u,v,h'"
  puts "  '-F' specifies the name of physical fields which one want to interpolate."
  exit
end

#
# igmconvert を呼ぶ際に渡す, コマンドライン引数を生成する. 
#
def generate_ArgsLine(input_fname, output_fname)

  args_line = ""

  # 最低限必要な 2 つの引数が指定されていない場合は, ヘルプを出力する. 
  if ARGV.length != 2
    puts 'Invalid arguments!'
    show_help
  end

  # 読み込むファイルの名前を設定
  args_line << "--Read_NetCDF=#{input_fname} "
  # 書き込むファイルの名前を設定
  args_line << "--Output_NetCDF=#{output_fname} "

  # glevel の設定
  glevel = get_glevel(input_fname)
  args_line << "--glevel=#{glevel} "
  
  #
  verticalLvNum = get_VerticalLevelNum(input_fname)
  args_line << "--vertical_level_num=#{verticalLvNum} "
  
  # help オプションの設定
  if @option_hash.has_key?(:h)
    args_line << "--help "
  end
  
  # 補間を行う 2,3 次元物理場の名前リストの設定
  if @option_hash.has_key?(:fields_name)
  
    field2Ds_name, field3Ds_name=divide_fieldNameList(input_fname, @option_hash[:fields_name])
 
    if field2Ds_name.length != 0
      args_line << "--Field2Ds_Name='#{field2Ds_name}' "  
    end
    
    if field3Ds_name.length != 0
      args_line << "--Field3Ds_Name='#{field3Ds_name}' "
    end
    
  end
  
  # 補間格子数の設定. 
  # 指定されていない場合には, auto_select_gpinterval を呼び出して, 
  # 適当な補間格子点数を設定する. 
  if @option_hash.has_key?(:gp_interval)
    lonpts, latpts = split_range1(@option_hash[:gp_interval]) 
    args_line << "--Num_lon_lat='#{lonpts.to_i},#{latpts.to_i}' "
  else
    auto_gpinterval=auto_select_gpinterval(glevel.to_i)
    puts 'Automatically selcet interpolating grid interval..'
    args_line << "--Num_lon_lat='#{auto_gpinterval}' "
  end
  
  # 補間を行う時間間隔の設定. 
  #
  if @option_hash.has_key?(:ip_time)
      t_start, t_end, tstep_interval = split_range2(@option_hash[:ip_time])
      
      if tstep_interval == nil
        args_line << "--Time_levels='#{t_start},#{t_end}' "
      else
        args_line << "--Time_levels='#{t_start},#{t_end},#{tstep_interval.to_i}' "
      end 
  end
 
  args_line << "--IcGrid_Mode='IcGrid3D' "
   
  return args_line
  
end

def launch_igmconvert(args_line)
  
  cmdline_str = "#{PROGRAM_NAME} #{args_line}" 
  p cmdline_str
  
  #IO.popen(cmdline_str) do |io|
  #  io.each{ |line|
  #    puts line
      
  #  }
  #end
  system(cmdline_str)
end


# コマンドライン引数を解析する. 
@input_filename, @output_filename = analize_CmdLineOpt()
# igmconvert (native program) を実行する際に, 渡すコマンドライン引数を生成する.  
arguments_line = generate_ArgsLine(@input_filename, @output_filename)
# 生成したコマンドライン引数を使って, igmconvert を実行する. 
launch_igmconvert(arguments_line)
