//-----------------------------------------------------------------------------
// Copyright Sandlot Games, 2007
//-----------------------------------------------------------------------------


$selectionAreaMode = false;
$selectionDragMode = false;
$canDragCommand = false;
$pointSelectionLength = 2500;

%minSaveNumber = 0;
%maxSaveNumber = 9;

$doublePressTime = 0.4;
$doubleClickTime = 0.4;

$loadGroupTimer = 0;
$lastLoadedGroup = 0;
$leftClickTimer = 0;

// selection and highlighting group ids
$SELECT_ID = 0;
$TEMPSELECT_ID = 0;
$HIGHLIGHT_ID = 0;
$GROUP0_ID = 0;
$GROUP1_ID = 0;
$GROUP2_ID = 0;
$GROUP3_ID = 0;
$GROUP4_ID = 0;
$GROUP5_ID = 0;
$GROUP6_ID = 0;
$GROUP7_ID = 0;
$GROUP8_ID = 0;
$GROUP9_ID = 0;
$GROUPSELECT_ID = 0;
$CS_TARGETGROUP = 0;
$DRAG_ID = 0;
$TARGET_HIGHLIGHT = 0;

function loadSelectionGroups()
{
   $SELECT_ID = gSelection.addGroup();
   $TEMPSELECT_ID = gSelection.addGroup();
   $HIGHLIGHT_ID = gSelection.addGroup();
   $GROUP0_ID = gSelection.addGroup();
   $GROUP1_ID = gSelection.addGroup();
   $GROUP2_ID = gSelection.addGroup();
   $GROUP3_ID = gSelection.addGroup();
   $GROUP4_ID = gSelection.addGroup();
   $GROUP5_ID = gSelection.addGroup();
   $GROUP6_ID = gSelection.addGroup();
   $GROUP7_ID = gSelection.addGroup();
   $GROUP8_ID = gSelection.addGroup();
   $GROUP9_ID = gSelection.addGroup();
   $GROUPSELECT_ID = gSelection.addGroup();
   $CS_TARGETGROUP = gSelection.addGroup();
   $DRAG_ID = gSelection.addGroup();
   $TARGET_HIGHLIGHT = gSelection.addGroup();
   slgSetSelectedGroup(gSelection.getSelectedGroup($SELECT_ID));
   
   PlayGui.setHighlightID($HIGHLIGHT_ID);
   PlayGui.setHighlightPos($BitmapPos::UR);
   PlayGui.setHighlightOffset(-30, 5);
   PlayGui.setHighlightIndent(8);
   PlayGui.setHighlightSpace(6);
}

function unloadSelectionGroups()
{
   slgSetSelectedGroup(0);
   gSelection.removeGroup($SELECT_ID);
   gSelection.removeGroup($TEMPSELECT_ID);
   gSelection.removeGroup($HIGHLIGHT_ID);
   gSelection.removeGroup($GROUP0_ID);
   gSelection.removeGroup($GROUP1_ID);
   gSelection.removeGroup($GROUP2_ID);
   gSelection.removeGroup($GROUP3_ID);
   gSelection.removeGroup($GROUP4_ID);
   gSelection.removeGroup($GROUP5_ID);
   gSelection.removeGroup($GROUP6_ID);
   gSelection.removeGroup($GROUP7_ID);
   gSelection.removeGroup($GROUP8_ID);
   gSelection.removeGroup($GROUP9_ID);
   gSelection.removeGroup($GROUPSELECT_ID);
   gSelection.removeGroup($CS_TARGETGROUP);
   gSelection.removeGroup($DRAG_ID);
   gSelection.removeGroup($TARGET_HIGHLIGHT);
}

// this tells the game not to update the mouse position, so we
// know when the area selection should start
function startSelection()
{
   $updateMousePos = false;
}

function performSelection(%doubleClick)
{
   // check for group select
   if (%doubleClick == true)
   {
      %groupSelect = checkGroupSelect();
   }

   // check if the selectron needs to be updated after it has been found
   %updateSelection = stopSelection();
   if (%updateSelection)
   {
     if (%groupSelect)
     {
        groupSelect();
     }
     
     // update task buttons
     updateTaskBtns();
     
     // update the selected decals on the ground
     updateSelectedSelectrons();

     // Send selection message
     %selList = gSelection.getSelectedGroup($SELECT_ID);
     MsgSender.postMsg($MSG_SLGOBJSELECT, $MRT_NETWORK, %selList);
   }
   
   // Update selected objects with command system
   csUpdateSelection();
   
   return %updateSelection;
}

function checkCursorSelectionChange(%xMouseDiff, %yMouseDiff)
{
   // check if mouse has moved farther away from the start point
   // and should move into area selection mode
   if ($updateMousePos == false && $selectionAreaMode == false &&
      $canDragCommand == false)
   {
      if (%xMouseDiff > 0 || %xMouseDiff < 0 ||
         %yMouseDiff > 0 || %yMouseDiff < 0)
      {
         $selectionAreaMode = true;
         PlayGui.areaSelectStart();
      }
   }
   // check if mouse has moved farther away from the start point
   // and should move into drag mode
   else if ($updateMousePos == false && $canDragCommand == true &&
      CmdStateTracker.isInState($CSS_SELECT))
   {
      if (%xMouseDiff > 0 || %xMouseDiff < 0 ||
         %yMouseDiff > 0 || %yMouseDiff < 0)
      {
         $updateMousePos = true;
         $selectionDragMode = true;
         csCmdDragBegin();
      }
   }
}

function stopSelection()
{
   if ($selectionAreaMode == true)
   {
     $selectionAreaMode = false;
     PlayGui.areaSelectStop();
   }

   %xPos = PlayGui.getMouse2DXPos();
   %yPos = PlayGui.getMouse2DYPos();

   %xMouseDiff = $mouseLastXPos - %xPos;
   %yMouseDiff = $mouseLastYPos - %yPos;

   // left mouse button has been clicked
   if (%xMouseDiff >= -$dragMouseOffset && %xMouseDiff <= $dragMouseOffset &&
      %yMouseDiff >= -$dragMouseOffset && %yMouseDiff <= $dragMouseOffset)
   {
      if ($selectionDragMode == false)
      {
         // handle the point collision, then update the selection group
         PlayGui.pointRollover($pointSelectionLength,
            $TypeMasks::BuildingObjectType + $TypeMasks::CharacterObjectType);

         gSelection.updateGroupFromPt($TEMPSELECT_ID, !$SLControl::Shift);
         %selected = gSelection.getSelectedGroup($TEMPSELECT_ID);
         if (%selected.getSize() > 0)
         {
            %link = %selected.getId(0);
            if (%link.isLinkObj() == true)
            {
               gSelection.removeFromGroup($TEMPSELECT_ID, %link);
               %temp = %link.getFirstLinkObj();
               if (%temp.getTeam() == $OST_PLAYER)
               {
                  gSelection.addToGroup($TEMPSELECT_ID, %temp);
               }
            }
         }

         gSelection.copyGroup($TEMPSELECT_ID, $SELECT_ID);
         //gSelection.updateGroupFromPt($SELECT_ID, !$SLControl::Shift);
         //If people were removed, send a message.
         %removedList = gSelection.getRemovedGroup($SELECT_ID);
         if (%removedList.getSize() > 0)
         {
            MsgSender.sendMsg($MSG_SLGOBJUNSELECT, $MRT_NETWORK, %removedList);
         }
         
         return true;
      }
   }
   // left mouse button has been dragged
   else
   {
     %xPos = getWord($mouseLast3DPos, 0);
     %yPos = getWord($mouseLast3DPos, 1);
     %zPos = getWord($mouseLast3DPos, 2);
     PlayGui.areaRollover(%xPos, %yPos, %zPos,
        $TypeMasks::BuildingObjectType + $TypeMasks::CharacterObjectType);
     gSelection.updateGroupFromArea($TEMPSELECT_ID, 1);

     // if more than one building, prop, or character is selected, weed out
     // the props and look for only buildings and characters
     %group = gSelection.getSelectedGroup($TEMPSELECT_ID);
     if (%group.getSize() > 1)
     {
        %link = 0;
        for (%index = 0; %index < %group.getSize(); %index++)
        {
           %object = %group.getId(%index);
           if (%object.isLinkObj() == true)
           {
              %value = %object.getFirstLinkObj();
              if (%link == 0) %link = %value;
              else if (%link != %value)
              {
                 %link = 0;
                 break;
              }
           }
           else
           {
              %link = 0;
              break;
           }
        }
        
        if (%link == 0)
        {
           %xPos = getWord($mouseLast3DPos, 0);
           %yPos = getWord($mouseLast3DPos, 1);
           %zPos = getWord($mouseLast3DPos, 2);
           PlayGui.areaRollover(%xPos, %yPos, %zPos,
              $TypeMasks::CharacterObjectType);
           gSelection.updateGroupFromArea($TEMPSELECT_ID, 1);
        }
     }
     
     // simulate what the new selection group would look like
     gSelection.copyGroup($SELECT_ID, $TEMPSELECT_ID);
     gSelection.updateGroupFromArea($TEMPSELECT_ID, !$SLControl::Shift);
     
     // then combine any link objects into single objects
     %linkList = "";
     %group = gSelection.getSelectedGroup($TEMPSELECT_ID);
     for (%index = 0; %index < %group.getSize(); )
     {
        %object = %group.getId(%index);
        if (%object.isLinkObj() == true && %object.isFirstLinkObj() == false)
        {
           gSelection.removeFromGroup($TEMPSELECT_ID, %object);
           
           %value = %object.getFirstLinkObj();           
           %linkCount = getWordCount(%linkList);
           for (%linkIndex = 0; %linkIndex < %linkCount; %linkIndex++)
           {
              if (getWord(%linkList, %linkIndex) $= %value)
              {
                 break;
              }
           }

           if (%linkIndex == %linkCount)
           {
              %linkList = %linkList @ %value @ " ";
           }

           continue;
        }
        
        %index++;
     }
     
     // add all of the link list objects here
     %count = getWordCount(%linkList);
     for (%index = 0; %index < %count; %index++)
     {
        %object = GetWord(%linkList, %index);
        if (%object.getTeam() == $OST_PLAYER)
        {
           gSelection.addToGroup($TEMPSELECT_ID, %object);
        }
     }
         
     // now copy the intended selection group to the actual group
     gSelection.copyGroup($TEMPSELECT_ID, $SELECT_ID);
     //gSelection.updateGroupFromArea($SELECT_ID, !$SLControl::Shift);
     
     //If people were removed, send a message.
     %removedList = gSelection.getRemovedGroup($SELECT_ID);
     if (%removedList.getSize() > 0) 
     {
        MsgSender.sendMsg($MSG_SLGOBJUNSELECT, $MRT_NETWORK, %removedList);
     }
     
     return true;
   }
   
   return false;
}

function updateSelectedSelectrons()
{
   // MGR:
   // Moved this since the construction sound wasn't playing due to it being
   // stopped on unselect (construction sound plays if you have character 
   // building selected or building under construction. Selecting from one to
   // the other stopped the construction sound due to previous ordering). 
   // Switching the call to unselect before select shouldn't hurt anything else.
   
   // objects that lost selection status
   %removedList = gSelection.getRemovedGroup($SELECT_ID);
   for (%index = 0; %index < %removedList.getSize(); %index++)
   {
     %deselect = %removedList.getID(%index);
     %deselect.onClientUnselect();
   }
   
   // newly selected objects
   %addedList = gSelection.getAddedGroup($SELECT_ID);
   for (%index = 0; %index < %addedList.getSize(); %index++)
   {
     %select = %addedList.getID(%index);     
     %select.onClientSelect();
   }

   %selectedList = gSelection.getSelectedGroup($SELECT_ID);
   if (%selectedList.getSize() == 0)
   {
      commandToServer('SetPortraitTarget', 0);
   }
   else
   {
      %select = %selectedList.getID(0);
      %ghostID = ServerConnection.getGhostID(%select);
      commandToServer('SetPortraitTarget', %ghostID);
   }
}

// closes any task buttons open if a character with task buttons is unselected
function updateTaskBtns()
{
   // get removed group
   %remGroup = gSelection.getRemovedGroup($SELECT_ID);
   if (isObject(%remGroup) == false)
   {
      return;
   }
   
   // for each object in removed group do
   %remSize  = %remGroup.getSize();
   for (%i = 0; %i < %remSize; %i++)
   {
      // close any task buttons open
      showTaskBtns(%remGroup.getID(%i), false);
   }
}

function getSelectionGroup(%val)
{
   switch (%val)
   {
      case 0:
         return $GROUP0_ID;
      case 1:
         return $GROUP1_ID;
      case 2:
         return $GROUP2_ID;
      case 3:
         return $GROUP3_ID;
      case 4:
         return $GROUP4_ID;
      case 5:
         return $GROUP5_ID;
      case 6:
         return $GROUP6_ID;
      case 7:
         return $GROUP7_ID;
      case 8:
         return $GROUP8_ID;
      case 9:
         return $GROUP9_ID;
   }
}

// save groups
function saveSelectionGroup(%val)
{
   %saveToGroup = getSelectionGroup(%val);
   if (%saveToGroup == 0)
   {
      return;
   }
   
   gSelection.copyGroup($SELECT_ID, %saveToGroup);
}

// load groups
function loadSelectionGroup(%val)
{
   %loadFromGroup = getSelectionGroup(%val);
   if (%loadFromGroup == 0)
   {
      return;
   }
   
   csClearTargetState();
   
   gSelection.copyGroup(%loadFromGroup, $SELECT_ID);

   // update task buttons
   updateTaskBtns();

   // update the selected decals on the ground
   updateSelectedSelectrons();

   // Update selected objects with command system
   csUpdateSelection();

   // Send selection message
   %selList = gSelection.getSelectedGroup($SELECT_ID);
   MsgSender.postMsg($MSG_SLGOBJSELECT, $MRT_NETWORK, %selList);
   
   // start up a timer that will be used to determine if the selection
   // group is double-loaded and needs to be centered
   if (timerExists($loadGroupTimer) && $lastLoadedGroup == %loadFromGroup)
   {
      // update the group timer being used (zero out centering)
      $lastGroupTimer = 0;
      
      // center the camera on the selected group
      %selectedList = gSelection.getSelectedGroup($SELECT_ID);
      %center = %selectedList.getCenter($serverCamera);
      if (%center)
      {
         // ensure that the camera component exists and center the component
         %component = $serverCamera.getCameraCmp();
         if (%component)
         {
            %component.moveToPos(getWord(%center, 0), getWord(%center, 1), true);
         }
      }
   }
   // if no timer has been loaded, load it   
   else
   {
      $lastLoadedGroup = %loadFromGroup;
      $loadGroupTimer = new SLTimer()
      {
         time = $doublePressTime;
      };
   }
}

function checkGroupSelect()
{
   if (timerExists($leftClickTimer) == true)
   {
     $leftClickTimer.delete();
     $leftClickTimer = 0;
     gSelection.copyGroup($SELECT_ID, $GROUPSELECT_ID);
     return true;
   }
   
   $leftClickTimer = new SLTimer()
   {
      time = $doubleClickTime;
   };
   
   return false;
}



function groupSelect()
{
   gSelection.copyGroup($SELECT_ID, $GROUPSELECT_ID);
   %addedList = gSelection.getAddedGroup($SELECT_ID);
   if (%addedList.getSize() > 0) return;

   %removedList = gSelection.getRemovedGroup($SELECT_ID);
   if (%removedList.getSize() > 0) return;

   %selectedList = gSelection.getSelectedGroup($SELECT_ID);
   if (%selectedList.getSize() != 1) return;

   // perform group selection here
   %object = %selectedList.getID(0);
   if (slgIsCharacter(%object))
   {
      // only player character work with double-clicking
      if (%object.getTeam() != $OST_PLAYER)
      {
         return;
      }
      
      // if the hero is double-clicked, only select the hero
      %datablock = %object.getDataBlock();
      if (%datablock == nameToId($HeroObject[$WW2HERO_FARMER]) ||
         %datablock == nameToId($HeroObject[$WW2HERO_BANKER]) ||
         %datablock == nameToId($HeroObject[$WW2HERO_HUNTER]))
      {
         return;
      }
      
      // now modify the selection list to include all selected objects
      gSelection.selectAllOfSameType($SELECT_ID, %object);
   }
}

function SLSelectIcon::buttonSelect(%icon)
{
   // if the icon does not have a target, we cannot select it
   %target = %icon.target;
   if (isObject(%target) == false)
   {
      return;
   }
   
   // now select the target (take shift into consideration)
   %selected = gSelection.getSelectedGroup($SELECT_ID);
   %addObject = true;
   if ($SLControl::Shift == true)
   {
      if (%selected.contains(%target) == true)
      {
         gSelection.removeFromGroup($SELECT_ID, %target.getId());
      }
      else
      {
         gSelection.addToGroup($SELECT_ID, %target.getId());
      }
   }
   else
   {
      removeAllFromSelection();
      gSelection.addToGroup($SELECT_ID, %target.getId());
   }
   
   // update task buttons
   updateTaskBtns();

   // update the selected decals on the ground
   updateSelectedSelectrons();

   // Update selected objects with command system
   csUpdateSelection();
}

function clientCmdSelectObject(%ghostID)
{
   %object = ServerConnection.resolveGhostId(%ghostID);
   selectObject(%object, 0, 0);
}

// removes any current objects from selection and selects the specified object
function selectObject(%object, %movecam, %fly)
{
   // must be an SLGameObj object
   if (%object.isMemberofClass("SLGameObj") == false) 
   {
      return false;
   }
   
   // remove all currently selected
   removeAllFromSelection();
   
   // select object
   if (gSelection.addToGroup($SELECT_ID, %object.getId()) == false)
   {
      return false;
   }
   
   // update task buttons
   updateTaskBtns();

   // update the selected decals on the ground
   updateSelectedSelectrons();

   // Update selected objects with command system
   csUpdateSelection();

   // Send selection message
   %selList = gSelection.getSelectedGroup($SELECT_ID);
   MsgSender.postMsg($MSG_SLGOBJSELECT, $MRT_NETWORK, %selList);
   
   // move camera
   if (%movecam $= "1")
   {
      commandToServer('MoveCameraToObject', ServerConnection.getGhostID(%object), %fly);
   }
   return true;
}

function clientCmdRemoveFromGroupSelection(%ghostID)
{
   %object = ServerConnection.resolveGhostId(%ghostID);
   removeFromGroupSelection(%object);
}

// removes the specified object from the selection group ONLY
// if there are other objects that are also selected
function removeFromGroupSelection(%object)
{
   // if one or less objects are selected, we will have no
   // objects selected if the remaining object is removed,
   // so do nothing
   if (getSelectionSize() <= 1)
   {
      return false;
   }
   
   if (gSelection.removeFromGroup($SELECT_ID, %object) == true)
   {
      // update task buttons
      updateTaskBtns();

      // update the selected decals on the ground
      updateSelectedSelectrons();

      // Update selected objects with command system
      csUpdateSelection();

      // Send selection message
      %selList = gSelection.getSelectedGroup($SELECT_ID);
      MsgSender.postMsg($MSG_SLGOBJSELECT, $MRT_NETWORK, %selList);
      return true;
   }
   
   return false;
}

// removes the specified object from the selection group
function removeFromSelection(%object)
{
   if (gSelection.removeFromGroup($SELECT_ID, %object) == true)
   {
      // update task buttons
      updateTaskBtns();

      // update the selected decals on the ground
      updateSelectedSelectrons();

      // Update selected objects with command system
      csUpdateSelection();

      // Send selection message
      %selList = gSelection.getSelectedGroup($SELECT_ID);
      MsgSender.postMsg($MSG_SLGOBJSELECT, $MRT_NETWORK, %selList);
      return true;
   }
   
   return false;
}

function removeAllFromSelection()
{
   if (gSelection.removeAllFromGroup($SELECT_ID) == true)
   {
      // update task buttons
      updateTaskBtns();

      // update the selected decals on the ground
      updateSelectedSelectrons();

      // Update selected objects with command system
      csUpdateSelection();

      // Send selection message
      %selList = gSelection.getSelectedGroup($SELECT_ID);
      MsgSender.postMsg($MSG_SLGOBJSELECT, $MRT_NETWORK, %selList);
   }
}

// gets the object at the specified index in the selection group
function getSelectedObject(%index)
{
   %selObjs = gSelection.getSelectedGroup($SELECT_ID);
   if (!isObject(%selObjs)) 
   {
      return ""; 
   }
   return %selObjs.getID(%index);
}

// gets the object that was dragged with the mouse
function getDraggedObject()
{
   %drgObjs = gSelection.getSelectedGroup($DRAG_ID);
   if (!isObject(%drgObjs)) 
   {
      return "";
   }
   return %drgObjs.getID(0);
}

// determines if an object is in the selected group.  Returns true if the object
// is in group.
function isSelected(%obj)
{
   %selObjs = gSelection.getSelectedGroup($SELECT_ID);
   if (!isObject(%selObjs)) 
   {
      return false;
   }
   return %selObjs.contains(%obj);
}

// determines if an object type is in the selected group.
// Returns true if the object in in the group.
function isTypeSelected(%type)
{
   %selObjs = gSelection.getSelectedGroup($SELECT_ID);
   if (!isObject(%selObjs)) 
   {
      return false;
   }
   return %selObjs.containsType(%type);
}

// returns the size of the currently selected group.
function getSelectionSize()
{
   %selObjs = gSelection.getSelectedGroup($SELECT_ID);
   if (!isObject(%selObjs)) 
   {
      return "";
   }
   return %selObjs.getSize();
}

// action map bindings
for (%i = %minSaveNumber; %i <= %maxSaveNumber; %i++)
{
   moveMap.bindCmd(keyboard, "ctrl " @ %i, "saveSelectionGroup(" @ %i @ ");", "");
   moveMap.bindCmd(keyboard, %i, "loadSelectionGroup(" @ %i @ ");", "");
}
