class Settings{
	constructor(){
		var ios = /iPhone|iPad/.test(navigator.userAgent)
		var phone = /Android|iPhone|iPad/.test(navigator.userAgent)
		
		this.items = {
			language: {
				type: "language",
				options: ["ja", "en", "cn", "tw", "ko"],
				default: this.getLang()
			},
			resolution: {
				type: "select",
				options: ["high", "medium", "low", "lowest"],
				default: phone ? "medium" : "high"
			},
			touchAnimation: {
				type: "toggle",
				default: !ios,
				touch: true
			},
			keyboardSettings: {
				type: "keyboard",
				default: {
					ka_l: ["d"],
					don_l: ["f"],
					don_r: ["j"],
					ka_r: ["k"]
				},
				touch: false
			}
		}
		
		this.storage = {}
		try{
			var storage = JSON.parse(localStorage.getItem("settings") || "{}")
			for(var i in this.items){
				var current = this.items[i]
				if(current.type === "language"){
					this.storage[i] = localStorage.getItem("lang")
					if(current.options.indexOf(this.storage[i]) === -1){
						this.storage[i] = null
					}
				}else if(i in storage){
					if(current.type === "select" && current.options.indexOf(storage[i]) === -1){
						this.storage[i] = null
					}else if(current.type === "keyboard"){
						var obj = {}
						for(var j in current.default){
							if(storage[i] && storage[i][j] && storage[i][j][0]){
								obj[j] = storage[i][j]
							}else{
								obj = null
								break
							}
						}
						this.storage[i] = obj
					}else{
						this.storage[i] = storage[i]
					}
				}else{
					this.storage[i] = null
				}
			}
		}catch(e){
			for(var i in this.items){
				this.storage[i] = null
			}
		}
	}
	getItem(name){
		var value = this.storage[name]
		return value === null ? this.items[name].default : value
	}
	setItem(name, value){
		this.storage[name] = value
		try{
			if(name === "language"){
				if(value){
					localStorage.setItem("lang", value)
				}else{
					localStorage.removeItem("lang")
				}
			}else{
				var language = this.storage.language
				delete this.storage.language
				localStorage.setItem("settings", JSON.stringify(this.storage))
				this.storage.language = language
			}
		}catch(e){}
	}
	getLang(){
		if("languages" in navigator){
			var userLang = navigator.languages.slice()
			userLang.unshift(navigator.language)
			for(var i in userLang){
				for(var j in allStrings){
					if(allStrings[j].regex.test(userLang[i])){
						return j
					}
				}
			}
		}
		return "ja"
	}
	setLang(lang, noEvent){
		strings = lang
		var boldFonts = strings.font === "Microsoft YaHei, sans-serif"
		loader.screen.style.fontFamily = strings.font
		loader.screen.style.fontWeight = boldFonts ? "bold" : ""
		loader.screen.classList[boldFonts ? "add" : "remove"]("bold-fonts")
		if(!noEvent){
			pageEvents.send("language-change", lang.id)
		}
	}
}

class SettingsView{
	constructor(touchEnabled, tutorial){
		this.touchEnabled = touchEnabled
		this.tutorial = tutorial
		if(!tutorial){
			loader.changePage("settings", tutorial)
			assets.sounds["bgm_settings"].playLoop(0.1, false, 0, 1.392, 26.992)
			this.defaultButton = document.getElementById("settings-default")
		}else if(touchEnabled){
			document.getElementById("tutorial-outer").classList.add("settings-outer")
		}
		if(touchEnabled){
			document.getElementById("tutorial-outer").classList.add("touch-enabled")
		}
		this.mode = "settings"
		
		this.tutorialTitle = document.getElementById("tutorial-title")
		this.endButton = document.getElementById("tutorial-end-button")
		if(!tutorial){
			this.setStrings()
		}
		this.resolution = settings.getItem("resolution")
		
		var content = document.getElementById("tutorial-content")
		this.items = []
		this.selected = tutorial ? 1 : 0
		for(let i in settings.items){
			var current = settings.items[i]
			if(
				!touchEnabled && current.touch === true ||
				touchEnabled && current.touch === false ||
				tutorial && current.type !== "language"
			){
				continue
			}
			var settingBox = document.createElement("div")
			settingBox.classList.add("setting-box")
			var nameDiv = document.createElement("div")
			nameDiv.classList.add("setting-name", "stroke-sub")
			var name = strings.settings[i].name
			nameDiv.innerText = name
			nameDiv.setAttribute("alt", name)
			settingBox.appendChild(nameDiv)
			var valueDiv = document.createElement("div")
			valueDiv.classList.add("setting-value")
			this.getValue(i, valueDiv)
			settingBox.appendChild(valueDiv)
			content.appendChild(settingBox)
			if(this.items.length === this.selected){
				settingBox.classList.add("selected")
			}
			pageEvents.add(settingBox, ["mousedown", "touchstart"], event => {
				if(event.type !== "mousedown" || event.which === 1){
					event.preventDefault()
					this.setValue(i)
				}
			})
			this.items.push({
				id: i,
				settingBox: settingBox,
				nameDiv: nameDiv,
				valueDiv: valueDiv
			})
		}
		if(!tutorial){
			this.items.push({
				id: "default",
				settingBox: this.defaultButton
			})
			pageEvents.add(this.defaultButton, ["mousedown", "touchstart"], this.defaultSettings.bind(this))
		}
		this.items.push({
			id: "back",
			settingBox: this.endButton
		})
		
		this.setKbd()
		pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this))
		pageEvents.keyAdd(this, "all", "down", this.keyEvent.bind(this))
		this.gamepad = new Gamepad({
			"confirm": ["b", "ls", "rs"],
			"up": ["u", "lsu"],
			"previous": ["l", "lb", "lt", "lsl"],
			"next": ["d", "r", "rb", "rt", "lsd", "lsr"],
			"back": ["start", "a"]
		}, this.keyPressed.bind(this))
		if(!tutorial){
			pageEvents.send("settings")
		}
	}
	setKbd(){
		var kbdSettings = settings.getItem("keyboardSettings")
		this.kbd = {
			"confirm": ["enter", " ", kbdSettings.don_l[0], kbdSettings.don_r[0]],
			"up": ["arrowup"],
			"previous": ["arrowleft", kbdSettings.ka_l[0]],
			"next": ["arrowright", "arrowdown", kbdSettings.ka_r[0]],
			"back": ["backspace", "escape"]
		}
	}
	getValue(name, valueDiv){
		var current = settings.items[name]
		var value = settings.getItem(name)
		if(current.type === "language"){
			value = allStrings[value].name + " (" + value + ")"
		}else if(current.type === "select"){
			value = strings.settings[name][value]
		}else if(current.type === "toggle"){
			value = value ? strings.settings.on : strings.settings.off
		}else if(current.type === "keyboard"){
			valueDiv.innerHTML = ""
			for(var i in value){
				var key = document.createElement("div")
				key.style.color = i === "ka_l" || i === "ka_r" ? "#009aa5" : "#ef2c10"
				key.innerText = value[i][0].toUpperCase()
				valueDiv.appendChild(key)
			}
			return
		}
		valueDiv.innerText = value
	}
	setValue(name){
		var current = settings.items[name]
		var value = settings.getItem(name)
		var selectedIndex = this.items.findIndex(item => item.id === name)
		var selected = this.items[selectedIndex]
		if(this.mode !== "settings"){
			if(this.selected === selectedIndex){
				this.keyboardBack(selected)
			}
			return
		}
		if(this.selected !== selectedIndex){
			this.items[this.selected].settingBox.classList.remove("selected")
			this.selected = selectedIndex
			selected.settingBox.classList.add("selected")
		}
		if(current.type === "language" || current.type === "select"){
			value = current.options[this.mod(current.options.length, current.options.indexOf(value) + 1)]
		}else if(current.type === "toggle"){
			value = !value
		}else if(current.type === "keyboard"){
			this.mode = "keyboard"
			selected.settingBox.style.animation = "none"
			selected.valueDiv.classList.add("selected")
			this.keyboardKeys = {}
			this.keyboardSet()
			assets.sounds["se_don"].play()
			return
		}
		settings.setItem(name, value)
		this.getValue(name, this.items[this.selected].valueDiv)
		assets.sounds["se_ka"].play()
		if(current.type === "language"){
			this.setLang(allStrings[value])
		}
	}
	keyEvent(event){
		if(event.keyCode === 27 || event.keyCode === 8 || event.keyCode === 9){
			// Escape, Backspace, Tab
			event.preventDefault()
		}
		if(!event.repeat){
			for(var i in this.kbd){
				if(this.kbd[i].indexOf(event.key.toLowerCase()) !== -1){
					if(this.mode !== "keyboard" || i === "back"){
						this.keyPressed(true, i)
						return
					}
				}
			}
			if(this.mode === "keyboard"){
				event.preventDefault()
				var currentKey = event.key.toLowerCase()
				for(var i in this.keyboardKeys){
					if(this.keyboardKeys[i][0] === currentKey || !currentKey){
						return
					}
				}
				this.keyboardKeys[this.keyboardCurrent] = [currentKey]
				this.keyboardSet()
			}
		}
	}
	keyPressed(pressed, name){
		if(!pressed){
			return
		}
		var selected = this.items[this.selected]
		if(this.mode === "settings"){
			if(name === "confirm"){
				if(selected.id === "back"){
					this.onEnd()
				}else if(selected.id === "default"){
					this.defaultSettings()
				}else{
					this.setValue(selected.id)
				}
			}else if(name === "up" || name === "previous" || name === "next"){
				selected.settingBox.classList.remove("selected")
				do{
					this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1))
				}while(this.items[this.selected].id === "default" && name !== "previous")
				selected = this.items[this.selected]
				selected.settingBox.classList.add("selected")
				selected.settingBox.scrollIntoView()
				assets.sounds["se_ka"].play()
			}else if(name === "back"){
				this.onEnd()
			}
		}else if(this.mode === "keyboard"){
			if(name === "back"){
				this.keyboardBack(selected)
			}
		}
	}
	keyboardSet(){
		var selected = this.items[this.selected]
		var current = settings.items[selected.id]
		selected.valueDiv.innerHTML = ""
		for(var i in current.default){
			var key = document.createElement("div")
			key.style.color = i === "ka_l" || i === "ka_r" ? "#009aa5" : "#ef2c10"
			if(this.keyboardKeys[i]){
				key.innerText = this.keyboardKeys[i][0].toUpperCase()
				selected.valueDiv.appendChild(key)
			}else{
				key.innerText = "[" + strings.settings[selected.id][i] + "]"
				selected.valueDiv.appendChild(key)
				this.keyboardCurrent = i
				return
			}
		}
		settings.setItem(selected.id, this.keyboardKeys)
		this.keyboardBack(selected)
		this.setKbd()
		pageEvents.setKbd()
	}
	keyboardBack(selected){
		this.mode = "settings"
		selected.settingBox.style.animation = ""
		selected.valueDiv.classList.remove("selected")
		this.getValue(selected.id, selected.valueDiv)
	}
	defaultSettings(event){
		if(event && event.type === "touchstart"){
			event.preventDefault()
		}
		if(this.mode === "keyboard"){
			this.keyboardBack(this.items[this.selected])
		}
		for(var i in settings.items){
			settings.setItem(i, null)
		}
		this.setLang(allStrings[settings.getItem("language")])
		this.setKbd()
		assets.sounds["se_don"].play()
	}
	onEnd(event){
		if(this.tutorial){
			this.clean()
			return this.tutorial.onEnd(event)
		}
		var touched = false
		if(event){
			if(event.type === "touchstart"){
				event.preventDefault()
				touched = true
			}else if(event.which !== 1){
				return
			}
		}
		this.clean()
		assets.sounds["se_don"].play()
		setTimeout(() => {
			new SongSelect("settings", false, touched)
		}, 500)
	}
	setLang(lang){
		settings.setLang(lang)
		if(failedTests.length !== 0){
			showUnsupported(strings)
		}
		for(var i in this.items){
			var item = this.items[i]
			if(item.valueDiv){
				var name = strings.settings[item.id].name
				item.nameDiv.innerText = name
				item.nameDiv.setAttribute("alt", name)
				this.getValue(item.id, item.valueDiv)
			}
		}
		this.setStrings()
	}
	setStrings(){
		if(this.tutorial){
			this.tutorial.setStrings()
		}else{
			this.tutorialTitle.innerText = strings.gameSettings
			this.tutorialTitle.setAttribute("alt", strings.gameSettings)
			this.defaultButton.innerText = strings.settings.default
			this.defaultButton.setAttribute("alt", strings.settings.default)
			this.endButton.innerText = strings.settings.ok
			this.endButton.setAttribute("alt", strings.settings.ok)
		}
	}
	mod(length, index){
		return ((index % length) + length) % length
	}
	clean(){
		this.gamepad.clean()
		assets.sounds["bgm_settings"].stop()
		pageEvents.keyRemove(this, "all")
		for(var i in this.items){
			pageEvents.remove(this.items[i].settingBox, ["mousedown", "touchstart"])
		}
		if(this.defaultButton){
			delete this.defaultButton
		}
		delete this.tutorialTitle
		delete this.endButton
		delete this.items
		if(this.resolution !== settings.getItem("resolution")){
			for(var i in assets.image){
				if(i === "touch_drum" || i.startsWith("bg_song_") || i.startsWith("bg_stage_") || i.startsWith("bg_don_")){
					URL.revokeObjectURL(assets.image[i].src)
					delete assets.image[i]
				}
			}
		}
	}
}
