# ****************************************************************************
# CUI
#
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
#
# The use, dissemination or disclosure of data in this file is subject to
# limitation or restriction. See accompanying README and LICENSE for details.
# ****************************************************************************
# * * ************************************** * *
# *   ****** Demonstration input file ******   *
# *   ******      UNCLASSIFIED        ******   *
# * * ************************************** * *


processor IADS_CMDR_TASK_MGR WSF_TASK_PROCESSOR
   number_of_servers            5

   track_update_interval        10.0 sec

   #script_debug_writes true
   #show_state_transitions
   #show_task_messages

   script_variables
      int MAX_SAMS_PER_TARGET     = 2;
      int MAX_ASSIGNMENTS_PER_SAM = 4;
      string WEAPON_NAME          = "sam";
   end_script_variables

   // determine if TRACK is assignable
   script bool IsAssignable()
      #writeln(TRACK);
      if ((! TRACK.IFF_Friend()) &&
          (TRACK.TimeSinceUpdated() < 30.0))
      {
         #writeln("find enermy");
         return true;
      }

      return false;
   end_script

   // determine if the subordinate and/or his subordinates have weapons remaining
   script bool WeaponsAvailable(WsfPlatform aAssignee)
      bool weaponsAvailable = false;

      int quantity = 0;
      WsfWeapon weapon = aAssignee.Weapon(WEAPON_NAME);
      if (weapon.IsTurnedOn())
      {
         quantity = quantity + weapon.QuantityRemaining();
      }
      if (quantity > 0)
      {
         weaponsAvailable = true;
      }
      else
      {
         foreach (WsfPlatform sub in aAssignee.Subordinates())
         {
            weapon = sub.Weapon(WEAPON_NAME);
            if (weapon.IsTurnedOn())
            {
               quantity = quantity + weapon.QuantityRemaining();
            }
         }

         if (quantity > 0) weaponsAvailable = true;
      }

      return weaponsAvailable;
   end_script

   script void MakeAssignments()
      #writeln("MakeAssignments ");
      Array<WsfPlatform> filter = Array<WsfPlatform>();
      Array<WsfPlatform> mover = Array<WsfPlatform>();
      Array<WsfPlatform> waiter = Array<WsfPlatform>();
      foreach (WsfPlatform sub in PLATFORM.Subordinates())
      {
         #writeln("is Subordinates");
         if (sub.Type() == "LARGE_SAM_LAUNCHER")
         {
            #writeln("is LARGE_SAM_LAUNCHER");
            if (WeaponsAvailable(sub) &&
                (TasksAssignedTo(sub) < MAX_ASSIGNMENTS_PER_SAM) &&
                (TasksAssignedTo(sub, TRACK.TrackId()) < 1) &&
                (TRACK.WithinZoneOf(sub, "battalion_sector")))
            {
               writeln("can fire");
               writeln("*** Adding ", sub.Name(), " to filter");
               filter.PushBack(sub);
            }
            if(WeaponsAvailable(sub) && 
            !(TRACK.WithinZoneOf(sub, "battalion_sector")))
            {
                writeln("*** Adding ", sub.Name(), " to mover");
                mover.PushBack(sub);
            }
            if(!WeaponsAvailable(sub))
            {
               waiter.PushBack(sub);
            }
         }
      }

      int i;
      int numAssignments = (int)MATH.Min(filter.Size(), MAX_SAMS_PER_TARGET);
      for (int i=0; i < numAssignments; i = i + 1)
      {
         writeln("assign fire");
         AssignTask(TRACK, "ENGAGE", filter[i]);
      }
      
      int numMover=(int)(mover.Size());
      for (int i=0; i < numMover; i = i + 1)
      {
         writeln("assign move");
         AssignTask(TRACK, "MOVE", mover[i]);
      }
      
      int numWaiter=(int)(waiter.Size());
      for (int i=0; i < numWaiter; i = i + 1)
      {
         writeln("assign wait");
         AssignTask(TRACK, "WAIT", waiter[i]);
      }
   end_script

# -------------------------------------------------------------------------
   script void sendMessage()
      #writeln("MakeAssignments ");
      Array<WsfPlatform> firer = Array<WsfPlatform>();
      Array<WsfPlatform> mover = Array<WsfPlatform>();
      Array<WsfPlatform> waiter = Array<WsfPlatform>();
      foreach (WsfPlatform sub in PLATFORM.Subordinates())
      {
         #writeln("is Subordinates");
         if (sub.Type() == "LARGE_SAM_LAUNCHER")
         {
            #writeln("is LARGE_SAM_LAUNCHER");
            if (WeaponsAvailable(sub) &&
                (TasksAssignedTo(sub) < MAX_ASSIGNMENTS_PER_SAM) &&
                (TasksAssignedTo(sub, TRACK.TrackId()) < 1) &&
                (TRACK.WithinZoneOf(sub, "battalion_sector")))
            {
               #writeln("can fire");
               writeln("*** Adding ", sub.Name(), " to firer");
               firer.PushBack(sub);
            }
            if(WeaponsAvailable(sub) && 
            !(TRACK.WithinZoneOf(sub, "battalion_sector")))
            {
                writeln("*** Adding ", sub.Name(), " to mover");
                mover.PushBack(sub);
            }
            if(!WeaponsAvailable(sub))
            {
               waiter.PushBack(sub);
            }
         }
      }
      
      
      int i;
      int numAssignments = (int)MATH.Min(firer.Size(), MAX_SAMS_PER_TARGET);
      for (int i=0; i < numAssignments; i = i + 1)
      {
         writeln("assign fire");
         WsfControlMessage msg = WsfControlMessage();
         msg.SetAuxData("track",TRACK);
         msg.SetAuxData("task","ENGAGE");
         PLATFORM.Comm("sub_net").SendMessage(msg,"red_mortar_carrier1","cmdr_net");
         
         #AssignTask(TRACK, "ENGAGE", firer[i]);
      }
      
      int numMover=(int)(mover.Size());
      for (int i=0; i < numMover; i = i + 1)
      {
         writeln("assign move");
         AssignTask(TRACK, "MOVE", mover[i]);
      }
      
      int numWaiter=(int)(waiter.Size());
      for (int i=0; i < numWaiter; i = i + 1)
      {
         writeln("assign wait");
         AssignTask(TRACK, "WAIT", waiter[i]);
      }
   end_script

# -------------------------------------------------------------------------

   evaluation_interval DETECTED 10.0 sec
   time_to_evaluate    DETECTED  5.0 secs
   state DETECTED
      next_state ASSIGNED
         if (! IsAssignable()) return false;
         #MakeAssignments();
         sendMessage();
         return true;
      end_next_state
   end_state

   evaluation_interval ASSIGNED 10.0 sec
   time_to_evaluate    ASSIGNED  1.0 secs
   state ASSIGNED
      next_state DETECTED
         if (! IsAssignable())
         {
            CancelTask(TRACK.TrackId());
            return true;
         }
         #MakeAssignments();
         sendMessage();
         return false;
      end_next_state
   end_state
end_processor


platform_type IADS_CMDR WSF_PLATFORM
   icon C4I

   infrared_signature    VEHICLE_INFRARED_SIGNATURE
   optical_signature     VEHICLE_OPTICAL_SIGNATURE
   radar_signature       VEHICLE_RADAR_SIGNATURE
   
   mover WSF_GROUND_MOVER
   
   end_mover

   comm sub_net RED_DATALINK
      network_name <local:master>
      internal_link data_mgr
      internal_link task_mgr
   end_comm

   processor data_mgr WSF_TRACK_PROCESSOR
      purge_interval       60 sec
   end_processor
   
   processor task_mgr IADS_CMDR_TASK_MGR
      operating_level ENGAGE 1
      
   end_processor
   

   include processors/commander_track_manager$(TRACKER_TYPE).txt

/*
   # ---------------------------------------------
   # Draw track to false targets and real targets
   # ---------------------------------------------
   script_variables
      # Create a WsfDraw object.
      WsfDraw draw = WsfDraw();
   end_script_variables

   execute at_interval_of 10.0 s
      foreach (WsfTrack track in MasterTrackList())
      {
         if (track.IsValid())
         {
            # use the track ID as a unique draw ID
            # a track icon and a line to the track icon
            # is drawn at each track update
            string trackId = track.TrackId().ToString();
            draw.SetId(trackId);
            draw.SetDuration(10.0); # this is faster than calling erase every time

            if (track.IsFalseTarget())
            {
               draw.SetColor(0,1,0);
               draw.BeginIcons(track.Heading(), "Wedge");
            }
            else
            {
               draw.SetColor(0,0,1);
               draw.BeginIcons(track.Heading(), "Wedge");
            }
            draw.Vertex(track.CurrentLocation());
            draw.End();

            # Draw a line to the track
            draw.SetLineStyle("dashed");
            draw.BeginLines();
            draw.Vertex(PLATFORM);
            draw.Vertex(track.CurrentLocation());
            draw.End();
         }
      }
   end_execute
*/
end_platform_type
