-- Global funcs

cm = {};

-- Function to setup the object tables with default values
cm.SetupTable = function(pTable)

   pTable.OnInit = function(pObj)
      end

   pTable.OnLoad = function(pObj)
      end

   pTable.OnLevelLoad = function(pObj)
      end

   pTable.OnLevelExit = function(pObj)
      end

   pTable.OnUse = function(pObj, pActingObj)
      end

   pTable.OnUpdate = function(pObj)
      end

   pTable.OnClick = function(pObj, pName, pActorObj, pPolyNum, pX, pY)
         return false;
      end

   pTable.OnDraw = function(pObj, pG)
      end

   pTable.OnMoused = function(pObj)
      pObj:StopParticleEmission(false);
      end

   pTable.OnUnMoused = function(pObj)
      end

   pTable.OnMouseEnter = function(pObj)
      end

   pTable.OnMouseLeave = function(pObj)
      end

   pTable.GetCursorInfo = function(pObj, pPolyNum, pName)
         local aCursorTable	= {};
         aCursorTable[0]		= true;
         aCursorTable[1]		= IcGobj.CURSOR_POINTER;
         return aCursorTable;
      end

   pTable.GetParticleSystemInfo = function(pObj, pPolyNum, pName)
         local aParticleSystemTable	= {};
         aParticleSystemTable[0]		= true;
         aParticleSystemTable[1]		= "PH_PSYS_UNDYING_SPARKLE";
         return aParticleSystemTable;
      end

end

-- Fetch spawn positions
cm.GetSpawnPos = function(pPobj, pNum, pPos)

	local aStrX = string.format("SpawnX%d", pNum);
	if pPobj.mCsData:IfExistsInt(aStrX) then
		local aStrY = string.format("SpawnY%d", pNum);
		local aX 	= pPobj.mCsData:GetInt(aStrX);
		local aY 	= pPobj.mCsData:GetInt(aStrY);
		if pPos then
			aX = aX + pPos.x;
			aY = aY + pPos.y;
		end
		return aX, aY;
	end

end

-- Spawn Object
cm.SpawnObject = function(pObj, pNum, pPos, pName)

   if not pObj.mPdata.mBar:CanAddSlot() then
      cm.ShowInfo(pObj, pObj.mGobj.mDataManager:GetString("PH_GEN_INFO_NO_SPAWN_SLOTS"), 220);
      return false;
   end

	local aX, aY = cm.GetSpawnPos(pObj, pNum, pPos);
	local aSpawnObject = pObj.mCsData:GetString(pName);
	--IcPrintLog("cm.SpawnObject(): Spawning Object: "..aSpawnObject.."\n");
	pObj.mPdata:AddKeyObject(aSpawnObject, aX, aY);
	
	return true;

end

-- Spawn objects at the mouse position
cm.SpawnObjectMouse = function(pObj, pNum, pX, pY, pName)

   if not pObj.mPdata.mBar:CanAddSlot() then
      cm.ShowInfo(pObj, pObj.mGobj.mDataManager:GetString("PH_GEN_INFO_NO_SPAWN_SLOTS"), 220);
      return false;
   end

	local aSpawnObject = pObj.mCsData:GetString(pName);
	--IcPrintLog("cm.SpawnObjectMouse(): Spawning Object: "..aSpawnObject.."\n");
	pObj.mPdata:AddKeyObject(aSpawnObject, pX, pY);

	return true;

end


-- Spawn Object without checking for slots
cm.SpawnObjectNoCheck = function(pObj, pNum, pPos, pName)

	local aX, aY = cm.GetSpawnPos(pObj, pNum, pPos);
	local aSpawnObject = pObj.mCsData:GetString(pName);
	--IcPrintLog("cm.SpawnObjectNoCheck(): Spawning Object: "..aSpawnObject.."\n");
	pObj.mPdata:AddKeyObject(aSpawnObject, aX, aY);

	return true;

end


-- Switch to zoom mode
cm.ZoomIn = function(pObj, aTime1)

	pObj.mCurImg = 1;
	pObj.mAlpha:AncEndChange();
	pObj.mAlpha:AncSetupChange(0.0, 255.0, aTime1, IcAutoNumChgr.IC_ANCM_LINEAR);
	pObj.mFrmPos = pObj.mSmPos;
	
	local aImg1 = IcImageWrap("PH_IMG_CMN_ZOOM_BOX");
	local aImg2 = IcImageWrap(pObj.mSmallImage);
	pObj.mFrmPos.x = pObj.mFrmPos.x - (aImg1:GetCelWidth()  - aImg2:GetCelWidth())/2;
	pObj.mFrmPos.y = pObj.mFrmPos.y - (aImg1:GetCelHeight() - aImg2:GetCelHeight())/2;

	if pObj.mFrmPos.x < 0 then
		pObj.mFrmPos.x = 0;
	elseif pObj.mFrmPos.x + aImg1:GetCelWidth() > gGobj.mWidth then
		pObj.mFrmPos.x = gGobj.mWidth - aImg1:GetCelWidth();
	end

	if pObj.mFrmPos.y < 0 then
		pObj.mFrmPos.y = 0;
	elseif pObj.mFrmPos.y + aImg1:GetCelHeight() > gGobj.mHeight - pObj.mPdata.mBar:GetWorkingHeight() then
		pObj.mFrmPos.y = gGobj.mHeight  - pObj.mPdata.mBar:GetWorkingHeight() - aImg1:GetCelHeight();
	end

	local aImg3 = IcImageWrap(pObj.mBigImage);
	pObj.mBigPos.y = pObj.mFrmPos.y + (aImg1:GetCelHeight() - aImg3:GetCelHeight())/2;
	pObj.mBigPos.x = pObj.mFrmPos.x + (aImg1:GetCelWidth() - aImg3:GetCelWidth())/2;
	pObj:StopParticleEmission(false);

	local aRadius = aImg1:GetCelWidth()/2;
	local aX = aRadius*math.cos(math.pi/4);
	local aY = aRadius*math.sin(math.pi/4);
	local aCbPos = IcVector2d(aRadius + aX, aRadius - aY);
	pObj.mCb:SetPos(aCbPos);
	pObj.mCb:StartAppearing(aTime1, aTime1);
	pObj.mCsData:SetValf("CbPosX", aCbPos.x);
	pObj.mCsData:SetValf("CbPosY", aCbPos.y);
	pObj.mCsData:SetVal("Time1", aTime1);
	
	IcPlaySample("PH_SFX_CLOSER_LOOK");

end

-- Generic zoom out
cm.ZoomOut = function(pObj)

	pObj:StopParticleEmission(false);
	pObj.mCsData:SetVal("Downsizing", true);
	pObj.mAlpha:AncEndChange();
	pObj.mAlpha:AncSetupChange(255.0, 0.0, PhGetBigTime, IcAutoNumChgr.IC_ANCM_LINEAR);
	IcPlaySample("PH_SFX_CLOSER_LOOK");

end

-- Generic zoom out
cm.ShowCloseButton = function(pObj)

	local aX	 = pObj.mCsData:GetFloat("CbPosX");
	local aY	 = pObj.mCsData:GetFloat("CbPosY");
	local aTime  = pObj.mCsData:GetInt("Time1");
	local aCbPos = IcVector2d(aX, aY);
	pObj.mCb:SetPos(aCbPos);
	pObj.mCb:InstantAppear(aTime);

end

-- Updates the zooming out status
cm.ZoomOutUpdate = function(pObj)

	if pObj.mCsData:GetBool("Downsizing") then
		if not pObj.mAlpha:AncIsChanging() then
			pObj.mCsData:SetVal("Downsizing", false);
			pObj.mCurImg = 0;
			pObj.mAlpha:AncSetCurrent(255);
		end
	end

end


-- Draws the zoomable object
cm.DrawZoomable = function(pObj, pG)


	local aRpos = pObj.mSmPos;
	local aImg  = IcImageWrap(pObj.mSmallImage);
	assert(aImg);
	local aRect = aImg:GetCelRect(pObj.mCurCell);
	pG:DrawImage(aImg:GetImage(), aRpos.x, aRpos.y, aRect);

	if (pObj.mCurImg == 1) then
		pG:SetColorizeImages(true);
		pG:SetColor(Color(255, 255, 255, pObj.mAlpha:AncGetVal()));

      -- Draw zoomed image
		aImg = IcImageWrap(pObj.mBigImage);
		assert(aImg);
		aRpos = pObj.mBigPos;
		aRect = aImg:GetCelRect(pObj.mCurCell);
		pG:DrawImage(aImg:GetImage(), aRpos.x, aRpos.y, aRect);

      -- Draw containing box/circle
		local aBoxImg = IcImageWrap("PH_IMG_CMN_ZOOM_BOX");
		assert(aBoxImg);
		aRect = aBoxImg:GetCelRect(0);
		aRpos = pObj.mFrmPos;
		pG:DrawImage(aBoxImg:GetImage(), aRpos.x, aRpos.y, aRect);
	end


end

-- Moves a keylike object to the slot
cm.MoveToSlot = function(pObj, pTime, pShowParticles)

	local aSlot = pObj.mPdata.mBar:FindSlot(pObj.mId);
	if not aSlot then
		pObj.mPdata.mBar:AddSlot(pObj.mId);
		aSlot = pObj.mPdata.mBar:FindSlot(pObj.mId);
	end

	local aImg	= IcImageWrap(pObj.mSmallImage);
	local aX	= aSlot.mMover.mSmPos.x;
	local aY	= aSlot.mMover.mSmPos.y;
	aX = aX + (pObj.mPdata.mBar:GetSlotWidth()  - aImg:GetCelWidth())/2;
	aY = aY + (pObj.mPdata.mBar:GetSlotHeight() - aImg:GetCelHeight())/2;
	pObj:SmSetupMove(IcVector2d(aX, aY), IcSimpleMovement.IC_SMM_DECCEL, pTime);
	
	if pShowParticles then
		pObj:SetupParticleSystem("PH_PSYS_UNDYING_TRAIL");
		pObj:StartParticleEmission(pObj:GetFirstActive(0));
	end

	aSlot.mOccupied  = true;
	aSlot.mPobj		 = pObj;
	pObj.mCsData:SetVal("MovingToSlot", true);
	pObj.mCsData:SetVal("PrevZ", pObj.mZ);
	pObj.mZ = pObj.mZ + 10;

end

-- Updates Moving a keylike object to the slot
cm.MoveToSlotUpdate = function(pObj)

	local aKey = "MovingToSlot";
	if pObj.mCsData:GetBool(aKey) then
		if not pObj:SmIsMoving() then

	      pObj.mCsData:SetVal(aKey, false);
			pObj.mDiscovered = false;
			pObj.mZ = pObj.mCsData:GetInt("PrevZ");
			pObj:StopParticleEmission(false);
			IcPlaySample("PH_SFX_OBJ_IN_INV");

		end
	end
end


-- Shows text info
cm.ShowInfo = function(pObj, pText, pTime, pMode)

	local aMode = IcLevelPlayData.IC_LPIDM_NORMAL_INFO;
	if pMode then
		aMode = pMode;
	end
	
	local aTime = 120;
	if pTime then
		assert(pTime > 0);
		aTime = pTime;
	end
	pObj.mPdata:ShowInfo(pText, aMode, aTime);

end


-- Shows 'does not work' info
local aStrIndexNum = 1;
cm.ObjDoesNotWork = function(pObj, pMode, pTime)

	local aTxtArray = {
		"That object goes elsewhere",
		"This won't work",
		"This object can't be used here",
		"Nothing happens",
		"That wasn't useful"
		};

	local aTime = 120;
	if pTime then
		assert(pTime > 0);
		aTime = pTime;
	end

	cm.ShowInfo(pObj, aTxtArray[aStrIndexNum], aTime, pMode);
	IcPlaySample("PH_SFX_DOES_NOT_WORK");

	local aSize = #aTxtArray;
	aStrIndexNum = aStrIndexNum + 1;
	if(aStrIndexNum > aSize) then
	 aStrIndexNum = 1;
	end

end


-- Fades between two rects
cm.FadeImageRects = function(pObj, pG, pImg, pPos, pRect1, pRect2)

   local aAlpha = pObj.mAlpha:AncGetVal();
	pG:SetColorizeImages(true);

	if pObj.mCsData:GetBool("DontFadePrevious") then
		pG:SetColor(Color(255, 255, 255, 255));
	else
		pG:SetColor(Color(255, 255, 255, 255 - aAlpha/2));
	end
	pG:DrawImage(pImg:GetImage(), pPos.x, pPos.y, pRect1);

	pG:SetColor(Color(255, 255, 255, aAlpha));
	pG:DrawImage(pImg:GetImage(), pPos.x, pPos.y, pRect2);

end


-- Fades between two rects
cm.StartFadeImageRects = function(pObj)

   pObj.mCsData:SetVal("FadingToNext", true);
   pObj.mAlpha:AncEndChange();
   pObj.mAlpha:AncSetupChange(0.0, 255.0, PhFadeAnotherTimeLong,
    IcAutoNumChgr.IC_ANCM_LINEAR);

end

cm.UpdateImageRects = function(pObj)

   if pObj.mCsData.GetBool("FadingToNext") then
      if not pObj.mAlpha:AncIsChanging() then
         pObj.mCsData:SetVal("FadingToNext", false);
      end
   end

end

-- Shows info object data
cm.GetShowInfo = function(pObj, pInfoStrId, pInfoTimeId)

   local aInfoStr  = pObj.mCsData:GetString(pInfoStrId);
   local aInfoTime = pObj.mCsData:GetInt(pInfoTimeId);
   cm.ShowInfo(pObj, pObj.mGobj.mDataManager:GetString(aInfoStr), aInfoTime);

end



-- Sets a global flag from object csdata value
cm.SetGlobalValIndirect = function(pObj, pFlagName, pValue)
   local aFlag  = pObj.mCsData:GetString(pFlagName);
   pObj.mPdata.mCsData:SetVal(aFlag, pValue);
end


-- Gets a global bool flag from object csdata value
cm.GetGlobalBoolIndirect = function(pObj, pFlagName)
   local aFlag  = pObj.mCsData:GetString(pFlagName);
   return pObj.mPdata.mCsData:GetBool(aFlag);
end

-- Gets a global int flag from object csdata value
cm.GetGlobalIntIndirect = function(pObj, pFlagName)
   local aFlag  = pObj.mCsData:GetString(pFlagName);
   return pObj.mPdata.mCsData:GetInt(aFlag);
end

-- Gets a global float flag from object csdata value
cm.GetGlobalFloatIndirect = function(pObj, pFlagName)
   local aFlag  = pObj.mCsData:GetString(pFlagName);
   return pObj.mPdata.mCsData:GetFloat(aFlag);
end

cm.DisableObject = function(pObj)
	pObj:DisablePolys();
	pObj.mDiscovered = false;
	pObj:StopParticleEmission(false);
end


cm.LaunchPuzzle =  function(pObj)

   local aPuzzleType = pObj.mCsData:GetString("PuzzleType");
   if aPuzzleType == "Jigsaw" then
      local aPuzzleFlag = pObj.mCsData:GetString("PuzzleFlag");
      local aPuzzIndex  = pObj.mCsData:GetInt("PuzzleNum");
      AddJigsawWidget(pObj.mPdata, aPuzzleFlag, aPuzzIndex);
   elseif aPuzzleType == "Sequence" then
	   local aPuzzleFlag = pObj.mCsData:GetString("PuzzleFlag");
	   local aPuzzIndex = pObj.mCsData:GetInt("PuzzleNum");
	   AddSequenceWidget(pObj.mPdata, aPuzzleFlag, aPuzzIndex);
   elseif aPuzzleType == "Sliders" then
	   local aPuzzleFlag = pObj.mCsData:GetString("PuzzleFlag");
	   local aPuzzIndex = pObj.mCsData:GetInt("PuzzleNum");
	   AddSliderWidget(pObj.mPdata, aPuzzleFlag, aPuzzIndex);
   elseif aPuzzleType == "Memory" then
	   local aPuzzleFlag = pObj.mCsData:GetString("PuzzleFlag");
	   AddMemoryWidget(pObj.mPdata, aPuzzleFlag);
   elseif aPuzzleType == "Password" then
	   local aPuzzleFlag = pObj.mCsData:GetString("PuzzleFlag");
	   local aPuzzIndex = pObj.mCsData:GetInt("PuzzleNum");
	   AddPasswordPuzzleWidget(pObj.mPdata, aPuzzleFlag, aPuzzIndex);
   elseif aPuzzleType == "NumLock" then
      local aPuzzleFlag = pObj.mCsData:GetString("PuzzleFlag");
      local aPuzzSol    = pObj.mCsData:GetInt("PuzzleSolution");
      local aNumSlot    = pObj.mCsData:GetInt("PuzzleSlotNum");
      AddNumberLockWidget(pObj.mPdata, aPuzzleFlag, aNumSlot, aPuzzSol);
   elseif aPuzzleType == "Winding" then
      local aPuzzleFlag = pObj.mCsData:GetString("PuzzleFlag");
      local aPuzzSol    = pObj.mCsData:GetString("PuzzleSolution");
      AddWindingPuzzleWidget(pObj.mPdata, aPuzzleFlag, aPuzzSol);
   elseif aPuzzleType == "PressureController" then
      local aPuzzleFlag     = pObj.mCsData:GetString("PuzzleFlag");
      local aPuzzleFailFlag = pObj.mCsData:GetString("PuzzleFailFlag");
      local aPuzzDisabled   = pObj.mCsData:GetBool("PuzzleDisabled");
      AddPressureControllerWidget(pObj.mPdata, aPuzzleFlag, aPuzzleFailFlag, aPuzzDisabled);
   end
  	IcPlaySample("PH_SFX_CLOSER_LOOK");

end


