------ All content © 2008 DigiPen (USA) Corporation, all rights reserved. ------
-- Author: Hamza M. Hutchinson
-- Updated: 10/31/2008

dofile( "../../Assets/Scripts/util_math.lua" )

--------------------------------------------------------------------------------
-- Fuctions!
-- This might look redundant, but avoids costly global lookup
--------------------------------------------------------------------------------

local ENTITY = Entity
local PLAYER = Player

local PLAYER_gLantern                 = Player.gLantern
local PLAYER_gFallDist                = Player.gFallDist

local GLOBAL_CreateEntityAt           = Global.CreateEntityAt
local GLOBAL_DeleteEntityByPtr        = Global.DeleteEntityByPtr
local GLOBAL_GetIslandInfo            = Global.GetIslandInfo
local GLOBAL_gVineAnyEndPoint         = Global.gVineAnyEndPoint
local GLOBAL_PlaceOnVine              = Global.PlaceOnVine
local GLOBAL_SetScarfMaxSegments      = Global.SetScarfMaxSegments
local GLOBAL_AddScarfSegment          = Global.AddScarfSegment
local GLOBAL_MoveScarfTo              = Global.MoveScarfTo
local GLOBAL_SetGameMode              = Global.SetGameMode
local GLOBAL_TimeElapsed              = Global.TimeElapsed
local GLOBAL_gCameraPosition          = Global.gCameraPosition
local GLOBAL_JumpCameraPositionTarget = Global.JumpCameraPositionTarget
local GLOBAL_SetLetterboxDirection    = Global.SetLetterboxDirection
local GLOBAL_IsGameButtonHeldFor      = Global.IsGameButtonHeldFor
local GLOBAL_SetFade                  = Global.SetFade

local VEC3_construct                  = vec3.construct
local VEC3_assign3                    = vec3.assign3
local VEC3_copyThis                   = vec3.copyThis
local VEC3_add                        = vec3.add
local VEC3_subtract                   = vec3.subtract
local VEC3_subtractThis               = vec3.subtractThis
local VEC3_subtractTwo                = vec3.subtractTwo
local VEC3_multiplyThis               = vec3.multiplyThis
local VEC3_dot                        = vec3.dot
local VEC3_normalize                  = vec3.normalize
local VEC3_magnitude                  = vec3.magnitude

local MATH_abs                        = math.abs
local MATH_max                        = math.max
local MATH_min                        = math.min

local STRING_find                     = string.find
local STRING_len                      = string.len
local STRING_byte                     = string.byte
local STRING_sub                      = string.sub
local STRING_gsub                     = string.gsub

local ENTITY_GetName                  = Entity.GetName
local ENTITY_GetID                    = Entity.GetID
local ENTITY_GetMyPointer             = Entity.GetMyPointer
local ENTITY_GetMyPointer             = Entity.GetMyPointer
local ENTITY_SHR_Refresh              = Entity.SHR_Refresh
local ENTITY_SPT_GiveNumber           = Entity.SPT_GiveNumber
local ENTITY_SPT_RefreshNumbers       = Entity.SPT_RefreshNumbers
local ENTITY_SHR_gPosition            = Entity.SHR_gPosition
local ENTITY_SHR_sPosition            = Entity.SHR_sPosition
local ENTITY_SHR_gVelocity            = Entity.SHR_gVelocity
local ENTITY_SHR_sVelocity            = Entity.SHR_sVelocity
local ENTITY_PHY_Refresh              = Entity.PHY_Refresh


--------------------------------------------------------------------------------
-- Vars
--------------------------------------------------------------------------------

local ASSETS_XML = "../../Assets/Xml/"
local REVIVERFLY = "entities/e_ReviverFly.xml"

local myData = {}
local pos = ENTITY_SHR_gPosition( ENTITY )
local vel = ENTITY_SHR_gVelocity( ENTITY )
local vector = VEC3_construct( 0, 0, 0 )
local posPos
local camPosFinal = GLOBAL_gCameraPosition()
local lastVineID = -1
local fallTimer = 0

local offVecs = { 
                  [  0 ] = VEC3_construct(  1,  0,  0 ),
                  [  1 ] = VEC3_construct(  0,  1,  0 ),
                  [  2 ] = VEC3_construct(  0,  0,  1 ),
                  [  3 ] = VEC3_construct( -1,  0,  0 ),
                  [  4 ] = VEC3_construct(  0, -1,  0 ),
                  [  5 ] = VEC3_construct(  1,  0, -1 ),
                  [  6 ] = VEC3_construct(  1,  1,  0 ),
                  [  7 ] = VEC3_construct(  1,  0,  1 ),
                  [  8 ] = VEC3_construct(  0,  1,  1 ),
                  [  9 ] = VEC3_construct(  1, -1,  0 ),
                  [ 10 ] = VEC3_construct(  1,  0, -1 ),
                  [ 11 ] = VEC3_construct(  0,  1, -1 ),
                  max = 11
                }
local iter = 0
while( iter < offVecs.max ) do
  offVecs[ iter ] = VEC3_multiplyThis( offVecs[ iter ], 10 )
  iter = iter + 1
  
end
local revivers = 0
local reviverFlies = {}

local pathBack = { [ 0 ] = GLOBAL_GetIslandInfo( 0 ) }
local pathBackNodes = 1
local hasDied      = false
local isRebirthing = false


--------------------------------------------------------------------------------
-- Here's what we do if we've collided
--------------------------------------------------------------------------------

local function WithStuff( theKey, theValue )
  fallTimer = 0
  local theName = ENTITY_GetName( theValue )
  
  ------------------------------------------------------------------------------
  -- collided with vine?
  if( STRING_find( theName, "Vine" ) ~= nil ) 
  then
    lastVineID = ENTITY_GetID( theValue )
    if( myData.onVineEnd == 0.0 ) then
      GLOBAL_PlaceOnVine( ENTITY_GetMyPointer( ENTITY ), lastVineID )
    end
  end
  
end


--------------------------------------------------------------------------------
-- Death sequence/subtle Evangelion reference
--------------------------------------------------------------------------------

local function DeathAndRebirth( island )

  if( myData.reviverFly )
  then
    revivers = revivers + myData.reviverFly
    myData.reviverFly = nil
    
  end

  if( revivers >= offVecs.max )
  then
    --ENTITY_SHR_sPosition( ENTITY, island.x, island.y, island.z )
    hasDied  = false
    revivers = 0
    return true
    
  else
    return false
    
  end
end

--------------------------------------------------------------------------------
-- Start Aster on vine end
--------------------------------------------------------------------------------
local InitialVineEndPoint = Global:gVineEndPoint()
ENTITY_SHR_sPosition( Entity, InitialVineEndPoint.x, InitialVineEndPoint.y, InitialVineEndPoint.z )

--------------------------------------------------------------------------------
-- Initial scarf junk
--------------------------------------------------------------------------------

GLOBAL_SetScarfMaxSegments( 20 )
GLOBAL_AddScarfSegment()
GLOBAL_AddScarfSegment()
GLOBAL_AddScarfSegment()
GLOBAL_AddScarfSegment()
GLOBAL_AddScarfSegment()
GLOBAL_AddScarfSegment()
GLOBAL_AddScarfSegment()
GLOBAL_AddScarfSegment()
GLOBAL_AddScarfSegment()


--------------------------------------------------------------------------------
-- Loop
--------------------------------------------------------------------------------

local island
local FALL_DIST = PLAYER_gFallDist( PLAYER )
local FALL_TIME_MAX = 25
local fallTimeCheck = FALL_TIME_MAX
local MIN_MOVE = 15
local MAX_MOVE = 55
local FADE_AMOUNT = 0
local FALL_TIME = 150
while( 1 ) 
do
  coroutine.yield()
  
  ENTITY = Entity

  ENTITY_SHR_Refresh( ENTITY, myData, true, false, false, true )
  ENTITY_PHY_Refresh( ENTITY, myData, true )
  ENTITY_SPT_RefreshNumbers( ENTITY, myData )
  pos = myData.pos
  vel = myData.vel
  
  table.foreach( myData.collisions, WithStuff )
  
  camPosFinal = GLOBAL_gCameraPosition()
  
  if( myData.endSequence == nil )
  then
 
    ------------------------------------------------------------------------------
    --check to see if Aster is falling
    if( vel.y < 0 ) and ( not isRebirthing )
    then
      fallTimeCheck = fallTimeCheck + 1
      if( fallTimeCheck >= FALL_TIME_MAX )
      then
        fallTimeCheck = 0
        pathBack[ pathBackNodes ] = VEC3_construct( pos.x, pos.y + 20, pos.z )
        pathBackNodes = pathBackNodes + 1
      
      end
      
    end
    
    
    --------------------------------------------------------------------------------
    --not falling? any fading to undo?
    if( not hasDied ) and ( not isRebirthing )
    then
      -- undo our fading 
      if( FADE_AMOUNT > .9 ) then
        FADE_AMOUNT = MATH_max( 0, FADE_AMOUNT - .0001 * GLOBAL_TimeElapsed() )
        
      else
        if( FADE_AMOUNT > 0 )
        then 
          FADE_AMOUNT = FADE_AMOUNT - .001 * GLOBAL_TimeElapsed()
          GLOBAL_SetLetterboxDirection( -1.0 )
          
          -- reset our path
          if( pathBackNodes > 1 ) and ( vel.y >= 0 )
          then
            pathBack = { [ 0 ] = pathBack[ 0 ] }
            pathBackNodes = 1
            fallTimeCheck = FALL_TIME_MAX
            
          end
          
        end
      
      end
        
    end
    
    
    ------------------------------------------------------------------------------
    --check to see if Aster has fallen off an island or wants to blow up
    local TriggerDying = false
    fallTimer = fallTimer + 1
    if( ( not hasDied ) and ( not isRebirthing ) )
    then
      if( ( pos.y < FALL_DIST ) or
          ( ( fallTimer > FALL_TIME ) and ( pos.y < Global:gVineEndPoint().y - 20 ) ) )
      then
        TriggerDying = true
      end
    end
   
    if( TriggerDying )
    then
      GLOBAL_SetGameMode( false )
    
      hasDied = true
      if( lastVineID > -1 ) then
        pathBack[ 0 ] = GLOBAL_gVineAnyEndPoint( lastVineID, 1 )
        pathBack[ 0 ].y = pathBack[ 0 ].y + 5 -- account for Aster's height
        
      end
      
      GLOBAL_SetLetterboxDirection( 1.0 )
      
      local iter = 0
      while( iter < offVecs.max ) 
      do
        posPos = VEC3_add( pos, offVecs[ iter ] )
        reviverFlies[ iter ] = GLOBAL_CreateEntityAt( ASSETS_XML .. REVIVERFLY,          posPos.x, posPos.y, posPos.z, 0, 0, 0 )
                               GLOBAL_CreateEntityAt( ASSETS_XML .. "entities/e_ParticleFlash.XML", posPos.x, posPos.y, posPos.z, 0, 0, 0 )
        iter = iter + 1
      
      end
      
    end
   
   
    ------------------------------------------------------------------------------
    --has Aster died?
    if( hasDied ) 
    then
      FADE_AMOUNT = MATH_min( 1, FADE_AMOUNT + .00025 * GLOBAL_TimeElapsed() )
      if( DeathAndRebirth( island ) ) 
      then
        isRebirthing = true
        
        local iter = offVecs.max - 1
        while( iter > 0 )
        do
          posPos = ENTITY_SHR_gPosition( reviverFlies[ iter ] )
          GLOBAL_CreateEntityAt( ASSETS_XML .. "entities/e_ParticleFlash.XML", posPos.x, posPos.y, posPos.z, 0, 0, 0 )
          GLOBAL_DeleteEntityByPtr( reviverFlies[ iter ] )
          reviverFlies[ iter ] = nil
          
          iter = iter - 1
          
        end
      
      end
      
    end
   
   
    ------------------------------------------------------------------------------
    --are we returning?
    if( isRebirthing )
    then
      -- we're done returning
      if( pathBackNodes <= 1 )
      then
        GLOBAL_SetGameMode( true )
        
        isRebirthing  = false
        
        posPos = ENTITY_SHR_gPosition( reviverFlies[ 0 ] )
        GLOBAL_CreateEntityAt( ASSETS_XML .. "entities/e_ParticleFlash.XML", posPos.x, posPos.y, posPos.z, 0, 0, 0 )
        GLOBAL_DeleteEntityByPtr( reviverFlies[ 0 ] )
        reviverFlies[ 0 ] = nil
          
        ENTITY_SHR_sVelocity( ENTITY, 0, 0, 0 )
      
      -- cycling backward
      else
        FADE_AMOUNT = MATH_min( 1, FADE_AMOUNT + .0004 * GLOBAL_TimeElapsed() )
        -- if we're not completely faded, follow the path
        if( FADE_AMOUNT < 1 )
        then
          local pathMax = table.maxn( pathBack )
          local pathGoing = ( pathBackNodes > 1 )
          local pathCheck = 15
          
          if( not pathGoing ) then
            pathCheck = 3
            
          end
          
          -- are we close?
          if( VEC3_magnitude( VEC3_subtract( pos, pathBack[ pathMax ] ) ) < pathCheck )
          then
            pathBack[ pathMax ] = nil
            pathBackNodes = pathBackNodes - 1
            
          -- get closer
          else
            vector = VEC3_normalize( VEC3_subtract( pathBack[ pathMax ], pos ) )
            if( pathGoing ) then
              vector = VEC3_multiplyThis( vector, MAX_MOVE )
              
            else
              vector = VEC3_multiplyThis( vector, MIN_MOVE )
              
            end
            
            ENTITY_SHR_sVelocity( ENTITY, vector.x, vector.y, vector.z )
            
          end
          
        -- otherwise, just set us
        else
          pathBackNodes = 1
          local wereBack = pathBack[ 0 ]
          ENTITY_SHR_sPosition( ENTITY, wereBack.x, wereBack.y, wereBack.z )
          GLOBAL_JumpCameraPositionTarget( wereBack.x - 7, wereBack.y + 10, wereBack.z - 7,
                                           wereBack.x,     wereBack.y,      wereBack.z )
          
        end
          
      end
        
    end
  
  end
  
  --ENTITY_SPT_GiveNumber( PLAYER_gLantern( PLAYER ), "fadeAmount", FADE_AMOUNT )
  --Global.SetFade(FADE_AMOUNT)
  
end
