#!/usr/local/bin/ruby
# -*- coding: euc-jp -*-

require "nkf"
require "cgi"

class Modes
	DEBUG = 0
	CGI = 1
end

#動作モードの設定
MODE = Modes::CGI

class Methods
	NONE = 0
	INDUCTANCE = 1
	WIRE_TURNS = 2
end

#計算する対象の設定
@method = Methods::NONE

class Shapes
	CIRCLE = 0
	SQUARE = 1
end

#コイルの形状（円形，長方形）
@shape = Shapes::SQUARE

FILE_NAGAOKA_DL = "./inductance-d-l.txt"
FILE_NAGAOKA_LD = "./inductance-l-d.txt"

#真空の透磁率
PERMEABILITY = Math::PI * 4 * (10 ** -7)

#コイルの直径(m)
@diameter = 0.0

#コイルのX・Yの長さ
@width = 0.0
@height = 0.0

#コイルの線幅(m)
@wireWidth = 0.0

#コイルの巻き数
@wireTurns = 0

#コイルの長さ(m)
@length = 0.0

#透磁率(空気=約1.0)
@permeability = 0.0
@permeabilityRel= 1.0

#長岡係数
@nagaoka = 0.0

#インダクタンス
@inuctance = 0

#diameter > length 時の長岡係数表表
@nagaokaTableD = Hash.new(nil)



def InitNagaoka()
	f = File.open(FILE_NAGAOKA_DL)
	cnt = 0
	@keyD = Hash.new(nil)
	f.each do |line|
		next	if(line == "")
		words = line.split(/\t/)
		next	if(words.length < 2) 
		next	if(words[0][0] == '#')
		key = words[0].to_s
		data = words[1].to_f
		@nagaokaTableD[key] = [] if @nagaokaTableD[key].nil? 
		@nagaokaTableD[key] =  data
		@keyD[cnt] = key
		cnt += 1
	end

	cnt = 0
	@keyD2 = Hash.new(nil)

	for i in 0...(@keyD.length-1)
		max = 10
		keyS = @keyD[i]
		keyE = @keyD[i+1]
		dataS = @nagaokaTableD[keyS]
		dataE = @nagaokaTableD[keyE]
		keyInt = (keyE.to_f - keyS.to_f) / max.to_f
		dataInt = (dataE - dataS) / max.to_f
		#puts(keyInt.to_s + ": " + dataInt.to_s)

		for j in 0...max
			d = dataS + dataInt * j
			k = keyS.to_f + j * 0.001
			#@nagaokaTableD[k] = [] if @nagaokaTableD[k].nil? 
			@nagaokaTableD[k.to_s] = d
			@keyD2[cnt] = k.to_s
			cnt +=1
		end
	end

	#for i in 0...(@keyD2.length)
	#	k = @keyD2[i]
	#		puts(k)
	#		puts(k.to_s + ": " + @nagaokaTableD[k].to_s)
	#	end
	#end
	f.close

	#length > diameter 時の長岡係数表
	@nagaokaTableL = Hash.new(nil);

	f = File.open(FILE_NAGAOKA_LD)
	cnt = 0
	@keyL = Hash.new(nil)
	f.each do |line|
		next	if(line == "")
		words = line.split(/\t/)
		next	if(words.length < 2) 
		next	if(words[0][0] == '#')
		key = words[0].to_s
		data = words[1].to_f
		@nagaokaTableL[key] = [] if @nagaokaTableL[key].nil? 
		@nagaokaTableL[key] = data
		@keyL[cnt] = key
		cnt += 1
	end
	cnt = 0
	@keyL2 = Hash.new(nil)
	for i in 0...(@keyL.length-1)
		max = 10
		keyS = @keyL[i]
		keyE = @keyL[i+1]
		dataS = @nagaokaTableL[keyS]
		dataE = @nagaokaTableL[keyE]
		keyInt = (keyE.to_f - keyS.to_f) / max.to_f
		dataInt = (dataE - dataS) / max.to_f
		#puts(keyInt.to_s + ": " + dataInt.to_s)
		for j in 0...max
			d = dataS + dataInt * j
			k = keyS.to_f + j * 0.001
			#@nagaokaTableL[k] = [] if @nagaokaTableL[k].nil? 
			@nagaokaTableL[k.to_s] = d
			#puts(k.to_s)
			@keyL2[cnt] = k.to_s
			cnt +=1
		end
	end
	f.close
end


def GetNagaoka()

	if(@length > @diameter)
		tmp = @diameter  / @length * 1000.0
		tmp = (tmp.round / 1000.0).to_s
	
		if @nagaokaTableD[tmp].nil?
			#puts("長岡係数の指定が間違っています")
			#puts(tmp)
			@nagaoka = -1
			return
		else 
			@nagaoka = @nagaokaTableD[tmp].to_f			#この書き方はよくわからん…
			#puts(tmp)
			#puts("長岡係数: " + @nagaoka.to_s)
		end
	else
		tmp = @length / @diameter * 1000.0
		tmp = (tmp.round / 1000.0).to_s

		if @nagaokaTableL[tmp].nil?
			#puts("長岡係数の指定が間違っています")
			#puts(tmp)
			@nagaoka = -1
			return
		else 
			@nagaoka = @nagaokaTableL[tmp].to_f			#この書き方はよくわからん…
			#puts(tmp)
			#puts("長岡係数: " + @nagaoka.to_s)
		end	
	end
	return
end

def GetInductance()
  if(@shape == Shapes::CIRCLE)
    @inductance = (@nagaoka * @permeability * Math::PI * (@radius ** 2) * (@wireTurns ** 2)) / @length
	else
    @inductance = (@nagaoka * @permeability * (@diameter ** 2) * (@wireTurns ** 2)) / @length
  end
  return
end

def GetNT()
  if(@shape == Shapes::CIRCLE)
    @nt = @inductance / @permeability /  Math::PI / (@radius ** 2) * @wireWidth
  #To modify
  else
    @nt = @inductance / @permeability /  (@diameter ** 2) * @wireWidth
  end
	return
end

def SearchNagaoka()
	@rates = Array.new
	@ns = Hash.new(nil)
	@ts = Hash.new(nil)
	cnt=0
	for i in 0...(@keyD2.length)
		k = @keyD2[i]
		n = @nagaokaTableD[k]
		l = @diameter / k.to_f 
		t = l / @wireWidth
		nt = n * t
		rate = (nt / @nt) -1.0       #->これが一番 小さくなる値を求める 
		@rates[cnt] = rate
		@ns[rate.to_s] = n
		@ts[rate.to_s] = t
		cnt += 1
	end

	for i in 0...(@keyL2.length)
		k = @keyL2[i] 
		n = @nagaokaTableL[k]
		l = k.to_f * @diameter
		t = l / @wireWidth  
		nt = n * t
		rate = (nt / @nt) -1.0
		@rates[cnt] = rate
		@ns[rate.to_s] = n
		@ts[rate.to_s] = t
		cnt += 1

		#puts(rate)
		#puts(@rates[cnt].to_s)
	end

	@values = @rates.sort
	#@n=0                 
	#@t=0
	@values.each do |d|
		if(d > 0)
			#puts(d)
			@nagaoka = @ns[d.to_s]
			@wireTurns = @ts[d.to_s]
			@length = @wireWidth * @wireTurns
			#puts(d.to_s + ": " + @n.to_s + ", " + @t.to_s)	
			return
		end
	end
	#@nagaoka = -1
	#return
end 


def PrintHtml(success)

	wireWidth = (@wireWidth * 1000.0).to_s
	diameter =  (@diameter * 1000.0).to_s
  width = (@width * 1000.0).to_s
  height = (@height * 1000.0).to_s
	wireTurns = sprintf("%#.2f", @wireTurns)
	inductance = sprintf("%#.2f", @inductance * 1000000.0)
	length = sprintf("%#.2f", (@length * 1000.0))
	nagaoka = @nagaoka.to_s
	permeabilityRel = @permeabilityRel.to_s

	puts <<-EOF
	<html><head><meta http-equiv="Content-Type" content="text/html; charset=EUC-JP">
  <title>インダクタンスの計算</title></head>
	<body bgcolor="white"><center><h3>インダクタンスの計算</h3></center>
	EOF

	if(!success)
		
		puts("<center><h3><font color=red>入力された数値にエラーがありました．もう一度やり直してください．</font></h3></center>")
	end
	
puts <<-EOF
<form action="./l.cgi" method="post" name="l" id="l">
<table width="600"  border="1" align="center" bordercolor="#0000FF">
  <tr>
    <td>　
        <table width="100%"  border="0" align="center">
          <tr bgcolor="#FFCCCC">
            <td colspan="4">※必ず入力</td>
          </tr>
          <tr bgcolor="#FFCCCC">
            <td width="25%">　線材の太さ:</td>
            <td width="25%">　
                <input name="wireWidth" type="text" id="wireWidth" value="#{wireWidth}" size="10" maxlength="10">
            mm </td>
            <td>　</td>
            <td>　</td>
          </tr>
          <tr>
            <td colspan="4">　</td>
          </tr>
          <tr bgcolor="#FFFFCC">
            <td colspan="4">※コイルの形状（どちらか選択＆入力）</td>
          </tr>
          <tr bgcolor="#FFFFCC">
EOF
            
  if(@shape == Shapes::CIRCLE)
    puts('<td colspan="2"><input name="shape" type="radio" value="0" checked>円形</td>')
    puts('<td colspan="2"><input name="shape" type="radio" value="1">長方形</td>')
  else
    diameter = "0"
		puts('<td colspan="2"><input name="shape" type="radio" value="0" >円形</td>')
    puts('<td colspan="2"><input name="shape" type="radio" value="1" checked>長方形</td>')
	end

  puts <<-EOF
          </tr>
          <tr bgcolor="#FFFFCC">
            <td bgcolor="#FFFFCC">　コイルの直径:</td>
            <td bgcolor="#FFFFCC">　
                <input name="diameter" type="text" id="diameter" size="10" maxlength="10" value ="#{diameter}">
  mm</td>
            <td>コイルの幅:</td>
            <td>　
              <input name="width" type="text" id="width" value ="#{width}" size="10" maxlength="10">
    mm</td>
          </tr>
          <tr bgcolor="#FFFFCC">
            <td bgcolor="#FFFFCC">　</td>
            <td bgcolor="#FFFFCC">　</td>
            <td>コイルの高さ:</td>
            <td>　
              <input name="height" type="text" id="height" value ="#{height}" size="10" maxlength="10">
    mm</td>
          </tr>
          <tr>
            <td colspan="4">　</td>
          </tr>
          <tr bgcolor="#FFFFCC">
            <td colspan="4">※計算モード（どちらか選択＆入力）</td>
          </tr>
          <tr bgcolor="#FFFFCC">
EOF
  
  inductanceColor = "#FFFFCC"
  wireTurnColor = "#FFFFCC"
  
	if(@method == Methods::WIRE_TURNS)
		puts('<td colspan="2"><input name="method" type="radio" value="2" checked>インダクタンスから巻き数を計算</td>')
    puts('<td colspan="2"><input name="method" type="radio" value="1" >巻き数からインダクタンスを計算</td>')
    wireTurnColor = "#CCFF66"
  elsif(@method == Methods::INDUCTANCE)
		puts('<td colspan="2"><input name="method" type="radio" value="2" >インダクタンスから巻き数を計算</td>')
		puts('<td colspan="2"><input name="method" type="radio" value="1" checked>巻き数からインダクタンスを計算</td>')
    inductanceColor = "#CCFF66"
  else
 		puts('<td colspan="2"><input name="method" type="radio" value="2" >インダクタンスから巻き数を計算</td>')
		puts('<td colspan="2"><input name="method" type="radio" value="1" checked>巻き数からインダクタンスを計算</td>') 
	end
  
  
  
  puts <<-EOF       
          </tr>
          <tr>
            <td width="25%"  bgcolor="#{inductanceColor}">　インダクタンス:</td>
            <td width="25%"  bgcolor="#{inductanceColor}">　
                <input name="inductance" type="text" id="inductance" size="10" maxlength="10" value ="#{inductance}">
            uH </td>
            <td  bgcolor="#{wireTurnColor}">巻き数:</td>
            <td  bgcolor="#{wireTurnColor}">　
                <input name="wireTurns" type="text" id="wireTurns" value = "#{wireTurns}" size="10" maxlength="10">
            回 </td>
          </tr>
          <tr>
            <td colspan="4">　</td>
          </tr>
          <tr bgcolor="#eeffff">
            <td colspan="4">※必要時のみ入力</td>
          </tr>
          <tr bgcolor="#eeffff">
            <td>比透磁率:</td>
            <td> 　
                <input name="permeability" type="text" id="permeability" value="#{permeabilityRel}" size="10" maxlength="10">
            </td>
            <td colspan="2">(空気 = 約1.00) </td>
          </tr>
          <tr>
            <td colspan="4">　</td>
          </tr>
          <tr>
            <td width="25%">※その他(入力不要)</td>
            <td>　</td>
            <td width="25%">　</td>
            <td>　</td>
          </tr>
          <tr>
            <td>コイルの長さ:</td>
            <td>　
                <input name="length" type="text" id="length" size="10" maxlength="10" value="#{length}">
            mm</td>
            <td>長岡係数:</td>
            <td>　
                <input name="nagaoka" type="text" id="nagaoka" size="10" maxlength="10"  value="#{nagaoka}"></td>
          </tr>
          <tr>
            <td colspan="4">　</td>
          </tr>
          <tr>
            <td colspan="2" align="center"><input type="submit" name="Submit" value="計算"></td>
            <td colspan="2" align="center"><input type="reset" name="Clear" value="クリア"></td>
          </tr>
          <tr>
            <td colspan="2" align="center">　<br>[<a href="antenna-mid.html#inductance">13.56MHzアンテナ編</a>]</td>
            <td colspan="2" align="center">　<br>[<a href="antenna-low.html#inductance">135KHzアンテナ編</a>]</td>
          </tr>
        </table>
      </form>
	  </body></html>
EOF
end


########################メインルーチン################################
#係数表の初期化
InitNagaoka()

if(MODE == Modes::DEBUG)
	puts("計算対象を入力してください．")
	puts("0: インダクタンス，1: 巻き数")
	inStr = gets()
  
	if(inStr.to_i == 0)
		@method = Methods::INDUCTANCE
	elsif(inStr.to_i == 1)
		@method = Methods::WIRE_TURNS
	else
		@method = Methods::INDUCTANCE
	end

	if(@method ==  Methods::INDUCTANCE)
		#一行読み込み
		puts("コイルの線幅を入力してください．(mm)")
		inStr = gets()
		@wireWidth = inStr.to_f / 1000.0
		#puts(@wireWidth)
    puts("コイルの形状を入力してください．")
  	puts("0: 円形，1: 長方形")
		inStr = gets()
  	if(inStr.to_i == 0)
		  @shape = Shapes::CIRCLE
	  elsif(inStr.to_i == 1)
	  	@shape = Shapes::SQUARE
	  else
		  @shape = Shapes::CIRCLE
	  end  
    
    if(@shape == Shapes::CIRCLE)
  		puts("コイルの直径を入力してください．(mm)")
  		inStr = gets()
  		@diameter = inStr.to_f  / 1000.0
    else
   		puts("コイルの幅(X)を入力してください．(mm)")
  		inStr = gets()
  		@width = inStr.to_f  / 1000.0
  		puts("コイルの高さ(Y)を入力してください．(mm)")
  		inStr = gets()
  		@height = inStr.to_f  / 1000.0
      @diameter = (@width + @height)  / 2.0
    end
		#puts(@diameter)
		puts("コイルの巻数を入力してください．(回数)")
		inStr = gets()
		@wireTurns = inStr.to_f
		#コイルの長さ
		@length = @wireWidth * @wireTurns
		#コイルの半径
		@radius = @diameter / 2.0
		#透磁率(空気=約1.0)
		@permeability = PERMEABILITY * @permeabilityRel

		#適切な係数を選択
		GetNagaoka()
		if(@nagaoka == -1)
			puts("長岡係数の指定が間違っています")
			puts("アプリケーションを終了します")
			exit
		else
			puts("長岡係数: " + @nagaoka.to_s)
		end

		#インダクタンスを計算
		GetInductance()
	
		#puts("コイルの長さ:" + @length.to_s)
		puts("インダクタンス: " + (@inductance * 1000000).to_s + " uH")

	elsif(@method == Methods::WIRE_TURNS)
		#一行読み込み
		puts("コイルの線幅を入力してください．(mm)")
		inStr = gets()
		@wireWidth = inStr.to_f / 1000.0
		#puts(@wireWidth)
    puts("コイルの形状を入力してください．")
  	puts("0: 円形，1: 長方形")
		inStr = gets()
  	if(inStr.to_i == 0)
		  @shape = Shapes::CIRCLE
	  elsif(inStr.to_i == 1)
	  	@shape = Shapes::SQUARE
	  else
		  @shape = Shapes::CIRCLE
	  end  
    if(@shape == Shapes::CIRCLE)
  		puts("コイルの直径を入力してください．(mm)")
  		inStr = gets()
  		@diameter = inStr.to_f  / 1000.0
    else
   		puts("コイルの幅(X)を入力してください．(mm)")
  		inStr = gets()
  		@width = inStr.to_f  / 1000.0
  		puts("コイルの高さ(Y)を入力してください．(mm)")
  		inStr = gets()
  		@height = inStr.to_f  / 1000.0
      @diameter = (@width + @height)  / 2.0
    end

		puts("必要なインダクタンスを入力してください．(uH)")
		inStr = gets()
		@inductance = inStr.to_f / 1000000.0 

		@radius = @diameter / 2.0
		#透磁率(空気=約1.0)
		@permeability = PERMEABILITY * 1.0

		#長岡係数 * 巻き数
		GetNT()

		#適切な組み合わせを検索
		SearchNagaoka()
		puts("長岡係数: " + @nagaoka.to_s)
	  puts("コイルの巻き数: " + @wireTurns.to_s)
	end
  
########################CGI処理################################
elsif(MODE == Modes::CGI)
	@cgi = CGI.new
	puts("Content-type: text/html")
	puts()

	#計測する対象
	inStr = @cgi['method'].to_s
	#inStr.chop!
	if(inStr.to_i == Methods::INDUCTANCE)
		@method = Methods::INDUCTANCE
		#puts("inductance")
	elsif(inStr.to_i == Methods::WIRE_TURNS)
		@method = Methods::WIRE_TURNS
		#puts("wire_turns")
	else
		@method = Methods::NONE
    @inductance = 0.0
    @width = 0.0
    @height = 0.0
    @diameter = 0.0
    @wireTurns = 0.0
		PrintHtml(true)
    exit
	end
  
  inStr = @cgi['shape'].to_s
  	if(inStr.to_i == 0)
		  @shape = Shapes::CIRCLE
	  elsif(inStr.to_i == 1)
	  	@shape = Shapes::SQUARE
	  else
		  @shape = Shapes::CIRCLE
	  end
    
    if(@shape == Shapes::CIRCLE)
  		inStr = @cgi['diameter'].to_s
  		@diameter = inStr.to_f  / 1000.0
      @width = 0
      @height = 0
      if(@diameter <= 0)
  		  PrintHtml(false)
		    exit
	    end
    else
  		inStr = @cgi['width'].to_s
  		@width = inStr.to_f  / 1000.0
  		inStr = @cgi['height'].to_s
  		@height = inStr.to_f  / 1000.0
      @diameter = (@width + @height)  / 2.0
      if(@width <= 0 || @height <= 0)
  		  PrintHtml(false)
		    exit
	    end
    end

  if(@method == Methods::INDUCTANCE)
		inStr = @cgi['wireWidth'].to_s
		@wireWidth = inStr.to_f / 1000.0
		
    inStr = @cgi['wireTurns'].to_s
		@wireTurns = inStr.to_f
    
		inStr = @cgi['permeability'].to_s
		@permeabilityRel = inStr.to_f
    
		@inductance = 0.0

		#入力値が不正な場合はエラー
		if(@wireWidth <= 0 ||@wireTurns <=0 ||@permeabilityRel <= 0)
			PrintHtml(false)
			exit
		end

		#コイルの長さ
		@length = @wireWidth * @wireTurns
		#コイルの半径
		@radius = @diameter / 2.0
		#透磁率(空気=約1.0)
		@permeability = PERMEABILITY * @permeabilityRel 

		#適切な係数を選択
		GetNagaoka()
		if(@nagaoka == -1)
			PrintHtml(false)
			exit
		else
			#puts("長岡係数: " + @nagaoka.to_s)
		end

		#インダクタンスを計算
		GetInductance()
		
		PrintHtml(true)

	elsif(@method == Methods::WIRE_TURNS)
		inStr = @cgi['wireWidth'].to_s
		@wireWidth = inStr.to_f / 1000.0
		
    inStr = @cgi['permeability'].to_s
		@permeabilityRel = inStr.to_f
    
		inStr = @cgi['inductance'].to_s
		@inductance = inStr.to_f / 1000000.0 

		@wireTurns = 0.0

		#入力値が不正な場合はエラー
		if(@inductance <= 0 || @wireWidth <= 0 ||@diameter <=0 ||@permeabilityRel <= 0)
			PrintHtml(false)
			exit
		end

		#コイルの半径
		@radius = @diameter / 2.0
		#透磁率(空気=約1.0)
		@permeability = PERMEABILITY * @permeabilityRel 

		#長岡係数 * 巻き数
		GetNT()
		
		#適切な組み合わせを検索
		SearchNagaoka()

		if(@nagaoka == -1)
			PrintHtml(false)
		else
			PrintHtml(true)
		end
	end
end
