# File generated by Wizard 2.9.0 on Dec 22, 2024.
processor airControl WSF_SCRIPT_PROCESSOR  

   update_interval 10 sec
   
   script_variables 
      string zNameOrPoint = "tw";
      string zType = "polygon";
      WsfTrackList tl = PLATFORM.MasterRawTrackList(); 
      double Radius = 50000;
      bool isOver = false;
      double LLR = 175000;
      double LR = 100000;
      double MR = 50000;
      double SR = 30000;
      double a = 10000000;
      bool laststate = false;
      bool finish = false;
      double startaTime = 0;
      double lastTime = 30;
            WsfWeapon aa_mrm = PLATFORM.Weapon("aa_mrm");  //     
   WsfTrack currentTarget;  //     
   end_script_variables
      
   //
   //@ flyPolygonalZone
   //
   script void flyPolygonalZone(string zName)
      WsfZone zone = zone.FindZone(zName);
      PLATFORM.GoToSpeed(1000,999);
      PLATFORM.GoToLocation(zone.Location());
   end_script
   
   //
   //@ flyCircleZone
   //
   script void flyCircleZone(string zPoint)
      WsfGeoPoint p = p.Construct(zPoint);
      PLATFORM.GoToSpeed(1000,999);
      PLATFORM.GoToLocation(p);
   end_script
   
   //
   //@ fly the zone
   //
   script void flyZone(string zNameOrPoint,string zType)
      if(zType == "polygon")
      {
         flyPolygonalZone(zNameOrPoint);
      }
      else if(zType == "circle")
      {
         flyCircleZone(zNameOrPoint);
      }
   end_script
   
   //
   //@ isInZone
   //
   script bool isInZone(string zNameOrPoint,string zType)
      if(zType == "polygon")
      {
         WsfZone zone = zone.FindZone(zNameOrPoint);
         return (PLATFORM.GroundRangeTo(zone.Location())<=100);
      }
      else if(zType == "circle")
      {
         WsfGeoPoint p = p.Construct(zNameOrPoint);
         return (PLATFORM.GroundRangeTo(p) < 1000);
      }
      return false;
   end_script
   
   
   // Calculate the distance to the nearest enemy target and return that target's Track
   script WsfTrack GetClosestEnemy()
      PLATFORM->closestTrack = WsfTrack();
       // Initialize an empty WsfTrack object
      double minDistance = 9999999.0;  // Set an extremely large initial distance
   
      // Iterate through all targets to find the nearest enemy
      for (int i = 0; i < PLATFORM.MasterTrackList().Count(); i = i + 1)
      {
         WsfTrack tempTrack = PLATFORM.MasterTrackList().TrackEntry(i);  // Get the target
         
         if (tempTrack.IsValid() && tempTrack.BelievedAlive())  // If the target is valid
         {
            double distanceToTarget = PLATFORM.GroundRangeTo(tempTrack);  // Calculate the ground distance from the current platform to the target
            
            if (distanceToTarget < minDistance)  // If this target is closer
            {
               minDistance = distanceToTarget;  // Update the minimum distance
               PLATFORM->closestTrack = tempTrack;  // Update the nearest target
            }
         }
      }
      
      return PLATFORM->closestTrack;  // Return the nearest target
   end_script
   
#   script bool isHaveTarget()
#      return(PLATFORM.MasterTrackList().Count() > 0);
#   end_script

   //
   //@ bounds Patrol
   //
   script void airPolygonPatrol(string zNameOrPoint) 
      WsfZone zone = zone.FindZone(zNameOrPoint);
      Array<WsfGeoPoint> boundsPoints = zone.PolyPoints();
      WsfRoute route;
      WsfRoute r1 = route.Create("lx");
      foreach(WsfGeoPoint vertex in boundsPoints)
      {
         vertex.SetAltitudeHAE(10000);
         r1.Append(vertex,1500);
      }
      r1.Waypoint(0).SetLabel("start");
      r1.Waypoint(r1.Size() - 1).SetGoToLabel("start");
      PLATFORM.FollowRoute(r1);
      isOver =true;
   end_script 
   
   //
   //@ generateCirclePoints
   //
   script Array<WsfGeoPoint> generateCirclePoints(string Center , double radius)
      WsfGeoPoint center= WsfGeoPoint.Construct(Center);
      Array<WsfGeoPoint>circlePoints={};
      double earthRadius =6371000.0;
      double angularDistance =radius /earthRadius;
      Array<double>angles ={0.0,120,240};
      foreach(double angle in angles)
      {
         double latCenter=center.Latitude()* MATH.PI()/ 180.0;
         double loncenter= center.Longitude()* MATH.PI()/ 180.0;
         double lat= MATH.ASin(MATH.Sin(latCenter)
                              * MATH.Cos(angularDistance)
                              + MATH.Cos(latCenter)
                              * MATH.Sin(angularDistance)
                              * MATH.Cos(angle));
         
         double lon = loncenter +MATH.ATan2(MATH.Sin(angle)
                                          * MATH.Sin(angularDistance)
                                          * MATH.Cos(latCenter)
                                          , MATH.Cos(angularDistance)
                                          - MATH.Sin(latCenter)
                                          * MATH.Sin(lat));
         circlePoints.PushBack(WsfGeoPoint.Construct(lat*180.0/MATH.PI() , lon *180.0 / MATH.PI(),5000));
      }
      return circlePoints;
   end_script

   //
   //@ circle execute
   //
   script void executeCircularPatrol(string zNameOrPoint)
      Array<WsfGeoPoint> circlePoints = generateCirclePoints(zNameOrPoint,Radius);
      WsfRoute route;
      WsfRoute r1= route.Create("lx");
      foreach(WsfGeoPoint vertex in circlePoints)
      {
         vertex.SetAltitudeHAE(10000);
         r1.Append(vertex,1500);
      }
      
      r1.Waypoint(0).SetLabel("start");
      r1 .Waypoint(r1.Size()-1).SetGoToLabel("start");
      PLATFORM.FollowRoute(r1);
   #   r1.Print();
      isOver =true;
   end_script 
   
   //
   //@ execute patrol
   //
   script void executePatrol(string zNameOrPoint,string zType)
      if(zType == "polygon")
      {
         airPolygonPatrol(zNameOrPoint);
      }
      else if(zType == "circle" )
      {
         executeCircularPatrol(zNameOrPoint);
      }  
   end_script
   
   //
   //@ isDecectedTarget
   //
   script bool isDecectedTarget()
      return(PLATFORM.MasterTrackList().Count() > 0 && 
         aa_mrm.QuantityRemaining() > 0     
#         PLATFORM->closestTrack.IsValid()        
      );
   end_script   
   
//           
   //
   //@ finishIntercept
   //
   script bool finishIntercept()
      bool finished = false;
      WsfTrack closestTarget = GetClosestEnemy();
      if (closestTarget.IsNull() || closestTarget.BelievedDead())
      {
         writeln("Target is destroyed or not valid.");
         finished = true;
      }

      double currentTime = TIME_NOW;
      if (currentTime - startaTime >= lastTime)
      {
         writeln("Task timeout.");
         finished = true;
      }

      return finished;
   end_script
   
   
   //
   //@ ON aa_intercept
   //   
   script void trunOnIntercept()
      WsfProcessor launchComputer = PLATFORM.Processor("intercept");
      if (! launchComputer.IsTurnedOn())
      {
         writeln("Starting attack at T=", TIME_NOW);
         launchComputer.TurnOn();
      }
   end_script
   
   //
   //@ OFF aa_intercept
   //     
   script void trunOffIntercept()
      WsfProcessor launchComputer = PLATFORM.Processor("intercept");
      if (! launchComputer.IsTurnedOff())
      {
         writeln("Stoping attack at T=", TIME_NOW);
         launchComputer.TurnOff();
      }
   end_script

/////////////////////execute//////////////////////////
   execute at_time 2 sec relative 
      writeln("start before PROCESSOR.SetState(MOVER)");
      PROCESSOR.SetState("MOVER");
   end_execute
/////////////////////state////////////////////////
   state MOVER
      on_entry 
         flyZone(zNameOrPoint,zType);
      end_on_entry
      
      next_state PATROL
         return isInZone(zNameOrPoint,zType);
      end_next_state
      
      next_state HIT
         return isDecectedTarget();
      end_next_state
      
      on_exit 
         GetClosestEnemy();
      end_on_exit
   end_state

   state PATROL
      on_entry
         executePatrol(zNameOrPoint,zType); 
      end_on_entry
      
      next_state HIT
         return isDecectedTarget();
      end_next_state
      
      on_exit 
         GetClosestEnemy();
      end_on_exit
   end_state
   
   state HIT
      on_entry 
         trunOnIntercept();
      end_on_entry
      
      next_state PATROL
         return (!isDecectedTarget());
      end_next_state
      
      on_exit 
         trunOffIntercept();
      end_on_exit
   end_state

end_processor