# coding: utf-8

"""
    LUSID API

    FINBOURNE Technology  # noqa: E501

    Contact: info@finbourne.com
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""


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

from datetime import datetime
from typing import Any, Dict, Optional, Union
from pydantic.v1 import BaseModel, Field, StrictBool, StrictFloat, StrictInt, StrictStr, constr
from lusid.models.compounding import Compounding
from lusid.models.flow_convention_name import FlowConventionName
from lusid.models.flow_conventions import FlowConventions
from lusid.models.fx_linked_notional_schedule import FxLinkedNotionalSchedule
from lusid.models.index_convention import IndexConvention
from lusid.models.step_schedule import StepSchedule

class LegDefinition(BaseModel):
    """
    Definition of the set of flow and index conventions along with other miscellaneous information required to generate an instrument leg.  # noqa: E501
    """
    convention_name: Optional[FlowConventionName] = Field(None, alias="conventionName")
    conventions: Optional[FlowConventions] = None
    index_convention: Optional[IndexConvention] = Field(None, alias="indexConvention")
    index_convention_name: Optional[FlowConventionName] = Field(None, alias="indexConventionName")
    notional_exchange_type: constr(strict=True, min_length=1) = Field(..., alias="notionalExchangeType", description="what type of notional exchange does the leg have    Supported string (enumeration) values are: [None, Initial, Final, Both].")
    pay_receive: constr(strict=True, min_length=1) = Field(..., alias="payReceive", description="Is the leg to be paid or received    Supported string (enumeration) values are: [Pay, Receive].")
    rate_or_spread: Union[StrictFloat, StrictInt] = Field(..., alias="rateOrSpread", description="Is there either a fixed rate (non-zero) or spread to be paid over the value of the leg.")
    reset_convention: Optional[StrictStr] = Field(None, alias="resetConvention", description="Control how resets are generated relative to swap payment convention(s).    Supported string (enumeration) values are: [InAdvance, InArrears].")
    stub_type: constr(strict=True, min_length=1) = Field(..., alias="stubType", description="If a stub is required should it be at the front or back of the leg.    Supported string (enumeration) values are: [None, ShortFront, ShortBack, LongBack, LongFront, Both].")
    compounding: Optional[Compounding] = None
    amortisation: Optional[StepSchedule] = None
    first_regular_payment_date: Optional[datetime] = Field(None, alias="firstRegularPaymentDate", description="Optional payment date of the first regular coupon.  Must be greater than the StartDate.  If set, the regular coupon schedule will be built such that the first regular coupon  will end on this date. The start date of this coupon will be calculated as normal and  a stub coupon will be created from the StartDate to the start of the first regular coupon.")
    first_coupon_type: Optional[StrictStr] = Field(None, alias="firstCouponType", description="Optional coupon type setting for the first coupon, can be used with Stub coupons.  If set to \"ProRata\" (the default), the coupon year fraction is calculated as normal,  however if set to \"Full\" the year fraction is overwritten with the standard year fraction  for a regular ful\" coupon. Note this does not use the day count convention but rather is defined  directly from the tenor (i.e. a quarterly leg will be set to 0.25).    Supported string (enumeration) values are: [ProRata, Full].")
    last_regular_payment_date: Optional[datetime] = Field(None, alias="lastRegularPaymentDate", description="Optional payment date of the last regular coupon.  Must be less than the Maturity date.  If set, the regular coupon schedule will be built up to this date and the final  coupon will be a stub between this date and the Maturity date.")
    last_coupon_type: Optional[StrictStr] = Field(None, alias="lastCouponType", description="Optional coupon type setting for the last coupon, can be used with Stub coupons.  If set to \"ProRata\" (the default), the coupon year fraction is calculated as normal,  however if set to \"Full\" the year fraction is overwritten with the standard year fraction  for a regular ful\" coupon. Note this does not use the day count convention but rather is defined  directly from the tenor (i.e. a quarterly leg will be set to 0.25).    Supported string (enumeration) values are: [ProRata, Full].")
    fx_linked_notional_schedule: Optional[FxLinkedNotionalSchedule] = Field(None, alias="fxLinkedNotionalSchedule")
    intermediate_notional_exchange: Optional[StrictBool] = Field(None, alias="intermediateNotionalExchange", description="Indicates whether there are intermediate notional exchanges.")
    __properties = ["conventionName", "conventions", "indexConvention", "indexConventionName", "notionalExchangeType", "payReceive", "rateOrSpread", "resetConvention", "stubType", "compounding", "amortisation", "firstRegularPaymentDate", "firstCouponType", "lastRegularPaymentDate", "lastCouponType", "fxLinkedNotionalSchedule", "intermediateNotionalExchange"]

    class Config:
        """Pydantic configuration"""
        allow_population_by_field_name = True
        validate_assignment = True

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

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        return json.dumps(self.to_dict())

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

    def to_dict(self):
        """Returns the dictionary representation of the model using alias"""
        _dict = self.dict(by_alias=True,
                          exclude={
                          },
                          exclude_none=True)
        # override the default output from pydantic by calling `to_dict()` of convention_name
        if self.convention_name:
            _dict['conventionName'] = self.convention_name.to_dict()
        # override the default output from pydantic by calling `to_dict()` of conventions
        if self.conventions:
            _dict['conventions'] = self.conventions.to_dict()
        # override the default output from pydantic by calling `to_dict()` of index_convention
        if self.index_convention:
            _dict['indexConvention'] = self.index_convention.to_dict()
        # override the default output from pydantic by calling `to_dict()` of index_convention_name
        if self.index_convention_name:
            _dict['indexConventionName'] = self.index_convention_name.to_dict()
        # override the default output from pydantic by calling `to_dict()` of compounding
        if self.compounding:
            _dict['compounding'] = self.compounding.to_dict()
        # override the default output from pydantic by calling `to_dict()` of amortisation
        if self.amortisation:
            _dict['amortisation'] = self.amortisation.to_dict()
        # override the default output from pydantic by calling `to_dict()` of fx_linked_notional_schedule
        if self.fx_linked_notional_schedule:
            _dict['fxLinkedNotionalSchedule'] = self.fx_linked_notional_schedule.to_dict()
        # set to None if reset_convention (nullable) is None
        # and __fields_set__ contains the field
        if self.reset_convention is None and "reset_convention" in self.__fields_set__:
            _dict['resetConvention'] = None

        # set to None if first_regular_payment_date (nullable) is None
        # and __fields_set__ contains the field
        if self.first_regular_payment_date is None and "first_regular_payment_date" in self.__fields_set__:
            _dict['firstRegularPaymentDate'] = None

        # set to None if first_coupon_type (nullable) is None
        # and __fields_set__ contains the field
        if self.first_coupon_type is None and "first_coupon_type" in self.__fields_set__:
            _dict['firstCouponType'] = None

        # set to None if last_regular_payment_date (nullable) is None
        # and __fields_set__ contains the field
        if self.last_regular_payment_date is None and "last_regular_payment_date" in self.__fields_set__:
            _dict['lastRegularPaymentDate'] = None

        # set to None if last_coupon_type (nullable) is None
        # and __fields_set__ contains the field
        if self.last_coupon_type is None and "last_coupon_type" in self.__fields_set__:
            _dict['lastCouponType'] = None

        # set to None if intermediate_notional_exchange (nullable) is None
        # and __fields_set__ contains the field
        if self.intermediate_notional_exchange is None and "intermediate_notional_exchange" in self.__fields_set__:
            _dict['intermediateNotionalExchange'] = None

        return _dict

    @classmethod
    def from_dict(cls, obj: dict) -> LegDefinition:
        """Create an instance of LegDefinition from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return LegDefinition.parse_obj(obj)

        _obj = LegDefinition.parse_obj({
            "convention_name": FlowConventionName.from_dict(obj.get("conventionName")) if obj.get("conventionName") is not None else None,
            "conventions": FlowConventions.from_dict(obj.get("conventions")) if obj.get("conventions") is not None else None,
            "index_convention": IndexConvention.from_dict(obj.get("indexConvention")) if obj.get("indexConvention") is not None else None,
            "index_convention_name": FlowConventionName.from_dict(obj.get("indexConventionName")) if obj.get("indexConventionName") is not None else None,
            "notional_exchange_type": obj.get("notionalExchangeType"),
            "pay_receive": obj.get("payReceive"),
            "rate_or_spread": obj.get("rateOrSpread"),
            "reset_convention": obj.get("resetConvention"),
            "stub_type": obj.get("stubType"),
            "compounding": Compounding.from_dict(obj.get("compounding")) if obj.get("compounding") is not None else None,
            "amortisation": StepSchedule.from_dict(obj.get("amortisation")) if obj.get("amortisation") is not None else None,
            "first_regular_payment_date": obj.get("firstRegularPaymentDate"),
            "first_coupon_type": obj.get("firstCouponType"),
            "last_regular_payment_date": obj.get("lastRegularPaymentDate"),
            "last_coupon_type": obj.get("lastCouponType"),
            "fx_linked_notional_schedule": FxLinkedNotionalSchedule.from_dict(obj.get("fxLinkedNotionalSchedule")) if obj.get("fxLinkedNotionalSchedule") is not None else None,
            "intermediate_notional_exchange": obj.get("intermediateNotionalExchange")
        })
        return _obj
