# 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 IncludeUnitcell 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.node.node import Node

_INCLUDEUNITCELL_CARD0 = (
    FieldSchema("filename", str, 0, 256, None),
)

_INCLUDEUNITCELL_CARD1 = (
    FieldSchema("inpt", int, 0, 10, 0),
    FieldSchema("oupt", int, 10, 10, 0),
    FieldSchema("nedof", int, 20, 10, 0),
)

_INCLUDEUNITCELL_CARD2 = (
    FieldSchema("dx", float, 0, 10, 1.0),
    FieldSchema("dy", float, 10, 10, 1.0),
    FieldSchema("dz", float, 20, 10, 1.0),
    FieldSchema("nex", int, 30, 10, 1),
    FieldSchema("ney", int, 40, 10, 1),
    FieldSchema("nez", int, 50, 10, 1),
    FieldSchema("nnpe", int, 60, 10, 8),
    FieldSchema("tol", float, 70, 10, None),
)

_INCLUDEUNITCELL_CARD3 = (
    FieldSchema("noff", int, 0, 10, None),
    FieldSchema("eoff", int, 10, 10, None),
    FieldSchema("pnm", int, 20, 10, None),
)

_INCLUDEUNITCELL_CARD4 = (
    FieldSchema("cnx", int, 0, 10, None),
    FieldSchema("cny", int, 10, 10, None),
    FieldSchema("cnz", int, 20, 10, None),
)

_INCLUDEUNITCELL_CARD5 = (
    FieldSchema("ecnx", int, 0, 10, None),
    FieldSchema("ecny", int, 10, 10, None),
    FieldSchema("ecnz", int, 20, 10, None),
)

class IncludeUnitcell(KeywordBase):
    """DYNA INCLUDE_UNITCELL keyword"""

    keyword = "INCLUDE"
    subkeyword = "UNITCELL"
    _link_fields = {
        "cnx": LinkType.NODE,
        "cny": LinkType.NODE,
        "cnz": LinkType.NODE,
        "ecnx": LinkType.NODE,
        "ecny": LinkType.NODE,
        "ecnz": LinkType.NODE,
    }

    def __init__(self, **kwargs):
        """Initialize the IncludeUnitcell class."""
        super().__init__(**kwargs)
        self._cards = [
            Card.from_field_schemas_with_defaults(
                _INCLUDEUNITCELL_CARD0,
                **kwargs,
            ),            Card.from_field_schemas_with_defaults(
                _INCLUDEUNITCELL_CARD1,
                **kwargs,
            ),            Card.from_field_schemas_with_defaults(
                _INCLUDEUNITCELL_CARD2,
                **kwargs,
            ),            Card.from_field_schemas_with_defaults(
                _INCLUDEUNITCELL_CARD3,
                **kwargs,
            ),            Card.from_field_schemas_with_defaults(
                _INCLUDEUNITCELL_CARD4,
                **kwargs,
            ),            Card.from_field_schemas_with_defaults(
                _INCLUDEUNITCELL_CARD5,
                **kwargs,
            ),        ]
    @property
    def filename(self) -> typing.Optional[str]:
        """Get or set the Name of the keyword file containing X, Y, Z coordinates as defined using keyword *DEFINE_CURVE_TRIM_3D..
        """ # nopep8
        return self._cards[0].get_value("filename")

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

    @property
    def inpt(self) -> int:
        """Get or set the Type of input:
        EQ.0:	Read * NODE information from the include file and add periodic boundary conditions to the include file.
        EQ.1 : Create a unit cell mesh with periodic boundary conditions,and output to the include file
        """ # nopep8
        return self._cards[1].get_value("inpt")

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

    @property
    def oupt(self) -> int:
        """Get or set the Type of output:
        EQ.1:	Create a new main keyword file where the keyword * INCLUDE_?UNITCELL is replaced by * INCLUDE with the include file name
        """ # nopep8
        return self._cards[1].get_value("oupt")

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

    @property
    def nedof(self) -> int:
        """Get or set the Number of extra nodal degrees of freedom (DOFs) for user-defined element. In the current implementation, the limit of NEDOF is 15
        """ # nopep8
        return self._cards[1].get_value("nedof")

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

    @property
    def dx(self) -> float:
        """Get or set the Length of the unit cell in the  x-direction
        """ # nopep8
        return self._cards[2].get_value("dx")

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

    @property
    def dy(self) -> float:
        """Get or set the Length of the unit cell in the y -direction
        """ # nopep8
        return self._cards[2].get_value("dy")

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

    @property
    def dz(self) -> float:
        """Get or set the Length of the unit cell in the  z-direction
        """ # nopep8
        return self._cards[2].get_value("dz")

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

    @property
    def nex(self) -> int:
        """Get or set the Number of elements along the  x-direction
        """ # nopep8
        return self._cards[2].get_value("nex")

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

    @property
    def ney(self) -> int:
        """Get or set the Number of elements along the  y-direction
        """ # nopep8
        return self._cards[2].get_value("ney")

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

    @property
    def nez(self) -> int:
        """Get or set the Number of elements along the  z-direction
        """ # nopep8
        return self._cards[2].get_value("nez")

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

    @property
    def nnpe(self) -> int:
        """Get or set the Number of nodes per element. The current implementation supports only 4-node tetrahedron or 8-node hexahedron elements
        """ # nopep8
        return self._cards[2].get_value("nnpe")

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

    @property
    def tol(self) -> typing.Optional[float]:
        """Get or set the Tolerance for searching for each pair of nodes in the periodic positions to create the periodic boundary conditions. This tolerance may be needed because numerical errors in the mesh can cause the coordinates of the pairs of nodes to not be exactly in the periodic positions. The default tolerance is computed based on the size of unit cell
        """ # nopep8
        return self._cards[2].get_value("tol")

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

    @property
    def noff(self) -> typing.Optional[int]:
        """Get or set the Offset of node IDs
        """ # nopep8
        return self._cards[3].get_value("noff")

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

    @property
    def eoff(self) -> typing.Optional[int]:
        """Get or set the Offset of element IDs
        """ # nopep8
        return self._cards[3].get_value("eoff")

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

    @property
    def pnm(self) -> typing.Optional[int]:
        """Get or set the Part ID
        """ # nopep8
        return self._cards[3].get_value("pnm")

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

    @property
    def cnx(self) -> typing.Optional[int]:
        """Get or set the Node ID of the 1st control point for the constraint in the  x direction
        """ # nopep8
        return self._cards[4].get_value("cnx")

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

    @property
    def cny(self) -> typing.Optional[int]:
        """Get or set the Node ID of the 2nd control point for the constraint in the  y direction
        """ # nopep8
        return self._cards[4].get_value("cny")

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

    @property
    def cnz(self) -> typing.Optional[int]:
        """Get or set the Node ID of the 3rd control point for the constraint in the  z direction
        """ # nopep8
        return self._cards[4].get_value("cnz")

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

    @property
    def ecnx(self) -> typing.Optional[int]:
        """Get or set the Node ID of extra control point for the constraint in x direction of 3 extra nodal DOFs
        """ # nopep8
        return self._cards[5].get_value("ecnx")

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

    @property
    def ecny(self) -> typing.Optional[int]:
        """Get or set the Node ID of extra control point for the constraint in y  direction of 3 extra nodal DOFs
        """ # nopep8
        return self._cards[5].get_value("ecny")

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

    @property
    def ecnz(self) -> typing.Optional[int]:
        """Get or set the Node ID of extra control point for the constraint in  z direction of 3 extra nodal DOFs
        """ # nopep8
        return self._cards[5].get_value("ecnz")

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

    @property
    def cnx_link(self) -> typing.Optional[KeywordBase]:
        """Get the NODE keyword containing the given cnx."""
        return self._get_link_by_attr("NODE", "nid", self.cnx, "parts")

    @property
    def cny_link(self) -> typing.Optional[KeywordBase]:
        """Get the NODE keyword containing the given cny."""
        return self._get_link_by_attr("NODE", "nid", self.cny, "parts")

    @property
    def cnz_link(self) -> typing.Optional[KeywordBase]:
        """Get the NODE keyword containing the given cnz."""
        return self._get_link_by_attr("NODE", "nid", self.cnz, "parts")

    @property
    def ecnx_link(self) -> typing.Optional[KeywordBase]:
        """Get the NODE keyword containing the given ecnx."""
        return self._get_link_by_attr("NODE", "nid", self.ecnx, "parts")

    @property
    def ecny_link(self) -> typing.Optional[KeywordBase]:
        """Get the NODE keyword containing the given ecny."""
        return self._get_link_by_attr("NODE", "nid", self.ecny, "parts")

    @property
    def ecnz_link(self) -> typing.Optional[KeywordBase]:
        """Get the NODE keyword containing the given ecnz."""
        return self._get_link_by_attr("NODE", "nid", self.ecnz, "parts")

