function HSVtoRGB(h, s, v)

  local r, g, b

  local i = math.floor(h * 6)
  local f = h * 6 - i
  local p = v * (1 - s)
  local q = v * (1 - f * s)
  local t = v * (1 - (1 - f) * s)

  local switch = i % 6
  if switch == 0 then
    r = v g = t b = p
  elseif switch == 1 then
    r = q g = v b = p
  elseif switch == 2 then
    r = p g = v b = t
  elseif switch == 3 then
    r = p g = q b = v
  elseif switch == 4 then
    r = t g = p b = v
  elseif switch == 5 then
    r = v g = p b = q
  end

  return math.floor(r*255), math.floor(g*255), math.floor(b*255)
  
end

WinState = class(Group, function(o, substate)
	Group.init(o)
	o.substate = substate
	o:setup()
end)
function WinState:setup()
	local o = self
	o.blackout = o:add(Object(0,0,bludG.camera.w, bludG.camera.h))
	o.blackout:setColor(0,0,0,0)
	o.blackout.sprite = sprites['tiles']['white.png']
	o.blackout.drawType = 'stretched'
	o.blackout:setScrollFactor(Vec2(0,0))

	o.bg = o:add(Object(0,-bludG.camera.h,bludG.camera.w, bludG.camera.h))
	o.bg.svg = SvgLoader(svg_root .. "interface/win_" .. player.currentWorld.id .. "_bg.svg", false)
	o.bg.drawType = 'svg'

	o.bg.svg:scale(bludG.camera.w/o.bg.svg:getMaxX(), bludG.camera.h/1024)
	o.bg.svg:setScrollFactor(0,0)
	o.iscale = bludG.camera.h/1024
	local interfacesvg = SvgLoader(svg_root .. "interface/win_" .. player.currentWorld.id .. ".svg", false)
	o.interface = o:add(Object(bludG.camera.w/2-interfacesvg:getMaxX()/2*o.iscale,-bludG.camera.h,bludG.camera.w, bludG.camera.h))
	o.interface.svg = nil
	o.interface.svg = interfacesvg
	o.interface.svg:scale(o.iscale, o.iscale)

	Tweener:addTween(o.blackout.tint, {a=191}, {time=1, onComplete=function()
		o.gameOver = true
		-- add the svg overlay
		o.interface.drawType = 'svg'
		o.interface.svg:setScrollFactor(0,0)
		Tweener:addTween(o.bg.pos, {y=0}, {func='outElastic'})
		Tweener:addTween(o.interface.pos, {y=0}, {func='outElastic', onComplete=function()
			local lossText = o:add(StringObject(0,0,"CLEARED",nil, 0.8))
			lossText:setColor(0,0,0)
			lossText:setScrollFactor(Vec2(0,0))
			local topRatio = 175/1024
			local topOff = bludG.camera.h*topRatio
			lossText:setPosition(-lossText.w, topOff)
			Tweener:addTween(lossText.pos, {x=bludG.camera.w/2-lossText.w/2})
			o:addHighScores()
			-- add the buttons for replay, etc
			if o.interface.svg.id then
				-- should move this into the svg loader
				for key, rbd in pairs(o.interface.svg.id) do
					local button = o:add(CameraButton(rbd.minX*o.iscale+o.interface.pos.x, rbd.minY*o.iscale+o.interface.pos.y, (rbd.maxX-rbd.minX)*o.iscale, (rbd.maxY-rbd.minY)*o.iscale))
					button.scrollFactor = Vec2(0,0)
					button.onPress = function()
						if o[key .. "_callback"] then o[key .. "_callback"](o) end
					end
					button:setColor(0,0,0,0)
				end
			end

		end})
	end})
	
	pd:startList("fromOF")
	pd:addSymbol("levelWon")
	pd:addFloat(1)
	pd:finish("fromOF")
	o.scorePing = 0.1
	local drafted = 'not drafted'
	if o.substate.customDraft then
		drafted = 'drafted'
	end
	player.achievements:completeLevel(o.substate.waveData.filename)
	player.achievements:submitUpdates()
	-- analytics:logEvent("level_won", {['filename']=o.substate.waveData.filename, ['drafted']=drafted})
end
function WinState:levelselectbutton_callback()
	mainState:changeState(LevelSelectState())
end
function WinState:addHighScores()
	-- pull the y position of the buttons so that we can stick the high scores below them
	local ypos = self.interface.svg.id.replaybutton.maxY*self.iscale
	-- loop through the different highscore types, and stick them below the buttons
	-- for now just a list.
	local limits = self.substate:getTowerLimits()
	local height = math.floor(((limits.maxY-limits.minY)/r_scale/60*8.5))
	local scoreTypes = {
		{['Height']=height},
		{['Profit']=self.substate.moneyController:getAmount()},
		{['Rooms Destroyed']= player:getLevelDestroy()},
		{['Rooms Remaining']= self.substate.rooms:countLiving()},
		{['Rounds Fired']= player:getLevelShots()}
	}
	player.achievements:newMoney(self.substate.moneyController:getAmount())
	local pro, remain, destroy, height, rounds = self.substate.moneyController:getAmount(), self.substate.rooms:countLiving(),  player:getLevelDestroy(), height, player:getLevelShots();
	local totalScore = math.floor(((pro*remain)/(destroy+1))+height+rounds)
	-- store the total score on the player
	player.leaderboards:addScore(self.substate.waveData.filename, totalScore)
	if not self.substate.customDraft and (not player.highscores[self.substate.waveData.filename] or player.highscores[self.substate.waveData.filename] < totalScore) then
		player.highscores[self.substate.waveData.filename] = totalScore
		scoreTypes[6] = {["New High Score"] = totalScore}
	else
		scoreTypes[6] = {["Score"] = totalScore}
	end
	local xpad = 20*r_scale
	ypos = ypos + 10*r_scale
	local mult = 0.5
	self.scores = self:add(Group())
	local currentTween = nil
	for i, score in ipairs(scoreTypes) do
		if i == 6 then mult = 0.7 end
		for k,v in pairs(score) do

			local title = self:add(StringObject(0, ypos, k, nil, mult))
			title.scrollFactor = Vec2(0,0)
			title:setPosition(-title.w, title.pos.y)

			local b = self.scores:add(StringObject(0, ypos, 0, nil, mult))
			b.text = {}
			b.text.target = v
			b.text.current = 0
			b:setColor(255, 255, 255, 0)
			if not currentTween then
				Tweener:addTween(title.pos, {x=xpad}, {time=0.2})
				currentTween = Tweener:addTween(b.text, {current=b.text.target}, {func="easeNone"})
				b:setColor(255, 255, 255, 255)
			else
				local nextTween = Tweener:addTween(b.text, {current=b.text.target}, {func="easeNone"})
				local titleTween = Tweener:addTween(title.pos, {x=xpad}, {time=0.2})
				titleTween.running = false
				nextTween.running = false
				currentTween.onComplete = function()
					nextTween.running = true
					titleTween.running = true
					b:setColor(255, 255, 255, 255)
				end
				currentTween = nextTween
			end
			if k == "New High Score" then
				self.rainbowTween = title
			end
			b.scrollFactor = Vec2(0,0)
			b:setPosition(bludG.camera.w-xpad-b.w, b.pos.y)
			ypos = ypos + b.h+8*r_scale
		end
	end
end

function WinState:replaybutton_callback()
	mainState:changeState(PlayState(self.substate.waveData))
end
function WinState:playbutton_callback()
	-- check to see if we should be loading a world
	if self.substate.waveData.next_level == 'game_over' then
		mainState:changeState(GameOverState())
	elseif self.substate.waveData.next_level:sub(1, 5) == 'world' then
		player.currentWorldCount = tonumber(self.substate.waveData.next_level:sub(7)-1)
		player.currentWorld = worlds[player.currentWorldCount+1]
		mainState:changeState(WorldSelectState(TitleScreenState()))
	else-- load the next level
		local levelData = persistence.load(blud.bundle_root .. "/badHotel_/assets/levelData/" .. self.substate.waveData.next_level .. ".lua");
		mainState:changeState(PlayState(levelData))
	end
end

function WinState:update()
	self.substate:update()
	Group.update(self)
	local canPing = false
	if self.scorePing > 0 then
		self.scorePing = self.scorePing - bludG.elapsed
	else
		canPing = true
		self.scorePing = self.scorePing + 0.1
	end
	if self.scores then
		local xpad = 20*r_scale
		for i,v in ipairs(self.scores.members) do
			local cstr = string.format("%i", v.text.current)
			if cstr ~= v.string then
				v:setValue(string.format("%i", v.text.current))
				v:setPosition(bludG.camera.w-xpad-v.w, v.pos.y)
				-- if canPing then
					pd:startList("fromOF")
					pd:addSymbol("scoreCounter")
					pd:addFloat(1)
					pd:finish("fromOF")
				-- end
			end
		end
	end
	if self.rainbowTween then
		for i,v in ipairs(self.rainbowTween.subs) do
			local r, g, b = HSVtoRGB(-i/15+bludG.last_t/2, 0.5, 1)
			v.tint = {r=r, g=g, b=b}
		end
	end
end

function WinState:sync()
	self.substate:sync()
end
function WinState:draw()
	self.substate:draw()
	Group.draw(self)
end