ScalarParameter = {}
ScalarParameter_mt = { __index = ScalarParameter }
setmetatable(ScalarParameter, Control_mt)

-- Constants
ScalarParameter.kHeight = 30
ScalarParameter.kWidth = 100
ScalarParameter.valueOutline = ParameterList.kValueOutlineSmall

function ScalarParameter.Create(root, parentObject, type, startValue, minValue, maxValue, dragScale, onChange)
	-- Create object
	local scalarParameter = Control.Create(root, parentObject)
	setmetatable(scalarParameter, ScalarParameter_mt)
	
	-- Set attributes
	scalarParameter.type = type
	scalarParameter.value = startValue
	scalarParameter.minValue = minValue
	scalarParameter.maxValue = maxValue
	scalarParameter.dragScale = dragScale
	scalarParameter.onChange = onChange
	
	scalarParameter.dragStartValue = nil
	scalarParameter.dragStartPos = nil
	scalarParameter.dragScaleMultiplier = 1
	
	scalarParameter.textEdit = nil

	-- Create parameter value surfaces
	scalarParameter.valueSurface = GSurface(ScalarParameter.kWidth, ScalarParameter.kHeight)
	scalarParameter:UpdateValueSurface()
	
	return scalarParameter	
end
	
function ScalarParameter:HandleEvent(window, rect, event)
	window:PushScissor(rect)
		local rect = window.currentScissor
		
		local isHot = rect:IsPointInside(event.pos) and not self:IsOtherControlActive()
		
		if (self.isActive==false) then
			if (event.type==kGEventMouseMoved) then
				self:SetHot(isHot)
			elseif (event.type==kGEventMouseDown) then
				if (event.button==kGEventMouseButtonLeft) then
					if (self.isHot) then
						if (event.clickCount==1) then
							-- Start drag
							self:SetActive(true)
							
							self.dragStartValue = self.value
							self.dragStartPos = GPoint(event.pos)
							
							-- Check fine and mega drag
							self.dragScaleMultiplier = 1.0
							if (event:HasModifier(kGEventModifierShift)) then
								self.dragScaleMultiplier = 0.05
							elseif (event:HasModifier(kGEventModifierControl)) then
								self.dragScaleMultiplier = 10
							end
						else
							--self:SetActive(true)
							self.textEdit = retain(intruder.GTextEdit(rect, self:GetParameterText(), 13, kGAlignCenter, kGVerticalAlignCenter))
							self:SetActive(true)
						end
					end
				end
			end
		else
			if (not self.textEdit) then
				if (event.type==kGEventMouseMoved) then
					-- Compute new value
					local delta = event.pos:Minus(self.dragStartPos)
					local dist = delta.x - delta.y
					
					local newValue = self.dragStartValue + dist * self.dragScale * self.dragScaleMultiplier / 100
					
					-- Clamp value, if applicable
					newValue = self:SanitizeValue(newValue)
					
					-- Update value
					self.value = newValue
					self:UpdateValueSurface()
					
					if (self.onChange) then
						self.onChange(self.value)
					end
				elseif (event.type==kGEventMouseUp) then
					-- Stop drag
					self:SetActive(false)
					self:SetHot(false)
					
					self.dragStartValue = nil
					self.dragStartPos = nil
				end
			end
		end	
		
		-- Check for text edit finish
		if (self.isActive and event.type==kGEventTextEditFinished) then
			if (self.textEdit) then
				if (self.textEdit.state==intruder.GTextEdit_kTextEditDone) then
					local str = self.textEdit.text
					
					local numberPositionInString = string.find(str, '[-+]?[0-9]*%.?[0-9]+')    -- will return nil if regexp couldn't be matched

					if (numberPositionInString) then
						local newValueStr = string.sub(str, numberPositionInString)
						local newValue = tonumber(newValueStr)

						if (newValue) then -- this check shouldn't be neccesary, since we parse using string.find. perhaps a bug in this old lua version?    but it means that some numbers on't be correctly parsed
							newValue = self:SanitizeValue(newValue)
							
							-- Update value
							self.value = newValue
							self:UpdateValueSurface()
							
							if (self.onChange) then
								self.onChange(self.value)
							end
						end
					end
				end
				
				self.textEdit = nil
				self:SetActive(false)
			end
		end
		
		-- Set cursor if applicable
		if (not self.textEdit and self.isActive) then
			window:SetCursor(intruder.GWindow_kGCursorArrowNESW)
		end
	window:PopScissor()
end

function ScalarParameter:Draw(window, rect)
	window:PushScissor(rect)
		self.valueSurface:DrawTexture(rect:GetTopLeft())
		
		if (self.isHot) then
			self.valueOutline:DrawTexture(rect:GetTopLeft())
		end
	window:PopScissor()
end

function ScalarParameter:SanitizeValue(newValue)
	if (self.minValue) then
		if (newValue < self.minValue) then
			newValue = self.minValue
		end
	end
	
	if (self.maxValue) then
		if (newValue > self.maxValue) then
			newValue = self.maxValue
		end
	end
	
	if (self.type==intruder.ZParameter_kTypeInt) then
		newValue = math.floor(newValue + 0.5)   --(poor mans round)
	end
	
	return newValue
end
	
function ScalarParameter:GetParameterText()
	if (self.type==intruder.ZParameter_kTypeFloat) then
		local str = string.format("%.5f", self.value)
		return str
	end
	if (self.type==intruder.ZParameter_kTypeInt) then
		local str = string.format("%d", self.value)
		return str
	end
end
	
function ScalarParameter:UpdateValueSurface(index)
	local str = self:GetParameterText()
	local surface = self.valueSurface
	surface:Clear(GColor(0, 0, 0, 0))
	surface:DrawTextAligned(intruder.kFontFaceEnvyBold, str, GColor(0, 0, 0), 13, kGAlignCenter, kGVerticalAlignCenter, GPoint(1,1));
	surface:DrawTextAligned(intruder.kFontFaceEnvyBold, str, GColor(255, 255, 255), 13, kGAlignCenter, kGVerticalAlignCenter, GPoint(0,0));
	surface:UpdateTexture()
end
