# coding: utf-8

"""
    Orbital transfer API

    An orbital transfer corresponds to a non-coplanar orbit transfer where semi-major axis, inclination and eccentricity can be simultaneously changed.  When considering a change in inclination, an efficiency factor is taken into account to consider the fact that this maneuver is  less efficient away from the orbital nodes. The length of the thrust arcs about the nodes is dictated by the duty cycle.   Different perturbations can be considered while performing this manoeuvre: Earth potential, third-body (Sun, Moon), atmospheric drag  and solar radiation pressure.   <b>CHANGELOG</b> <ul>   <li><b>2.2.0</b> - 2024-07-11 - Add space weather data source choice to <b>NRLMSISE00AtmosphericModel</b> schema</li>   <li><b>2.1.0</b> - 2024-07-03 - Add <b>atmosphericModel</b> in <b>DragPerturbation</b> schema</li>   <li><b>2.0.0</b> - 2024-06-06 - Complete refactoring of the API</li> </ul> 

    The version of the OpenAPI document: 2.2.2
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""  # noqa: E501


from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictFloat, StrictInt, StrictStr, field_validator
from typing import Any, ClassVar, Dict, List, Optional, Union
from orbital_transfer.models.custom_maneuvering_strategy import CustomManeuveringStrategy
from orbital_transfer.models.orbit import Orbit
from orbital_transfer.models.perturbation import Perturbation
from orbital_transfer.models.platform import Platform
from orbital_transfer.models.propulsion_system import PropulsionSystem
from orbital_transfer.models.spacecraft_geometry import SpacecraftGeometry
from typing import Optional, Set
from typing_extensions import Self

class OrbitalTransferSimulationRequestInputs(BaseModel):
    """
    The computation inputs. 
    """ # noqa: E501
    mission_date_time: Optional[StrictStr] = Field(default=None, description="The mission date and time.  This is the date and time at which the mission starts. ", alias="missionDateTime")
    maximum_duration: Optional[StrictInt] = Field(default=None, description="The simulation maximum duration (in days).  This is the maximum duration expected for the mission. If the target is not reached after that duration,  the mission would fail. This parameter is used to avoid unpredicted long simulation. ", alias="maximumDuration")
    propagation_type: StrictStr = Field(description="The type of propagation to use for the computation.  Two type of propagation can be performed : <ul>   <li><b>Numerical propagation</b>: this gives the most accurate results at the expenses of an increased      computational load. The integrator used is an adaptative step Dormand-Prince which guarantees high      precision. The maximum step is set to 100 seconds and the minimum one to 0.01 seconds.</li>    <li><b>Semi-analytical propagation</b>: this allows to propagate the mean orbital elements      (as per the DSST theory) using a very large step. This results in very fast yet accurate propagations.      An adaptative step integrator is used (Dormand-Prince). The step is computed as a function of the      orbital period and its maximum value is set to 20 times the Keplerian orbital period. Eclipse,      attitude and power system can not be simulated in semi-analytical propagation.</li> </ul> ", alias="propagationType")
    initial_orbit: Orbit = Field(alias="initialOrbit")
    target_orbit: Orbit = Field(alias="targetOrbit")
    spacecraft_geometry: Optional[SpacecraftGeometry] = Field(default=None, alias="spacecraftGeometry")
    platform: Optional[Platform] = None
    propulsion_system: Optional[PropulsionSystem] = Field(default=None, alias="propulsionSystem")
    perturbations: Optional[List[Perturbation]] = Field(default=None, description="The perturbations to apply to the orbit propagation")
    custom_maneuvering_strategy: Optional[CustomManeuveringStrategy] = Field(default=None, alias="customManeuveringStrategy")
    thrust_efficiency_cutoff: Optional[Union[StrictFloat, StrictInt]] = Field(default=None, description="Thrust efficiency is a measure that indicates how effectively thrusting at a specific point in orbit contributes to moving  the spacecraft toward its desired final orbit.   By defining a Thrust Efficiency Cutoff, the user can set a threshold below which thrusting is not permitted.  This threshold helps avoid using propellant in less efficient regions of the orbit, balancing between how long the mission  takes and how much fuel is used. ", alias="thrustEfficiencyCutoff")
    terrestrial_longitude_targeted: Optional[StrictBool] = Field(default=False, description="Terrestrial Longitude Targeted allows for targeting a specific terrestrial longitude at the end of the orbital transfer.  During the transfer, the spacecraft temporarily stops thrusting and coasts in its orbit. As it nears the desired longitude,  it resumes thrusting to reach the final targeted longitude ", alias="terrestrialLongitudeTargeted")
    __properties: ClassVar[List[str]] = ["missionDateTime", "maximumDuration", "propagationType", "initialOrbit", "targetOrbit", "spacecraftGeometry", "platform", "propulsionSystem", "perturbations", "customManeuveringStrategy", "thrustEfficiencyCutoff", "terrestrialLongitudeTargeted"]

    @field_validator('propagation_type')
    def propagation_type_validate_enum(cls, value):
        """Validates the enum"""
        if value not in set(['NUMERICAL', 'SEMI_ANALYTICAL']):
            raise ValueError("must be one of enum values ('NUMERICAL', 'SEMI_ANALYTICAL')")
        return value

    model_config = ConfigDict(
        populate_by_name=True,
        validate_assignment=True,
        protected_namespaces=(),
    )


    def to_str(self) -> str:
        """Returns the string representation of the model using alias"""
        return pprint.pformat(self.model_dump(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> Optional[Self]:
        """Create an instance of OrbitalTransferSimulationRequestInputs from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self) -> Dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        """
        excluded_fields: Set[str] = set([
        ])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of initial_orbit
        if self.initial_orbit:
            _dict['initialOrbit'] = self.initial_orbit.to_dict()
        # override the default output from pydantic by calling `to_dict()` of target_orbit
        if self.target_orbit:
            _dict['targetOrbit'] = self.target_orbit.to_dict()
        # override the default output from pydantic by calling `to_dict()` of spacecraft_geometry
        if self.spacecraft_geometry:
            _dict['spacecraftGeometry'] = self.spacecraft_geometry.to_dict()
        # override the default output from pydantic by calling `to_dict()` of platform
        if self.platform:
            _dict['platform'] = self.platform.to_dict()
        # override the default output from pydantic by calling `to_dict()` of propulsion_system
        if self.propulsion_system:
            _dict['propulsionSystem'] = self.propulsion_system.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in perturbations (list)
        _items = []
        if self.perturbations:
            for _item in self.perturbations:
                if _item:
                    _items.append(_item.to_dict())
            _dict['perturbations'] = _items
        # override the default output from pydantic by calling `to_dict()` of custom_maneuvering_strategy
        if self.custom_maneuvering_strategy:
            _dict['customManeuveringStrategy'] = self.custom_maneuvering_strategy.to_dict()
        return _dict

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of OrbitalTransferSimulationRequestInputs from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        _obj = cls.model_validate({
            "missionDateTime": obj.get("missionDateTime"),
            "maximumDuration": obj.get("maximumDuration"),
            "propagationType": obj.get("propagationType") if obj.get("propagationType") is not None else 'NUMERICAL',
            "initialOrbit": Orbit.from_dict(obj["initialOrbit"]) if obj.get("initialOrbit") is not None else None,
            "targetOrbit": Orbit.from_dict(obj["targetOrbit"]) if obj.get("targetOrbit") is not None else None,
            "spacecraftGeometry": SpacecraftGeometry.from_dict(obj["spacecraftGeometry"]) if obj.get("spacecraftGeometry") is not None else None,
            "platform": Platform.from_dict(obj["platform"]) if obj.get("platform") is not None else None,
            "propulsionSystem": PropulsionSystem.from_dict(obj["propulsionSystem"]) if obj.get("propulsionSystem") is not None else None,
            "perturbations": [Perturbation.from_dict(_item) for _item in obj["perturbations"]] if obj.get("perturbations") is not None else None,
            "customManeuveringStrategy": CustomManeuveringStrategy.from_dict(obj["customManeuveringStrategy"]) if obj.get("customManeuveringStrategy") is not None else None,
            "thrustEfficiencyCutoff": obj.get("thrustEfficiencyCutoff"),
            "terrestrialLongitudeTargeted": obj.get("terrestrialLongitudeTargeted") if obj.get("terrestrialLongitudeTargeted") is not None else False
        })
        return _obj


