# ****************************************************************************
# 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.
# ****************************************************************************



behavior interpret_flank_jobs

   script_debug_writes off

   script_variables
      WsfDraw     draw              = WsfDraw();
      bool        mDrawFlankLines   = false;
      WsfRIPRJob  mMyJob;
   end_script_variables


   on_init
      draw.SetLineSize(2);
      draw.SetColor(1.0, 0.0, 1.0); //purple
   end_on_init


   precondition

      if (!PROCESSOR.IsA_TypeOf("WSF_RIPR_PROCESSOR"))
      {
         return Failure("behavior not attached to a RIPR processor!");
      }

      writeln_d("precondition interpret_flank_jobs");
      draw.SetDuration(PROCESSOR.UpdateInterval());
      WsfRIPRProcessor commander = ((WsfRIPRProcessor)PROCESSOR).GetRIPRCommanderProcessor();
      if (commander.IsValid())
      {
        mMyJob = commander.GetJobFor(TIME_NOW, ((WsfRIPRProcessor)PROCESSOR));
      if (mMyJob.IsValid() && mMyJob.Name() == "flank")
      {
         return true;
      }
      else
      {
         //remove any jobs this behavior created
         Array<WsfRIPRJob> jobs = ((WsfRIPRProcessor)PROCESSOR).GetJobs();
         foreach (WsfRIPRJob job in jobs)
         {
              if (job.IsValid() && job.Data().Exists("flankPointName"))
            {
               //its a valid flank point job created by this behavior, remove it
               ((WsfRIPRProcessor)PROCESSOR).RemoveJob(job);
            }
         }

         extern Map<int, WsfGeoPoint> mFlankJobIdToFlankPointMap;
         mFlankJobIdToFlankPointMap.Clear();

         return Failure("Agent does not have a flank job!");
        }
      }
      else
      {
          return Failure("Agent does not have a commander!");
      }
   end_precondition


   execute
      writeln_d("executing interpret_flank_jobs");

      WsfGeoPoint zonePoint    = (WsfGeoPoint)mMyJob.GetData("ZonePoint");
      double      zoneBearing  = (double)     mMyJob.GetData("ZoneBearing");
      bool        bearingValid = (bool)       mMyJob.GetData("ZoneBearingValid");
      WsfZone     flankZone    = (WsfZone)    mMyJob.GetData("FlankZone");
      double      flankDist    = (double)     mMyJob.GetData("FlankDistance");
      string      zoneName     = (string)     mMyJob.GetData("ZoneName");

     #extern Map<int, WsfGeoPoint> mFlankJobIdToFlankPointMap;
      WsfGeoPoint flankPoint   = mFlankJobIdToFlankPointMap.Get( mMyJob.GetId() );

      if (mDrawFlankLines)
      {
         //draw the outline of the flank zone
         flankZone.DebugDrawZone(zonePoint, zoneBearing*MATH.RAD_PER_DEG());

         //draw flank point of interest (target we are flanking), white dot
         draw.BeginPoints();
            draw.SetColor(1.0, 1.0, 1.0);
            draw.Vertex(zonePoint);
         draw.End();

         if (bearingValid)
         {
            //cluster heading is with reference to east (instead of north), so subtract 90 degrees
           #doulbe clusterBearingTrue = MATH.NormalizeAngle0_360( zoneBearing - 90.0 );
            double clusterBearingTrue = MATH.NormalizeAngle0_360( zoneBearing );

            WsfGeoPoint bPoint = WsfGeoPoint(zonePoint);
            bPoint.Extrapolate( clusterBearingTrue, flankDist );

            //draw red-orange line to represent heading of target's flight
            draw.BeginLines();
               draw.SetColor(1.0, 0.3, 0.1);
               draw.Vertex(zonePoint);
               draw.Vertex(bPoint);
            draw.End();
         }

         //draw green line to the flank point (the side we are flying towards)
         draw.BeginLines();
            draw.SetColor(0.1, 1.0, 0.4);
            draw.Vertex(zonePoint);
            draw.Vertex(flankPoint);
         draw.End();
      }

      //see if any subordinates are in the flank zone, if they are... flanking is done
      foreach( WsfPlatform sub in PLATFORM.Subordinates() )
      {
         if (flankZone.PointIsInside(sub.Location(), zonePoint, zoneBearing*MATH.RAD_PER_DEG(), 0.0))
         {
            writeln_d( "@@@ aifl subordinate ", sub.Name(), " inside flank zone!");
            mMyJob.SetProgress( ((WsfRIPRProcessor)PROCESSOR), 1.0 );   #mark the job as complete
         }
      }

      int NumSubordinates = PLATFORM.Subordinates().Count();

      //if flank job doesn't exist yet, create it
      WsfRIPRJob job = ((WsfRIPRProcessor)PROCESSOR).GetJobByData("flankPointName", zoneName);
      if( ! job.IsValid() )
      {
         if (NumSubordinates > 0)
         {
            extern double cFlankPointPriority;
            //set max job winners to number of subordinates (so all can proceed into zone)
            WsfRIPRJob temp = WsfRIPRJob.Create(   ((WsfRIPRProcessor)PROCESSOR),
                                                   "pursue-point",
                                                   "pursue-point-" + zoneName,
                                                   cFlankPointPriority,
                                                   NumSubordinates);
            temp.SetData( "targetTrackName", zoneName ); //hack for now, so other code here works
            temp.SetData( "targetPoint", flankPoint );
            temp.SetData( "flankPointName", zoneName );
            ((WsfRIPRProcessor)PROCESSOR).AddJob(temp);
            writeln_d("--- ", PLATFORM.Name(), " job change, ADD: ", zoneName );
         }
      }
      else
      {
         job.SetData( "targetPoint" , flankPoint );
         writeln_d("   aiFL - updated flank pursue-point job ", zoneName, ", ( ", flankPoint.Latitude(), ", ", flankPoint.Longitude(), " )" );
      }

      //remove all jobs that aren't involved with flanking
      Array<WsfRIPRJob> jobs = ((WsfRIPRProcessor)PROCESSOR).GetJobs();
      foreach (WsfRIPRJob x in jobs)
      {
         string name = (string)x.GetData("targetTrackName");
         if ( name != zoneName )
         {
            writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", name);
            ((WsfRIPRProcessor)PROCESSOR).RemoveJob(x);
         }
      }

   end_execute

end_behavior
