var HitchAnimation = func {
#
# ---------------------------------------------------------------------------------
#                              Bridle Animation                 Status: 19.07.2020
# ---------------------------------------------------------------------------------
#
  var hitchname = getprop("sim/hitches/aerotow/force_name_jsbsim");

  # sim/hitches/aerotow/bridle/exist:
  # 0 := bridle does not exist; no animation
  # 1 := bridle exists; bridle hook closed; weaklink closed; bridle animation
  # 2 := bridle exists; bridle hook open; weaklink closed;
  # 3 := bridle exists; bridle hook closed; weaklink open;
  # 4 := bridle exists; bridle hook open; weaklink open;

  var bridle_exist  = getprop("sim/hitches/aerotow/bridle/exist");

  if( bridle_exist > 0 ){
#print("bridle exist");

    var aerotow_open  = getprop("sim/hitches/aerotow/open");

    if(getprop("sim/hitches/aerotow/broken") and getprop("sim/hitches/aerotow/bridle/exist") == 1)
       setprop("sim/hitches/aerotow/bridle/exist",3);

    if (bridle_exist == 2) {
      # open hitch
#print("Hitch is open");
      # Bridle rope is only connected to the upper fixation
      # No tie point exists. Bridle looks like a normal towrope
      # data for bridle rope model animation
      var s1_length_m  = getprop("sim/hitches/aerotow/bridle/bridle-length-m");
      var s2_length_m  = 0.;
      var angles = bridle_deflection();
      var alpha_deg = angles[0];
      var beta_deg  = angles[1];
      var s1_alpha_deg = 90 - alpha_deg;
      var s1_beta_deg  = beta_deg;
      var s2_alpha_deg = 90 - alpha_deg;
      var s2_beta_deg  = beta_deg;
    }
    else if (bridle_exist == 3) {
      # broken weak link
#print("Weak link is broken");
      # Bridle rope (without weak link) is connected to the lower fixation
      # Bridle part with weak link remains at upper fixation
      # No tie point exists.
      # data for bridle rope model animation
      var weaklink_length_m = 0.9;
      var s1_length_m  = weaklink_length_m;
      var s2_length_m  = getprop("sim/hitches/aerotow/bridle/bridle-length-m") - weaklink_length_m ;
      var angles = bridle_deflection();
      var alpha_deg = angles[0];
      var beta_deg  = angles[1];
      var s1_alpha_deg = 90 - alpha_deg;
      var s1_beta_deg  = beta_deg;
      var s2_alpha_deg = 90 - alpha_deg;
      var s2_beta_deg  = beta_deg;
    }
    else if (bridle_exist == 4) {
      # broken weak link and  bridle hitch is open
#print("Weak link is broken and bridle hitch is open");
      # only weak link part of bridle rope is remaining at the upper fixation
      # No bridle rope at the lower fixation.
      # data for bridle rope model animation
      var weaklink_length_m = 0.9;
      var s1_length_m  = weaklink_length_m;
      var s2_length_m  = 0.;
      var angles = bridle_deflection();
      var alpha_deg = angles[0];
      var beta_deg  = angles[1];
      var s1_alpha_deg = 90 - alpha_deg;
      var s1_beta_deg  = beta_deg;
      var s2_alpha_deg = 90 - alpha_deg;
      var s2_beta_deg  = beta_deg;
    }
    else if (bridle_exist == 1) {
      # calculate tie point location (aeotow hitch position) and closed bridle animation
      var angles = bridle_deflection();
      var alpha_bridle_deg = angles[0];
      var beta_bridle_deg  = angles[1];
      var beta_bridle_rad  = beta_bridle_deg * D2R ;
#print("bridle modeling");
      # Bridle modeling:
      # The location  of the tie point of towrope with bridle depends on the towrope angle.
      # The set of all possible locations defines an ellipse.
      # (Definition ellipses see https://en.wikipedia.org/wiki/Ellipse)
      #   focus F1: upper rope fixation
      #   focus F2: lower rope fixation
      #   a: semi-major axis,
      #   b: semi-minor axis,
      #   c: linear eccentricity,
      #   linear eccentricity (2.8m / 2 = 1.4m)
      #   2a = bridle rope length (7m => a = 3.5m = s1 + s2)
      #   (x0,y0): point on ellipse

      # --------- Input from Dragonfly model (Model-System) ------------
      # Approximation: As a start semi-major axis aligns with z-axis !
      var center_ellipse_x_m = 3.65;
      var center_ellipse_z_m = 0.68;
      var distance_foci_m    = 2.8;
      # ----------------------------------------------------------------

      # Tangent angle:
      var alpha_tangent_deg = 90. - alpha_bridle_deg;
      var alpha_tangent_rad = alpha_tangent_deg * D2R;
 
      var bridle_length_m = getprop("sim/hitches/aerotow/bridle/bridle-length-m");
      var a = bridle_length_m / 2.;
      var c = distance_foci_m / 2.;
      var b = a * math.sqrt( 1. - (c/a)*(c/a) );
      var x0 = math.sqrt( a*a / ( b/a*b/a*math.tan(alpha_tangent_rad)*math.tan(alpha_tangent_rad) + 1. ) );
      var y0 = b/a*math.sqrt( a*a - x0*x0 );

      # identify quadrant of the ellipse
      if(alpha_tangent_deg >  90. or alpha_tangent_deg < -90.) x0 = -x0;
      if(alpha_tangent_deg > 180. or alpha_tangent_deg <   0.) y0 = -y0;

      # Tie point (JSBSim-Structural-System: x-> back / y -> right wing / z -> up )
      var hitch_location_x_m = center_ellipse_x_m + y0 * math.cos(beta_bridle_rad);
      var hitch_location_y_m = y0 * math.sin(beta_bridle_rad);
      var hitch_location_z_m = center_ellipse_z_m + x0;

      # Tie point (hitch location) (JSBSim-Body-System: x-> nose / y -> right wing / z -> down)
      setprop("fdm/jsbsim/external_reactions/" ~ hitchname~ "/location-x-in", hitch_location_x_m * M2IN);
      setprop("fdm/jsbsim/external_reactions/" ~ hitchname~ "/location-y-in", hitch_location_y_m * M2IN);
      setprop("fdm/jsbsim/external_reactions/" ~ hitchname~ "/location-z-in", hitch_location_z_m * M2IN);

      if( getprop("sim/model/banner-on-hook") ){
        setprop("fdm/jsbsim/external_reactions/banner/location-x-in", hitch_location_x_m * M2IN);
        setprop("fdm/jsbsim/external_reactions/banner/location-y-in", hitch_location_y_m * M2IN);
        setprop("fdm/jsbsim/external_reactions/banner/location-z-in", hitch_location_z_m * M2IN);
      }

      # hitch location for towrope animation is automatically set by towing function
      # but needed for banner-mp
      if( getprop("sim/model/banner-on-hook") ){
        # YASim-System ( x points to the nose, y points to the left wing, z points upwards )
        setprop("sim/hitches/aerotow/local-pos-x", hitch_location_x_m );
        setprop("sim/hitches/aerotow/local-pos-y", -hitch_location_y_m );
        setprop("sim/hitches/aerotow/local-pos-z", -hitch_location_z_m );
      }

      # data for bridle rope model animation
      var s1_length_m = math.sqrt( (x0-c)*(x0-c) + y0*y0 );
      var s2_length_m = math.sqrt( (x0+c)*(x0+c) + y0*y0 );
      var s1_alpha_deg = math.atan2( y0,(x0-c) ) * R2D;
      var s2_alpha_deg = math.atan2( y0,(x0+c) ) * R2D;
      var s1_beta_deg = beta_bridle_deg;
      var s2_beta_deg = beta_bridle_deg;
      # -----------------------------------------------------
      # Fake lower bridle segment:
      # Use lower hitch at Dragonfly instead of focus f2
      # ----- Input from Dragonfly model (Model-System) -----
      var lower_hitch_x_m = 3.085;
      var lower_hitch_z_m = -0.605;
      # -----------------------------------------------------
      var dist_x_m = hitch_location_x_m - lower_hitch_x_m;
      var dist_y_m = hitch_location_y_m;
      var dist_z_m = hitch_location_z_m - lower_hitch_z_m;
      var dist_xy_m = math.sqrt(dist_x_m*dist_x_m + dist_y_m*dist_y_m );

      var s2_length_m = math.sqrt( (dist_x_m*dist_x_m) + (dist_y_m*dist_y_m) + (dist_z_m*dist_z_m) );
      var s2_alpha_deg = 90. - math.atan2( dist_z_m,dist_xy_m ) * R2D;
      var s2_beta_deg = math.atan2( dist_y_m,dist_x_m ) * R2D;
      #-----------------------------------------------------------
    } # end bridle hitch animation


    setprop("sim/hitches/aerotow/bridle/bridle_length_segment1-m", s1_length_m);
    setprop("sim/hitches/aerotow/bridle/bridle_length_segment2-m", s2_length_m);
    setprop("sim/hitches/aerotow/bridle/bridle_alpha_segment1-deg", s1_alpha_deg);
    setprop("sim/hitches/aerotow/bridle/bridle_alpha_segment2-deg", s2_alpha_deg);
    setprop("sim/hitches/aerotow/bridle/bridle_beta_segment1-deg", s1_beta_deg);
    setprop("sim/hitches/aerotow/bridle/bridle_beta_segment2-deg", s2_beta_deg);

  }   # end with bridle

}  # end function


################################################################################################
#
# bridle deflection due to aero, gravity and tow/banner force
#
################################################################################################

var bridle_deflection = func (){

  var prop_induced_velocity_m_s = getprop("fdm/jsbsim/propulsion/engine/prop-induced-velocity_fps") * FT2M;

  # taking yaw and pitch rate into account
  # dist_x_m: (loction x center ellipse) - (location x c.g.)
  # JSBsim structural frame (x positive to aft)

  # ----------------  input  ----------------
  # Location center_ellipse_x_m
  var center_ellipse_x_m = 3.65;
  # -----------------------------------------

  var cg_x_m = getprop ("fdm/jsbsim/inertia/cg-x-in") * IN2M;
  var dist_x_m = center_ellipse_x_m - cg_x_m;
  
  var pitch_rate_rad_sec = getprop("fdm/jsbsim/velocities/q-aero-rad_sec");
  var yaw_rate_rad_sec   = getprop("fdm/jsbsim/velocities/r-aero-rad_sec");

  #----------------------------------------------------------------------
  # forces on bridle due to acceleration
  var mass_bridle_lbs = 0.1;
  # accel_x -> back / accel_y -> left / accel_z -> up (Not a RHS!)
  #var nx = getprop("accelerations/pilot/x-accel-fps_sec");
  #var ny = getprop("accelerations/pilot/y-accel-fps_sec");
  #var nz = getprop("accelerations/pilot/z-accel-fps_sec");

  # nx -> back / ny -> left / nz -> down
  var nx = getprop("fdm/jsbsim/accelerations/Nx");
  var ny = getprop("fdm/jsbsim/accelerations/Ny");
  var nz = getprop("fdm/jsbsim/accelerations/Nz");
  
  # force : x-> nose / y -> right wing / z -> down (JSBSim body-frame)
  var fx_due_to_acceleration_lbs = - mass_bridle_lbs * nx;
  var fy_due_to_acceleration_lbs = - mass_bridle_lbs * ny;
  var fz_due_to_acceleration_lbs =   mass_bridle_lbs * nz;

  #----------------------------------------------------------------------
  # forces on bridle due to aero (drag of bridle)
  var CDxA_bridle_sqft = 0.1;
  var rho_slugs_ft3 = getprop("fdm/jsbsim/atmosphere/rho-slugs_ft3");
  var f_vt2 = CDxA_bridle_sqft*0.5*rho_slugs_ft3;
  # velocity: vx -> tail / vy -> left wing / vz -> up (JSBSim model-frame)
  # velocity: u  -> tail / v  -> left wing / w  -> up (JSBSim model-frame)
  var vx_m_s = getprop("fdm/jsbsim/velocities/u-aero-fps")*FT2M + prop_induced_velocity_m_s;
  var vy_m_s = getprop("fdm/jsbsim/velocities/v-aero-fps")*FT2M - yaw_rate_rad_sec * dist_x_m;
  var vz_m_s = getprop("fdm/jsbsim/velocities/w-aero-fps")*FT2M + pitch_rate_rad_sec * dist_x_m;

  #force: fx-> nose / fy -> right wing / fz -> down (JSBSim body-frame)
  var fx_due_to_aero_lbs = - f_vt2 * vx_m_s*math.abs(vx_m_s) *M2FT*M2FT;
  var fy_due_to_aero_lbs = - f_vt2 * vy_m_s*math.abs(vy_m_s) *M2FT*M2FT;
  var fz_due_to_aero_lbs = - f_vt2 * vz_m_s*math.abs(vz_m_s) *M2FT*M2FT;

  #----------------------------------------------------------------------
  # forces on bridle due to towrope (aero-towing)
  var magnitude = getprop("fdm/jsbsim/external_reactions/hitch/magnitude");
  # force: fx-> nose / fy -> right wing / fz -> down (JSBSim body-frame)
  var fx_due_to_towrope_lbs = getprop("fdm/jsbsim/external_reactions/hitch/x")*magnitude;
  var fy_due_to_towrope_lbs = getprop("fdm/jsbsim/external_reactions/hitch/y")*magnitude;
  var fz_due_to_towrope_lbs = getprop("fdm/jsbsim/external_reactions/hitch/z")*magnitude;
#print("towsystem: towrope magnitude= ", magnitude);

  #----------------------------------------------------------------------
  # forces on bridle due to banner (banner drag)
  var magnitude = getprop("fdm/jsbsim/external_reactions/banner/magnitude");
  # force: fx-> nose / fy -> right wing / fz -> down (JSBSim body-frame)
  var fx_due_to_banner_lbs = getprop("fdm/jsbsim/external_reactions/banner/x")*magnitude;
  var fy_due_to_banner_lbs = getprop("fdm/jsbsim/external_reactions/banner/y")*magnitude;
  var fz_due_to_banner_lbs = getprop("fdm/jsbsim/external_reactions/banner/z")*magnitude;
#print("towsystem: banner magnitude= ", magnitude);

  var fx_total_lbs = fx_due_to_acceleration_lbs + fx_due_to_aero_lbs + fx_due_to_towrope_lbs + fx_due_to_banner_lbs;
  var fy_total_lbs = fy_due_to_acceleration_lbs + fy_due_to_aero_lbs + fy_due_to_towrope_lbs + fy_due_to_banner_lbs;
  var fz_total_lbs = fz_due_to_acceleration_lbs + fz_due_to_aero_lbs + fz_due_to_towrope_lbs + fz_due_to_banner_lbs;
  var fxy_total_lbs = math.sqrt(fx_total_lbs*fx_total_lbs + fy_total_lbs*fy_total_lbs);
  
  var alpha_bridle_deg = math.atan2(-fz_total_lbs,fxy_total_lbs) * R2D;
  var beta_bridle_deg  = math.atan2( fy_total_lbs,-fx_total_lbs) * R2D;

  var angles = [alpha_bridle_deg,beta_bridle_deg];

#print("alpha= ",alpha_bridle_deg,"  beta= ",beta_bridle_deg);
#print("fx: gravity= ",fx_due_to_acceleration_lbs,"  aero= ",fx_due_to_aero_lbs,"  towrope= ",fx_due_to_towrope_lbs);
#print("fy: gravity= ",fy_due_to_acceleration_lbs,"  aero= ",fy_due_to_aero_lbs,"  towrope= ",fy_due_to_towrope_lbs);
#print("fz: gravity= ",fz_due_to_acceleration_lbs,"  aero= ",fz_due_to_aero_lbs,"  towrope= ",fz_due_to_towrope_lbs);

  return (angles);

}


################################################################################################
#
# Set default aerotow values
#
################################################################################################

var set_defaults = func (device){

  if(device == "aerotow") {
    #setprop("sim/hitches/aerotow/tow/brake-force", 1200.);
    # should be 1200N in real life due to safety reasons. Here set to a high value to avoid frustrations
    # (timelag in multiplayer could lead to higher forces).
    setprop("sim/hitches/aerotow/tow/brake-force", 10000.);
    setprop("sim/hitches/aerotow/bridle/bridle-length-m", 7.);
    setprop("sim/hitches/aerotow/bridle/bridle-diameter-mm", 8.);
    setprop("sim/hitches/aerotow/rope/rope-diameter-mm", 8.);
  }
}

# Start HitchAnimation ASAP
#HitchAnimation();
# orientation/alpha-deg and side-slip-deg are not available at startup.
# Hence start function a little bit later
var hitchAnimationTimer = maketimer( 0.0, HitchAnimation );
hitchAnimationTimer.simulatedTime = 1;

var ls = setlistener("/sim/signals/fdm-initialized", func{
	hitchAnimationTimer.start();
	removelistener( ls );
});
