---------------------------------------------------------------------------
---------------------- API functions --------------------------------------
---------------------------------------------------------------------------
-- The functions defined here simplify the access to (some of)           --
-- the C++ classes and methods exported by the PinaCore C++ dll.         --
---------------------------------------------------------------------------

-- the (empty) table that will store the functions
api={}

function api:playMusic(p_File)
   --local soundMgr = getFMODSoundManager()
   --soundMgr:playMusic(p_File)
end

function api:playEffect(p_File)
   --local soundMgr = getFMODSoundManager()
   --soundMgr:playSample(p_File)
   SoundMgr:playFile(p_File)
end

function sound(p_File)
   SoundMgr:playFile(p_File .. ".ogg")
end

function api:playEffect_(p_File, p_Volume)
   --local soundMgr = getFMODSoundManager()
   --local channel = soundMgr:playSample(p_File)
   --soundMgr:setVolume(channel, p_Volume)
end

function api:animateMusicVolume(p_TargetVolume)
   --local soundMgr = getFMODSoundManager()
   --soundMgr:animateMusicVolume(p_TargetVolume)
end

---------------------------------------------------------------------------
-- fades the screen to black
---------------------------------------------------------------------------
function api:fadeOut()
   GameStateMgr:fadeOut(1.0)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- fades the screen to black in the given amount of time (in seconds)
---------------------------------------------------------------------------
function api:fadeOut_(p_BlendTime)
   GameStateMgr:fadeOut(p_BlendTime)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- fades the screen from black
---------------------------------------------------------------------------
function api:fadeIn()
   GameStateMgr:fadeIn(1.0)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- sets the visibility of the plate covering the whole screen
---------------------------------------------------------------------------
function api:setPlateVisible(p_Visible)
   if p_Visible then
      GameStateMgr:showPlate()
   else
      GameStateMgr:hidePlate()
   end
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- shows the plate covering the whole screen
---------------------------------------------------------------------------
function api:showPlate()
   api:setPlateVisible(true)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- hides the plate covering the whole screen
---------------------------------------------------------------------------
function api:hidePlate()
   api:setPlateVisible(false)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- fades the screen from black in the given amount of time (in seconds)
---------------------------------------------------------------------------
function api:fadeIn_(p_BlendTime)
   GameStateMgr:fadeIn(p_BlendTime)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- starts the conversation with the given name using a blend time of 1 second
-- if the conversation does not exist, it will be created
---------------------------------------------------------------------------
function api:conversation(p_ConversationName)
   -- check if the conversation already exists - create it if this is not the case
   if ConversationMgr:queryConversation(p_ConversationName) == ConversationManager.CS_NON_EXISTENT then
      ConversationMgr:createConversation(p_ConversationName)
   end
   -- we made sure the conversation exists, so we can safely start it
   ConversationMgr:startConversation(p_ConversationName,1.0)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- starts the conversation with the given name using the given blend time
-- if the conversation does not exist, it will be created
---------------------------------------------------------------------------
function api:conversation_(p_ConversationName, p_BlendTime)
   -- check if the conversation already exists - create it if this is not the case
   if ConversationMgr:queryConversation(p_ConversationName) == ConversationManager.CS_NON_EXISTENT then
      ConversationMgr:createConversation(p_ConversationName)
   end
   -- we made sure the conversation exists, so we can safely start it
   ConversationMgr:startConversation(p_ConversationName,p_BlendTime)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- starts the conversation with the given name using a blend time of 1 second
-- if the conversation does not exist, it will be created
-- In addition, the given lua function will be executed when the conversation
-- has come to an end
---------------------------------------------------------------------------
function api:conversation__(p_ConversationName, p_LuaFunctionOnConversationFinished)
   -- check if the conversation already exists - create it if this is not the case
   if ConversationMgr:queryConversation(p_ConversationName) == ConversationManager.CS_NON_EXISTENT then
      ConversationMgr:createConversation(p_ConversationName)
   end
   -- we made sure the conversation exists, so we can safely start it
   ConversationMgr:startConversation(p_ConversationName,1.0)
   subscribeConversationFinished(p_ConversationName, p_LuaFunctionOnConversationFinished)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- starts the conversation with the given name using the given blend time
-- if the conversation does not exist, it will be created
---------------------------------------------------------------------------
function api:conversation___(p_ConversationName, p_BlendTime, p_LuaFunctionOnFinished)
   -- check if the conversation already exists - create it if this is not the case
   if ConversationMgr:queryConversation(p_ConversationName) == ConversationManager.CS_NON_EXISTENT then
      ConversationMgr:createConversation(p_ConversationName)
   end
   -- we made sure the conversation exists, so we can safely start it
   ConversationMgr:startConversation(p_ConversationName,p_BlendTime)
   subscribeConversationFinished(p_ConversationName, p_LuaFunctionOnFinished)
end
---------------------------------------------------------------------------
   
---------------------------------------------------------------------------
-- cancels the given conversation (if it is running)
---------------------------------------------------------------------------
function api:cancelConversation(p_ConversationName)
   ConversationMgr:cancelConversation(p_ConversationName)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- starts the cutscene with the given name using a blend time of 1 second
-- if the cutscene does not exist, it will be created
---------------------------------------------------------------------------
function api:cutscene(p_CutsceneName)
   -- check if the cutscene already exists - create it if this is not the case
   if CutsceneMgr:queryCutscene(p_CutsceneName) == CutsceneManager.CS_NON_EXISTENT then
      CutsceneMgr:createCutscene(p_CutsceneName)
   end
   -- we made sure the cutscene exists, so we can safely start it
   CutsceneMgr:startCutscene(p_CutsceneName,1.0)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- starts the cutscene with the given name using the given blend time
-- if the cutscene does not exist, it will be created
---------------------------------------------------------------------------
function api:cutscene_(p_CutsceneName, p_BlendTime)
   -- check if the cutscene already exists - create it if this is not the case
   if CutsceneMgr:queryCutscene(p_CutsceneName) == CutsceneManager.CS_NON_EXISTENT then
      CutsceneMgr:createCutscene(p_CutsceneName)
   end
   -- we made sure the cutscene exists, so we can safely start it
   CutsceneMgr:startCutscene(p_CutsceneName,p_BlendTime)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- starts the cutscene with the given name using a blend time of 1 second
-- if the cutscene does not exist, it will be created
---------------------------------------------------------------------------
function api:cutscene__(p_CutsceneName, p_LuaFunctionOnFinished)
   -- check if the cutscene already exists - create it if this is not the case
   if CutsceneMgr:queryCutscene(p_CutsceneName) == CutsceneManager.CS_NON_EXISTENT then
      CutsceneMgr:createCutscene(p_CutsceneName)
   end
   -- we made sure the cutscene exists, so we can safely start it
   CutsceneMgr:startCutscene(p_CutsceneName,1.0)
   subscribeCutsceneFinished(p_CutsceneName, p_LuaFunctionOnFinished)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- starts the cutscene with the given name using the given blend time
-- if the cutscene does not exist, it will be created
---------------------------------------------------------------------------
function api:cutscene___(p_CutsceneName, p_BlendTime, p_LuaFunctionOnFinished)
   -- check if the cutscene already exists - create it if this is not the case
   if CutsceneMgr:queryCutscene(p_CutsceneName) == CutsceneManager.CS_NON_EXISTENT then
      CutsceneMgr:createCutscene(p_CutsceneName)
   end
   -- we made sure the cutscene exists, so we can safely start it
   CutsceneMgr:startCutscene(p_CutsceneName, p_BlendTime)
   subscribeCutsceneFinished(p_CutsceneName, p_LuaFunctionOnFinished)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- creates the converation with the given name
---------------------------------------------------------------------------
function api:createConversation(p_ConversationName)
   -- check if the conversation already exists, log a warning if that is the case
   if ConversationMgr:queryConversation(p_ConversationName) == ConversationManager.CS_NON_EXISTENT then
      ConversationMgr:createConversation(p_ConversationName)
   else
      _LogWarning(p_ConversationName,"conversation already exists")
   end
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- creates the cutscene with the given name
---------------------------------------------------------------------------
function api:createCutscene(p_CutsceneName)
   -- check if the conversation already exists, log a warning if that is the case
   if CutsceneMgr:queryCutscene(p_CutsceneName) == CutsceneManager.CS_NON_EXISTENT then
      CutsceneMgr:createCutscene(p_CutsceneName)
   else
      _LogWarning(p_CutsceneName,"cutscene already exists")
   end
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- subscribes the given lua function to the EventFinished event of the
-- given conversation
---------------------------------------------------------------------------
function api:subscribeConversationFinished(p_ConversationName, p_FunctionName)
   -- check if the conversation already exists, log a warning if that is not the case
   if ConversationMgr:queryConversation(p_ConversationName) == ConversationManager.CS_NON_EXISTENT then
      _LogWarning(p_ConversationName,"api:subscribeConversationFinished: conversation does not exist")
      ConversationMgr:createConversation(p_ConversationName)
   end
   ConversationMgr:subscribeConversationEvent(p_ConversationName,
					      "ConversationFinished",
					      p_FunctionName,
					      true)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- subscribes the given lua function to the EventFinished event of the
-- given cutscene
---------------------------------------------------------------------------
function api:subscribeCutsceneFinished(p_CutsceneName, p_FunctionName)
   -- check if the cutscene already exists, log a warning if that is not the case
   if CutsceneMgr:queryCutscene(p_CutsceneName) == CutsceneManager.CS_NON_EXISTENT then
      _LogWarning(p_CutsceneName,"api:subscribeCutsceneFinished: cutscene does not exist")
      CutsceneMgr:createCutscene(p_CutsceneName)
   end
   CutsceneMgr:subscribeCutsceneEvent(p_CutsceneName,
				      "EventCutsceneFinished",
				      p_FunctionName,
				      true)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- subscribes the given lua function to the named event of the given cutscene
---------------------------------------------------------------------------
function api:subscribeConversationEvent(p_ConversationName, p_EventName, p_FunctionName)
   -- check if the conversation already exists, log a warning if that is not the case
   if ConversationMgr:queryConversation(p_ConversationName) == ConversationManager.CS_NON_EXISTENT then
      _LogWarning(p_ConversationName,"subscribeConversationFinished: conversation does not exist")
      createConversation(p_ConversationName)
   end
   ConversationMgr:subscribeConversationEvent(p_ConversationName,
					      p_EventName,
					      p_FunctionName,
					      true)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- subscribes the given lua function to the named event of the given cutscene
---------------------------------------------------------------------------
function api:subscribeCutsceneEvent(p_CutsceneName, p_EventName, p_FunctionName)
   -- check if the cutscene already exists, log a warning if that is not the case
   if CutsceneMgr:queryCutscene(p_CutsceneName) == CutsceneManager.CS_NON_EXISTENT then
      _LogWarning(p_CutsceneName,"subscribeCutsceneFinished: cutscene does not exist")
      createCutscene(p_CutsceneName)
   end
   CutsceneMgr:subscribeCutsceneEvent(p_CutsceneName,
				      p_EventName,
				      p_FunctionName,
				      true)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- reinitializes the game meta data from the database
---------------------------------------------------------------------------
function api:reinitializeFromDatabase()
   _LogInfo("api:reinitializeFromDatabase", "InteractionMgr...")
   InteractionMgr:initializeFromDatabase()
   _LogInfo("api:reinitializeFromDatabase", "InteractorConfigurationMgr...")
   InteractorConfigurationMgr:initializeFromDatabase()
   if App:isUsingLocalizedStringTables() then
      _LogInfo("api:reinitializeFromDatabase", "StringTable...")
      StringTable:initializeFromDatabase()
   end
   _LogInfo("api:reinitializeFromDatabase", "Resetting Configs...")
   GameEntityMgr:resetInteractorConfigurations()
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- sets the visibility of the current's location objects by type
---------------------------------------------------------------------------
function api:setObjectsVisibleByType(p_ObjectType, p_Visible)
   local location=LocationMgr:getLocation(LocationMgr:getCurrentLocation())
   location:setInteractorsVisible(p_ObjectType, p_Visible)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- activates the camera with the given name
---------------------------------------------------------------------------
function api:camera(p_CameraName)
   CameraMgr:activateCamera(p_CameraName,0.0)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- lua does not support function overloading, so we add an underscore
---------------------------------------------------------------------------
function api:camera_(p_CameraName, p_BlendTime)
   CameraMgr:activateCamera(p_CameraName, p_BlendTime)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- executes the (lua) script with the given file name
---------------------------------------------------------------------------
function api:script(p_ScriptName)
   LuaInterpreter:executeScript(p_ScriptName)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- attaches the Controller named @a p_AnimName to the Controllable object
-- named @a p_Controllable and plays the animation
---------------------------------------------------------------------------
function api:animation(p_Controllable, p_AnimName)
   local controller=ControllerMgr:getController(p_AnimName)
   controller:setCycleType(AnimationController.Detach)
   controller:reset()
   controller:setAnimationLocality(AnimationController.Global)
   local obj=GameEntityMgr:getGameEntity(p_Controllable)
   obj:attachController(p_AnimName)
   ControllerMgr:resumeController(p_AnimName)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- attaches the Controller named @a p_AnimName to the Controllable object
-- named @a p_Controllable and plays the animation
---------------------------------------------------------------------------
function api:_animation(p_Controllable, p_AnimName, p_BlockTime)
   local ctrlName = p_Controllable .. "/" .. p_AnimName
   local controller=ControllerMgr:getController(ctrlName)
   controller:setCycleType(AnimationController.Detach)
   controller:reset()
   controller:setAnimationLocality(AnimationController.Global)
   local obj=GameEntityMgr:getGameEntity(p_Controllable)
   obj:attachController(ctrlName)
   ControllerMgr:resumeController(ctrlName)
   MouseIface:blockInput(p_BlockTime)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- attaches the Animated Object named @a p_AnimObj to the Character
-- named @a p_Character on the Bone named @a p_Bone only if not already
-- attached
---------------------------------------------------------------------------
function api:attachToBoneSafely(p_Character, p_AnimObj, p_Bone)
   local character = GameEntityMgr:getCharacter(p_Character)
   if not character:isAttachedToBone(p_AnimObj) then
      character:attachToBone(p_AnimObj,p_Bone)
   end
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- detaches the Animated Object named @a p_AnimObj from the Character
-- named @a p_Character only if it is really attached
---------------------------------------------------------------------------
function api:detachFromBoneSafely(p_Character, p_AnimObj)
   local character = GameEntityMgr:getCharacter(p_Character)
   if character:isAttachedToBone(p_AnimObj) then
      character:detachFromBone(p_AnimObj)
   end
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
---------------------------------------------------------------------------
function api:checkIactors(p_Interactor, p_InteractedInteractor,
			  p_InteractorString, p_InteractedInteractorString)
   if (p_Interactor == p_InteractorString and 
       p_InteractedInteractor == p_InteractedInteractorString) or
      (p_Interactor == p_InteractedInteractorString and
       p_InteractedInteractor == p_InteractorString) then
      return true
   else
      return false
   end
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
---------------------------------------------------------------------------
function iaction(p_Interactor, p_InteractedInteractor,
		 p_InteractorString, p_InteractedInteractorString)
   if (p_Interactor == p_InteractorString and 
       p_InteractedInteractor == p_InteractedInteractorString) or
      (p_Interactor == p_InteractedInteractorString and
       p_InteractedInteractor == p_InteractorString) then
      return true
   else
      return false
   end
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- toggles the control gui window visibility
---------------------------------------------------------------------------
function api:toggleGUIWindow(p_GUIWindow)
   if GUIWindowMgr:isVisible(p_GUIWindow) then
      GUIWindowMgr:setVisible(p_GUIWindow, false)
   else
      GUIWindowMgr:setVisible(p_GUIWindow, true)
   end
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- adds the given item to the inventory (if it is not there alredy)
---------------------------------------------------------------------------
function give(p_Item)
   Inventory:addItemSafely("item_" .. p_Item)
end
---------------------------------------------------------------------------
---------------------------------------------------------------------------
-- removes the given item to the inventory (if it is not there already)
---------------------------------------------------------------------------
function takeAway(p_Item)
   Inventory:removeItemSafely("item_" .. p_Item)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
-- calls the function after the given amount of time
---------------------------------------------------------------------------
function api:callDelayed(p_Function, p_Time)
   TimedEventMgr:createTimedEvent(p_Function, p_Time)
end
---------------------------------------------------------------------------

---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
function msg(p_Text)
   App:showDebugText(p_Text, 2.0)
end
---------------------------------------------------------------------------

function api:setMainCharacter(p_Character)
   if GameEntityMgr:getMainCharacter() ~= p_Character then
      Ankh:toggleMainChar()
   end
end
---------------------------------------------------------------------------
function api:getDistanceSqr(p_Vec1,p_Vec2)
   local x = p_Vec1.x-p_Vec2.x
   local y = p_Vec1.y-p_Vec2.y
   local z = p_Vec1.z-p_Vec2.z
   return PinaVector3(x,y,z):getNormSqr()
end
---------------------------------------------------------------------------
