--[[
ルビ拡張規格でタイムタグ出力
  ver.6 (2022.9.30)
    ・@Rubyで親文字やルビに半角カンマ「,」があると仕様で使う記号と被るので「&#44;」として出力するように変更。
  ver.5 (2020.11.25)
    ・ルビ適用時刻の重なりを許可して、ワイプの終わりまで適用終了時刻を引き延ばす新仕様に対応。
      (@RubyN群の中でヒットするものが複数出るため注意。ヒットした中で開始時刻が一番近い(時刻が一番遅い)ものが対象となる)
  ver.4 (2016.7.31)
    ・@タグの出力に対応。RhythmicaLyricsの「@タグ-オプション」ウィンドウから設定してください。
      （@RubyはRLtable.output.formatの[@その他]の位置に出力することにする）
  ver.3 (2016.5.29）
    ・重複判定の見直し。（例えば「今日(きょう)」と「日（ひ）」の２つのルビがあるとき重複処理されていなかった）
    ・その他細かい箇所の変更。
  ver.2 (2016.3.12）
    ・例えば「今(いま)」というルビがあったとき「今日(きょう)」のルビを考慮できていなくて重複していた問題に対処。できたハズ。。。
    ・歌詞の途中でタイムタグが逆転していても問題なく出力できるように修正。（ニコカラ複数行同時ワイプのため）
    ・配列処理の見直し。
  ver.1 (2016.2.27)
    ・完成
--]]
--ミリ秒をタイムタグに変換
function MirisecToTag( msec )
	local mm = math.floor(msec/60/1000)
	local ss = math.floor(msec%(60*1000)/1000)
	local xx = math.floor((msec%1000)/10)
	return string.format("[%02d:%02d:%02d]",mm,ss,xx)
end
--タイムタグをミリ秒に変換
function TagToMirisec( tag )
	if tag=="" or tag==nil then
		return 0
	end
	local msec = 0
	local mm
	local ss
	local xx
	for mm,ss,xx in string.gmatch(tag, "(%d%d):(%d%d):(%d%d)") do
		msec = mm*60*1000 + ss*1000 + xx*10
	end
	return msec
end
--次のタイムタグを取得(＋で連結されていない箇所のもの)
--  ルビ適用時刻の重なりを許可して、ワイプの終わりまで適用終了時刻を引き延ばす新仕様のため[ver.5〜]
--  [面倒臭いので下の処理の一部をそのまま流用]
function GetNextPlainTimeTag( RLtable, _gyo, __retsu )
	_retsu = __retsu + 1
	timetag = "[99:59:99]"
	for gyo=_gyo, RLtable.ymax do
		for retsu=_retsu, RLtable[gyo].xmax do
			flgRenketsu = 0 --フラグリセット
			--今回のルビに＋の連結支持があるか確認してフラグを立てる
			if RLtable[gyo][retsu].rubysmax >0 then
				if RLtable[gyo][retsu].rubys[RLtable[gyo][retsu].rubysmax] == "＋" then
					flgRenketsu=1 --フラグを立てる
				end
			end
			if flgRenketsu == 0 then
				--【タイムタグ/ミリ秒】
				if RLtable[gyo][retsu].timetag ~= "" then
					timetag = RLtable[gyo][retsu].timetag
					break
				end
			end
		end
		if timetag ~= "[99:59:99]" then
			break
		end
		_retsu = 1
	end
	return timetag
end

--RhythmicaLyrics拡張出力
function SaveAs( RLtable, initxt )

	--最初に拡張出力のバージョンを確認
	if RLtable.version < 2 then
		error("RhythmicaLyrics Ver.4.3 以上を使用してください。")
	end

	--まず全てのルビを走査してリストにしてしまう（＋があれば一つの塊にする）

	--配列宣言
	list={}
	--[[
		こんな感じのテーブルを作っていく
		list[1] = { kashi="詞", timetagMirisec=0, ruby="こ[00:00:10]と[00:00:20]ば", rubyStartTimetag="[00:00:00]", rubyEndTimetag="[99:59:99]", ikoKashi="詞の〜" }
			kashi             --歌詞
			timetagMirisec    --タイムタグをミリ秒に変換したもの(処理用。出力しない)
			ruby              --ルビと補助タイムタグを合わせたルビ拡張規格の形式->"る[00:00:10]び"（時間はタイムタグとの差分）
			rubyStartTimetag  --適用開始時刻
			rubyEndTimetag    --適用終了時刻
			ikoKashi          --重複確認のため、行末までの歌詞一文を格納する(処理用。出力しない)
			rubyWipeEndTimetag--ルビ適用時刻の重なりを許可して、ワイプの終わりまで適用終了時刻を引き延ばす新仕様のため(処理用。rubyEndTimetagと比べ時刻の遅い方を使用)[ver.5〜]
	--]]
	listCount = 0

	prevTimetagMirisec = 0 --一つ手前の有効なタイムタグ(timetagMirisec)を保持する
	flgRenketsu = 0 --連結フラグ初期化

	_logRL=""
	
	for gyo=1, RLtable.ymax do
		
		
		for retsu=1, RLtable[gyo].xmax do
			
			--前の文字で＋連結支持があった場合、前回のものに足す（リストのカウントアップはしない）
			if flgRenketsu~=1 then
				listCount = listCount+1 --リストカウントアップ
			end
			
			--リストに足し入れる
			if flgRenketsu~=1 then
				--【配列の初期化】
				list[listCount]={}
				--リストカウントアップされたとき（前回が＋でなかったとき）だけ入れる（または初期化する）ものがある
				--【タイムタグ/ミリ秒】
				if RLtable[gyo][retsu].timetag ~= "" then
					list[listCount].timetagMirisec = TagToMirisec(RLtable[gyo][retsu].timetag)
				else 
					list[listCount].timetagMirisec = prevTimetagMirisec
				end
				--【適用開始時刻】
				list[listCount].rubyStartTimetag = "[00:00:00]"
				--【適用終了時刻】
				list[listCount].rubyEndTimetag = "[99:59:99]"
				--【ワイプ終了時刻】
				list[listCount].rubyWipeEndTimetag = GetNextPlainTimeTag( RLtable, gyo, retsu )
			end
			--一つ手前の有効なタイムタグ(timetagMirisec)として保持する
			if RLtable[gyo][retsu].timetag ~= "" then
				prevTimetagMirisec = TagToMirisec(RLtable[gyo][retsu].timetag)
			end
			
			--【歌詞】
			if list[listCount].kashi == nil then list[listCount].kashi = "" end    --nilと文字列の加算が行われないように初期化
			list[listCount].kashi = list[listCount].kashi .. RLtable[gyo][retsu].word
			--【行末までの歌詞】
			if list[listCount].ikoKashi == nil then list[listCount].ikoKashi = "" end    --nilと文字列の加算が行われないように初期化
			for i=retsu, RLtable[gyo].xmax do
				list[listCount].ikoKashi = list[listCount].ikoKashi .. RLtable[gyo][i].word
			end
			
			--【ルビ】
			if list[listCount].ruby == nil then list[listCount].ruby = "" end    --nilと文字列の加算が行われないように初期化
			for i=1, RLtable[gyo][retsu].rubysmax do
				--もし連結フラグが立っていた場合、今回のtimetagはruby1文字目のsubtimetagとして扱われる必要がある
				if flgRenketsu==1 and RLtable[gyo][retsu].timetag~="" and i==1 then
					diffmsec = TagToMirisec(RLtable[gyo][retsu].timetag) - list[listCount].timetagMirisec
					list[listCount].ruby = list[listCount].ruby .. MirisecToTag(diffmsec)
				end
				--通常ruby1文字目はタイムタグは付かない
				if i>1 and (i-1)<=RLtable[gyo][retsu].subtimetagsmax then
					diffmsec = TagToMirisec(RLtable[gyo][retsu].subtimetags[i-1]) - list[listCount].timetagMirisec
					list[listCount].ruby = list[listCount].ruby .. MirisecToTag(diffmsec)
				end
				--ルビを足し入れるけど＋は入れないでおく（後でもう一度＋を確認してフラグを立てる）
				if RLtable[gyo][retsu].rubys[i]~="＋" then
					list[listCount].ruby = list[listCount].ruby .. RLtable[gyo][retsu].rubys[i]
				end
			end
			
			flgRenketsu = 0 --フラグリセット
			
			--今回のルビに＋の連結支持があるか確認してフラグを立てる
			if RLtable[gyo][retsu].rubysmax >0 then
				if RLtable[gyo][retsu].rubys[RLtable[gyo][retsu].rubysmax] == "＋" then
					flgRenketsu=1 --フラグを立てる
				end
			end
		end
	end


	--複数行同時ワイプ対策として、list[i].timetagMirisec 昇降順でソートする
	table.sort(list,
		function(a,b)
			return (a.timetagMirisec < b.timetagMirisec)
		end
	)
	--[[
	  リストの上から順に適用開始時刻と適用終了時刻をセットしていく。
	  1. i番目のkashiのとき、まず下方向(j)に走査。
	     "list[i].kashiがlist[j].kashiに含まれるとき"or"kashiが同じでもrubyが異なるとき" が出てくるまでループして、出たらlist[i].rubyEndTimetag=list[j].timetagMirisec。ループ終了。
	     "kashiが同じでrubyも同じとき"は無視する。また、ruby=""なら走査もしない。
	  2. 次にi番目のkashiを、上方向(h)に走査。
	     同じように"list[i].kashiがlist[h].kashiに含まれるとき"or"kashiが同じでもrubyが異なるとき" が出てくるまでループ。
	     ただし今回は、最初にtempRubyStartTimetag=list[i].timetagMirisecして、"kashiが同じでrubyも同じ時"が出たらtempRubyStartTimetag=list[h].timetagMirisecで更新。
	     ループ終了条件が出てきたらlist[i].rubyStartTimetag=tempRubyStartTimetag。
	     同じように"kashiが同じでrubyも同じとき"は無視する。また、ruby=""なら走査もしない。
	  
	  ＜イメージ＞
	    今日(きょう) −−−  
	    今  (いま)   ・↑↑  この区間の「今」は ruby も rubyStartTimetag も rubyEndTimetag も一緒になる。つまりは後で一つに纏められる。
	    今  (いま)   ↓・↑  
	    今  (いま)   ↓↓・  
	    今日(きょう) −−−  
	    今  (いま)   
	--]]
	for i=1, table.maxn(list) do
	_logRL=_logRL..string.format("i=%d",i).."\r\n"
		--ruby=""なら走査しない。
		if list[i].ruby~="" then
		
			--まず下方向に走査
			for j=i+1, table.maxn(list) do
				-- "list[i].kashiがlist[j].kashiに含まれるとき"
				if string.find(string.sub(list[j].ikoKashi,1,string.len(list[j].kashi)+string.len(list[i].kashi)-1), list[i].kashi,1,true) then
					--"kashiが同じでrubyも同じとき"
					if (list[i].kashi == list[j].kashi)and(list[i].ruby == list[j].ruby) then
						--無視する
					else
						--出たら
						list[i].rubyEndTimetag=MirisecToTag(list[j].timetagMirisec)
						--ループ終了
						break
					end
				end
			end
			
			--次に上方向に走査
			tempRubyStartTimetag=list[i].timetagMirisec  --最初に
			for h=i-1, 1, -1 do
				-- "list[i].kashiがlist[h].kashiに含まれるとき"
				if string.find(string.sub(list[h].ikoKashi,1,string.len(list[h].kashi)+string.len(list[i].kashi)-1), list[i].kashi,1,true) then
					--"kashiが同じでrubyも同じとき"
					if (list[i].kashi == list[h].kashi)and(list[i].ruby == list[h].ruby) then
						--出たら更新。
						tempRubyStartTimetag=list[h].timetagMirisec
						--で、無視する
					else
						--出たら
						list[i].rubyStartTimetag=MirisecToTag(tempRubyStartTimetag)
						--ループ終了
						break
					end
				end
				
			end
			
		end
	end
	
	--[[
	  リストの上から順に重複確認。i番目に注目したとき下方向に走査。（上方向はしない）
	  kashi, ruby, rubyStartTimetag, rubyEndTimetag が重複しているものを見つけたら、list[j].ruby="", list[j].rubyStartTimetag="[00:00:00]" して拡張ルビ出力から排除されるようにする。
	  見つけても、最後までループして確認する。
	  (ver.5〜)rubyWipeEndTimetag は大きい(遅い)方の時間を残す。
	--]]
	for i=1, table.maxn(list) do
		--ruby=""なら走査しない。
		if list[i].ruby~="" then
			--下方向に走査
			for j=i+1, table.maxn(list) do
				if list[i].kashi==list[j].kashi and list[i].ruby==list[j].ruby and list[i].rubyStartTimetag==list[j].rubyStartTimetag and list[i].rubyEndTimetag==list[j].rubyEndTimetag then
					list[j].ruby=""
					list[j].rubyStartTimetag="[00:00:00]"
					if TagToMirisec( list[i].rubyWipeEndTimetag ) < TagToMirisec( list[j].rubyWipeEndTimetag ) then
						list[i].rubyWipeEndTimetag = list[j].rubyWipeEndTimetag
					end
				end
			end
		end
	end
	
	
	--ルビ拡張規格として出力
	extRuby=""
	rubyCount=1
	for i=1, table.maxn(list) do
		if list[i].ruby=="" and list[i].rubyStartTimetag=="[00:00:00]" then
			--ルビに何もなくて、開始時間も0のものは出力しない
		else
			--拡張ルビを出力
			extRuby = extRuby .. string.format("@Ruby%d=%s,%s", rubyCount, string.gsub(list[i].kashi,",","&#44;"), string.gsub(list[i].ruby,",","&#44;") )
			
			--適用終了時刻は.rubyEndTimetagと.rubyWipeEndTimetagの大きい(遅い)方の時間を採用する。
			if TagToMirisec( list[i].rubyEndTimetag ) > TagToMirisec( list[i].rubyWipeEndTimetag ) then
				rubyEndTimetag_ = list[i].rubyEndTimetag
			else
				rubyEndTimetag_ = list[i].rubyWipeEndTimetag
			end
			if list[i].rubyStartTimetag=="[00:00:00]" and rubyEndTimetag_=="[99:59:99]" then
				--開始/終了時刻を省略
				
			elseif list[i].rubyStartTimetag~="[00:00:00]" and rubyEndTimetag_=="[99:59:99]" then
				--終了時刻のみ省略
				extRuby = extRuby .. "," .. list[i].rubyStartTimetag
				
			elseif list[i].rubyStartTimetag=="[00:00:00]" and rubyEndTimetag_~="[99:59:99]" then
				--開始時刻のみ省略
				extRuby = extRuby .. ",," .. rubyEndTimetag_
				
			else
				--開始/終了時刻とも省略しない
				extRuby = extRuby .. string.format(",%s,%s",list[i].rubyStartTimetag,rubyEndTimetag_)
				
			end
			
			extRuby = extRuby .. "\r\n"
			rubyCount = rubyCount+1
		end
	end
	
	
	--通常のタイムタグ付き歌詞を出力
	lyrics = ""
	for gyo=1, RLtable.ymax do
		for retsu=1, RLtable[gyo].xmax do
			--タイムタグ出力
			lyrics = lyrics .. RLtable[gyo][retsu].timetag
			--歌詞出力
			if RLtable[gyo][retsu].word == "\\n" then
				--改行
				lyrics = lyrics .. "\r\n"
				
			elseif RLtable[gyo][retsu].word == "nil" then
				--連続タイムタグ位置（何も書かない）
				
			else
				--通常の歌詞
				lyrics = lyrics .. RLtable[gyo][retsu].word
				
			end
		end
	end
	
	
	--------------------
	-- 出力整形
	--------------------
	OutputText=RLtable.output.format
	--[BODY]
	patt="%[BODY%]"
	OutputText = string.gsub(OutputText,patt,lyrics)
	--[@Title]
	patt="%[@Title%]"
	if RLtable.attag.titleFlg==0 or RLtable.attag.title=="" then
		if string.find(OutputText,"%[@Title%]\r\n")~=nil then patt="%[@Title%]\r\n" end
		OutputText = string.gsub(OutputText,patt,"")
	else
		OutputText = string.gsub(OutputText,patt,"@Title="..RLtable.attag.title)
	end
	--[@Artist]
	patt="%[@Artist%]"
	if RLtable.attag.artistFlg==0 or  RLtable.attag.artist=="" then
		if string.find(OutputText,"%[@Artist%]\r\n")~=nil then patt="%[@Artist%]\r\n" end
		OutputText = string.gsub(OutputText,patt,"")
	else
		OutputText = string.gsub(OutputText,patt,"@Artist="..RLtable.attag.artist)
	end
	--[@Album]
	patt="%[@Album%]"
	if RLtable.attag.albumFlg==0 or RLtable.attag.album=="" then
		if string.find(OutputText,"%[@Album%]\r\n")~=nil then patt="%[@Album%]\r\n" end
		OutputText = string.gsub(OutputText,patt,"")
	else
		OutputText = string.gsub(OutputText,patt,"@Album="..RLtable.attag.album)
	end
	--[@TaggingBy]
	patt="%[@TaggingBy%]"
	if RLtable.attag.taggingbyFlg==0 or RLtable.attag.taggingby=="" then
		if string.find(OutputText,"%[@TaggingBy%]\r\n")~=nil then patt="%[@TaggingBy%]\r\n" end
		OutputText = string.gsub(OutputText,patt,"")
	else
		OutputText = string.gsub(OutputText,patt,"@TaggingBy="..RLtable.attag.taggingby)
	end
	--[@SilencemSec]
	patt="%[@SilencemSec%]"
	if RLtable.attag.silencemsecFlg==0 or RLtable.attag.silencemsec==0 then
		if string.find(OutputText,"%[@SilencemSec%]\r\n")~=nil then patt="%[@SilencemSec%]\r\n" end
		OutputText = string.gsub(OutputText,patt,"")
	else
		OutputText = string.gsub(OutputText,patt,"@SilencemSec="..RLtable.attag.silencemsec)
	end
	--[@other] //@Rubyを追加
	patt="%[@その他%]"
	if RLtable.attag.other ~= "" then extRuby = "\r\n" .. extRuby end
	if (RLtable.attag.other .. extRuby)=="" then
		if string.find(OutputText,"%[@その他%]\r\n")~=nil then patt="%[@その他%]\r\n" end
		OutputText = string.gsub(OutputText,patt,"")
	else
		OutputText = string.gsub(OutputText,patt,(RLtable.attag.other .. extRuby))
	end
	--[@TimeRatio]は消してしまう
	patt="%[@TimeRatio%]"
	if string.find(OutputText,"%[@TimeRatio%]\r\n")~=nil then patt="%[@TimeRatio%]\r\n" end
	OutputText = string.gsub(OutputText,patt,"")
	
	
	--出力したデータをRhythmicaLyricsへ返す
	return OutputText
end