/*
 ストップウオッチ その4
Javascriptに移植してみるですよ。 2004/03/15 kiyo/Nekomataya

2004/03/20 ちょっと修正
ラップ表示エレメントとMaxLapの記述が違っていたら
MaxLapを減らしてエラーがでないようにした。
ラップ表示の初期値をヌルから0に変更

2004/04/13 ほつれ直し
いろいろ不具合修正。ラップ表示は正常になったかな？

も一つおまけにMacOSX-Tigerダッシュボード対応画像付き版	2005/09/19

このプログラムの著作権は「ねこまたや」にあります。

あなたは、このプログラムのこの著作権表示を改変しないかぎり
自由にプログラムの使用・複製・再配布などを行うことができます。

あなたは、このプログラムを自己の目的にしたがって改造することができます。
その場合、このプログラムを改造したものであることを明記して、この著作権表示を
添付するように努めてください。

このプログラムを使うも使わないもあなたの自由なのです。

ただし、作者はこのプログラムを使用したことによって起きたいかなる
不利益に対しても責任を負いません。
あなたは、あなたの判断と責任においてこのプログラムを使用するのです。

なんか、困ったことがあったら以下で連絡してもらえると何とかなるかもしれません。
http://homepage2.nifty.com/Nekomata/
mailto:nekomata_ya@mac.com

そんな感じです。
*/

//	変数初期化
var VER="Type04";
//	画面の設定 は、javascriptに移植した時点で、呼び出す側のhtml自身のスタイルシートや
//	デザインにゆだねることにしたので、ここではなし。
//	**ダッシュボード対応のため以下の変数を設定のこと。
	var LapColor="#777777";
	var LapColorStrong="#444444";

//	初期状態の設定
// 初期状態は、呼び出し側に記述された値で上書きするのでこちらを特に変更する必要はなさそう。
//	時計の設定
var useHands=true;//針式？
var useRi=true;//テキスト？
var ccrate = 1000 ;//最少計測単位(javascriptではミリ秒固定)
var MODE = "clock" ;//表示の初期モード(時計)
var ClockOption = 12 ;//時計の初期モード (12時制)
var STATUS = "stop" ;
//	計測モード	ここの並びでループする　RT 24FPS 30NDF 30DF 25FPS
RATEs = ["RT","24FPS","30NDF","30DF","25FPS"];
var RATE = "24FPS" ;
var frate = 24. ;
//	マウスクリックでアクションするかどうかのフラグ
var m_action= true ; 
//	ログ配列を初期化
Log = new Array() ;
function nas_Push_Log(str) {Log = Log.concat([str])}
//	ログ 初期化してみる
nas_Push_Log( "Program Started " + VER);
nas_Push_Log( Date() );
nas_Push_Log( "     FrameRate" + frate + "(" + RATE + ")");
nas_Push_Log( "     Start Mode      [" + MODE + "]" );
//ラップの最大保持数をここに記入
MaxLap = 6;
//	ラップ用のメモリを初期化

function nas_Clear_LAP() {
var checkMX=MaxLap;
	LAP = new Array(MaxLap);
	COL = new Array(MaxLap)
	LapName = new Array(MaxLap);
		for(i = 0; i < MaxLap; i++){
LapName[i] = "lapView" + i;
LAP[i] = nas_FR2TC(0)[1] ;
COL[i] = LapColor;
// ラップ表示欄は、きちんとラップメモリの数だけ作ってね。
// でないとラップを減らしちゃうよ。
try {
	document.getElementById(LapName[ i ]).innerHTML = LAP[i];
	document.getElementById(LapName[ i ]).style.color = COL[i];
	var VoiD = document.getElementById(LapName[i]).innerHTML;
} catch(eRR) {
	checkMX= i + 1 ;	
	nas_Push_Log("\tcheck " + LapName[i] + eRR);
	nas_Push_Log(VoiD);
}
			} 
	MaxLap = checkMX;
	nas_Push_Log("\tLap memory clear");
 }
//	nas_Clear_LAP(MaxLap);
//	時間関連オブジェクトの初期化
ClockClicks = new Date();

var Start = 0;
var Stop = 0;

var nas_display = "";
//ランニングインジケータ設定
Ri = new Array() ;
var running = "";
function initRi(_base){
//var _base = '|::::::::::::::::::::::::|';
//var _base = '|________________________|';
Ri.length=(_base.length-1);
for (n = 0; n < (_base.length-1); n++) {Ri[n] = _base.substring(0,n + 1) + "|" + _base.substring(n + 1,(_base.length+1))}
running = Ri[0];
}

//initRi('|::::::::::::::::::::::::|');
// 時計の針関連変数初期化
var centerOffset=[112,112];
var hands=new Array(4);
var handsRads=[-54,-48,-42,44];
var ChipWidth=[4,8,12,8];
var handClick=0;

function initHands(){
	for (i=0;i<hands.length;i++){
		hands[i]=new Object();
		hands[i].rad=handsRads[i];
		hands[i].Chiprad=[ChipWidth[i]/2,ChipWidth[i]/2];
	}
}
//
//	clock clicks の値からモード別に表示値を生成
function nas_cc2dp(cc) {
	if (MODE == "watch") {
		frms = nas_cc2FR( cc - Start );
		TC = nas_FR2TC( frms );
		f = TC[0][3];
	return TC[1] ;
	} else  {
		xNow = new Date();
		h = xNow.getHours();
		m = xNow.getMinutes();
		s = xNow.getSeconds();
		switch (ClockOption) {
case "12":
	if(h <=11) {tf="AM"} else {h = h -12; tf="PM"};
clockdisplay =  nas_Zfill(h,2)+ ":" + nas_Zfill(m,2) + ":" + nas_Zfill(s,2) + " " + tf;
	break;
default:
clockdisplay = ".  " + nas_Zfill(h,2)+ ":" + nas_Zfill(m,2) + ":" + nas_Zfill(s,2) + "  ." 
		}
return clockdisplay
	}
}
//	end proc
//	TC値からフレーム値を算出
function nas_TC2FR(TC) {
//TCのフォーマットは [h,m,s,f] 配列にする
	h = TC[0]; m = TC[1]; s = TC[2]; f = TC[3];
switch(RATE) {
case "RT":
	FR = h * 360000 + m * 6000 + s * 100 + f ; break;
case "24FPS":
	FR = h * 86400 + m * 1440 + s * 24 + f ; break;
case "30NDF":
	FR = h * 108000 + m * 1800 + s * 30 + f ; break;
case "30DF":
	FR = h * 107892 + (m / 10) * 17982  ;
	if((m % 10) != 0) {FR = FR + s * 30 + f} else {
		if(s) {
FR = FR + (m % 10) * 1800 - ((m % 10) - 1) * 2 + s * 28 + (s - 1) * 2 + f ;
		} else {
if(f <= 1) {f = f + 2 }
FR = FR + (m % 10) * 1800 - ((m % 10) - 1) * 2 + f - 2;
		}
	}
	break;
default :
	FR = h * RATE * 3600 + m * RATE * 60 + s * RATE + f
}
return FR }
//	end proc
//	FR値からTC値を算出
function nas_FR2TC(FR) {
	switch (RATE) {
case "RT":
	h = Math.floor(FR / 360000) % 100;
	m = Math.floor(FR / 6000) % 60;
	s = Math.floor(FR / 100) % 60;
	f = Math.floor(FR) % 100;
TCs = nas_Zfill(h,2)+":"+nas_Zfill(m,2)+":"+nas_Zfill(s,2)+"."+nas_Zfill(f,2);
	break;
case "24FPS":
	h = Math.floor(FR / 86400) % 100;
	m = Math.floor(FR / 1440) % 60;
	s = Math.floor(FR / 24) % 60;
	f = Math.floor(FR) % 24;
TCs = nas_Zfill(h,2)+":"+nas_Zfill(m,2)+":"+nas_Zfill(s,2)+"+"+nas_Zfill(f,2);
	break;
case "30NDF":
	h =Math.floor(FR / 108000) % 100;
	m =Math.floor(FR / 1800) % 60;
	s =Math.floor(FR / 30) % 60;
	f =Math.floor(FR) % 30;
TCs = nas_Zfill(h,2)+":"+nas_Zfill(m,2)+":"+nas_Zfill(s,2)+":"+nas_Zfill(f,2);
	break;
case "30DF":
	h =Math.floor((FR / 107892) % 100);
	if(FR % 17982 < 1800) {
	m =Math.floor(((FR / 17982) % 6) * 10  + ((FR % 17982) / 1800))
	} else {
	m =Math.floor(((FR / 17982) % 6) * 10  + (((FR % 17982 ) - 2) / 1798))
	}
	s = Math.floor((((m % 10) * 2 + (FR / 17982) * 18 + FR) / 30) % 60);
	if ((m % 10) != 0) {
	f = Math.floor(((m % 10) * 2 + (FR / 17982 ) * 18 + FR) % 30)
	} else {
	if (s != 0) {
	f = Math.floor((((FR / 17982 ) * 18 + FR) % 30) + 2)
	} else {
	f = Math.floor(((m % 10) * 2 + (FR / 17982 ) * 18 + FR) % 30)
	}
	}
TCs = nas_Zfill(h,2)+":"+nas_Zfill(m,2)+":"+nas_Zfill(s,2)+";"+nas_Zfill(f,2);
	break;
default :
	h = Math.floor(FR / (frate * 3600)) % 100;
	m = Math.floor(FR / (frate * 60)) % 60;
	s = Math.floor(FR / frate) % 60;
	f = Math.floor(FR) % Math.floor(frate);
TCs = nas_Zfill(h,2)+":"+nas_Zfill(m,2)+":"+nas_Zfill(s,2)+"-"+nas_Zfill(f,2)
}
TC = [h,m,s,f];
	return [TC,TCs]
}
//	end proc

//	cc値からFR値
function nas_cc2FR(cc) {
//global ccrate frate
	FR = Math.floor((frate * cc) / ccrate)
	return FR
}
//	end proc
//	FR値からcc値
function nas_FR2cc(FR) {return Math.floor((FR / frate) * ccrate)}
//	end proc
//	ゼロ埋め
function nas_Zfill(n,s) {if(n < Math.pow(10,(s - 1))) {
	rt = Math.pow(10,s) + n + "";
//document.getElementById("status").value = rt;
return rt.substr(1,rt.length-1)
} else {
return "" + n}}
//	終了
//	tclsh 互換リスト操作サブプロシージャ
//	lsearch(配列,検索値)
function nas_Alsearch(arr,ser) {for(n=0; n<arr.length; n++){if( arr[n] == ser ){ return n; break;}}}
//	フレームレート変更
function chgfps(pint){nas_ChangeRATE(pint)}
function nas_ChangeRATE(newrate) {
	ClockClicks = new Date();
	MODE = "watch";
//キャンセル用に変更前の値を退避
	cancel_Action = "ChangeRATE";oldrate = RATE;

switch(newrate) {
case "next":
newrate = RATEs[ nas_Alsearch(["25FPS","RT","24FPS","30NDF","30DF"],pastrate) ];break;
case "24FPS":
case "25FPS":
case "RT":
case "30NDF":
case "30DF":	newrate=newrate;break;
default:
A = isNaN(newrate);
if(A == true) {newrate = "RT"} else {
if(newrate <=0) {newrate = "RT"} else {if(newrate >= 101) {newrate = "RT"} else {newrate = newrate}}}
}
	switch(newrate) {
case "RT":	frate = 100.	; RATE = newrate; pastrate = RATE; break;
case "24FPS":	frate = 24.	; RATE = newrate; pastrate = RATE; break;
case "30NDF":	frate = 30.	; RATE = newrate; pastrate = RATE; break;
case "30DF":	frate = 29.97	; RATE = newrate; pastrate = RATE; break;
case "25FPS":	frate = 25.	; RATE = newrate; pastrate = RATE; break;
default:	frate = newrate ; RATE = newrate + "fps";
	}
	switch(STATUS) {
case "stop":
 document.getElementById("nas_display").value = nas_FR2TC(nas_cc2FR(Stop - Start))[1];
 break;
case "run\-lap": break;
case "run":
 document.getElementById("nas_display").value = nas_cc2dp(ClockClicks.getTime()) ;
 break;
default :
	}
//alert(RATE+" : "+frate)
	document.getElementById("nas_RATE").innerHTML = RATE.toString();
	nas_Push_Log("Change RATE\t"+ newrate )
	nas_Push_Log("Change frate\t"+ frate )
}
//	end proc

function nas_ChangeMODE() {
	switch(MODE) {
case "watch":   MODE = "clock"; nas_Push_Log("Change Mode Clock");
		break;
case "clock":   MODE = "watch"; nas_Push_Log("Change Mode Stop-Watch"); break;
	}
document.getElementById("nas_display").blur();
}
//	end proc
//表示用インターバルプロシージャ
function nas_update_View() {
	ClockClicks = new Date();
frms = Math.floor((ClockClicks.getTime() - Start) / (ccrate / frate));
	TC = nas_FR2TC(frms);
	f = TC[0][3];
		switch(MODE) {
case "clock": nas_display = nas_cc2dp(0);
	if(nas_display != document.getElementById("nas_display").value) {
	document.getElementById("nas_display").value = nas_display}
	break;
case "watch":
	switch(STATUS) {
case "stop":
	nas_display = nas_FR2TC(nas_cc2FR(Stop - Start))[1];
	if(nas_display != document.getElementById("nas_display").value) {
document.getElementById("nas_display").value = nas_display;
if(useHands) handRoll(nas_cc2FR(Stop - Start));
	}
	break;
case "run":
if(TC[1] != document.getElementById("nas_display").value ) {
	document.getElementById("nas_display").value =TC[1];
//	handRoll(frms);
}
	 break;

default:
	}
		}

	switch(STATUS) {
case "run\-lap":	;
case "run":
if(useRi){
running = Ri[Math.floor(Ri.length * (f / frate))];
if(running != document.getElementById("nas_Ri").value) {document.getElementById("nas_Ri").value= running }
}
if(useHands && handClick != frms){handRoll(frms);handClick=frms;}

break;
default:
	}

}
//	end proc
//針の回転処理
function handRoll(frames)
{
	roundFrames=frate*6;//6秒固定
	BASEx=-Math.sin(Math.PI*2*(frames%roundFrames)/roundFrames);
	BASEy=Math.cos(Math.PI*2*(frames%roundFrames)/roundFrames);

	for (i=0;i<hands.length;i++)
	{
hands[i].position=sub(add(centerOffset,[Math.round(BASEx*hands[i].rad),Math.round(BASEy*hands[i].rad)]),hands[i].Chiprad);
document.getElementById("hands"+i).style.top=hands[i].position[1];
document.getElementById("hands"+i).style.left=hands[i].position[0];
	}
}
//end proc

function nas_push_LAP(cc) {
//	TCの場合 
	for(n = MaxLap - 1 ;n > 0 ;n-- ) {
		LAP[n] = LAP[n - 1];COL[n]=COL[n - 1];}
	LAP[0] = nas_FR2TC(nas_cc2FR(cc - Start))[1];
	COL[0] = LapColorStrong;
	document.getElementById("nas_display").value = LAP[0];
	for(n = 0 ; n < MaxLap ;n++) {
document.getElementById("lapView"+ n).innerHTML=LAP[n];
document.getElementById("lapView"+ n).style.color=COL[n];
}
//	LOG
	switch(STATUS) {
case "stop":    PreFix ="Stop"; break;
case "run":     ;
case "run\-lap":	PreFix ="Lap"; break;
default :       PreFix =""
	}
	nas_Push_Log(PreFix + "\t" + LAP[0])
}
//	end proc
//	スタートとストップ引数なし
function nas_Start_Stop() {
//呼出元にしたがって 基準時刻の選択 ダメならとりあえず現在時刻をとる
switch (nas_capt) {
case "Key"	:now = ct_K; break;
case "Object"	:now = ct_O; break;
case "Mouse"	:now = ct_M; break;
default:
ClockClicks = new Date(); now =ClockClicks.getTime()
}

	switch(STATUS) {
case "stop":    Start = now - (Stop - Start);
		if(Stop != 0) {nas_push_LAP(now)} else {nas_Push_Log("Start")}
		STATUS ="run"; break;
case "run":     nas_cc2dp(now);
		Stop = now;
		STATUS = "stop"; break;
case "run\-lap":STATUS = "run"; break;
	}
	switch(MODE) {
case "clock":   MODE = "watch" ;nas_Push_Log("Cheange Mode Stop-Watch"); break;
default : 
	}
document.getElementById("status").innerHTML = STATUS
}
//	end proc
function nas_Lap_Reset() {

//呼出元にしたがって 基準時刻の選択 ダメならとりあえず現在時刻をとる
switch (nas_capt) {
case "Key"	:now = ct_K; break;
case "Object"	:now = ct_O; break;
case "Mouse"	:now = ct_M; break;
default:
ClockClicks = new Date(); now =ClockClicks.getTime()
}
	switch(STATUS) {
case "stop":    nas_cc2dp(Start);
		if(Stop != 0) {nas_push_LAP(Stop)}
		Start = 0 ; Stop = 0 ; nas_Push_Log("\treset\n");
if(useRi){
		running = Ri[0];
		document.getElementById("nas_Ri").value = running;
}
		document.getElementById("status").innerHTML = "ready";

		if(useHands) handRoll(0);
		break;
case "run":     nas_push_LAP(now);
		STATUS = "run-lap";
		document.getElementById("status").innerHTML = STATUS;
		break;
case "run-lap": nas_cc2dp(now);
		nas_push_LAP(now);
//		if(useHands) handRoll(frms);
	}
}
//	end proc
function nas_Input(key) {
ClockClicks = new Date();ct_K = ClockClicks.getTime();nas_capt = "Key";
//alert(key);
	switch(key) {
case 13 :       nas_Lap_Reset(); break;//enter
case 27 :       nas_Clear_LAP(); break;//esc
case 32 :       nas_Start_Stop(); break;//space
case 49 :       nas_ChangeRATE("RT"); break;//1
case 50 :       nas_ChangeRATE("24FPS"); break;//2
case 51 :       nas_ChangeRATE("30NDF"); break;//3
case 52 :       nas_ChangeRATE("30DF"); break;//4
case 53 :       nas_ChangeRATE("25FPS"); break;//5
case 65 :       about_nas(); break;//a
case 76 :       nas_write_Log(); break;//l
case 84 :       nas_ChangeMODE(); break;//T
default :       return false
	}
//
return false;
}
//	end proc
function nas_Mouse(Bt,Ob) {
ClockClicks = new Date();ct_M = ClockClicks.getTime();nas_capt = "Mouse"
//IEのとき event.button event.srcElement と入れ換える
if( navigator.appName == "Microsoft Internet Explorer" ) { Ob = event.srcElement ;Bt = event.button ;
// for IE
switch(Ob.type) {
case "text":	;
case "":	;
case "button":	m_action = false ;break ;
default:	
if (Ob.id=="baseBody"){m_action = true;}else{m_action = false;};
}
 } else {
// for NN
if( Ob == "[object HTMLFormElement]" || Ob.id == "baseBody" ) {m_action = true} else {m_action = false}
}

if( m_action) {
	switch(Bt) {
case 4: ;
case 2: ;
case 3:	nas_Lap_Reset(); break;
default:nas_Start_Stop()
	}
} else {
if (true){
	switch(Ob.id){
case "start":nas_Start_Stop();break;
case "lap":nas_Lap_Reset();break;
	}
}
return false }
}
//	end proc
/*	汎用のアクションキャプチャ
 呼び出しタイムラグを最少にする必要のある場合は、以下の書式でこの関数を呼び出します。
	nas_Capt("機能名称") 
 必要な引数は、受け渡し用の変数を別に立てて あらかじめ値を入力する必要あり。
 (ただし今のところべつになし)
 ここにある時間関連コマンド以外の関数は、直接呼び出す。
*/
function nas_Capt(Action_Name){
ClockClicks = new Date();ct_O = ClockClicks.getTime();nas_capt = "Object";
CaptureAction = Action_Name ;

	switch(Action_Name) {
case "Lap_Reset"	: nas_Lap_Reset(); break;
case "Clear_LAP"	: nas_Clear_LAP(); break;
case "Start_Stop"	: nas_Start_Stop(); break;
default	: return false
	} 
}
// end function

//ログの表示　別ウィンドウを開いて書き出す。
function nas_write_Log(){
	LW1=window.open("","LW","width=320");
	LW1.document.open();
	LW1.document.write("<HTML><HEAD><TITLE>StopWatch-Log</TITLE></HEAD><BODY>");
	LW1.document.write("<PRE>");
	for(l=0; l<Log.length;l ++){LW1.document.write(Log[l]+"\n")}
	LW1.document.write("</PRE>");
	LW1.document.write("</BODY></HTML>");
//LW1.document.write();
//LW1.document.write();
LW1.document.close();
}

//	end proc
//############### ABOUT Display
function about_nas(){
alert("Nekomataya Animation System \(Unsupported\) \nStopWatch "+ VER + "\n2004/03/15\n http://homepage2.nifty.com/Nekomata/")
}
/*
ストップウオッチフォームが読み込まれた直後に呼び出されて、
ストップウオッチを最終的に開始させる関数。
フォーム上のカスタム変数の読み込み(オーバーライド)および
表示インターバルの開始
明示的な終了手続きは特になし。
*/
function nas_Action_Startup() {
//IEの場合、画像入れ替え
	if( navigator.appName == "Microsoft Internet Explorer" )
	{
		var ImgNames=["start","lap","lens","cls"];
	for(i=0;i<ImgNames.length;i++){
		document.getElementById(ImgNames[i]).src=
		"images/"+ImgNames[i]+".gif";
	}
		document.getElementById("hands0").src=
		"images/hands4p.gif";
		document.getElementById("hands1").src=
		"images/hands8p.gif";
		document.getElementById("hands2").src=
		"images/hands12p.gif";
		document.getElementById("hands3").src=
		"images/hands8p.gif";
}
		document.getElementById("status").innerHTML = "startup";

	if( navigator.appName == "Netscape" ) {document.captureEvents( Event.MOUSEDOUN )}
//フォーム上のカスタム変数を読み取る
	useHands=eval(document.getElementById("useHands").value);
		if (useHands){initHands();};

		pastrate = RATE; 	//新レートを設定する前に元のレートを退避
		nas_ChangeRATE( document.getElementById("frameRATE").value);
	MaxLap = document.getElementById("MaxLap").value;
	ClockOption = document.getElementById("ClockOption").value;
	MODE=document.getElementById("MODE").value;
	nas_ChangeMODE();

	useRi=eval(document.getElementById("useRi").value);
if(useRi){
	initRi(document.getElementById("nas_Ri_base").value);
	document.getElementById("nas_Ri").value = running;
}
//	 = document.getElementById("").value;
//	 = document.getElementById("").value;
	if(useHands) handRoll(0);//計測針を初期位置に
//	再初期化終了・動作開始
	nas_cc2dp();
	nas_Clear_LAP();
	document.getElementById("status").innerHTML = "ready";
	m_action = true;
	CaptureAction = "";
//	表示インターバル開始
		Action = setInterval("nas_update_View()",10);
document.getElementById("nas_display").blur();

//	お後がよろしいようで
}
// プログラムおしまい　とっぴんぱらりのぷぅ
/*	ストップウオッチ関数リファレンス

*/
