require 'scripts/core/core.lua'

--------------------------------------------------------------------------------
-- ScrollingList Object script
--------------------------------------------------------------------------------

ScrollingList = class()

-- Callback when object is added to the world
function ScrollingList:start()
	print('ScrollingList:start()')
	self.animator = WorldNode_getComponentByTypeName(self.worldNode, 'animator')
	self.minElem = 1
	self.maxElem = 1
	self.elementNames = { '<empty>' }
	self.currentIndex = 1
	self.currentPos = 1
	self.currentVel = 0
	self.targetPos = 1
	self.tempPos = 1
	self.elements = {}
	self.background = WorldNode_getChildByName(self.worldNode, 'background')
	local elements  = WorldNode_getChildByName(self.background, 'elements')
	for i = 1, 8 do
		local elemNode = WorldNode_getChildByName(elements, 'elem_' .. i)
		local elemButtonComp = WorldNode_getScriptComponent(elemNode, 'GUIButton')
		local labelAnimNode  = WorldNode_getChildByName(elemNode, 'label_scale')
		local labelNode = WorldNode_getChildByName(labelAnimNode, 'label')
		local labelComponent = WorldNode_getComponentByTypeName(labelNode, 'label')
		self.elements[#self.elements + 1] = { elemNode = elemNode, labelNode = labelNode, labelComponent = labelComponent, elemButtonComp = elemButtonComp}
	end
	self.buttonUpNode = WorldNode_getChildByName(self.worldNode, 'arrow_up')
	self.buttonUpComp = getScript(self.worldNode, {'arrow_up'}, 'GUIButtonTurbo')	
	self.buttonDownNode = WorldNode_getChildByName(self.worldNode, 'arrow_down')
	self.buttonDownComp = getScript(self.worldNode, {'arrow_down'}, 'GUIButtonTurbo')
	self.clicked = {}
	self.additionalAccelTime = 0
	self.additionalAccel = 0
	self.disabled = false
	self.stiffness = 25
	self.isDecided = false
end

-- Callback when object is removed from the world
function ScrollingList:stop()
end

-- Callback called every frames
function ScrollingList:update(dt)
	local touchX       = Input_getState(TOUCH_DEVICE, TOUCH_X)
	local touchY       = 480 - Input_getState(TOUCH_DEVICE, TOUCH_Y)
	local touched      = Input_getState(TOUCH_DEVICE, TOUCH_TOUCHED)
	local touchedDelta = Input_getStateDelta(TOUCH_DEVICE, TOUCH_TOUCHED)
	
	local x, y = WorldNode_getWorldPosition(self.background)
	local w, h = VisualComponent_getSize(WorldNode_getComponentByTypeName(self.background, 'sheet_sprite'))

	-- local stiffness = 25
	local pixelsPerItem = 64
	
	if not self.disabled then 	
		if not GUI.isTouchBanned then
			touchX, touchY = CameraComponent_screenToWorldPosition(self.camera, touchX, touchY)
			
			if not self.drag and touchedDelta > 0 and touchX > x - w/2 and touchX < x + w/2 and touchY > y - h/2 + 30 and touchY < y + h/2 - 30 then
				self.drag = true
				self.dragStartY = touchY
				self.dragStartPos = math.floor(math.floor(self.currentPos + 0.5))

			end
			
			if self.drag then
				if touched == 0 then
					self.drag = false
					self.targetPos = clamp(math.floor(self.currentPos + 0.5 * self.currentVel / self.stiffness + 0.5), self.minElem, self.maxElem)
				else
					if touchX > x - w/2 and touchX < x + w/2  then
						if math.abs(touchY - self.dragStartY) > 2*GUI.dragThresholdY then
							self.stiffness = 25
							GUI.pressedCommandTarget = nil
							local offset = (touchY - self.dragStartY) / pixelsPerItem
							self.targetPos = self.dragStartPos + offset
							
							if self.targetPos < self.minElem then
								self.targetPos = self.minElem
							elseif self.targetPos > self.maxElem then
								self.targetPos = self.maxElem
							end
						end
					else 
						self.drag = false
						self.targetPos = clamp(math.floor(self.targetPos + 0.5 * self.currentVel / self.stiffness + 0.5), self.minElem, self.maxElem)
					end
				
				end
				self.changed = true
			end
		end
	
		if not self.drag then
		
			if GUI:isDownPressed(g_menu.invokerDevice) or self.clicked[self.buttonDownComp] then
				self.stiffness = 25
				if self.targetPos < self.maxElem then
					if self.clicked[self.buttonDownComp] then
						self.buttonDownComp:playClickedAnimation()
					end
					self.targetPos = math.floor(self.currentPos + 0.5) + 1
					self.changed = true
				end
			end
			if GUI:isUpPressed(g_menu.invokerDevice) or self.clicked[self.buttonUpComp] then
				self.stiffness = 25
				if self.targetPos > self.minElem then
					if self.clicked[self.buttonUpComp] then
						self.buttonUpComp:playClickedAnimation()
					end
					self.targetPos = math.floor(self.currentPos + 0.5) -1
					self.changed = true
				end
			end
			for i = 1, 8 do
				if self.clicked[self.elements[i].elemButtonComp] then
					if self.targetPos == self:getElemNameIndex(i) and math.abs(self.targetPos - self.currentPos) < 0.1 then
						self.isDecided = true
					elseif math.abs(self.currentVel) < 1 then
						self.targetPos = self:getElemNameIndex(i)
						self.stiffness = 14
						self.changed = true
					end
				end
			end
			
			
		end

	else
		self.targetPos = clamp(math.floor(self.currentPos + 0.5), self.minElem, self.maxElem)
		self.changed = true

	end
	
	self.targetPos = clamp(self.targetPos, self.minElem, self.maxElem)
	self.currentPos, self.currentVel = springSmoothUpdate(self.currentPos, self.currentVel, self.targetPos, self.stiffness, dt)
	self.currentVel = clamp(self.currentVel, -14, 14)

	
	if (self.currentPos < self.maxElem - 0.05) and (self.currentPos > self.minElem + 0.05) then
		WorldNode_setEnabled(self.buttonDownNode, true)
		WorldNode_setEnabled(self.buttonUpNode, true)
	elseif self.currentPos < self.minElem + 0.05 then
		WorldNode_setEnabled(self.buttonUpNode, false)
		self.buttonUpComp.states.turbo.state = 0
		GUI.pressMode = "once"
		WorldNode_setEnabled(self.buttonDownNode, true)
	elseif self.currentPos > self.maxElem - 0.05 then
		WorldNode_setEnabled(self.buttonUpNode, true)
		WorldNode_setEnabled(self.buttonDownNode, false)
		self.buttonDownComp.states.turbo.state = 0
		GUI.pressMode = "once"
	end

	if self.tempPos ~= math.floor(self.currentPos + 0.5) then
		VC_playSoundId(SOUND_SCROLL)
		self.changed = true
		self.tempPos = math.floor(self.currentPos + 0.5)
	end
	
	local index = math.floor(self.currentPos)
	local animationDuration = 8
	AnimatorComponent_setCurrentTime(self.animator, (self.currentPos - index) * animationDuration)
	if index ~= self.currentIndex then
		self.currentIndex = index
		local offset = -math.floor(#self.elements / 2)
		for i = 1, #self.elements do
			local elemIndex = index + i + offset
			local enabled = self.minElem <= elemIndex and elemIndex <= self.maxElem
			WorldNode_setEnabled(self.elements[i].elemNode, enabled)
			if enabled then
				LabelComponent_setText(self.elements[i].labelComponent, self.elementNames[elemIndex])
				self:setTextScale(self.elements[i].labelNode, self.elementNames[elemIndex])
			end
		end
	end

	while next(self.clicked) do
		self.clicked[next(self.clicked)] = nil
	end

end

-- Callback when object starts colliding with another
function ScrollingList:beginCollision(componentA, componentB)

end

-- Callback when object finishes colliding with another
function ScrollingList:endCollision(componentA, componentB)

end

-- Callback when object is a button and is pressed
function ScrollingList:onPressed()

end

-- Callback when object is a button and is released
function ScrollingList:onReleased()
end

function ScrollingList:setElements(elementNames, currentPos)
	self.minElem = 1
	self.maxElem = #elementNames
	self.elementNames = {}
	for i = 1, #elementNames do
		self.elementNames[i] = elementNames[i]
	end
	self.currentPos = currentPos or 1
	self.currentVel = 0
	self.targetPos = currentPos or 1
	self.tempPos = self.currentPos
	self.changed = true
	local index = math.floor(self.currentPos)
	local offset = -math.floor(#self.elements / 2)
	for i = 1, #self.elements do
		local elemIndex = index + i + offset
		local enabled = self.minElem <= elemIndex and elemIndex <= self.maxElem
		WorldNode_setEnabled(self.elements[i].elemNode, enabled)
		if enabled then
			LabelComponent_setText(self.elements[i].labelComponent, self.elementNames[elemIndex])
			self:setTextScale(self.elements[i].labelNode, self.elementNames[elemIndex])
		end
	end
end

function ScrollingList:getElemNameIndex(elementButtonIndex)
	local index = math.floor(self.currentPos)
	local offset = -math.floor(#self.elements / 2)
	local elemIndex = index + elementButtonIndex + offset
	return elemIndex
end

function ScrollingList:onButtonPress(pressedButton)
	if pressedButton == self.buttonUpComp or pressedButton == self.buttonDownComp then
		self.clicked[pressedButton] = true
		if not self.buttonPressed then
			VC_playSoundId(SOUND_SELECT)
			self.buttonPressed = true
		end
	else 
		for i = 1, 8 do 
			if pressedButton == self.elements[i].elemButtonComp then
				if self.targetPos ~= self:getElemNameIndex(i) then
					VC_playSoundId(SOUND_SELECT)
				end
			end
		end
	end
end

function ScrollingList:onButtonRelease(releasedButton)
	if releasedButton ~= self.buttonUpComp and releasedButton ~= self.buttonDownComp then
		self.clicked[releasedButton] = true
	end
	self.buttonPressed = false
end

function ScrollingList:setTextScale(labelNode, text)
	if text == "VCメニュー" then
		WorldNode_setLocalScale(labelNode, 0.7, 0.7)
	elseif text == "Cボタンユニット" then
		WorldNode_setLocalScale(labelNode, 0.5, 0.5)
	else 
		local elemStringLen = utfstrlen(text)
		if elemStringLen >= 9 then
			WorldNode_setLocalScale(labelNode, 0.75, 0.75)
		elseif elemStringLen == 8 then
			WorldNode_setLocalScale(labelNode, 0.80, 0.80)
		elseif elemStringLen == 7 then
			WorldNode_setLocalScale(labelNode, 0.88, 0.88)
		elseif elemStringLen == 6 then
			WorldNode_setLocalScale(labelNode, 0.95, 0.95)
		else
			WorldNode_setLocalScale(labelNode, 1.0, 1.0)
		end
	end
end