# 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 typing import Any, Dict, List, Optional
from pydantic.v1 import BaseModel, Field, conlist
from lusid.models.model_selection import ModelSelection
from lusid.models.pricing_options import PricingOptions
from lusid.models.result_key_rule import ResultKeyRule
from lusid.models.vendor_model_rule import VendorModelRule

class PricingContext(BaseModel):
    """
    Pricing context node. In order to price an instrument a number of configuration parameters are required to determine which  (a) pricing model (ranging from a simple lookup of a market quote/price through to a Monte-Carlo simulation for the behaviour of its cashflows)  (b) vendor library (Lusid internal models or those provided through an external Vendor such as Refinitiv (proprietary) or QuantLib (open source)  are used in the pricing.    In conjunction with these there are a number of parameters that govern the behaviour of these models. For example, in pricing an Fx volatility  dependent product such as an Fx option, there are various parameters that affect model behaviour for the smile. In Lusid a distinction is made between  those which are understood natively and those which are only held for use with a given vendor-model combination. The problem is that, unlike market  quote data, there are few standards around model descriptions. Hence, apparently similar terminology can be mis-leading; for example in SABR models where  the basic parameters are agreed upon but most practical models have used an approximation with adjustments where the parameters can have wildly different meanings.  To avoid confusion or mis-behaviour in this area, where parameters are not understood to be interchangeable, they are only settable on a per-library per-model  basis, essentially as opaque data that will be given to the Vendor library \"verbatim\" but not used with any other.  # noqa: E501
    """
    model_rules: Optional[conlist(VendorModelRule)] = Field(None, alias="modelRules", description="The set of model rules that are available. There may be multiple rules for Vendors, but only one per model-instrument pair.  Which of these preference sets is used depends upon the model choice selection if specified, or failing that the global default model specification  in the options.")
    model_choice: Optional[Dict[str, ModelSelection]] = Field(None, alias="modelChoice", description="The choice of which model selection (vendor library, pricing model) to use in evaluation of a given instrument type.")
    options: Optional[PricingOptions] = None
    result_data_rules: Optional[conlist(ResultKeyRule)] = Field(None, alias="resultDataRules", description="Set of rules that control querying of unit results either for direct queries into aggregation or for  overriding intermediate calculations. For example, a dirty price is made up from a clean price and the accrued interest.  One might consider overriding the accrued interest calculated by a model (perhaps one wants to match an external value or simply disagrees with the  calculated result) and use that in calculation of the dirty price.")
    __properties = ["modelRules", "modelChoice", "options", "resultDataRules"]

    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) -> PricingContext:
        """Create an instance of PricingContext 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 each item in model_rules (list)
        _items = []
        if self.model_rules:
            for _item in self.model_rules:
                if _item:
                    _items.append(_item.to_dict())
            _dict['modelRules'] = _items
        # override the default output from pydantic by calling `to_dict()` of each value in model_choice (dict)
        _field_dict = {}
        if self.model_choice:
            for _key in self.model_choice:
                if self.model_choice[_key]:
                    _field_dict[_key] = self.model_choice[_key].to_dict()
            _dict['modelChoice'] = _field_dict
        # override the default output from pydantic by calling `to_dict()` of options
        if self.options:
            _dict['options'] = self.options.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in result_data_rules (list)
        _items = []
        if self.result_data_rules:
            for _item in self.result_data_rules:
                if _item:
                    _items.append(_item.to_dict())
            _dict['resultDataRules'] = _items
        # set to None if model_rules (nullable) is None
        # and __fields_set__ contains the field
        if self.model_rules is None and "model_rules" in self.__fields_set__:
            _dict['modelRules'] = None

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

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

        return _dict

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

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

        _obj = PricingContext.parse_obj({
            "model_rules": [VendorModelRule.from_dict(_item) for _item in obj.get("modelRules")] if obj.get("modelRules") is not None else None,
            "model_choice": dict(
                (_k, ModelSelection.from_dict(_v))
                for _k, _v in obj.get("modelChoice").items()
            )
            if obj.get("modelChoice") is not None
            else None,
            "options": PricingOptions.from_dict(obj.get("options")) if obj.get("options") is not None else None,
            "result_data_rules": [ResultKeyRule.from_dict(_item) for _item in obj.get("resultDataRules")] if obj.get("resultDataRules") is not None else None
        })
        return _obj
