class Func
  def header
    print "module gms_math_function\n"
    print "  use datatype\n"
    print "  use mem_manager\n"
    print "  implicit none\n"
  end

  def contains
    print "contains\n"
  end

  def footer
    print "end module gms_math_function\n"
  end
end

class Func1
  def header(name)
    print "  interface ", name, "\n"
    print "    module procedure ", name ,"_x, " , name ,"_y, ", name ,"_z, ", name ,"_xy, ", name ,"_xz, ", name ,"_yz, ", name ,"_xyz\n "
    print "end interface\n\n"
  end

  def output(name, type)
    if type == "real" then return end

    print "  function ", name, "_", type, "(input) result(output)\n"
    print "    type(var_", type, "), intent(in) :: input\n"
    print "    type(var_", type, ") :: output\n"
    print "    integer :: new_id\n\n"

    print "    call get_new_id_", type, "(new_id)\n\n"

    print "    work_", type, "(:,:,:,new_id) = ", name, "(work_", type, "(:,:,:,input%id))\n\n"
    print "    output%id = new_id\n"
    print "    output%grid = input%grid\n"

    print "  end function ", name, "_", type, "\n\n"
  end
end

class Func2
  def header(name)
    print "  interface ", name, "\n"
    print "    module procedure ", name ,"_x, " , name ,"_y, ", name ,"_z, ", name ,"_xy, ", name ,"_xz, ", name ,"_yz, ", name ,"_xyz\n "
    print "    module procedure ", name ,"_real_x, " , name ,"_real_y, ", name ,"_real_z, ", name ,"_real_xy, ", name ,"_real_xz, ", name ,"_real_yz, ", name ,"_real_xyz\n "
    print "    module procedure ", name ,"_x_real, " , name ,"_y_real, ", name ,"_z_real, ", name ,"_xy_real, ", name ,"_xz_real, ", name ,"_yz_real, ", name ,"_xyz_real\n "

    print "end interface\n\n"
  end

  def output(name, type1, type2)
    if type1 == "real" && type2 == "real" then return end

    if type1 == type2 then
    print "  function ", name, "_", type1, "(input1, input2) result(output)\n"
    print "    type(var_", type1, "), intent(in) :: input1, input2\n"
    print "    type(var_", type1, ") :: output\n"
    print "    integer :: new_id\n\n"

    print "    call get_new_id_", type1, "(new_id)\n\n"

    print "    work_", type1, "(:,:,:,new_id) = ", name, "(work_", type1, "(:,:,:,input1%id), work_", type1, "(:,:,:,input2%id))\n\n"
    print "    output%id = new_id\n"
    print "    output%grid = input1%grid\n"
    print "  end function ", name, "_", type1, "\n\n"

    elsif type1 == "real" then 
    print "  function ", name, "_", type1, "_",type2, "(input1, input2) result(output)\n"
    print "    real(8), intent(in) :: input1\n"
    print "    type(var_", type2, "), intent(in) :: input2\n"
    print "    type(var_", type2, ") :: output\n"
    print "    integer :: new_id\n\n"

    print "    call get_new_id_", type2, "(new_id)\n\n"

    print "    work_", type2, "(:,:,:,new_id) = ", name, "(input1, work_", type2, "(:,:,:,input2%id))\n\n"
    print "    output%id = new_id\n"
    print "    output%grid = input2%grid\n"
    print "  end function ", name, "_", type1, "_", type2, "\n\n"

    elsif type2 == "real" then 
    print "  function ", name, "_", type1, "_",type2, "(input1, input2) result(output)\n"
    print "    type(var_", type1, "), intent(in) :: input1\n"
    print "    real(8), intent(in) :: input2\n"
    print "    type(var_", type1, ") :: output\n"
    print "    integer :: new_id\n\n"

    print "    call get_new_id_", type1, "(new_id)\n\n"

    print "    work_", type1, "(:,:,:,new_id) = ", name, "(work_", type1, "(:,:,:,input1%id), input2)\n\n"
    print "    output%id = new_id\n"
    print "    output%grid = input1%grid\n"
    print "  end function ", name, "_", type1, "_", type2, "\n\n"
    end
  end
end







list1 = open("func_list1", "r")
list2 = open("func_list2", "r")

func = Func.new
func1 = Func1.new
func2 = Func2.new

type1=[7]
type2=[7]

type1[0] = type2[0] = "x"
type1[1] = type2[1] = "y"
type1[2] = type2[2] = "z"
type1[3] = type2[3] = "xy"
type1[4] = type2[4] = "xz"
type1[5] = type2[5] = "yz"
type1[6] = type2[6] = "xyz"
type1[7] = type2[7] = "real"

func.header

while line1 = list1.gets
  line1.chop!
  func1.header(line1)
end

while line2 = list2.gets
  line2.chop!
  func2.header(line2)
end

#list1.close
#list2.close


func.contains

list1.reopen("func_list1", "r")
list2.reopen("func_list2", "r")



while line1 = list1.gets
line1.chop!

  for  i in 0..7 do
    func1.output(line1, type1[i])
  end
end

while line2 = list2.gets
line2.chop!
  
  for  i in 0..7 do
    for  j in 0..7 do

      func2.output(line2, type1[i], type2[j])
    end
  end
end

func.footer
