# Copyright (C) 2021 - 2024 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""Module providing the BoundaryFluxTrajectory class."""
import typing
from ansys.dyna.core.lib.card import Card, Field, Flag
from ansys.dyna.core.lib.field_schema import FieldSchema
from ansys.dyna.core.lib.keyword_base import KeywordBase
from ansys.dyna.core.lib.keyword_base import LinkType
from ansys.dyna.core.keywords.keyword_classes.auto.define.define_curve import DefineCurve

_BOUNDARYFLUXTRAJECTORY_CARD0 = (
    FieldSchema("ssid", int, 0, 10, None),
    FieldSchema("pserod", int, 10, 10, None),
    FieldSchema("nsid1", int, 20, 10, None),
    FieldSchema("spd1", float, 30, 10, 0.0),
    FieldSchema("nsid2", int, 40, 10, None),
    FieldSchema("spd2", float, 50, 10, 0.0),
    FieldSchema("relvel", int, 60, 10, 0),
)

_BOUNDARYFLUXTRAJECTORY_CARD1 = (
    FieldSchema("erod", int, 0, 10, 0),
    FieldSchema("loc", int, 10, 10, None),
    FieldSchema("lcrot", int, 20, 10, None),
    FieldSchema("lclat", int, 30, 10, None),
)

_BOUNDARYFLUXTRAJECTORY_CARD2 = (
    FieldSchema("iform", int, 0, 10, None),
    FieldSchema("lctim", int, 10, 10, None),
    FieldSchema("q", float, 20, 10, 0.0),
    FieldSchema("lcinc", int, 30, 10, None),
    FieldSchema("enfor", int, 40, 10, 0),
)

_BOUNDARYFLUXTRAJECTORY_CARD3 = (
    FieldSchema("p1", float, 0, 10, None),
    FieldSchema("p2", float, 10, 10, None),
    FieldSchema("p3", float, 20, 10, None),
    FieldSchema("p4", float, 30, 10, None),
    FieldSchema("p5", float, 40, 10, None),
    FieldSchema("p6", float, 50, 10, None),
    FieldSchema("p7", float, 60, 10, None),
    FieldSchema("p8", float, 70, 10, None),
)

_BOUNDARYFLUXTRAJECTORY_CARD4 = (
    FieldSchema("tx", float, 0, 10, None),
    FieldSchema("ty", float, 10, 10, None),
    FieldSchema("tz", float, 20, 10, None),
)

class BoundaryFluxTrajectory(KeywordBase):
    """DYNA BOUNDARY_FLUX_TRAJECTORY keyword"""

    keyword = "BOUNDARY"
    subkeyword = "FLUX_TRAJECTORY"
    _link_fields = {
        "lcrot": LinkType.DEFINE_CURVE,
        "lclat": LinkType.DEFINE_CURVE,
        "lctim": LinkType.DEFINE_CURVE,
        "lcinc": LinkType.DEFINE_CURVE,
        "nsid1": LinkType.SET_NODE,
        "pserod": LinkType.SET_PART,
        "ssid": LinkType.SET_SEGMENT,
    }

    def __init__(self, **kwargs):
        """Initialize the BoundaryFluxTrajectory class."""
        super().__init__(**kwargs)
        self._cards = [
            Card.from_field_schemas_with_defaults(
                _BOUNDARYFLUXTRAJECTORY_CARD0,
                **kwargs,
            ),            Card.from_field_schemas_with_defaults(
                _BOUNDARYFLUXTRAJECTORY_CARD1,
                **kwargs,
            ),            Card.from_field_schemas_with_defaults(
                _BOUNDARYFLUXTRAJECTORY_CARD2,
                **kwargs,
            ),            Card.from_field_schemas_with_defaults(
                _BOUNDARYFLUXTRAJECTORY_CARD3,
                **kwargs,
            ),            Card.from_field_schemas_with_defaults(
                _BOUNDARYFLUXTRAJECTORY_CARD4,
                **kwargs,
            ),        ]
    @property
    def ssid(self) -> typing.Optional[int]:
        """Get or set the Segment set ID containing segments that are potentially heated
        by surface heat source (flux)..
        """ # nopep8
        return self._cards[0].get_value("ssid")

    @ssid.setter
    def ssid(self, value: int) -> None:
        """Set the ssid property."""
        self._cards[0].set_value("ssid", value)

    @property
    def pserod(self) -> typing.Optional[int]:
        """Get or set the Part set ID for updating boundary segments exposed to the environment as solid elements erode.
        """ # nopep8
        return self._cards[0].get_value("pserod")

    @pserod.setter
    def pserod(self, value: int) -> None:
        """Set the pserod property."""
        self._cards[0].set_value("pserod", value)

    @property
    def nsid1(self) -> typing.Optional[int]:
        """Get or set the Node set defining the path of the weld source. The source travels
        along the path at speed SPD1. The nodes are traversed according
        to their ordering in the node set. See Remark 1.
        """ # nopep8
        return self._cards[0].get_value("nsid1")

    @nsid1.setter
    def nsid1(self, value: int) -> None:
        """Set the nsid1 property."""
        self._cards[0].set_value("nsid1", value)

    @property
    def spd1(self) -> float:
        """Get or set the Speed of the heat source on the weld trajectory
        GT.0.0: constant speed
        LT.0.0: |SPD1| is a load curve ID defining weld speed as a function of time.
        """ # nopep8
        return self._cards[0].get_value("spd1")

    @spd1.setter
    def spd1(self, value: float) -> None:
        """Set the spd1 property."""
        self._cards[0].set_value("spd1", value)

    @property
    def nsid2(self) -> typing.Optional[int]:
        """Get or set the Node or segment set containing information for the weld source aiming direction:
        GT.0: NSID2 together with SPD2 define a curve in the same
        way that NSID1 and SPD1 define a curve. Aiming direction
        is taken to be the vector pointing from the current
        position along NSID2 (for example your hand holding
        the torch) to the current position on NSID1 (the weld source).
        EQ.0: beam aiming direction is (TX, TY, TZ) input on Card 5.
        """ # nopep8
        return self._cards[0].get_value("nsid2")

    @nsid2.setter
    def nsid2(self, value: int) -> None:
        """Set the nsid2 property."""
        self._cards[0].set_value("nsid2", value)

    @property
    def spd2(self) -> float:
        """Get or set the Speed of reference point in NSID2 (ignored unless NSID2 > 0)
        GT.0: constant speed
        LT.0: |SPD2| is a load curve ID defining weld speed as a
        function of time.
        """ # nopep8
        return self._cards[0].get_value("spd2")

    @spd2.setter
    def spd2(self, value: float) -> None:
        """Set the spd2 property."""
        self._cards[0].set_value("spd2", value)

    @property
    def relvel(self) -> int:
        """Get or set the Defines if SPD1 and SPD2 are relative or absolute speeds in
        coupled simulations
        EQ.0: absolute speeds
        EQ.1: relative speeds with respect to underlying structure.
        """ # nopep8
        return self._cards[0].get_value("relvel")

    @relvel.setter
    def relvel(self, value: int) -> None:
        """Set the relvel property."""
        if value not in [0, 1, None]:
            raise Exception("""relvel must be `None` or one of {0,1}.""")
        self._cards[0].set_value("relvel", value)

    @property
    def erod(self) -> int:
        """Get or set the Flag for updating boundary segments exposed to the
        environment as solid elements (defined in PSEROD) erode; see Remark 5.
        EQ.0: no propagation onto new segments
        EQ.1: propagation onto new segments.
        """ # nopep8
        return self._cards[1].get_value("erod")

    @erod.setter
    def erod(self, value: int) -> None:
        """Set the erod property."""
        if value not in [0, 1, None]:
            raise Exception("""erod must be `None` or one of {0,1}.""")
        self._cards[1].set_value("erod", value)

    @property
    def loc(self) -> typing.Optional[int]:
        """Get or set the For a thick thermal shell, the flux will be applied to the surface
        identified by LOC. See field THSHEL on the *CONTROL_SHELL keyword.
        EQ.-1: lower surface of thermal shell element
        EQ.0: middle surface of thermal shell element
        EQ.1: upper surface of thermal shell element.
        """ # nopep8
        return self._cards[1].get_value("loc")

    @loc.setter
    def loc(self, value: int) -> None:
        """Set the loc property."""
        self._cards[1].set_value("loc", value)

    @property
    def lcrot(self) -> typing.Optional[int]:
        """Get or set the Load curve defining the rotation (angle in degrees) of weld source
        around the trajectory as function of time. See Remark 2.
        """ # nopep8
        return self._cards[1].get_value("lcrot")

    @lcrot.setter
    def lcrot(self, value: int) -> None:
        """Set the lcrot property."""
        self._cards[1].set_value("lcrot", value)

    @property
    def lclat(self) -> typing.Optional[int]:
        """Get or set the Load curve for lateral offset of weld source as function of time. See Remark 2.
        """ # nopep8
        return self._cards[1].get_value("lclat")

    @lclat.setter
    def lclat(self, value: int) -> None:
        """Set the lclat property."""
        self._cards[1].set_value("lclat", value)

    @property
    def iform(self) -> typing.Optional[int]:
        """Get or set the Geometry description for energy rate density distribution (see Remark 3):
        EQ.1: double elliptic with constant density
        EQ.2: double elliptic with Gaussian distribution
        EQ.3: user defined function.
        """ # nopep8
        return self._cards[2].get_value("iform")

    @iform.setter
    def iform(self, value: int) -> None:
        """Set the iform property."""
        self._cards[2].set_value("iform", value)

    @property
    def lctim(self) -> typing.Optional[int]:
        """Get or set the Load curve ID for flux energy input rate multiplier q1(t) as a
        function of time, see Remark 4.
        EQ.0: use constant multiplier value q1(t) = 1.0.
        """ # nopep8
        return self._cards[2].get_value("lctim")

    @lctim.setter
    def lctim(self, value: int) -> None:
        """Set the lctim property."""
        self._cards[2].set_value("lctim", value)

    @property
    def q(self) -> float:
        """Get or set the Base energy input rate Qb [energy/time], see Remark 4.
        """ # nopep8
        return self._cards[2].get_value("q")

    @q.setter
    def q(self, value: float) -> None:
        """Set the q property."""
        self._cards[2].set_value("q", value)

    @property
    def lcinc(self) -> typing.Optional[int]:
        """Get or set the Load curve ID for flux energy input rate multiplier q2(a) as a. The value of the angle α range from 0° (segment normal and heat source point in the same direction) to 180° (segment normal and heat source point in opposite directions).
        function of inclination angle a, see Remark 4
        EQ.0: use constant multiplier value q2(a) = 1.0.
        """ # nopep8
        return self._cards[2].get_value("lcinc")

    @lcinc.setter
    def lcinc(self, value: int) -> None:
        """Set the lcinc property."""
        self._cards[2].set_value("lcinc", value)

    @property
    def enfor(self) -> int:
        """Get or set the Flag for heat input enforcement option (see Remark 4)
        EQ.0: no additional scaling of heat source
        EQ.1: account for inclination angle a of heat source by energy
        input rate multiplier q3(a) = cos(a)
        EQ.2: scale the nodal fluxes by a multiplier q4(t) such that the
        resulting heat input equals the user input Q(t) =Qb*q1(t)
        EQ.3: apply option 1 and 2.
        """ # nopep8
        return self._cards[2].get_value("enfor")

    @enfor.setter
    def enfor(self, value: int) -> None:
        """Set the enfor property."""
        self._cards[2].set_value("enfor", value)

    @property
    def p1(self) -> typing.Optional[float]:
        """Get or set the Parameters defining flux geometry, depending on field IFORM.
        See Remark 3 for details.
        """ # nopep8
        return self._cards[3].get_value("p1")

    @p1.setter
    def p1(self, value: float) -> None:
        """Set the p1 property."""
        self._cards[3].set_value("p1", value)

    @property
    def p2(self) -> typing.Optional[float]:
        """Get or set the Parameters defining flux geometry, depending on field IFORM.
        See Remark 3 for details.
        """ # nopep8
        return self._cards[3].get_value("p2")

    @p2.setter
    def p2(self, value: float) -> None:
        """Set the p2 property."""
        self._cards[3].set_value("p2", value)

    @property
    def p3(self) -> typing.Optional[float]:
        """Get or set the Parameters defining flux geometry, depending on field IFORM.
        See Remark 3 for details.
        """ # nopep8
        return self._cards[3].get_value("p3")

    @p3.setter
    def p3(self, value: float) -> None:
        """Set the p3 property."""
        self._cards[3].set_value("p3", value)

    @property
    def p4(self) -> typing.Optional[float]:
        """Get or set the Parameters defining flux geometry, depending on field IFORM.
        See Remark 3 for details.
        """ # nopep8
        return self._cards[3].get_value("p4")

    @p4.setter
    def p4(self, value: float) -> None:
        """Set the p4 property."""
        self._cards[3].set_value("p4", value)

    @property
    def p5(self) -> typing.Optional[float]:
        """Get or set the Parameters defining flux geometry, depending on field IFORM.
        See Remark 3 for details.
        """ # nopep8
        return self._cards[3].get_value("p5")

    @p5.setter
    def p5(self, value: float) -> None:
        """Set the p5 property."""
        self._cards[3].set_value("p5", value)

    @property
    def p6(self) -> typing.Optional[float]:
        """Get or set the Parameters defining flux geometry, depending on field IFORM.
        See Remark 3 for details.
        """ # nopep8
        return self._cards[3].get_value("p6")

    @p6.setter
    def p6(self, value: float) -> None:
        """Set the p6 property."""
        self._cards[3].set_value("p6", value)

    @property
    def p7(self) -> typing.Optional[float]:
        """Get or set the Parameters defining flux geometry, depending on field IFORM.
        See Remark 3 for details.
        """ # nopep8
        return self._cards[3].get_value("p7")

    @p7.setter
    def p7(self, value: float) -> None:
        """Set the p7 property."""
        self._cards[3].set_value("p7", value)

    @property
    def p8(self) -> typing.Optional[float]:
        """Get or set the Parameters defining flux geometry, depending on field IFORM.
        See Remark 3 for details.
        """ # nopep8
        return self._cards[3].get_value("p8")

    @p8.setter
    def p8(self, value: float) -> None:
        """Set the p8 property."""
        self._cards[3].set_value("p8", value)

    @property
    def tx(self) -> typing.Optional[float]:
        """Get or set the Weld beam direction vector in global coordinates (NSID2 = 0 only).
        """ # nopep8
        return self._cards[4].get_value("tx")

    @tx.setter
    def tx(self, value: float) -> None:
        """Set the tx property."""
        self._cards[4].set_value("tx", value)

    @property
    def ty(self) -> typing.Optional[float]:
        """Get or set the Weld beam direction vector in global coordinates (NSID2 = 0 only).
        """ # nopep8
        return self._cards[4].get_value("ty")

    @ty.setter
    def ty(self, value: float) -> None:
        """Set the ty property."""
        self._cards[4].set_value("ty", value)

    @property
    def tz(self) -> typing.Optional[float]:
        """Get or set the Weld beam direction vector in global coordinates (NSID2 = 0 only).
        """ # nopep8
        return self._cards[4].get_value("tz")

    @tz.setter
    def tz(self, value: float) -> None:
        """Set the tz property."""
        self._cards[4].set_value("tz", value)

    @property
    def lcrot_link(self) -> typing.Optional[DefineCurve]:
        """Get the DefineCurve object for lcrot."""
        if self.deck is None:
            return None
        for kwd in self.deck.get_kwds_by_full_type("DEFINE", "CURVE"):
            if kwd.lcid == self.lcrot:
                return kwd
        return None

    @lcrot_link.setter
    def lcrot_link(self, value: DefineCurve) -> None:
        """Set the DefineCurve object for lcrot."""
        self.lcrot = value.lcid

    @property
    def lclat_link(self) -> typing.Optional[DefineCurve]:
        """Get the DefineCurve object for lclat."""
        if self.deck is None:
            return None
        for kwd in self.deck.get_kwds_by_full_type("DEFINE", "CURVE"):
            if kwd.lcid == self.lclat:
                return kwd
        return None

    @lclat_link.setter
    def lclat_link(self, value: DefineCurve) -> None:
        """Set the DefineCurve object for lclat."""
        self.lclat = value.lcid

    @property
    def lctim_link(self) -> typing.Optional[DefineCurve]:
        """Get the DefineCurve object for lctim."""
        if self.deck is None:
            return None
        for kwd in self.deck.get_kwds_by_full_type("DEFINE", "CURVE"):
            if kwd.lcid == self.lctim:
                return kwd
        return None

    @lctim_link.setter
    def lctim_link(self, value: DefineCurve) -> None:
        """Set the DefineCurve object for lctim."""
        self.lctim = value.lcid

    @property
    def lcinc_link(self) -> typing.Optional[DefineCurve]:
        """Get the DefineCurve object for lcinc."""
        if self.deck is None:
            return None
        for kwd in self.deck.get_kwds_by_full_type("DEFINE", "CURVE"):
            if kwd.lcid == self.lcinc:
                return kwd
        return None

    @lcinc_link.setter
    def lcinc_link(self, value: DefineCurve) -> None:
        """Set the DefineCurve object for lcinc."""
        self.lcinc = value.lcid

    @property
    def nsid1_link(self) -> typing.Optional[KeywordBase]:
        """Get the SET_NODE_* keyword for nsid1."""
        return self._get_set_link("NODE", self.nsid1)

    @nsid1_link.setter
    def nsid1_link(self, value: KeywordBase) -> None:
        """Set the SET_NODE_* keyword for nsid1."""
        self.nsid1 = value.sid

    @property
    def pserod_link(self) -> typing.Optional[KeywordBase]:
        """Get the SET_PART_* keyword for pserod."""
        return self._get_set_link("PART", self.pserod)

    @pserod_link.setter
    def pserod_link(self, value: KeywordBase) -> None:
        """Set the SET_PART_* keyword for pserod."""
        self.pserod = value.sid

    @property
    def ssid_link(self) -> typing.Optional[KeywordBase]:
        """Get the SET_SEGMENT_* keyword for ssid."""
        return self._get_set_link("SEGMENT", self.ssid)

    @ssid_link.setter
    def ssid_link(self, value: KeywordBase) -> None:
        """Set the SET_SEGMENT_* keyword for ssid."""
        self.ssid = value.sid

