------ All content © 2008 DigiPen (USA) Corporation, all rights reserved. ------
-- Author: Ian Eller
-- Updated: 09/22/2008, ice

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

--------------------------------------------------------------------------------
-- Convert vector into view space
--------------------------------------------------------------------------------

local function ConvertToCamDir( v, camDir )
  camDir.forw, camDir.side = Global:gCameraDirection()
  
  v = vec3.normalize( vec3.construct( vec3.dot( vec3.normalize( vec3.construct( camDir.forw.x, camDir.up.x, camDir.side.x ) ), v ),
                                      vec3.dot( vec3.normalize( vec3.construct( camDir.forw.y, camDir.up.y, camDir.side.y ) ), v ),
                                      vec3.dot( vec3.normalize( vec3.construct( camDir.forw.z, camDir.up.z, camDir.side.z ) ), v ) ) )
  return v 
end


--------------------------------------------------------------------------------
-- Vaaaars!
--------------------------------------------------------------------------------

local GAMEMODENONE   = Global:GameModeNONE()
local GAMEMODECAMERA = Global:GameModeCAMERA()
local GAMEMODEFULL   = Global:GameModeFULL()

local BUTTON_ENTITY    = "1"
local BUTTON_LOAD      = "2"
local BUTTON_SAVE      = "3"
local BUTTON_ATTACH    = "4"
local BUTTON_EDITMODE  = "5"
local BUTTON_PLANEMODE = "6"
local BUTTON_NEW       = "0"
local BUTTON_NEWISLE   = "Numpad 0"
local BUTTON_FOR = "Arrow Up"
local BUTTON_BAK = "Arrow Down"
local BUTTON_RGT = "Arrow Right"
local BUTTON_LFT = "Arrow Left"
local BUTTON_RESELECT = "Backspace" 
local BUTTON_TABTHRU  = "Tab"
local BUTTON_SCROLLUP = "Wheel Up"
local BUTTON_SCROLLDN = "Wheel Down"
local BUTTON_PLUS  = "Numpad +"
local BUTTON_MINUS = "Numpad -"
local BUTTON_ISLANDJUMP = "Numpad Enter"
local BUTTON_FORCEDPENETRATION = "Numpad *"
local BUTTON_DOCKINGINFO = "Control Left"

local ENT_MODE = 0
local LGT_MODE = 1
local ISL_MODE = 2
local eEditMode = ENT_MODE
local entityModes = { [ ENT_MODE ] = "Entities", [ LGT_MODE ] = "Lights", [ ISL_MODE ] = "Islands" }

local POS_MODE = 0
local ROT_MODE = 1
local cEditMode = POS_MODE
local editModes = { [ POS_MODE ] = "Positioning(" .. BUTTON_EDITMODE .. "):", [ ROT_MODE ] = "Rotating(" .. BUTTON_EDITMODE .. "):" }

local XZ_MODE = 0
local X_MODE  = 0
local Y_MODE  = 1
local Z_MODE  = 2
local pEditMode = XZ_MODE
local planeModes = { [ 0 ] = { [ XZ_MODE ] = "XZ", [ Y_MODE ] = "Y" },
                     [ 1 ] = { [ X_MODE ]  = "X",  [ Y_MODE ] = "Y", [ Z_MODE ] = "Z" } }
                     
local enteringTextMusicLayer  = "Music Layer:\n1 - 9"
local enteringTextMusicAction = "Music Action:\n1 - PUSH\n2 - REPLACE\n3 - REMOVE"
local enteringTextMusicFileA  = "Music File (area):\n1 - 3"
local enteringTextMusicFileP  = "Music File (piece):\n2 - 6"
local enteringTextPoem        = "Poem:"
local enteringTextModes = { enteringText = 0,
                            dockingText = "",
                            [ 1 ] = { xmlText = "musicLayer", text = "Music Layer:\n1 - 9\n\n" },
                            [ 2 ] = { xmlText = "musicAction", text = "Music Action:\n1 - PUSH\n2 - REPLACE\n3 - REMOVE\n\n" },
                            [ 3 ] = { xmlText = "musicFile", text = "Music File (area_piece):\nArea, 1 - 3\nPiece, 2 - 6\n\n" },
                            [ 4 ] = { xmlText = "poem", text = "Poem:\n\n" }
                          }
enteringTextModes.enteringTextMax = table.maxn( enteringTextModes )                          

local myData  = Entity:Data()
local visible = false

-- move the camera with me
myData.mover = Global:CreateEntity( "../../Assets/XML/entities/e_Nentity.xml" )
myData.moverSpeed = 1
-- text galore!
myData.newText    = Global:CreateEntityAt( "../../Assets/XML/entities/editor_Button.xml", 600,   0, 0, 0, 0, 0 )
myData.loadText   = Global:CreateEntityAt( "../../Assets/XML/entities/editor_Button.xml", 750,   0, 0, 0, 0, 0 )
myData.saveText   = Global:CreateEntityAt( "../../Assets/XML/entities/editor_Button.xml", 900,   0, 0, 0, 0, 0 )
myData.modeText   = Global:CreateEntityAt( "../../Assets/XML/entities/editor_Button.xml", 400, 752, 0, 0, 0, 0 )
myData.planeText  = Global:CreateEntityAt( "../../Assets/XML/entities/editor_Button.xml", 870, 752, 0, 0, 0, 0 )
myData.enterText  = Global:CreateEntityAt( "../../Assets/XML/entities/editor_Button.xml",   0, 752, 0, 0, 0, 0 )
myData.attachText = Global:CreateEntityAt( "../../Assets/XML/entities/editor_Button.xml",   0, 740, 0, 0, 0, 0 )
myData.camRelText = Global:CreateEntityAt( "../../Assets/XML/entities/editor_Button.xml",   0,  80, 0, 0, 0, 0 )
myData.messageText = 
            { ent = Global:CreateEntityAt( "../../Assets/XML/entities/editor_Button.xml", 350, 400, 0, 0, 0, 0 ),
              txt = "",
              aaa = 0,
              bbb = 0 }
-- who's selected?
myData.selected     = myData.mover
myData.selectedFile = nil
myData.selectedOld     = myData.mover
myData.selectedOldFile = nil
myData.selectedAcc = { x = 0, y = 0, z = 0 }
myData.selectedVel = { x = 0, y = 0, z = 0 }
myData.selectedOldAcc = { x = 0, y = 0, z = 0 }
myData.selectedOldVel = { x = 0, y = 0, z = 0 }
-- island selection
myData.island = 0
myData.islander = Global:CreateEntity( "../../Assets/XML/entities/game_Islander.xml" )
myData.islandName = ""
-- translating into our coordinate system
myData.camDir = { forw = { x = 1, y = 0, z = 0 }, 
                  up   = { x = 0, y = 1, z = 0 },
                  side = { x = 0, y = 0, z = 1 } }
                  
                  
--------------------------------------------------------------------------------
-- Move entity function
--------------------------------------------------------------------------------

local function MoveEntity( pEditMode, range )
  local update = vec3.construct( 0.0, 0.0, 0.0 )
  if( pEditMode == XZ_MODE ) 
  then
    if( range.x == 0 ) and ( range.z ~= 0 ) then
      range.x = -range.z
      range.z = 0
    
    elseif( range.z == 0 ) and ( range.x ~= 0 ) then
      range.z = range.x
      range.x = 0
    
    elseif( ( range.x > 0 ) and ( range.z > 0 ) ) or
      ( ( range.x < 0 ) and ( range.z < 0 ) ) then
      range.x = -range.x
    
    else
      range.z = -range.z
      
    end
  
    update.x = range.x
    update.y = 0
    update.z = range.z
  
  elseif( pEditMode == Y_MODE ) 
  then
    update.x = 0
    update.y = -range.z
    update.z = 0
  
  end

  return update
end


--------------------------------------------------------------------------------
-- Rotate entity function
--------------------------------------------------------------------------------

local function RotateEntity( pEditMode, range )
  local update = vec3.construct( 0.0, 0.0, 0.0 )
  if( pEditMode == X_MODE ) 
  then
    update.x = range.x
    update.y = 0
    update.z = 0
  
  elseif( pEditMode == Y_MODE ) 
  then
    update.x = 0
    update.y = range.x
    update.z = 0
  
  elseif( pEditMode == Z_MODE ) 
  then
    update.x = 0
    update.y = 0
    update.z = range.x
  
  end

  return update
end


--------------------------------------------------------------------------------
-- Swap physics data
--------------------------------------------------------------------------------

local function PhyDataSwap( e )
  if( myData.selected:PHY_Has() ) 
  then
    myData.selected:PHY_SetAccel(  myData.selectedAcc.x, myData.selectedAcc.y, myData.selectedAcc.z )
    myData.selected:SHR_sVelocity( myData.selectedVel.x, myData.selectedVel.y, myData.selectedVel.z )
    
  end
  if( e:PHY_Has() )
  then
    myData.selectedAcc = e:PHY_GetAccel()
    myData.selectedVel = e:SHR_gVelocity()
    e:PHY_SetAccel( 0, 0, 0 )
    e:SHR_sVelocity( 0, 0, 0 )
    
  end
          
end


--------------------------------------------------------------------------------
-- Main execution loop
--------------------------------------------------------------------------------

local maxIslands
local checkForPicked = false
local movingAlongPlane = false
local enteringText = 0
local ENTERING_ISLANDNAME = 1
local ENTERING_DOCKINGINFO = 2
local MESSAGE_TIME = 70
myData.messageText.bbb = MESSAGE_TIME
while( 1 ) 
do
  coroutine.yield( 1 )
  
  maxIslands = Editor:GetTotalIslands()
  local islePos = ( maxIslands ~= 0 ) and Editor:GetIslandPosition( myData.island ) or vec3.construct( 0.0, 0.0, 0.0 )
  myData.islander:SHR_sPosition( islePos.x, islePos.y, islePos.z )
  
  local camPos = Global:gCameraPosition()
  local camDir = Global:gCameraDirection()
  local attachedIslePos = Editor:GetIslandPosition( myData.island )
  local camRelPos = vec3.subtract( camPos, attachedIslePos )
    
  --[[
  if( Global:IsTriggered( key_names_to_values( "F3" ) ) ) 
  then
    visible = not visible
    
    -- Show only our debug lines
    Global:SetDebug( visible )
    Global:SetDebugLineLayer( visible, 1 )
    
    -- give us our cursor
    Global:ShowCursor( visible )
    Global:ContainCursor( not visible )
    
    -- toggle game mode
    Global:SetGameMode( not visible )
    
    -- who do we look at?
    if( visible ) then
      Global:SetCameraTargetObject( myData.mover )
      
    else
      local lantern = Player:gLantern()
      lantern:SPT_GiveNumber( "TakeCamera", 1.0 )
      
    end
  
  end
  --]]
    
    
  ------------------------------------------------------------------------------
  -- Toggle debug
  ------------------------------------------------------------------------------
  
  if( Global:IsTriggered( key_names_to_values( "Tilde" ) ) ) 
  then
    Global:SetDebugLineLayer( showDebug, 1 )
    showDebug = not showDebug
  
  end
    
    
  ------------------------------------------------------------------------------
  -- Do the shit
  ------------------------------------------------------------------------------
  
  if( visible )
  then
    
    ----------------------------------------------------------------------------
    -- Mover
    ----------------------------------------------------------------------------
    
    local moverPos    = myData.mover:SHR_gPosition()
    local moverUpdate = vec3.construct( 0, 0, 0 )
    if( Global:IsPressed( key_names_to_values( "w" ) ) ) then
      moverUpdate.x = .25
      
    elseif( Global:IsPressed( key_names_to_values( "s" ) ) ) then
      moverUpdate.x = -.25
      
    end
    if( Global:IsPressed( key_names_to_values( "q" ) ) ) then
      moverUpdate.y = .25
      
    elseif( Global:IsPressed( key_names_to_values( "e" ) ) ) then
      moverUpdate.y = -.25
      
    end
    if( Global:IsPressed( key_names_to_values( "a" ) ) ) then
      moverUpdate.z = -.25
      
    elseif( Global:IsPressed( key_names_to_values( "d" ) ) ) then
      moverUpdate.z = .25
      
    end
    
    moverPos = vec3.add( moverPos, vec3.multiply( ConvertToCamDir( moverUpdate, myData.camDir ), myData.moverSpeed ) )
    myData.mover:SHR_sPosition( moverPos.x, 
                                moverPos.y, 
                                moverPos.z )
    
    
    ----------------------------------------------------------------------------
    -- Mover speed
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( BUTTON_PLUS ) ) ) or
      ( Global:IsTriggered( key_names_to_values( "Page Up" ) ) ) 
    then
      if( myData.moverSpeed > 1 ) then
        myData.moverSpeed = myData.moverSpeed + 1
        
      else
        myData.moverSpeed = myData.moverSpeed + .1
        
      end
    
    elseif( Global:IsTriggered( key_names_to_values( BUTTON_MINUS ) ) ) or
          ( Global:IsTriggered( key_names_to_values( "Page Down" ) ) ) 
    then
      if( myData.moverSpeed > 1 ) then
        myData.moverSpeed = math.max( myData.moverSpeed - 1, 1 )
        
      else
        myData.moverSpeed = math.max( myData.moverSpeed - .1, 0 )
        
      end
    
    end
    
    
    ----------------------------------------------------------------------------
    -- Mover jump to island
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( BUTTON_ISLANDJUMP ) ) or
        Global:IsTriggered( key_names_to_values( "j" ) )  ) 
    then
      myData.mover:SHR_sPosition( islePos.x, 
                                  islePos.y, 
                                  islePos.z )
      Player:gAster():SHR_sPosition( islePos.x, 
                                     islePos.y, 
                                     islePos.z )
    
    end
    
    
    ----------------------------------------------------------------------------
    -- Switching camera
    ----------------------------------------------------------------------------
    
    if( Global:IsMouseTriggered( mouse_names_to_values( "Mouse Middle" ) ) ) 
    then
      local isInGameMode = Global:IsInGameMode()
      if( isInGameMode ~= GAMEMODECAMERA ) then
        Global:SetGameMode( GAMEMODECAMERA )
        
      else
        Global:SetGameMode( GAMEMODENONE )
        
      end
    
      local showAndContain = ( isInGameMode == GAMEMODECAMERA )
      Global:ShowCursor   ( showAndContain     )
      Global:ContainCursor( not showAndContain )
      
    end
    
  ------------------------------------------------------------------------------
  -- Entering text?
  ------------------------------------------------------------------------------
    
  if( enteringText == ENTERING_ISLANDNAME ) 
  then
    
    ----------------------------------------------------------------------------
    -- Created a new island; reading user input
    ----------------------------------------------------------------------------
    
    myData.islandName = Global:GetCurrentInput()
    if( Global:IsTriggered( key_names_to_values( "Enter" ) ) )
    then
      enteringText = 0
      
      Editor:NewIsland( myData.islandName, camDir.x + camPos.x, 
                                           camDir.y + camPos.y, 
                                           camDir.z + camPos.z )
      myData.islandName = ""
    
    end
    
  elseif( enteringText == ENTERING_DOCKINGINFO ) 
  then
    
    ----------------------------------------------------------------------------
    -- Entering docking information
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( "Enter" ) ) ) 
    then
      --where are we?
      if( enteringTextModes.enteringText < 3 ) then                     -- musicLayer, musicAction are numbers
        -- new info
        myData.selected:SPT_GiveNumberEx( enteringTextModes[ enteringTextModes.enteringText ].xmlText, tonumber( enteringTextModes.dockingText ), '\0' )
        
      elseif( enteringTextModes.enteringText == 3 ) then                -- musicFile needs .mp3 added at end
        -- new info
        enteringTextModes.dockingText = "../../Assets/Sounds/music_" .. enteringTextModes.dockingText .. ".mp3"
        myData.selected:SPT_GiveStringEx( enteringTextModes[ enteringTextModes.enteringText ].xmlText, enteringTextModes.dockingText )
        
      elseif( enteringTextModes.enteringText == 4 ) then                -- poem has special circumstances
        -- new info
        myData.selected:SPT_GiveStringEx( enteringTextModes[ enteringTextModes.enteringText ].xmlText, enteringTextModes.dockingText )
        
      end
      
      enteringTextModes.enteringText = enteringTextModes.enteringText + 1
      
      if( enteringTextModes.enteringText > enteringTextModes.enteringTextMax ) 
      then
        myData.messageText.txt = "Complete!"
        myData.messageText.aaa = 0
        myData.messageText.bbb = MESSAGE_TIME
        enteringTextModes.enteringText = 0
        
        enteringText = 0
        
      end
      
    else
      if( enteringTextModes.enteringText <= enteringTextModes.enteringTextMax ) 
      then
        enteringTextModes.dockingText = Global:GetCurrentInput()
        myData.messageText.txt = enteringTextModes[ enteringTextModes.enteringText ].text .. "Input:" .. enteringTextModes.dockingText
      
      end
    
    end
    
    
  ------------------------------------------------------------------------------
  -- More than entering text
  ------------------------------------------------------------------------------
    
  else
    
    ----------------------------------------------------------------------------
    -- Picking
    ----------------------------------------------------------------------------
    
    if( Global:IsMouseTriggered( mouse_names_to_values( "Mouse Left" ) ) ) and ( Global:IsInGameMode() == GAMEMODENONE )
    then
      if( eEditMode == ENT_MODE ) 
      then
        checkForPicked = true
        Editor:PickEntity( Global:gMouseXY() )
        
      elseif( eEditMode == LGT_MODE ) then
        movingAlongPlane = true
        
      end
      
    end
    
    if( checkForPicked )
    then
      checkForPicked = false
      local e = Global:FindEntityByID( Editor:GetCurrentPicked() )
      if( e ) 
      then
        if( e == myData.selected ) then
          movingAlongPlane = true
          
        else
        
          -- save physics data for old selection
          myData.selectedOldAcc = myData.selectedAcc
          myData.selectedOldVel = myData.selectedVel
        
          -- check physics data for selections, modify
          PhyDataSwap( e )
          
          -- store old selection, change new selection
          myData.selectedOld = myData.selected
          myData.selectedOldFile = myData.selectedFile
          myData.selected = e
        
        end
        
      end
    
    end
    
    
    ----------------------------------------------------------------------------
    -- Attached lines
    ----------------------------------------------------------------------------
    
    local areWeAttached = Editor:FindAttachedIsland( myData.selected )
    if( myData.selected )
    then
      if( areWeAttached > -1 )
      then
        local islePos = Editor:GetIslandPosition( areWeAttached )
        local entiPos = myData.selected:SHR_gPosition()
        Editor:AttachedDebugLine( islePos.x, islePos.y, islePos.z,
                                  entiPos.x, entiPos.y, entiPos.z,
                                        1.0,       1.0,       0.0,
                                                                1 )
                                                                
      end
        
    end
    
    
    ----------------------------------------------------------------------------
    -- Backspace
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( BUTTON_RESELECT ) ) )
    then
      -- give selected entity back their physics
      if( myData.selected:PHY_Has() )
      then
        myData.selected:PHY_SetAccel(  myData.selectedAcc.x, myData.selectedAcc.y, myData.selectedAcc.z )
        myData.selected:SHR_sVelocity( myData.selectedVel.x, myData.selectedVel.y, myData.selectedVel.z )
        
      end
      if( myData.selectedOld:PHY_Has() )
      then
        myData.selectedOld:PHY_SetAccel(  myData.selectedOldAcc.x, myData.selectedOldAcc.y, myData.selectedOldAcc.z )
        myData.selectedOld:SHR_sVelocity( myData.selectedOldVel.x, myData.selectedOldVel.y, myData.selectedOldVel.z )
        
      end
      
      myData.selected = myData.selectedOld
      myData.selectedFile = myData.selectedOldFile
    
    end
    
    
    ----------------------------------------------------------------------------
    -- Tab
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( BUTTON_TABTHRU ) ) )
    then
      local e = Editor:TabCurrentPicked( myData.selected, areWeAttached, myData.island )
      
      PhyDataSwap( e )
      myData.selected = e
    
    end
    
    
    ----------------------------------------------------------------------------
    -- Moving with mouse
    ----------------------------------------------------------------------------
    
    ----------------------------------------------------------------------------
    -- Moving entities
    if( movingAlongPlane ) and ( eEditMode == ENT_MODE )
    then
      local range = Global:gRangeState( 1 )
          
      --------------------------------------------------------------------------
      -- Movement
      if( cEditMode == POS_MODE )
      then
        local pos = myData.selected:SHR_gPosition()
        local moverPos = myData.mover:SHR_gPosition()
        local update = MoveEntity( pEditMode, range )
        
        pos = vec3.add( pos, vec3.multiply( ConvertToCamDir( vec3.normalize( update ), myData.camDir ),  .5 * myData.moverSpeed ) )
        myData.selected:SHR_sPosition( pos.x, pos.y, pos.z )
        moverPos = vec3.add( moverPos, vec3.multiply( ConvertToCamDir( vec3.normalize( update ), myData.camDir ), .4 * myData.moverSpeed ) )
        myData.mover:SHR_sPosition( moverPos.x, moverPos.y, moverPos.z )
        
      --------------------------------------------------------------------------
      -- Rotating
      elseif( cEditMode == ROT_MODE ) and ( eEditMode == ENT_MODE )
      then
        local rot = myData.selected:SHR_gRotation()
        local update = RotateEntity( pEditMode, range )
        
        rot = vec3.add( rot, ConvertToCamDir( vec3.normalize( update ), myData.camDir ) )
        myData.selected:SHR_sRotation( rot.x, rot.y, rot.z )
      
      end
      
      -- still moving?
      movingAlongPlane =  Global:IsMousePressed( mouse_names_to_values( "Mouse Left" ) )
      
    end
      
    ----------------------------------------------------------------------------
    -- Adjusting lights
    if( eEditMode == LGT_MODE ) and ( not Global:IsMouseTriggered( mouse_names_to_values( "Mouse Right" ) ) )
    then
      local rad = myData.selected:VIS_GetLightRadius()
      if( Global:IsMouseTriggered( mouse_names_to_values( BUTTON_SCROLLUP ) ) ) then
        myData.selected:VIS_SetLightRadius( rad + 1 )
      
      elseif( Global:IsMouseTriggered( mouse_names_to_values( BUTTON_SCROLLDN ) ) ) then
        myData.selected:VIS_SetLightRadius( rad - 1 )
      
      end
    
    end
    
    
    ---------------------------------------------------------------------------
    -- Moving with keyboard
    ----------------------------------------------------------------------------
    
    local keyboardMoves = false  
    local keyboardRange = vec3.construct( 0.0, 0.0, 0.0 )      
    if( Global:IsPressed( key_names_to_values( BUTTON_FOR ) ) ) 
    then
      keyboardRange.z = -1
      keyboardMoves = true
        
    elseif( Global:IsPressed( key_names_to_values( BUTTON_BAK ) ) ) 
    then
      keyboardRange.z = 1
      keyboardMoves = true
      
    elseif( Global:IsPressed( key_names_to_values( BUTTON_RGT ) ) ) 
    then
      keyboardRange.x = 1
      keyboardMoves = true
    
    elseif( Global:IsPressed( key_names_to_values( BUTTON_LFT ) ) ) 
    then
      keyboardRange.x = -1
      keyboardMoves = true
    
    end
        
    if( keyboardMoves )
    then
      if( cEditMode == POS_MODE )
      then
      
        --------------------------------------------------------------------------
        -- Moving entities or lights
        if( eEditMode == ENT_MODE ) or ( eEditMode == LGT_MODE )
        then
          local pos = myData.selected:SHR_gPosition()
          local moverPos = myData.mover:SHR_gPosition()
          local update = MoveEntity( pEditMode, keyboardRange )
          
          pos = vec3.add( pos, vec3.multiply( ConvertToCamDir( vec3.normalize( update ), myData.camDir ), .5 * myData.moverSpeed  ) )
          myData.selected:SHR_sPosition( pos.x, pos.y, pos.z )
          moverPos = vec3.add( moverPos, vec3.multiply( ConvertToCamDir( vec3.normalize( update ), myData.camDir ), .4 * myData.moverSpeed  ) )
          myData.mover:SHR_sPosition( moverPos.x, moverPos.y, moverPos.z )
        
        
        --------------------------------------------------------------------------
        -- Moving islands
        elseif( eEditMode == ISL_MODE )
        then
          local isleDir = vec3.multiply( ConvertToCamDir( MoveEntity( pEditMode, keyboardRange ), myData.camDir ), myData.moverSpeed )
          if( Global:IsPressed( key_names_to_values( "Shift Left" ) ) ) or
            ( Global:IsPressed( key_names_to_values( "Shift Right" ) ) ) then
            Editor:ShiftIslander( myData.island, isleDir.x, isleDir.y, isleDir.z )
            
          else
            Editor:ShiftIsland( myData.island, isleDir.x, isleDir.y, isleDir.z )
            
          end
          
        end
      
      elseif( cEditMode == ROT_MODE )
      then
      
        --------------------------------------------------------------------------
        -- Rotating entities or lights
        if( eEditMode == ENT_MODE )
        then
          local rot = myData.selected:SHR_gRotation()
          local update = RotateEntity( pEditMode, keyboardRange )
          rot = vec3.add( rot, ConvertToCamDir( vec3.normalize( update ), myData.camDir ) )
          myData.selected:SHR_sRotation( rot.x, rot.y, rot.z )
          
        end
      
      end
    
    end


    ----------------------------------------------------------------------------
    -- Forced penetration
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( BUTTON_FORCEDPENETRATION ) ) or
        Global:IsTriggered( key_names_to_values( "v" ) ) )
        and ( eEditMode == ENT_MODE )
    then
      if( myData.selected ) then
        myData.selected:SPT_GiveNumber( "forcedPenetration", 1 )
        
      end
      
    end


    ----------------------------------------------------------------------------
    -- Forced penetration
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( BUTTON_DOCKINGINFO ) )
        and ( eEditMode == ENT_MODE ) )
    then
      enteringText = ENTERING_DOCKINGINFO
      enteringTextModes.enteringText = 1
      myData.messageText.txt = enteringTextModes[ enteringTextModes.enteringText ].xmlText
      
      Global:ClearCurrentInput()
      
    end


    ----------------------------------------------------------------------------
    -- New, Loading or Saving
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( BUTTON_NEW ) ) ) and ( eEditMode == ISL_MODE ) 
    then
      Global:ClearCurrentInput()
      enteringText = ENTERING_ISLANDNAME
      
    elseif( Global:IsTriggered( key_names_to_values( BUTTON_LOAD ) ) ) 
    then
      if( eEditMode == ENT_MODE )
      then
        local e = myData.selected
        local f = myData.selectedFile
        myData.selected, myData.selectedFile = Editor:SelectFileToLoad()
        if( not myData.selected )
        then
          myData.selected = e
          myData.selectedFile = f
          
        end
      
      elseif( eEditMode == LGT_MODE )
      then
        myData.selectedFile = "../../Assets/XML/entities/e_DefaultLight.xml"
        myData.selected = Global:CreateEntity( myData.selectedFile )
        local color = Editor:SelectColor()
        
        myData.selected:VIS_SetLightColor( color.r, color.g, color.b )
        
      elseif( eEditMode == ISL_MODE )
      then
        Editor:LoadIsland()
        
      end
        
      if( myData.selected ) then
        myData.selected:SHR_sPosition( camDir.x + camPos.x, camDir.y + camPos.y, camDir.z + camPos.z )
        
      end
      
    elseif( Global:IsTriggered( key_names_to_values( BUTTON_SAVE ) ) ) and ( eEditMode == ISL_MODE )
    then
      local file = Editor:SelectFileToSave()
      if( file ~= "" ) then
        Editor:SaveIsland( myData.island, file )
        
      end
      
    end


    ----------------------------------------------------------------------------
    -- Switching Modes
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( BUTTON_ENTITY ) ) ) 
    then
      eEditMode = ( eEditMode + 1 ) % ( table.maxn( entityModes ) + 1 )
      myData.selected = myData.mover
      myData.selectedFile = nil
      
    elseif( Global:IsTriggered( key_names_to_values( BUTTON_ATTACH ) ) ) then
      myData.island = ( myData.island + 1 ) % maxIslands
    
    elseif( Global:IsTriggered( key_names_to_values( BUTTON_EDITMODE ) ) ) 
    then
      cEditMode = ( cEditMode + 1 ) % ( table.maxn( editModes ) + 1 )
      pEditMode = 0
      
    elseif( Global:IsTriggered( key_names_to_values( BUTTON_PLANEMODE ) ) )
    then
      if( cEditMode == POS_MODE ) then
        pEditMode = ( pEditMode + 1 ) % 2
        
      elseif( cEditMode == ROT_MODE ) then
        pEditMode = ( pEditMode + 1 ) % 3
        
      end
      
    end


    ----------------------------------------------------------------------------
    -- Attach to island
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( "Enter" ) ) )
    then
      if( myData.selected ~= nil ) and ( myData.selectedFile ~= nil ) 
      then
        if( eEditMode == ENT_MODE ) 
        then
          local success
          if( Global:IsPressed( key_names_to_values( "Shift Left" ) ) ) or
            ( Global:IsPressed( key_names_to_values( "Shift Right" ) ) ) then
            success = Editor:AttachIslandEntity( myData.island, myData.selected, myData.selectedFile )
            
          else
            success = Editor:AttachToIsland( myData.island, myData.selected, myData.selectedFile )
            
          end
          
          if( success ~= 0 )
          then
            myData.messageText.txt = ( success == 1 ) and "Already attached to island" or "Already attached to another"
            myData.messageText.aaa = 0
            
          else
            myData.messageText.txt = "Attached " .. myData.selected:GetName() .. " to island" .. myData.island
            myData.messageText.aaa = 0
            
          end
          
        elseif( eEditMode == LGT_MODE ) 
        then
          local col = myData.selected:VIS_GetLightColor()
          Editor:AttachLightToIsland( myData.island, 
                                      myData.selected,
                                      col.r, col.g, col .b, 
                                      myData.selected:VIS_GetLightRadius() )
                                      
          myData.messageText.txt = "Attached " .. myData.selected:GetName() .. " to island" .. myData.island
          myData.messageText.aaa = 0
        
        end
        
      end
      
    end
    
    
    ---------------------------------------------------------------------------
    -- Making an Island from Two Texture Files
    ----------------------------------------------------------------------------
    
    if( Global:IsTriggered( key_names_to_values( BUTTON_NEWISLE ) ) )
    then
      local inTexTop, inTexBottom = Editor:SelectIslandTextures()
      if( inTexTop ~= "" ) and ( inTexBottom ~= "" )
      then
        local outIsleBin = Editor:SelectFileToSave()
        if( outIsleBin ~= "" )
        then
          print(inTexTop,type(inTexTop),"\n")
          print(inTexBottom,type(inTexBottom),"\n")
          print(outIsleBin,type(outIsleBin),"\n")
      
          Editor:BuildIslandModel( inTexTop, inTexBottom, outIsleBin )
          
        end
        
      end

    end
    
  end
    
    ----------------------------------------------------------------------------
    -- Setting text
    ----------------------------------------------------------------------------
    
    -- title, save, load text
    Entity:VIS_SetText( "Terrable Editor v1.6.0" .. "\n" .. "(" .. BUTTON_ENTITY .. ")" .. entityModes[ eEditMode ] )
    myData.loadText:VIS_SetText( "Load(" .. BUTTON_LOAD ..")" )
    if( eEditMode < ISL_MODE ) 
    then
      myData.newText:VIS_SetText( "" )
      myData.loadText:SHR_sPosition( 900, 0, 0 )
      myData.saveText:VIS_SetText( "" )
    
    else
      myData.newText:SHR_sPosition(  600, 0, 0 )
      myData.newText:VIS_SetText( "New(" .. BUTTON_NEW ..")" )
      myData.loadText:SHR_sPosition( 750, 0, 0 )
      myData.saveText:SHR_sPosition( 900, 0, 0 )
      myData.saveText:VIS_SetText( "Save(" .. BUTTON_SAVE ..")" )
    
    end
    
    -- edit mode text (pos vs rot)
    local editModeText = editModes[ cEditMode ]
    if( myData.selected ~= nil ) then
      editModeText = editModeText .. "\n" .. myData.selected:GetName()
      
    end
    myData.modeText:VIS_SetText( editModeText )
    
    -- plane mode test (X, Y, Z)
    local planeModeText = "Plane(" .. BUTTON_PLANEMODE .. "):" .. "\n" .. planeModes[ cEditMode ][ pEditMode ]
    myData.planeText:VIS_SetText( planeModeText )
    
    -- island, attach text
    local attachText = ""
    if( enteringText ~= ENTERING_ISLANDNAME )
    then
      attachText = "Island(" .. BUTTON_ATTACH .."):"
      if( myData.island ~= nil ) then
        attachText = attachText .. "\n" .. myData.island
        
      end
      
    elseif( enteringText == ENTERING_ISLANDNAME ) then
      attachText = "Name: " .. myData.islandName
      
    end
    myData.attachText:VIS_SetText( attachText ) 
    
    if( eEditMode < ISL_MODE ) 
    then
      myData.enterText:SHR_sPosition( 0, 752, 0 )
      myData.attachText:SHR_sPosition( 0, 740, 0 )
      myData.enterText:VIS_SetText( "(Enter) attaches to" )
      
    else
      myData.attachText:SHR_sPosition( 0, 752, 0 )
      myData.enterText:VIS_SetText( "" )
      
    end
    
    -- camRelText
    myData.camRelText:VIS_SetText( "Relative X: " .. camRelPos.x .. "\n" ..
                                   "Relative Y: " .. camRelPos.y .. "\n" ..
                                   "Relative Z: " .. camRelPos.z )
    
    -- message text
    if( enteringText ~= ENTERING_DOCKINGINFO )
    then
      if( myData.messageText.txt ~= "" ) and ( myData.messageText.aaa < myData.messageText.bbb ) then
        myData.messageText.aaa = myData.messageText.aaa + 1
        
      else
        myData.messageText.txt = ""
        
      end
      
    end
    myData.messageText.ent:VIS_SetText( myData.messageText.txt )
      
    
  else
    Entity:VIS_SetText( "" )
    myData.newText:VIS_SetText( "" )
    myData.loadText:VIS_SetText( "" )
    myData.saveText:VIS_SetText( "" )
    myData.modeText:VIS_SetText( "" )
    myData.planeText:VIS_SetText( "" )
    myData.enterText:VIS_SetText( "" )
    myData.attachText:VIS_SetText( "" )
    myData.camRelText:VIS_SetText( "" )
    myData.messageText.ent:VIS_SetText( "" )
    myData.selected = myData.mover
    
    myData.mover:SHR_sPosition( camPos.x, camPos.y, camPos.z )
    
  end

end
