e-対戦 [e-typing]

e-typingに対戦機能を追加したい

Per 05-08-2023. Zie de nieuwste versie.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         e-対戦 [e-typing]
// @namespace    http://tampermonkey.net/
// @version      1.9
// @description  e-typingに対戦機能を追加したい
// @author       Toshi
// @match        https://www.e-typing.ne.jp/app/jsa_std*
// @exclude      https://www.e-typing.ne.jp/app/ad*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=e-typing.ne.jp
// @license MIT
// @require      https://www.gstatic.com/firebasejs/7.2.1/firebase-app.js
// @require      https://www.gstatic.com/firebasejs/7.2.1/firebase-auth.js
// @require      https://www.gstatic.com/firebasejs/7.2.1/firebase-database.js
// @grant unsafeWindow


// ==/UserScript==


const firebaseConfig = {
	//テスト用データベース
/* 	apiKey: "AIzaSyARzYljiRuZCoABA32_wnuyMkjScpcZUN8",
	databaseURL: "https://e-typing-battle-fb330-default-rtdb.firebaseio.com/" */

	//本番用データベース
	apiKey: "AIzaSyDsHiPII5dgN_AEGwOtMehyveucoF4Twvs",
	databaseURL: "https://e-typing-battle-default-rtdb.firebaseio.com"
};


class MyResult{

	constructor(){
		this.interval
		this.battlePlayerResultData = {}

		this.etypingPlus = ['score','level','time','typeCount','missCount','wpm','correct','latency','rkpm']
		this.normal = ['score','level','time','typeCount','missCount','wpm','correct','weakKey']
	}



	sendResult(){
		playerStateChange.update('result')

		const RESULT_DATA = document.getElementsByClassName("result_data")[0].firstElementChild.children
		const RESULT_ITEM = RESULT_DATA.length == 9 ? this.etypingPlus : this.normal
		let updates = {}
		let sendData = {}


		for(let i=0; i<RESULT_ITEM.length; i++){
			sendData[RESULT_ITEM[i]] = RESULT_DATA[i].lastElementChild.textContent
		}




		updates['/users/' + myID + '/result/'] = sendData
		firebase.database().ref().update(updates)


		this.createBattlePlayerResultArea()
		//相手のリザルトを取得していた場合、相手のリザルトを表示
		const BATTLE_PLAYPER_RESULT = Object.keys(this.battlePlayerResultData)

		if(BATTLE_PLAYPER_RESULT.length){
				const RESULT_DATA = document.getElementsByClassName("result_data")[1].firstElementChild.children
				const RESULT_ITEM = RESULT_DATA.length == 9 ? myResult.etypingPlus : myResult.normal

				for(let i=0;i<BATTLE_PLAYPER_RESULT.length;i++){
					const INDEX = RESULT_ITEM.indexOf(BATTLE_PLAYPER_RESULT[i])

					if(INDEX >= 0){
						RESULT_DATA[INDEX].lastElementChild.textContent = this.battlePlayerResultData[BATTLE_PLAYPER_RESULT[i]]
					}
				}

			document.getElementById("prev").firstElementChild.textContent = battleUserData.data.name

		}

	}


	createBattlePlayerResultArea(){
		const RESULT_DATA = document.getElementsByClassName("result_data")[1].firstElementChild.children
		document.getElementById("prev").firstElementChild.textContent = '待機中'

		for(let i=0; i<RESULT_DATA.length; i++){
			RESULT_DATA[i].lastElementChild.textContent = ''
			RESULT_DATA[i].lastElementChild.style.color = '#23c21f'
		}


	}


	onBattleResultDisplay(snapshot){
		const uid = snapshot.ref_.path.pieces_[1];
		const Info = snapshot.ref_.path.pieces_[3]
		const SnapShotValue = snapshot.val()


		myResult.battlePlayerResultData[Info] = SnapShotValue

		if(playerStateChange.prevState == 'result'){
		const RESULT_DATA = document.getElementsByClassName("result_data")[1].firstElementChild.children
		const RESULT_ITEM = RESULT_DATA.length == 9 ? myResult.etypingPlus : myResult.normal

			const INDEX = RESULT_ITEM.indexOf(Info)

			if(INDEX >= 0){
				RESULT_DATA[INDEX].lastElementChild.textContent = SnapShotValue
			}
			document.getElementById("prev").firstElementChild.textContent = battleUserData.data.name
		}
		firebase.database().ref('usersState/').off('child_changed');
	}

	reBuildResultAria(){

		//e-typing plus用
		document.getElementById("RTCGamePlayScene").style.marginTop = ''
		document.getElementById("RTCGamePlayScene").style.display = 'none'
		document.getElementById("comment").style.display = 'none'
		document.getElementById("result").querySelector('article').style.height = '441px'
		document.getElementById("current").style.height = '414px'
		document.getElementById("exampleList").style.height = '345px'
		document.getElementsByClassName("result_data")[0].style.height = '365px'
		document.getElementById("prev").style.height = '414px'
		document.getElementsByClassName("result_data")[1].style.height = '365px'

		for(let i=0;i<2;i++){
			document.getElementsByClassName("result_data")[i].firstElementChild.insertAdjacentHTML('beforeend',
`<li class='battle-result'><div class="data"></div></li><li class='input-mode'><div class="data"></div></li>`)
		}

	}


	checkResultDisplay(){
		myResult.sendResult()
		myResult.reBuildResultAria()
		clearInterval(myResult.interval)
	}



}
let myResult



class DeleteUser {

	constructor(){

	}

	userTimeoutCheck(DeleteTimeStamp){

		firebase.database().ref('users').once('value').then(users => {

			const PLAYERS_KEY = Object.keys(users.val())
			let updates = {}

			for(let i=0;i<PLAYERS_KEY.length;i++){

				const checkID = PLAYERS_KEY[i]
				const TIMEOUT_TIME = DeleteTimeStamp - users.val()[checkID].deleteTimeStamp

				if(TIMEOUT_TIME >= 100000){
					//50秒TimeStampの更新が無ければユーザーを削除する
					updates['/users/' + checkID] = null;
					updates['/usersState/' + checkID] = null;

				}else if(TIMEOUT_TIME >= 20000){
					//20秒TimeStampの更新が無ければタイムアウト状態にする
					updates['/usersState/' + checkID + '/state'] = "timeOut"
				}

			}

			firebase.database().ref().update(updates);
		});
	}

}
let deleteUser = new DeleteUser()


class PlayerStateChange {

	constructor(){
		this.prevState = 'idle'
	}


	update(state){

		if(this.prevState == 'oldVersion'){return;}

		let updates = {}

		updates['/usersState/' + myID + '/state'] = this.prevState = state;


		switch(state){
			case "oldVersion":

				break;

			case "move":

				break;

			case "idle":

				break;

			case "preStart":
				firebase.database().ref('usersState/').off('child_changed');
				firebase.database().ref('usersState/').on('child_changed', battleUserData.onChangeUserState);
				break;

			case "matching":
				battleArea.displayReadyButton()
				break;


			case "ready":
				updates['/users/' + myID + '/status/' + '/lineInput'] = '準備完了';
				break;
			case "play":

				break;

			case "soloPlay":

				break;

			case "result":

				break;
		}

		firebase.database().ref().update(updates)

	}

}
let playerStateChange



class MyData {

	constructor(){
		this.locationDateTimeStamp
		this.localDateTimeStamp
		this.myName
		this.UserCheckTimeCount = 0
		this.lineInput = ''
		this.clearCount = 0

		myResult = new MyResult()
		deleteUser = new DeleteUser()
		playerStateChange = new PlayerStateChange()

		this.update()
		this.loggedIn()
		this.getLocationDate().then( () => myData.startingClockTime())
	}



	update(){
		var updates = {};
		this.myName = localStorage.getItem("battleName")

		//ユーザーネーム更新
		updates['/usersState/' + myID + '/name'] = this.myName;
		updates['/users/' + myID + '/version'] = GM_info.script.version
		updates['/users/' + myID + '/status/' + '/lineInput'] = '';
		updates['/users/' + myID + '/status/' + '/clearCount'] = 0;

		firebase.database().ref().update(updates)
		playerStateChange.update(playerStateChange.prevState)
	}

	loggedIn(){

		document.getElementById("start_btn").style.display = 'block'
		document.getElementsByClassName("loading")[0].style.display = 'none'

		window.addEventListener('beforeunload', e => playerStateChange.update('move'));

		if(window.parent.document.getElementsByClassName("pp_close").length){
			window.parent.document.getElementsByClassName("pp_close")[0].addEventListener('click',e => playerStateChange.update('move') ,false);
		}

	}

	updateTimeStamp(){
		const newDate = new Date().getTime()
		var updates = {};
		const deleteTimeStamp = myData.locationDateTimeStamp + (newDate - myData.localDateTimeStamp)
		updates['/users/' + myID + '/deleteTimeStamp'] = deleteTimeStamp


		//30秒に一度、ルーム内のユーザーの存在をチェックする
		if(newDate - myData.UserCheckTimeCount >= 30000){
			myData.UserCheckTimeCount = newDate
			deleteUser.userTimeoutCheck(deleteTimeStamp)
		}

		firebase.database().ref().update(updates);
	}


	startingClockTime(){
		//ユーザー確認用タイムスタンプを更新
		this.updateTimeStamp()
		setInterval(this.updateTimeStamp,5000)
	}

	async getLocationDate(){
		const resp = await fetch(window.location.href)

		//サーバー時刻のタイムスタンプ
		this.locationDateTimeStamp = await new Date(resp.headers.get("date")).getTime()
		//ローカル時刻タイムスタンプ
		this.localDateTimeStamp = new Date().getTime()

		return true
	}

}
let myData






let myID
class LoginFirebase {

	constructor(){
		firebase.initializeApp(firebaseConfig)
		this.roginAnon()
	}


	roginAnon(){

		firebase.auth().signInAnonymously().catch(function(error) {
			// Handle Errors here.
			var errorCode = error.code;
			var errorMessage = error.message;

			console.log(errorCode);
			console.log( errorMessage);
			alert("RealTimeCombatting:Firebaseのサインインに失敗しました。");
			return false;
			// ...
		});

		firebase.auth().onAuthStateChanged(function(user) {

			if (user) {
				// User is signed in.
				myID = "U"+user.uid
				console.log('!!!')

				var path = firebase.database().ref('users/' + myID);

				path.transaction(function(currentData) {
					//ユーザー情報を更新
					myData = new MyData()
				}).then( () => loginFirebase.versionCheck());
			}
		});

	}


	versionCheck(){
		firebase.database().ref('newVersion').once('value').then(version => {
			const newVersion = version.val()

			if(+GM_info.script.version < +newVersion){

				if(confirm(`e-対戦:新しいバージョンがあります。スクリプトの更新をお願いします。`)){
					open('https://greatest.deepsurf.us/ja/scripts/471999-e-%E5%AF%BE%E6%88%A6-e-typing/versions')
				}

				playerStateChange.update('oldVersion')

				}

		}).catch(error => console.log(error));
	}
}

let loginFirebase













const typingAppMod = () => {


	//タイピング画面に移動した。

		if(setUp.battleSwitch){

			battleArea = new BattleArea()
			keyJudge = new KeyJudge()


		}

}


class SetMutationObserver {

	constructor(){
		this.observer
		this.elem = document.getElementById("app")
		this.config = {
			childList: true//「子ノード(テキストノードも含む)」の変化
		};

		this.set()
		this.startObserve()
	}

	startObserve(){
		this.observer.observe(this.elem, this.config);
	}

	stopObserve(){
		this.observer.disconnect();
	}

	set(){
		this.observer = new MutationObserver(function(event){

			const add = event[0].addedNodes[0]
			const remove = event[0].removedNodes[0]
			console.log(add)
			console.log(remove)

			if(remove && remove.id == 'hands' && playerStateChange.prevState != "soloPlay"){
				console.log('resultDisplay')
				setMutationObserver.resultObserve()
				return;
			}

			if(add && add.id == 'example_container'){
				console.log('battleAreaSetUp')

				if(battleUserData && battleUserData.data){
					battleUserData.deleteBattlePlayerEvents()
				}

				typingAppMod()
				return;
			}
		});
	}


	resultObserve(){
		this.result = document.getElementById("result")

		this.resultObserve = new MutationObserver(function(){
			console.log('result!')
			myResult.checkResultDisplay()
			setMutationObserver.resultObserve.disconnect();

		});

		this.resultObserve.observe(this.result, this.config);
	}

}
let setMutationObserver






class KeyJudge {

	constructor(){
		this.wordReload = false;
		this.clearLine = 0

		if(keyJudge){
			keyJudge.removeEvent()
		}

		this.addEvent()
	}

	addEvent(){
		this.Event = this.wait.bind(this)
		this.playEvent = this.startSpaceKey.bind(this)
		window.addEventListener("keydown",this.Event)
		window.addEventListener("keydown",this.playEvent)
	}

	removeSpaceKeyEvent(){
		window.removeEventListener("keydown",this.playEvent)
	}

	removeEvent(){
		window.removeEventListener("keydown",this.Event)
	}


	wait(event){
		setTimeout(() => this.keyDown(event))
	}

	startSpaceKey(event){
		if(event.code == 'Space' || event.code == 'KeyL'){
			playerStateChange.update('soloPlay')
			this.removeSpaceKeyEvent()
			document.getElementById('virtual_keyboard').style.display = 'block';
			document.getElementById('hands').style.display = 'block';
			document.getElementById('RTCGamePlayScene').style.display = 'none';

		}
	}


	judge(event , sentenceText){
		let result
		if(setUp.typingMode == "roma"){
			result = sentenceText.textContent.slice(-1).toLowerCase() == event.key ? true:false
		}else if(setUp.typingMode == "eng"){
			result = sentenceText.textContent.slice(-1).replace("␣", " ") == event.key ? true:false
		}else if(setUp.typingMode == "kana"){
			result = this.createKanaChar(event).includes(sentenceText.textContent.slice(-1))
		}
		return result;
	}

	keyDown(event){

		if(playerStateChange.prevState == 'soloPlay'){return}

		const sentenceText = document.getElementsByClassName("entered")[setUp.enteredClass]
		let key

		if(sentenceText){
			key = this.judge(event , sentenceText)
		}

		if(event.key == "Escape"){
			this.wordReload = false
		}

		if(!sentenceText && this.wordReload){
			this.sendWordData('')
			this.wordReload = true

			if(!sentenceText){
				this.wordReload = false
			}

		}else if(sentenceText && key){

			this.sendWordData(sentenceText.textContent)
			this.wordReload = true

			if(!sentenceText){
				this.wordReload = false
			}

		}
	}

	createKanaChar(event){
		let char = windows_keymap[event.code] ? windows_keymap[event.code] : kana_keymap[event.key];

		if(event.shiftKey){
			if(event.code == "KeyE"){char[0] = "ぃ";}
			if(event.code == "KeyZ"){char[0] = "っ";}
		}

		if(event.shiftKey && event.key === "0"){char = ["を"];}

		return char;
	}

	sendWordData(text) {

		var updates = {}
		updates['/users/' + myID + '/status/' + '/lineInput'] = text.substr( -25, 25 );

		if(!text){
			this.clearLine++
			updates['/users/' + myID + '/status/' + '/clearCount'] = this.clearLine

		}

		firebase.database().ref().update(updates)
	}

}
let keyJudge








class BattleArea {

	constructor(){
		battleUserData = new BattleUserData()
		playerStateChange.update('preStart')

		const RTC = document.getElementById("RTCGamePlayScene")
		if(RTC){
			RTC.remove()
		}

		this.createArea()
		this.resetResult()
		this.Lstart = false
	}


	displayReadyButton(){
		document.getElementById("l-ready-button").style.display = 'block'
		document.getElementById("ready-button").style.display = 'block'
	}

	hideReadyButton(){
		document.getElementById("l-ready-button").style.display = 'none'
		document.getElementById("ready-button").style.display = 'none'
	}



	createArea(){
		document.getElementById('virtual_keyboard').style.display = 'none';
		document.getElementById('hands').style.display = 'none';

		document.getElementById('start_msg').insertAdjacentHTML("afterbegin" ,
`<div style="cursor: pointer; display: none;position: absolute;bottom: -23px;left: 28px;width: 130px;font-size: 1.1rem;" class="loading" id='ready-button'>準備完了</div>
<div style="cursor: pointer;display: none;position: absolute;bottom: -23px;width: 130px;right: 26px;font-size: 0.8rem;" class="loading" id='l-ready-button'>Lスタートで準備完了</div>`)

		document.getElementById("ready-button").addEventListener('click', event => {
			event.target.style.display = 'none'
			document.getElementById("l-ready-button").style.display = 'none'
			battleArea.Lstart = false
			playerStateChange.update('ready')
		})

		document.getElementById("l-ready-button").addEventListener('click', event => {
			event.target.style.display = 'none'
			document.getElementById("ready-button").style.display = 'none'
			battleArea.Lstart = true
			playerStateChange.update('ready')
		})



		document.getElementById('example_container').insertAdjacentHTML('afterend',`<div id="RTCGamePlayScene" style='margin-top:3rem;'></div>`)


	}



	addbattleStatusTable(userName,key,inputType){
		const INPUT_TYPE = inputType != 'kana' ? 'ローマ字' : 'かな'

		const TABLE = `<table class='user-table' rules="all" border="1"><tbody>
<tr id="${key}">
<td class='user-name'>${userName}</td>
<td><span  class="RTCLine"></span><div id="battle-progress-bar"></div></td>
<td class="InputMode">${INPUT_TYPE}</td></tbody></table>`

		document.getElementById("RTCGamePlayScene").insertAdjacentHTML('beforeend',TABLE)

		document.getElementById("battle-progress-bar").style.width = (document.getElementsByClassName("RTCLine")[0].parentElement.clientWidth-3) + 'px'

	}


	resetResult(){

		let updates = {};
		updates['/users/' + myID + '/result/'] = ''
		updates['/usersState/' + myID + '/matchPlayerKey'] = null
		firebase.database().ref().update(updates)

	}

}
let battleArea



class BattleUserData{

	constructor(){
		this.data
	}


	onUpdateUserStatus(snapshot){
		const uid = snapshot.ref_.path.pieces_[1];
		const Update_Info = snapshot.ref_.path.pieces_[3]
		const SnapShotValue = snapshot.val()

		switch(Update_Info){
			case "clearCount":
				document.getElementById("battle-progress-bar").style.transform = `scaleX(${(100 - (+SnapShotValue / 15 * 100))/100})`

				break;

			case "lineInput":
				if(SnapShotValue){
					document.getElementsByClassName('RTCLine')[0].textContent = SnapShotValue;
				}else{
					document.getElementsByClassName('RTCLine')[0].textContent = "";
				}
				break;
		}
	}

	findBattlePlayer(name,key,state){
		battleUserData.data = {
			name:name,
			key:key,
			mode:'roma',
			state:state
		}

		battleArea.addbattleStatusTable(battleUserData.data.name , battleUserData.data.key , battleUserData.data.mode)
		this.addBattlePlayerEvents()
		playerStateChange.update('matching')

		let updates = {}
		updates['/usersState/' + myID + '/matchPlayerKey'] = battleUserData.data.key

		firebase.database().ref().update(updates)
	}

	addBattlePlayerEvents(){
		firebase.database().ref('users/' + battleUserData.data.key + '/status').on('child_changed', battleUserData.onUpdateUserStatus);
		firebase.database().ref('users/' + battleUserData.data.key + '/result').on('child_added', myResult.onBattleResultDisplay);
	}


	deleteBattlePlayerEvents(){
		firebase.database().ref('users/' + battleUserData.data.key + '/status').off('child_changed');
		firebase.database().ref('users/' + battleUserData.data.key + '/result').off('child_changed');
	}

	lostBattlePlayer(){
		this.deleteBattlePlayerEvents()
		battleUserData.data = null
		battleArea.hideReadyButton()
		playerStateChange.update('preStart')
		document.getElementsByClassName("user-table")[0].remove()
	}


	resultTimeoutPlayer(){
		this.deleteBattlePlayerEvents()
		const RESULT_DATA = document.getElementsByClassName("result_data")[1].firstElementChild.children
		document.getElementById("prev").firstElementChild.textContent = 'タイムアウト'

		for(let i=0; i<RESULT_DATA.length; i++){
			RESULT_DATA[i].lastElementChild.textContent = '-'
			RESULT_DATA[i].lastElementChild.style.color = '#23c21f'
		}

	}

	onChangeUserState(snapshot){
		const uid = snapshot.ref_.path.pieces_[1];
		const Update_Info = snapshot.ref_.path.pieces_[3]
		const name = snapshot.val().name
		const state = snapshot.val().state
		const matchPlayerKey = snapshot.val().matchPlayerKey

		//対戦相手のstateを更新する
		if(battleUserData.data && uid == battleUserData.data.key){
			battleUserData.data.state = state;
		}

		//お互いに状態がpreStartのプレイヤーをマッチさせる
		if( playerStateChange.prevState == "preStart"){

			//先にマッチ画面で待機していたプレイヤー
			if(uid != myID && state == 'preStart'){
				battleUserData.findBattlePlayer(name , uid , state)
			}

			//後から入室したプレイヤー
			if(matchPlayerKey == myID && state == 'matching'){
				battleUserData.findBattlePlayer(name , uid , state)
			}

		}

		if(battleUserData.data){

			//自分と相手が準備完了したら同時に開始。
			if( (battleUserData.data.key == uid || myID == uid) && (battleUserData.data.state == 'ready' && playerStateChange.prevState == "ready") ){
				document.dispatchEvent( new KeyboardEvent("keydown",{
					// keyCode:32 スペースキー keyCode:76 Lキー
					// keyプロパティ & codeプロパティでは開始できませんでした。
					keyCode: (battleArea.Lstart ? 76 : 32)

				}))
				document.getElementsByClassName('RTCLine')[0].textContent = '';
				playerStateChange.update('play')
				keyJudge.removeSpaceKeyEvent()
			}

			//相手が離脱した。
			if(uid == battleUserData.data.key && (state == 'soloPlay' || state == 'idle' || state == 'timeOut' || state == 'move')){

				if(playerStateChange.prevState != "play" && playerStateChange.prevState != "result"){
					battleUserData.lostBattlePlayer()
				}else if(playerStateChange.prevState == "play"){
					document.getElementsByClassName('RTCLine')[0].textContent = 'タイムアウトしました。';
					battleUserData.deleteBattlePlayerEvents()
				}else if(playerStateChange.prevState == "result"){
					battleUserData.resultTimeoutPlayer()
				}
				battleArea.resetResult()
			}


		}

	}


}
let battleUserData




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////







const kana_keymap = {
	0: ["わ"],
	1: ["ぬ"],
	"!": ["ぬ"],
	2: ["ふ"],
	3: ["あ"],
	4: ["う"],
	5: ["え"],
	6: ["お"],
	7: ["や"],
	8: ["ゆ"],
	9: ["よ"],
	"-": ["ほ","-"],
	"q": ["た"],
	"Q": ["た"],
	"w": ["て"],
	"W": ["て"],
	"e": ["い"],
	"E": ["い"],
	"r": ["す"],
	"R": ["す"],
	"t": ["か"],
	"T": ["か"],
	"y": ["ん"],
	"Y": ["ん"],
	"u": ["な"],
	"U": ["な"],
	"i": ["に"],
	"I": ["に"],
	"o": ["ら"],
	"O": ["ら"],
	"p": ["せ"],
	"P": ["せ"],
	"a": ["ち"],
	"A": ["ち"],
	"s": ["と"],
	"S": ["と"],
	"d": ["し"],
	"D": ["し"],
	"f": ["は"],
	"F": ["は"],
	"g": ["き"],
	"G": ["き"],
	"h": ["く"],
	"H": ["く"],
	"j": ["ま"],
	"J": ["ま"],
	"k": ["の"],
	"K": ["の"],
	"l": ["り"],
	"L": ["り"],
	"z": ["つ"],
	"Z": ["つ"],
	"x": ["さ"],
	"X": ["さ"],
	"c": ["そ"],
	"C": ["そ"],
	"v": ["ひ"],
	"V": ["ひ"],
	"b": ["こ"],
	"B": ["こ"],
	"n": ["み"],
	"N": ["み"],
	"m": ["も"],
	"M": ["も"],
	",": ["ね",","],
	"<": ["、"],
	".": ["る","."],
	">": ["。"],
	"/": ["め","/"],
	"?": ["・"],
	"#": ["ぁ"],
	"$": ["ぅ"],
	"%": ["ぇ"],
	"'": ["ゃ","’","'"],
	"^": ["へ"],
	"~": ["へ"],
	"&": ["ぉ"],
	"(": ["ゅ"],
	")": ["ょ"],
	'|': ["ー"],
	"_": ["ろ"],
	"=": ["ほ"],
	"+": ["れ"],
	";": ["れ"],
	'"': ["ふ","”","“","\""],
	"@": ["゛"],
	'`': ["゛"],
	"[": ["゜"],
	']': ["む"],
	"{": ["「"],
	'}': ["」"],
	":": ["け"],
	"*": ["け"]
}

const windows_keymap = {
	'IntlYen': ["ー","¥","\\"],
	"IntlRo": ["ろ","¥","\\"],
	"Space": [" "],
	"Numpad1": [],
	"Numpad2": [],
	"Numpad3": [],
	"Numpad4": [],
	"Numpad5": [],
	"Numpad6": [],
	"Numpad7": [],
	"Numpad8": [],
	"Numpad9": [],
	"Numpad0": [],
	"NumpadDivide": [],
	"NumpadMultiply": [],
	"NumpadSubtract": [],
	"NumpadAdd": [],
	"NumpadDecimal": []
}



class SetUp {

	constructor(){

		this.typingMode = 'roma'
		this.enteredClass = 2
		this.battleSwitch = true

		this.checkDisplayMenu()
		loginFirebase = localStorage.getItem("battle-option") != "false" ? new LoginFirebase() : null
	}


	checkDisplayMenu(){
		const config = {
			childList: true//「子ノード(テキストノードも含む)」の変化
		};
		const Observe = new MutationObserver(function(event){
			setUp.createMenu()
			setMutationObserver = new SetMutationObserver()
			Observe.disconnect();
		});

		Observe.observe(document.getElementById("app"), config);

	}


	checkTypingMode(){

		if(location.href.match(/kana\.1/)){
			this.typingMode = "kana"
			this.enteredClass = 1
		}else if(location.href.match(/std\.2/) || location.href.match(/lstn\.4/)){
			this.typingMode = "eng"
			this.enteredClass = 1
		}else{
			this.typingMode = "roma"
			this.enteredClass = 2
		}

	}

	createMenu(){

		const NAME = localStorage.getItem("battleName")
		setUp.battleSwitch = localStorage.getItem("battle-option") == "false" ? false : true;

		if(loginFirebase){
			document.getElementById("start_btn").style.display = setUp.battleSwitch == false ? '' : 'none'
			document.getElementById("start_btn").insertAdjacentHTML('afterend',`<div class='loading'>対戦データベースに接続中</div>`)
		}

		this.addCss()
		const FUNC_VIEW = document.getElementById("func_view")

		FUNC_VIEW.style.height = document.getElementById("func_view").clientHeight + 30 + "px"
		FUNC_VIEW.insertAdjacentHTML('beforeend' ,
									 `<div><div>
<label><small>対戦機能</small>
<input id="battle-option" type="checkbox" style="display:none;" ${setUp.battleSwitch == false ? "" : "checked"}>
<div id="sound-effect-btn" style="margin-left:4px;" class="switch_btn"><a class="on_btn btn show">ON</a>
<a class="off_btn btn" style="display:${setUp.battleSwitch == false ? "block" : ""};">OFF</a></div>
</label>
<input type="text" id="battle-name" placeholder="Name" value="${NAME ? NAME : 'Guest'}" maxlength="10" style="display:${setUp.battleSwitch == false ? "none" : "inline"}; position: absolute;width: 7rem;margin: 2px;right: 85px;">
</div></div>`)

		if(!NAME){
			localStorage.setItem("battleName" , 'Guest')
		}


		document.getElementById("battle-name").addEventListener("change", event => {
			localStorage.setItem("battleName" , event.target.value)
			myData.update()
		})

		document.getElementById("battle-option").addEventListener("change" , event => {
			localStorage.setItem("battle-option" , event.target.checked);

			if(event.target.checked){
				document.querySelector("#sound-effect-btn .off_btn").style.display = ""
				document.getElementById("battle-name").style.display = "inline"
				setUp.battleSwitch = true;

				if(!loginFirebase){
					loginFirebase = new LoginFirebase()
					document.getElementById("start_btn").style.display = setUp.battleSwitch == false ? '' : 'none'
					document.getElementById("start_btn").insertAdjacentHTML('afterend',`<div class='loading'>対戦データベースに接続中</div>`)
				}

			}else{
				document.querySelector("#sound-effect-btn .off_btn").style.display = "block"
				document.getElementById("battle-name").style.display = "none"
				setUp.battleSwitch = false;
			}

		})
	}

	addCss(){

		document.getElementById("app").insertAdjacentHTML('afterend',`<style>


.loading{
    color: #fff;
    font-size: 12px;
    font-weight: bold;
    background-color: #057fff;
    width: 160px;
    height: 45px;
    margin: 0 auto;
    text-align: center;
    line-height: 45px;
    overflow: hidden;
    border-radius: 3px;
}

.user-table{
width: 100%;
position: relative;
height: 68px;
left: 0;
right: 0;
margin: auto;
}

.user-table tr{
font-weight:bold;
height: 3rem;
}

.user-name{
    font-size: 1rem;
    width: 90px;
text-align: center;
}

.RTCLine{
max-width: 350px;
white-space: nowrap;
overflow:hidden;
width: 68%;
color:#ffd0a6;
font-size: 26px;
font-weight: normal;
}

.InputMode{
font-size: 1rem;
    width: 95px;
text-align: center;
}

.clear-line{
font-size: 1rem;
text-align: center;
}

#RTCGamePlayScene{
margin: 8px;
}

#battle-progress-bar{
    position: absolute;
    bottom: 1px;
    background-color: #bcbcbc;
    height: 4px;
    transform-origin: left top;
}
</style>`)

	}



}

const setUp = new SetUp()