# RCAIDE/Library/Methods/Powertrain/Propulsors/Internal_Combustion_Engine/compute_internal_combustion_engine_performance.py
# 
# 
# Created:  Jul 2023, M. Clarke

# ----------------------------------------------------------------------------------------------------------------------
#  IMPORT
# ----------------------------------------------------------------------------------------------------------------------
# RCAIDE imports  
from RCAIDE.Framework.Core import Units  
from RCAIDE.Library.Methods.Powertrain.Converters.Engine import compute_power_from_throttle
from RCAIDE.Library.Methods.Powertrain.Converters.Rotor.compute_rotor_performance import  compute_rotor_performance

# pacakge imports  
from copy import deepcopy
import numpy as np  

# ----------------------------------------------------------------------------------------------------------------------
# compute_internal_combustion_engine_performance
# ---------------------------------------------------------------------------------------------------------------------- 
def compute_internal_combustion_engine_performance(propulsor, state, center_of_gravity=[[0.0, 0.0, 0.0]]):
    """
    Computes the performance of an internal combustion engine propulsion system.
    
    Parameters
    ----------
    propulsor : RCAIDE.Library.Components.Propulsors.Internal_Combustion_Engine
        Internal combustion engine propulsor component with the following attributes:
            - tag : str
                Identifier for the propulsor
            - engine : Data
                Engine component
                    - tag : str
                        Identifier for the engine
            - propeller : Data
                Propeller component
                    - tag : str
                        Identifier for the propeller
                    - origin : list of lists
                        Origin coordinates [[x, y, z]] [m]
    state : RCAIDE.Framework.Mission.Common.State
        State object containing:
            - conditions : Data
                Flight conditions
                    - energy : Data
                        Energy conditions
                            - propulsors : dict
                                Propulsor energy conditions indexed by tag
                            - converters : dict
                                Converter energy conditions indexed by tag
            - ones_row : function
                Function to create array of ones with specified length
    center_of_gravity : list of lists, optional
        Center of gravity coordinates [[x, y, z]] [m]
        Default: [[0.0, 0.0, 0.0]]
    
    Returns
    -------
    thrust : numpy.ndarray
        Thrust force vector [N]
    moment : numpy.ndarray
        Moment vector [N·m]
    power : numpy.ndarray
        Mechanical power [W]
    power_elec : numpy.ndarray
        Electrical power [W] (zero for non-hybrid engines)
    stored_results_flag : bool
        Flag indicating if results are stored
    stored_propulsor_tag : str
        Tag of the propulsor with stored results
    
    Notes
    -----
    This function computes the performance of an internal combustion engine propulsion system
    by linking the engine to the propeller. It performs the following steps:
        * Sets the engine throttle based on the propulsor throttle
        * Computes the engine power output using the throttle setting
        * Transfers the engine's angular velocity and throttle to the propeller
        * Computes the propeller performance
        * Calculates the moment generated by the propeller thrust
        * Stores the results in the conditions data structure
    
    The function assumes a direct mechanical connection between the engine and propeller,
    with no electrical power generation or consumption (non-hybrid configuration).
    
    **Major Assumptions**
        * Direct mechanical connection between engine and propeller
        * No electrical power generation or consumption
    
    See Also
    --------
    RCAIDE.Library.Methods.Powertrain.Converters.Engine.compute_power_from_throttle
    RCAIDE.Library.Methods.Powertrain.Converters.Rotor.compute_rotor_performance
    """
    conditions              = state.conditions  
    engine                  = propulsor.engine 
    propeller               = propulsor.propeller
    ice_conditions          = conditions.energy.propulsors[propulsor.tag]

    # Throttle the engine 
    conditions.energy.converters[engine.tag].throttle        = conditions.energy.propulsors[propulsor.tag].throttle 
    compute_power_from_throttle(engine,conditions)        
     
    # Run the propeller to get the power
    conditions.energy.converters[propeller.tag].omega          = conditions.energy.converters[engine.tag].omega 
    conditions.energy.converters[propeller.tag].throttle       = conditions.energy.converters[engine.tag].throttle
    conditions.energy.converters[propeller.tag].commanded_thrust_vector_angle =  conditions.energy.propulsors[propulsor.tag].commanded_thrust_vector_angle
    compute_rotor_performance(propeller,conditions)

    # Compute moment 
    moment_vector           = 0*state.ones_row(3)
    moment_vector[:,0]      = propeller.origin[0][0]  -  center_of_gravity[0][0] 
    moment_vector[:,1]      = propeller.origin[0][1]  -  center_of_gravity[0][1] 
    moment_vector[:,2]      = propeller.origin[0][2]  -  center_of_gravity[0][2]
    moment                  =  np.cross(moment_vector, conditions.energy.converters[propeller.tag].thrust)       
    
    # Create the outputs
    ice_conditions.fuel_flow_rate            = conditions.energy.converters[engine.tag].fuel_flow_rate  
    stored_results_flag                      = True
    stored_propulsor_tag                     = propulsor.tag 


    # compute total forces and moments from propulsor (future work would be to add moments from motors)
    ice_conditions.thrust      = conditions.energy.converters[propeller.tag].thrust 
    ice_conditions.moment      = moment
    ice_conditions.power       = conditions.energy.converters[propeller.tag].power  
    
    # currently, no hybridization
    power_elec =  0*state.ones_row(1)
    
    return ice_conditions.thrust,ice_conditions.moment,ice_conditions.power,power_elec,stored_results_flag,stored_propulsor_tag  
    
    
def reuse_stored_internal_combustion_engine_data(propulsor,state,network,stored_propulsor_tag,center_of_gravity= [[0.0, 0.0,0.0]]):
    '''Reuses results from one propulsor for identical propulsors
    
    Assumptions: 
    N/A

    Source:
    N/A

    Inputs:  
    conditions           - operating conditions data structure        [-]  
    fuel_line            - fuel line                                  [-] 
    propulsor            - propulsor data structure               [-] 
    total_thrust         - thrust of propulsor group              [N]
    total_power          - power of propulsor group               [W] 

    Outputs:  
    total_thrust         - thrust of propulsor group              [N]
    total_power          - power of propulsor group               [W] 
    
    Properties Used: 
    N.A.        
    ''' 

    # unpack
    conditions   = state.conditions 
    engine       = propulsor.engine
    propeller    = propulsor.propeller 
    engine_0     = network.propulsors[stored_propulsor_tag].engine
    propeller_0  = network.propulsors[stored_propulsor_tag].propeller  
    
    # deepcopy results 
    conditions.energy.propulsors[propulsor.tag]     = deepcopy(conditions.energy.propulsors[stored_propulsor_tag.tag])
    conditions.energy.converters[engine.tag]        = deepcopy(conditions.energy.converters[engine_0.tag])
    conditions.energy.converters[propeller.tag]     = deepcopy(conditions.energy.converters[propeller_0.tag])
   
    # compoment 
    thrust_vector           = conditions.energy.converters[propeller.tag].thrust 
    power                   = conditions.energy.converters[propeller.tag].power   
    moment_vector           = 0*state.ones_row(3) 
    moment_vector[:,0]      = propeller.origin[0][0]  -  center_of_gravity[0][0] 
    moment_vector[:,1]      = propeller.origin[0][1]  -  center_of_gravity[0][1] 
    moment_vector[:,2]      = propeller.origin[0][2]  -  center_of_gravity[0][2]
    moment                  =  np.cross(moment_vector, thrust_vector)
    
    # pack 
    conditions.energy.converters[propeller.tag].moment = moment  
    conditions.energy.propulsors[propulsor.tag].thrust = thrust_vector   
    conditions.energy.propulsors[propulsor.tag].moment = moment  
    conditions.energy.propulsors[propulsor.tag].power  = power
  
    power_elec =  0*state.ones_row(1)
    
    return thrust_vector,moment,power, power_elec

            
               