//------------------------------------------------------------
// Copyright Sandlot Games, 2007
// author: Michael Felice
// file: client_questHud.cs
// brief: This file contains all of the target gui control
// functionality (construction timers and health bars at the
// moment).  The creation and deletion of these objects are
// set up here in the event that they will be called in
// multiple places and to centralize the gameplay conditions
// for creation and deletion of these objects.
//------------------------------------------------------------

$EmployedIcon = "~/client/ui/employedIcon.png";
$EmployedIconFocus = "~/client/ui/employedIconfocus.png";
$UnemployedIcon = "~/client/ui/unemployedIcon.png";
$HousedIcon = "~/client/ui/housedIcon.png";
$HousedIconFocus = "~/client/ui/housedIconfocus.png";
$UnhousedIcon = "~/client/ui/unhousedIcon.png";
$EmployedIconDim = "25 31";
$EmployedIconScreenOffset = "20 10";
$EmployedIconSpacing = 1;

$IconReformExtent    = "45 42";
$IconReformBitmap    = "~/client/ui/icons/drunkarresticon.png";
$IconReformWorldOff  = "0 0 5.5";
$IconReformScreenOff = "0 0";

$PlayerHealthRightFullColor = "0 1 0 1";
$PlayerHealthLeftFullColor = "0 1 0.706 1";
$PlayerHealthRightEmptyColor = "0 1 0 1";
$PlayerHealthLeftEmptyColor = "1 0.784 0 1";

$NeutralHealthRightFullColor = "1 1 0.49 1";
$NeutralHealthLeftFullColor = "0.49 0.49 0.49 1";
$NeutralHealthRightEmptyColor = "0.49 0.49 0.49 1";
$NeutralHealthLeftEmptyColor = "0.902 0.706 1 1";

$EnemyHealthRightFullColor = "1 0 0 1";
$EnemyHealthLeftFullColor = "0 0 0 1";
$EnemyHealthRightEmptyColor = "1 0 0 1";
$EnemyHealthLeftEmptyColor = "1 0.588 0 1";



//*************************************************************
//             CREATE AND DESTROY HEALTH BARS
//*************************************************************

// this function checks if the object should have a health bar
// created before creating it (must be highlighted and/or
// selected and not already have a health bar)
function CreateHealthBar(%object)
{
   // only characters and buildings can have health bars
   if (slgIsCharacter(%object) == false &&
      slgIsBuilding(%object) == false)
   {
      return;
   }

   // only give health bars to non-combat units   
   if (slgIsCharacter(%object) == true)
   {
      %combat = slgQueryInterface(%object, $CID_COMBAT);
      if (isObject(%combat) == false)
      {
         return;
      }
   }
   
   // if the object is not selected or highlighted, it should not
   // get a health bar
   %highlighted = gSelection.getSelectedGroup($HIGHLIGHT_ID);
   %selected = gSelection.getSelectedGroup($SELECT_ID);
   if (%highlighted.contains(%object) == false &&
      %selected.contains(%object) == false)
   {
      return;
   }
   
   // if the object already has a health bar, don't create a new one
   if (isObject(%object.healthbar) == true)
   {
      return;
   }
   
   // check if the building is in the proper state to have a
   // visible health bar
   %component = slgQueryInterface(%object, $CID_BUILDING);
   if (isObject(%component) == true &&
      (%component.getState() == $BuildingState::NoState ||
      %component.getState() == $BuildingState::Construction ||
      %component.getState() == $BuildingState::Destruction))
   {
      return;
   }
   
   // the object's datablock is needed to set up the health bar (with the image)
   %datablock = %object.getDataBlock();
   if (%datablock.healthImage $= "")
   {
      return;
   }
   
   // determine the health bar colors based on the team color
   // use the player's team color:
   if (%object.getTeam() == $OST_PLAYER)
   {
      %leftFull = $PlayerHealthLeftFullColor;
      %leftEmpty = $PlayerHealthLeftEmptyColor;
      %rightFull = $PlayerHealthRightFullColor;
      %rightEmpty = $PlayerHealthRightEmptyColor;
   }
   // use the neutral team color:
   else if (%object.getTeam() == $OST_NEUTRAL)
   {
      %leftFull = $NeutralHealthLeftFullColor;
      %leftEmpty = $NeutralHealthLeftEmptyColor;
      %rightFull = $NeutralHealthRightFullColor;
      %rightEmpty = $NeutralHealthRightEmptyColor;
      
      // no healthbar for neutral objects
      return;
   }
   // use the enemy team color:
   else
   {
      %leftFull = $EnemyHealthLeftFullColor;
      %leftEmpty = $EnemyHealthLeftEmptyColor;
      %rightFull = $EnemyHealthRightFullColor;
      %rightEmpty = $EnemyHealthRightEmptyColor;
   }
   
   %object.healthbar = new SLHealthBar()
   {
      // bitmap gui control functionality
      extent = %datablock.healthExtent;
      visible = "1";
      bitmap = %datablock.healthImage;
      
      // gui target control functionality
      target = %object;
      renderFront = true;
      worldOffset = %datablock.healthWorldOffset;
      screenOffset = %datablock.healthScreenOffset;
      bboxHeight = %datablock.healthBBoxHeight;

      // health bar control functionality      
      leftHealthColorFull = %leftFull;
      leftHealthColorEmpty = %leftEmpty;
      rightHealthColorFull = %rightFull;
      rightHealthColorEmpty = %rightEmpty;
      healthPosition = "3 3";
      healthExtent = getWord(%datablock.healthExtent, 0) - 8 @ " " @ getWord(%datablock.healthExtent, 1) - 8;
   };
   
   // add the health bar as the first control object
   HealthBarGroup.addGuiControl(%object.healthbar);
   //HealthBarGroup.addGuiControlFirst(%object.healthbar);
   
   // if it is a building object, then create the employee and tenant objects
   %component = slgQueryInterface(%object, $CID_BUILDING);
   if (isObject(%component) == false)
   {
      return;
   }
   
   %screenOffsetX = -getWord(%datablock.healthExtent, 0) / 2 +
      getWord(%datablock.healthScreenOffset, 0) +
      getWord($EmployedIconScreenOffset, 0);
   %screenOffsetY = getWord($EmployedIconScreenOffset, 1);
   if (%screenOffsetY < 0) %screenOffsetY -= getWord(%datablock.healthExtent, 1);
   else %screenOffsetY += getWord(%datablock.healthExtent, 1);
   %screenOffsetY += getWord(%datablock.healthScreenOffset, 1);
   %screenIndex = getWord($EmployedIconDim, 0) + $EmployedIconSpacing;

   // use the employee list for rendering the employee icons
   %count = 0;
   %inside = "";
   %outside = "";
   if (%component.getTenantMax() < %component.getEmployeeMax())
   {
      %object.employeeIconCount = %component.getEmployeeMax();
      %count = %component.getEmployeeCount();
      %inside = $EmployedIcon;
      %outside = $UnemployedIcon;
   }
   // use the tenant list for rendering the tenant icons
   else
   {
      %object.employeeIconCount = %component.getTenantMax();
      %count = %component.getTenantCount();
      %inside = $HousedIcon;
      %outside = $UnhousedIcon;
   }
   
   // add the tenant/employee icons to the health bar
   for (%index = 0; %index < %object.employeeIconCount; %index++)
   {
      // check which icon should be used (in or out)
      %icon = %inside;
      if (%index >= %count) %icon = %outside;
      
      // create the employee/tenant icon based on the settings above
      // and the position of the health bar for the object
      %object.employeeIcon[%index] = new SLGuiTarget()
      {
         // bitmap gui control functionality
         extent = $EmployedIconDim;
         visible = "1";
         bitmap = %icon;
         
         // gui target control functionality
         target = %object;
         renderFront = true;
         worldOffset = %datablock.healthWorldOffset;
         screenOffset = %screenOffsetX @ " " @ %screenOffsetY;
         bboxHeight = %datablock.healthBBoxHeight;
      };
      
      // add the icon to the gui control list
      PlayGui.addGuiControlFirst(%object.employeeIcon[%index]);

      // update the position of the next employee/tenant icon
      %screenoffsetX += %screenIndex;
   }
}

function clientCmdUpdateHealthBar(%ghostID, %team, %count)
{
   %object = ServerConnection.resolveGhostID(%ghostID);
   %component = slgQueryInterface(%object, $CID_BUILDING);
   %character = 0;
   if (isObject(%component) == false)
   {
      %character = slgQueryInterface(%object, $CID_CHARACTER);
      if (isObject(%character) == false)
      {
         return;
      }
   }
   
   // update the team (for team changes on the server)
   %object.setTeam(%team);
   
   // if no health bar is present, there is nothing to update
   if (isObject(%object.healthbar) == false)
   {
      // if the object is selected or highlighted, try to
      // create a health bar (the healthbar, if it exists
      // will be updated afterwards)
      CreateHealthBar(%object);
      if (isObject(%object.healthbar) == false)
      {
         return;
      }
   }
   else
   {
      // check if the healthbar should be removed because
      // the team has changed to neutral
      if (%team == $OST_NEUTRAL)
      {
         %object.healthbar.delete();
         %object.healthbar = 0;
         return;
      }
   }
   
   // update the color of the health bar
   // use the player's team color
   if (%team == $OST_PLAYER)
   {
      %leftFull = $PlayerHealthLeftFullColor;
      %leftEmpty = $PlayerHealthLeftEmptyColor;
      %rightFull = $PlayerHealthRightFullColor;
      %rightEmpty = $PlayerHealthRightEmptyColor;
   }
   // use the enemy team color:
   else
   {
      %leftFull = $EnemyHealthLeftFullColor;
      %leftEmpty = $EnemyHealthLeftEmptyColor;
      %rightFull = $EnemyHealthRightFullColor;
      %rightEmpty = $EnemyHealthRightEmptyColor;
   }
   
   // update the color
   %object.healthbar.leftHealthColorFull = %leftFull;
   %object.healthbar.leftHealthColorEmpty = %leftEmpty;
   %object.healthbar.rightHealthColorFull = %rightFull;
   %object.healthbar.rightHealthColorEmpty = %rightEmpty;
   
   // if this is a character object, stop updating here
   if (isObject(%component) == false)
   {
      return;
   }
   
   // use the employee list for rendering the employee icons
   if (%component.getTenantMax() < %component.getEmployeeMax())
   {
      %inside = $EmployedIcon;
      %outside = $UnemployedIcon;
   }
   // use the tenant list for rendering the tenant icons
   else
   {
      %inside = $HousedIcon;
      %outside = $UnhousedIcon;
   }
   
   // update all of the employee icons for the building
   for (%index = 0; %index < %object.employeeIconCount; %index++)
   {
      %icon = %inside;
      
      // reset bitmap timers (if any)
      %object.employeeIcon[%index].bmpTimer = 0;
      
      if (%index >= %count)
      {
         %icon = %outside;

         // add bitmap timer
         if (%index == %count && isObject(%component.houseTimer))
         {
            %object.employeeIcon[%index].bmpTimer = %component.houseTimer;
         }
      }
      
      %object.employeeIcon[%index].bitmap = %icon;
   }
}

// this function checks if the object should be destroyed before
// destroying it (must not be highlighted or selected and exist)
function DestroyHealthBar(%object)
{
   // if the object is not selected or highlighted, it should not
   // get a health bar
   %highlighted = gSelection.getSelectedGroup($HIGHLIGHT_ID);
   %selected = gSelection.getSelectedGroup($SELECT_ID);
   if (%highlighted.contains(%object) == true ||
      %selected.contains(%object) == true)
   {
      if (%object.health > 0)
      {
         return;
      }
   }
   
   // if the object already has a health bar, don't highlight it
   if (isObject(%object.healthbar) == false)
   {
      return;
   }

   %object.healthbar.delete();
   %object.healthbar = 0;
   
   // if it is a building object, remove any employee and tenant objects
   for (%index = 0; %index < %object.employeeIconCount; %index++)
   {
      // just in case check for this
      if (isObject(%object.employeeIcon[%index].bmpTimer))
      {
         %object.employeeIcon[%index].bmpTimer = 0;
      }
      
      %object.employeeIcon[%index].delete();
      %object.employeeIcon[%index] = 0;
   }
   %object.employeeIconCount = 0;
}

// this function is called from the server to remove an employee
// from the health bar (this will update the icon as soon as possible,
// instead of waiting for the client-side object to be udpated first)
function clientCmdRemoveEmployeeFromMeter(%ghostID)
{
   // get the client-side object based on the ghost id
   %object = slgResolveGhost(%ghostID);
   if (isObject(%object) == false)
   {
      return;
   }
   
   // the object must be a building
   %component = slgQueryInterface(%object, $CID_BUILDING);
   if (isObject(%component) == false)
   {
      return;
   }
 
   // use the employee list for rendering the employee icons
   %count = 0;
   if (%component.getTenantMax() < %component.getEmployeeMax())
   {
      %count = %component.getEmployeeCount();
   }
   // use the tenant list for rendering the tenant icons
   else
   {
      %count = %component.getTenantCount();
   }
   
   // remove an employee/tenant
   %count--;
   
   // update all of the employee icons for the building
   for (%index = 0; %index < %object.employeeIconCount; %index++)
   {
      %icon = $EmployedIcon;
      if (%index >= %count)
      {
         %icon = $UnemployedIcon;
      }
      
      %object.employeeIcon[%index].bitmap = %icon;
   }
}

// this function is called from the server to add an employee
// to the health bar (this will update the icon as soon as possible,
// instead of waiting for the client-side object to be udpated first)
function clientCmdAddEmployeeToMeter(%ghostID)
{
   // get the client-side object based on the ghost id
   %object = slgResolveGhost(%ghostID);
   if (isObject(%object) == false)
   {
      return;
   }
   
   // the object must be a building
   %component = slgQueryInterface(%object, $CID_BUILDING);
   if (isObject(%component) == false)
   {
      return;
   }
 
   // use the employee list for rendering the employee icons
   %count = 0;
   if (%component.getTenantMax() < %component.getEmployeeMax())
   {
      %count = %component.getEmployeeCount();
   }
   // use the tenant list for rendering the tenant icons
   else
   {
      %count = %component.getTenantCount();
   }
   
   // add an employee/tenant
   %count++;
   
   // update all of the employee icons for the building
   for (%index = 0; %index < %object.employeeIconCount; %index++)
   {
      %icon = $EmployedIcon;
      if (%index >= %count)
      {
         %icon = $UnemployedIcon;
      }
      
      %object.employeeIcon[%index].bitmap = %icon;
   }
}



//*************************************************************
//             CREATE AND DESTROY HEALTH CLOCKS
//*************************************************************

function clientCmdCreateHealthClock(%ghostID)
{
   %object = ServerConnection.resolveGhostId(%ghostID);
   CreateHealthClock(%object);
}

// this function ensures that the object is a building and that
// health clock can be placed (as a construction timer) on the
// building before creating the health clock
function CreateHealthClock(%object)
{
   // make sure the object exists and is a building
   if (isObject(%object) == false || slgIsBuilding(%object) == false)
   {
      return;
   }
   
   // get the building's component
   %component = slgQueryInterface(%object, $CID_BUILDING);
   if (isObject(%component) == false)
   {
      return;
   }
    
   // create the health clock
   %clock = new SLHealthClock()
   {
      // bitmap gui control functionality
      extent = "60 60";
      visible = "1";
      bitmap = "~/client/ui/constructionTimer";
      
      // base object
      target = %object;
      renderFront = false;
      worldOffset = "0 0 5";
      screenOffset = "0 0";
      bboxHeight = false;
      
      // clock object
      radius = 20;
      center = "29 33";
      centerColor = "1 0 0 1";
      outsideStartColor = ".04 .68 .89 1";
      outsideEndColor = "0 1 0 1";
      backgroundColor = "0.87 0.78 0.56 1";
      arrowLengthFar = "20";
      arrowLengthShort = "14";
      arrowAngle = "10";
      arrowColor = "0 0 0 1";
      tickDistance = 1;
   };
   %object.clock = %clock;
   HealthClockGroup.addGuiControl(%clock);
   //HealthClockGroup.addGuiControlFirst(%clock);
}

// this function ensures that the object is a building and that
// health clock can be destroyed on the building before attempting
// to destroy the building's health clock
function DestroyHealthClock(%object)
{
   // make sure the object exists and is a building
   if (isObject(%object) == false || slgIsBuilding(%object) == false)
   {
      return;
   }
   
   // get the building's component
   %component = slgQueryInterface(%object, $CID_BUILDING);
   if (isObject(%component) == false)
   {
      return;
   }
   
   // check if the clock exists, and if it does, delete it
   if (isObject(%object.clock) == true)
   {
      %object.clock.delete();
      %object.clock = 0;
   }
}


//*************************************************************
//             CREATE AND DESTROY RESOURCE INFOS
//*************************************************************

$GoldIcon  = -1;
$WoodIcon  = -1;
$WaterIcon = -1;
$FoodIcon  = -1;
$GoldIconPath  = "~/client/ui/icons/gold";
$WoodIconPath  = "~/client/ui/icons/wood";
$WaterIconPath = "~/client/ui/icons/water";
$FoodIconPath  = "~/client/ui/icons/food";

function InitializeResourceInfo()
{
   $GoldIcon = addResourceInfoIcon("assets/client/ui/icons/gold", 0.93, 0.8, 0.1);
   $WoodIcon = addResourceInfoIcon("assets/client/ui/icons/wood", 0.5, 0.5, 0);
   $WaterIcon = addResourceInfoIcon("assets/client/ui/icons/water", 0, 0.47, 0.90);
   $FoodIcon = addResourceInfoIcon("assets/client/ui/icons/food", 0.98, 0.27, 0.27);
   $PeopleIcon = addResourceInfoIcon("assets/client/ui/icons/townpop", 0.68, 0, 1);
   $ExperienceIcon = addResourceInfoIcon("assets/client/ui/icons/experience", 0.06, 0.85, 0);
   $HappinessIcon = addResourceInfoIcon("assets/client/ui/happiness5", 0, 1, 0);
}

function ClearResourceInfo()
{
   %riCount = ResourceInfoGroup.getCount();
   while (ResourceInfoGroup.getCount() > 0) 
   {
      %ri = ResourceInfoGroup.getObject(%i);
      %ri.delete();
   }
}

function clientCmdCreateResourceInfo(%ghostID, %info)
{
   %object = ServerConnection.resolveGhostId(%ghostID);
   if (isObject(%object) == false)
   {
      return;
   }
   
   %list[0] = "0 -1";
   %list[1] = "0 -1";
   %list[2] = "0 -1";
   
   %count = getWordCount(%info) / 2;
   for (%index = 0; %index < %count; %index++)
   {
      %resourceIndex = %index * 2;
      %list[%index] = getWord(%info, %resourceIndex) @ " ";
      
      %resource = getWord(%info, %resourceIndex + 1);
      if (%resource $= "gold") %list[%index] = %list[%index] @ $GoldIcon;
      else if (%resource $= "wood") %list[%index] = %list[%index] @ $WoodIcon;
      else if (%resource $= "water") %list[%index] = %list[%index] @ $WaterIcon;
      else if (%resource $= "food") %list[%index] = %list[%index] @ $FoodIcon;
      else if (%resource $= "people") %list[%index] = %list[%index] @ $PeopleIcon;
      else if (%resource $= "experience") %list[%index] = %list[%index] @ $ExperienceIcon;
      //else if (%resource $= "happiness") %list[%index] = %list[%index] @ $HappinessIcon;
      else %list[%index] = %list[%index] @ "-1";
   }

   // create the resource info
   if (isObject(%object.info) == false)
   {
      %object.info = new SLResourceInfo()
      {
         // bitmap gui control functionality
         extent = "40 40";
         visible = "1";
         profile = "WestwardLeftProfile";
         
         // base object
         target = %object;
         renderFront = true;
         worldOffset = "0 0 3";
         screenOffset = "0 0";
         bboxHeight = false;
         
         // resource info object
         addResourceData = %list[0];
         addResourceData = %list[1];
         addResourceData = %list[2];
         speed = 20;
         delay = 5;
         fade = 0.8;
         textSpacing = 2;
         iconSpacing = 5;
         resourceSpacing = 15;
      };
      ResourceInfoGroup.addGuiControl(%object.info);
      %object.info.yOffset = 0;
      %object.info.yBase = getWord(%object.info.screenOffset, 1);
      //ResourceInfoGroup.addGuiControlFirst(%object.info);
   }
   else
   {
      %object.info.addResourceData = %list[0];
      %object.info.addResourceData = %list[1];
      %object.info.addResourceData = %list[2]; 
   }
}

function SLResourceInfo::OnStart(%object)
{
   if (isObject(%object.timer) == true)
   {
      return;
   }
   
   %object.time = 0;
   %object.timer = new SLEndlessTimer()
   {
   };
   %object.timer.notifyOnUpdate(OnMove, %object);
   
   %timer = new SLTimer()
   {
      time = %object.delay;
   };
   %timer.notifyOnFire(OnDelayed, %object);
}

function SLResourceInfo::OnMove(%object)
{
   %newTime = %object.timer.getElapsedTime();
   %timeStep = %newTime - %object.time;
   %object.time = %newTime;
   
   %xPos = getWord(%object.screenOffset, 0);
   %object.yOffset -= %timeStep * %object.speed;
   %yPos = %object.yBase + %object.yOffset;
   %object.screenOffset = %xPos @ " " @ %yPos;
   
   // this will tell the object to create new resource icons
   // after half a second has passed
   if (%object.target != 0 && %newTime > 0.5)
   {
      %object.target.info = 0;
   }
   
   /*
   %xPos = getWord(%object.worldOffset, 0);
   %yPos = getWord(%object.worldOffset, 1);
   %zPos = getWord(%object.worldOffset, 2) + %timeStep * %object.speed;
   %object.worldOffset = %xPos @ " " @ %yPos @ " " @ %zPos;
   */
}

function SLResourceInfo::OnDelayed(%object)
{
   %object.target.info = 0;
   
   %object.fadeTimer = new SLTimer()
   {
      time = %object.fade;
   };
   %object.fadeTimer.notifyOnUpdate(OnFade, %object);
   %object.fadeTimer.notifyOnFire(OnEnd, %object);
}

function SLResourceInfo::OnFade(%object)
{
   %elapsedTime = %object.fadeTimer.getElapsedTime();
   %alpha = 1 - %elapsedTime / %object.fade;
   %object.alpha = %alpha;
}

function SLResourceInfo::OnEnd(%object)
{
   if (isObject(%object.timer) == true)
   {
      %object.timer.delete();
      %object.timer = 0;
   }
   
   %object.delete();
}


//*************************************************************
//             CREATE AND DESTROY REFORM ICONS
//*************************************************************

// Creates a reform head icon if one does not exist
function CreateReformIcon(%object)
{
   if (!isObject(%object)) 
   {
      return;
   }
   
   // Create only if one does not exist
   if (isObject(%object.reformIcon)) 
   {
      return;
   }
   
   // Create head icon
   %icon = new SLGuiTarget() 
   {
      // Base fields
      extent  = $IconReformExtent;
      visible = true;
      bitmap  = $IconReformBitmap;
      
      // Gui target fields
      target       = %object;
      renderFront  = true;
      worldOffset  = $IconReformWorldOff;
      screenOffset = $IconReformScreenOff;
   };
   
   // Tie icon to object
   %object.reformIcon = %icon;
   ReformIconGroup.addGuiControl(%icon);
}

// Destroys the reform head icon on the object
function DestroyReformIcon(%object)
{
   if (!isObject(%object))
   {
      return;
   }
   if (!isObject(%object.reformIcon)) 
   {
      return;
   }
   %object.reformIcon.delete();
   %object.reformIcon = "";
}
