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

   script_variables
      double      mLagPursuitTime  =  5.0;   #when flying lag pursuit, fly to where the target was this many seconds ago

      double      mTurnRadius = -1.0;
      WsfGeoPoint mTurnPost = WsfGeoPoint();
      bool        mDrawPost = false;
      bool        mDrawLag  = false;
      WsfDraw     mDraw = WsfDraw();

      double   cGRAVITY_ACCEL          =          9.80665;        # 1 G
      double   cDEFAULT_ACCEL          = (cGRAVITY_ACCEL * 7.5);  # m/s^2  ~7.5 Gs
   end_script_variables


   precondition
      writeln("precondition avoid_overshoot");

      //check relative position and rates against target

      WsfTrack targetTrack = PROCESSOR.GetTarget();
      WsfMover mover = PLATFORM.Mover();

      if (targetTrack.IsNull() || !targetTrack.IsValid() || mover.IsNull() || !mover.IsValid())
      {
         writeln("target or mover not valid for executing avoid_overshoot");
         return false;
      }

      //check if target is turning & I'm in pursuit
      //check if I'm in danger of overshooting the target
      //if inside the turn circle: fly lag
      //if outside the turn circle, check closing speed and range: fly to post

      WsfPlatform tPlatform   = targetTrack.Target();
      Vec3        tAccel      = tPlatform.AccelerationWCS();
                  mTurnRadius = tPlatform.VelocityWCS().MagnitudeSquared() / tAccel.Magnitude();   //equation of circular motion
      Vec3        tTurnPost   = tAccel.Normal();
                  tTurnPost   . Scale(mTurnRadius);                                                //turning post is center of turning circle
                  tTurnPost   = Vec3.Add(tPlatform.Location().LocationWCS(), tTurnPost);           //(one radius in the direction of acceleration)
                  mTurnPost   . Set(tTurnPost);

      if (!mTurnPost.IsValid() || mTurnPost.Altitude() < 0 || mTurnPost.Altitude() != mTurnPost.Altitude())
      {
         writeln("mTurnPost is NOT VALID!");
         return false;
      }

      if (PLATFORM.SlantRangeTo(mTurnPost) > mTurnRadius)
      {
         //we are outside the target's turning circle
         double tCloseSpeed = PLATFORM.ClosingSpeedOf(tPlatform);


         //don't want to swing it too wide


      }
      else
      {
         //we are inside the target's turning circle
         return true;
      }

      return false;
   end_precondition


   execute
      WsfTrack    targetTrack  = PROCESSOR.GetTarget();
      if (targetTrack.IsNull() || !targetTrack.IsValid())
      {
         writeln("target track not valid for executing avoid_overshoot");
         return;
      }

      writeln("executing avoid_overshoot");
      PLATFORM.Comment("avoid_overshoot");

      //fly lag &/or climb
      double maxLagDist = 0.40 * PLATFORM.SlantRangeTo(targetTrack);
      double maxLagTime = maxLagDist / targetTrack.Speed();
      double lagTime = mLagPursuitTime;
      if (lagTime > maxLagTime)
      {
         lagTime = maxLagTime;
      }
      WsfGeoPoint targetLagPos = targetTrack.LocationAtTime(TIME_NOW - lagTime);

      //use track's old position (just extrapolated with velocity, backwards)

      double tAlt = targetTrack.Altitude();
      if (PLATFORM.Altitude() > tAlt)
      {
         tAlt = PLATFORM.Altitude();
      }
      PLATFORM.GoToAltitude(tAlt, 100);

      PLATFORM.TurnToHeading(PLATFORM.TrueBearingTo(targetLagPos), cDEFAULT_ACCEL);

      if (mDrawPost)
      {
         mDraw.SetLineSize(2);
         mDraw.SetColor(0.2, 1.0, 0.2); //greenish
         mDraw.SetDuration(PROCESSOR.UpdateInterval());
         mDraw.BeginLines();
            mDraw.Vertex(PLATFORM.Location());
            mDraw.Vertex(mTurnPost);
         mDraw.End();
      }

      if (mDrawLag)
      {
         mDraw.SetLineSize(2);
         mDraw.SetColor(0.8, 1.0, 0.2); //yellow-ish
         mDraw.SetDuration(PROCESSOR.UpdateInterval());
         mDraw.BeginLines();
            mDraw.Vertex(PLATFORM.Location());
            mDraw.Vertex(targetLagPos);
         mDraw.End();
      }

      double tSpeed = targetTrack.Speed();
      //double percentSpeed = 1.0 + (PLATFORM.SlantRangeTo(mTurnPost) / (mTurnRadius * 100));   //vary speed based on distance from from post
      double percentSpeed = 0.95; //match the targets speed for now

      //writeln("tSpeed=", tSpeed, ", mTurnPost=", mTurnPost.ToString(), ", SlantRangeTo(mTurnPost)=", PLATFORM.SlantRangeTo(mTurnPost), ", mTurnRadius=", mTurnRadius, ", percentSpeed=", percentSpeed);

      PLATFORM.GoToSpeed(tSpeed*percentSpeed, cDEFAULT_ACCEL, true);

      //use out of plan manuevers if necessary to slow down & preserve energy (climb)
      ###PLATFORM.GoToAltitude(mBiggestThreat.Altitude(), cDEFAULT_ACCEL, true);
   end_execute


end_behavior

