# -*- coding: utf-8 -*-
"""
CraftPilot for houdini engine's internal data types
Author  : Cheneyshen
Email   : cheneyshen@tencent.com
"""
import ctypes
from ctypes import Structure, Array, \
    c_int, c_int32, c_int64, c_float, c_double, c_bool, c_uint
import enum
import numpy as np


class StructureWithEnums(Structure):
    """Add missing enum feature to ctypes Structures.
    ref:  https://gist.github.com/christoph2/9c390e5c094796903097
    """
    _map = {}

    def __getattribute__(self, name):
        _map = Structure.__getattribute__(self, '_map')
        value = Structure.__getattribute__(self, name)
        if name in _map:
            enum_class = _map[name]
            if isinstance(value, Array):
                return [enum_class(x) for x in value]
            return enum_class(value)
        return value

    def __str__(self):
        result = []
        result.append("struct {0} {{".format(self.__class__.__name__))
        for field in self._fields_:
            attr, attr_type = field
            if attr in self._map:
                attr_type = self._map[attr]
            value = getattr(self, attr)
            result.append("    {0} [{1}] = {2!r}".format(
                attr, attr_type.__name__, value))
        result.append("}")
        return '\n'.join(result)

    __repr__ = __str__


#####################################################################################################
# Enums
#####################################################################################################

class LicenseType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_License
    """
    NONE = 0
    HOUDINI_ENGINE = 1
    HOUDINI = 2
    HOUDINI_FX = 3
    HOUDINI_ENGINE_INDIE = 4
    HOUDINI_INDIE = 5
    HOUDINI_ENGINE_UNITY_UNREAL = 6
    MAX = 7


class StatusType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_StatusType
    """
    CALL_RESULT = 0
    COOK_RESULT = 1
    COOK_STATE = 2
    MAX = 3


class StatusVerbosity(enum.IntEnum):
    """Equivalent of HAPI's HAPI_StatusVerbosity
    """
    ALL = 2
    ERRORS = 0
    WARNINGS = 1
    MESSAGES = 2


class Result(enum.IntEnum):
    """Equivalent of HAPI's HAPI_Result
    """
    SUCCESS = 0
    FAILURE = 1
    ALREADY_INITIALIZED = 2
    NOT_INITIALIZED = 3
    CANT_LOADFILE = 4
    PARM_SET_FAILED = 5
    INVALID_ARGUMENT = 6
    CANT_LOAD_GEO = 7
    CANT_GENERATE_PRESET = 8
    CANT_LOAD_PRESET = 9
    ASSET_DEF_ALREADY_LOADED = 10

    NO_LICENSE_FOUND = 110
    DISALLOWED_NC_LICENSE_FOUND = 120
    DISALLOWED_NC_ASSET_WITH_C_LICENSE = 130
    DISALLOWED_NC_ASSET_WITH_LC_LICENSE = 140
    DISALLOWED_LC_ASSET_WITH_C_LICENSE = 150
    DISALLOWED_HENGINEINDIE_W_3PARTY_PLUGIN = 160

    ASSET_INVALID = 200
    NODE_INVALID = 210

    USER_INTERRUPTED = 300

    INVALID_SESSION = 400


class ErrorCode(enum.IntEnum):
    """Equivalent of HAPI's HAPI_ErrorCode
    """
    ASSET_DEF_NOT_FOUND = 1 << 0
    PYTHON_NODE_ERROR = 1 << 1


class SessionType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_SessionType
    """
    INPROCESS = 0
    THRIFT = 1
    CUSTOM1 = 2
    CUSTOM2 = 3
    CUSTOM3 = 4
    MAX = 5


class State(enum.IntEnum):
    """Equivalent of HAPI's HAPI_State
    """
    READY = 0
    READY_WITH_FATAL_ERRORS = 1
    READY_WITH_COOK_ERRORS = 2
    STARTING_COOK = 3
    COOKING = 4
    STARTING_LOAD = 5
    LOADING = 6
    MAX = 7

    MAX_READY_STATE = READY_WITH_COOK_ERRORS


class PackedPrimInstancingMode(enum.IntEnum):
    """Equivalent of HAPI's HAPI_PackedPrimInstancingMode
    """
    INVALID = -1
    DISABLED = 0
    HIERARCHY = 1
    FLAT = 2
    MAX = 3


class Permissions(enum.IntEnum):
    """Equivalent of HAPI's HAPI_Permissions
    """
    NON_APPLICABLE = 0
    READ_WRITE = 1
    READ_ONLY = 2
    WRITE_ONLY = 3
    MAX = 4


class RampType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_RampType
    """
    INVALID = -1
    FLOAT = 0
    COLOR = 1
    MAX = 2


class ParmType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_ParmType
    """
    INT = 0
    MULTIPARMLIST = 1
    TOGGLE = 2
    BUTTON = 3

    FLOAT = 4
    COLOR = 5

    STRING = 6
    PATH_FILE = 7
    PATH_FILE_GEO = 8
    PATH_FILE_IMAGE = 9

    NODE = 10

    FOLDERLIST = 11
    FOLDERLIST_RADIO = 12

    FOLDER = 13
    LABEL = 14
    SEPARATOR = 15
    PATH_FILE_DIR = 16

    MAX = 17

    INT_START = INT
    INT_END = BUTTON

    FLOAT_START = FLOAT
    FLOAT_END = COLOR

    STRING_START = STRING
    STRING_END = NODE

    PATH_START = PATH_FILE
    PATH_END = PATH_FILE_IMAGE

    NODE_START = NODE
    NODE_END = NODE

    CONTAINER_START = FOLDERLIST
    CONTAINER_END = FOLDERLIST_RADIO

    NONVALUE_START = FOLDER
    NONVALUE_END = SEPARATOR


class PrmScriptType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_PrmScriptType
    """
    # "int", "integer"
    INT = 0
    FLOAT = 1
    ANGLE = 2
    STRING = 3
    FILE = 4
    DIRECTORY = 5
    IMAGE = 6
    GEOMETRY = 7
    # "toggle", "embed"
    TOGGLE = 8
    BUTTON = 9
    VECTOR2 = 10
    # "vector", "vector3"
    VECTOR3 = 11
    VECTOR4 = 12
    INTVECTOR2 = 13
    # "intvector", "intvector3"
    INTVECTOR3 = 14
    INTVECTOR4 = 15
    UV = 16
    UVW = 17
    # "dir", "direction"
    DIR = 18
    # "color", "rgb"
    COLOR = 19
    # "color4", "rgba"
    COLOR4 = 20
    OPPATH = 21
    OPLIST = 22
    OBJECT = 23
    OBJECTLIST = 24
    RENDER = 25
    SEPARATOR = 26
    GEOMETRY_DATA = 27
    KEY_VALUE_DICT = 28
    LABEL = 29
    RGBAMASK = 30
    ORDINAL = 31
    RAMP_FLT = 32
    RAMP_RGB = 33
    FLOAT_LOG = 34
    INT_LOG = 35
    DATA = 36
    FLOAT_MINMAX = 37
    INT_MINMAX = 38
    INT_STARTEND = 39
    BUTTONSTRIP = 40
    ICONSTRIP = 41
    # The following apply to HAPI_PARMTYPE_FOLDER type parms.
    # Radio buttons Folder
    GROUPRADIO = 1000
    # Collapsible Folder
    GROUPCOLLAPSIBLE = 1001
    # Simple Folder
    GROUPSIMPLE = 1002
    # Tabs Folder
    GROUP = 1003


class ChoiceListType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_ChoiceListType
    """
    NONE = 0
    NORMAL = 1
    MINI = 2
    REPLACE = 3
    TOGGLE = 4


class PresetType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_PresetType
    """
    INVALID = -1
    BINARY = 0
    IDX = 1
    MAX = 2


class NodeType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_NodeType
    """
    ANY = -1
    NONE = 0
    OBJ = 1 << 0
    SOP = 1 << 1
    CHOP = 1 << 2
    ROP = 1 << 3
    SHOP = 1 << 4
    COP = 1 << 5
    VOP = 1 << 6
    DOP = 1 << 7
    TOP = 1 << 8


class NodeFlags(enum.IntEnum):
    """Equivalent of HAPI's HAPI_NodeFlags
    """
    ANY = -1
    NONE = 0

    # Recursive Flag
    DISPLAY = 1 << 0
    RENDER = 1 << 1
    TEMPLATED = 1 << 2
    LOCKED = 1 << 3
    EDITABLE = 1 << 4
    BYPASS = 1 << 5
    NETWORK = 1 << 6

    # OBJ Node Specific Flags
    OBJ_GEOMETRY = 1 << 7
    OBJ_CAMERA = 1 << 8
    OBJ_LIGHT = 1 << 9
    OBJ_SUBNET = 1 << 10

    # SOP Node Specific Flags
    # Looks for "curve"
    SOP_CURVE = 1 << 11
    # Looks for Guide Geometry
    SOP_GUIDE = 1 << 12

    # TOP Node Specific Flags
    # All TOP nodes except schedulers
    TOP_NONSCHEDULER = 1 << 13
    # Nodes that are not bypassed
    NON_BYPASS = 1 << 14


class GroupType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_GroupType
    """
    INVALID = -1
    POINT = 0
    PRIM = 1
    EDGE = 2
    MAX = 3


class AttributeOwner(enum.IntEnum):
    """Equivalent of HAPI's HAPI_AttributeOwner
    """
    INVALID = -1
    VERTEX = 0
    POINT = 1
    PRIM = 2
    DETAIL = 3
    MAX = 4


class CurveType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_CurveType
    """
    INVALID = -1
    LINEAR = 0
    NURBS = 1
    BEZIER = 2
    MAX = 3


class VolumeType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_VolumeType
    """
    INVALID = -1
    HOUDINI = 0
    VDB = 1
    MAX = 2


class VolumeVisualType(enum.IntEnum):
    INVALID = -1,
    SMOKE = 0
    RAINBOW = 1
    ISO = 2
    INVISIBLE = 3
    HEIGHTFIELD = 4
    MAX = 5


class StorageType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_StorageType
    """
    INVALID = -1
    INT = 0
    INT64 = 1
    FLOAT = 2
    FLOAT64 = 3
    STRING = 4
    UINT8 = 5
    INT8 = 6
    INT16 = 7
    INT_ARRAY = 8
    INT64_ARRAY = 9
    FLOAT_ARRAY = 10
    FLOAT64_ARRAY = 11
    STRING_ARRAY = 12
    UINT8_ARRAY = 13
    INT8_ARRAY = 14
    INT16_ARRAY = 15
    MAX = 16


class AttributeTypeInfo(enum.IntEnum):
    """Equivalent of HAPI's HAPI_AttributeTypeInfo
    """
    INVALID = -1
    NONE = 0
    POINT = 1
    HPOINT = 2
    VECTOR = 3
    NORMAL = 4
    COLOR = 5
    QUATERNION = 6
    MATRIX3 = 7
    MATRIX = 8
    ST = 9
    HIDDEN = 10
    BOX2 = 11
    BOX = 12
    TEXTURE = 13
    MAX = 14


class HGeoType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_GeoType
    """
    INVALID = -1
    DEFAULT = 0
    INTERMEDIATE = 1
    INPUT = 2
    CURVE = 3
    MAX = 4


class PartType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_PartType
    """
    INVALID = -1
    MESH = 0
    CURVE = 1
    VOLUME = 2
    INSTANCER = 3
    BOX = 4
    SPHERE = 5
    MAX = 6


class InputType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_InputType
    """
    INVALID = -1
    TRANSFORM = 0
    GEOMETRY = 1
    MAX = 2


class CurveOrders(enum.IntEnum):
    """Equivalent of HAPI's HAPI_CurveOrders
    """
    HAPI_VARYING = 0
    HAPI_INVALID = 1
    HAPI_LINEAR = 2
    HAPI_QUADRATIC = 3
    HAPI_CUBIC = 4


class TransformComponent(enum.IntEnum):
    """Equivalent of HAPI's HAPI_TransformComponent
    """
    HAPI_TRANSFORM_TX = 0
    HAPI_TRANSFORM_TY = 1
    HAPI_TRANSFORM_TZ = 2
    HAPI_TRANSFORM_RX = 3
    HAPI_TRANSFORM_RY = 4
    HAPI_TRANSFORM_RZ = 5
    HAPI_TRANSFORM_QX = 6
    HAPI_TRANSFORM_QY = 7
    HAPI_TRANSFORM_QZ = 8
    HAPI_TRANSFORM_QW = 9
    HAPI_TRANSFORM_SX = 10
    HAPI_TRANSFORM_SY = 11
    HAPI_TRANSFORM_SZ = 12


class RSTOrder(enum.IntEnum):
    """Equivalent of HAPI's HAPI_RSTOrder
    """
    HAPI_TRS = 0
    HAPI_TSR = 1
    HAPI_RTS = 2
    HAPI_RST = 3
    HAPI_STR = 4
    HAPI_SRT = 5

    HAPI_RSTORDER_DEFAULT = 5


class XYZOrder(enum.IntEnum):
    """Equivalent of HAPI's HAPI_XYZOrder
    """
    HAPI_XYZ = 0
    HAPI_XZY = 1
    HAPI_YXZ = 2
    HAPI_YZX = 3
    HAPI_ZXY = 4
    HAPI_ZYX = 5

    HAPI_XYZORDER_DEFAULT = 0


class ImageDataFormat(enum.IntEnum):
    """Equivalent of HAPI's HAPI_ImageDataFormat
    """
    HAPI_IMAGE_DATA_UNKNOWN = -1
    HAPI_IMAGE_DATA_INT8 = 0
    HAPI_IMAGE_DATA_INT16 = 1
    HAPI_IMAGE_DATA_INT32 = 2
    HAPI_IMAGE_DATA_FLOAT16 = 3
    HAPI_IMAGE_DATA_FLOAT32 = 4
    HAPI_IMAGE_DATA_MAX = 5

    HAPI_IMAGE_DATA_DEFAULT = 0


class ImagePacking(enum.IntEnum):
    """Equivalent of HAPI's HAPI_ImagePacking
    """
    HAPI_IMAGE_PACKING_UNKNOWN = -1
    HAPI_IMAGE_PACKING_SINGLE = 0
    HAPI_IMAGE_PACKING_DUAL = 1
    HAPI_IMAGE_PACKING_RGB = 2
    HAPI_IMAGE_PACKING_BGR = 3
    HAPI_IMAGE_PACKING_RGBA = 4
    HAPI_IMAGE_PACKING_ABGR = 5
    HAPI_IMAGE_PACKING_MAX = 6

    HAPI_IMAGE_PACKING_DEFAULT3 = 2
    HAPI_IMAGE_PACKING_DEFAULT4 = 4


class EnvIntType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_EnvIntType
    """
    HAPI_ENVINT_INVALID = -1

    # The three components of the Houdini version that HAPI is expecting to link against.
    HAPI_ENVINT_VERSION_HOUDINI_MAJOR = 100
    HAPI_ENVINT_VERSION_HOUDINI_MINOR = 110
    HAPI_ENVINT_VERSION_HOUDINI_BUILD = 120
    HAPI_ENVINT_VERSION_HOUDINI_PATCH = 130

    # The two components of the Houdini Engine (marketed) version.
    HAPI_ENVINT_VERSION_HOUDINI_ENGINE_MAJOR = 200
    HAPI_ENVINT_VERSION_HOUDINI_ENGINE_MINOR = 210

    '''
    /// This is a monotonously increasing API version number that can be used
    /// to lock against a certain API for compatibility purposes. Basically,
    /// when this number changes code compiled against the HAPI.h methods
    /// might no longer compile. Semantic changes to the methods will also
    /// cause this version to increase. This number will be reset to 0
    /// every time the Houdini Engine version is bumped.
    '''
    HAPI_ENVINT_VERSION_HOUDINI_ENGINE_API = 220

    HAPI_ENVINT_MAX = 221


class SessionEnvIntType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_SessionEnvIntType
    """
    HAPI_SESSIONENVINT_INVALID = -1
    HAPI_SESSIONENVINT_LICENSE = 100
    HAPI_SESSIONENVINT_MAX = 101


class CacheProperty(enum.IntEnum):
    """Equivalent of HAPI's HAPI_CacheProperty
    """
    # Current memory usage in MB. Setting this to 0 invokes a cache clear.
    HAPI_CACHEPROP_CURRENT = 0

    # True if it actually has a minimum size.
    HAPI_CACHEPROP_HAS_MIN = 1
    # Min cache memory limit in MB.
    HAPI_CACHEPROP_MIN = 2
    # True if it actually has a maximum size.
    HAPI_CACHEPROP_HAS_MAX = 3
    # Max cache memory limit in MB.
    HAPI_CACHEPROP_MAX = 4

    '''
    /// How aggressive to cull memory. This only works for:
    ///     - ::HAPI_CACHE_COP_COOK where:
    ///         0   ->  Never reduce inactive cache.
    ///         1   ->  Always reduce inactive cache.
    ///     - ::HAPI_CACHE_OBJ where:
    ///         0   ->  Never enforce the max memory limit.
    ///         1   ->  Always enforce the max memory limit.
    ///     - ::HAPI_CACHE_SOP where:
    ///         0   ->  When to Unload = Never
    ///                 When to Limit Max Memory = Never
    ///         1-2 ->  When to Unload = Based on Flag
    ///                 When to Limit Max Memory = Never
    ///         3-4 ->  When to Unload = Based on Flag
    ///                 When to Limit Max Memory = Always
    ///         5   ->  When to Unload = Always
    ///                 When to Limit Max Memory = Always
    '''
    HAPI_CACHEPROP_CULL_LEVEL = 5


class HeightFieldSampling(enum.IntEnum):
    """Equivalent of HAPI's HAPI_HeightFieldSampling
    """
    HAPI_HEIGHTFIELD_SAMPLING_CENTER = 0
    HAPI_HEIGHTFIELD_SAMPLING_CORNER = 1


class PDG_State(enum.IntEnum):
    """Equivalent of HAPI's HAPI_PDG_State
    """
    HAPI_PDG_STATE_READY = 0
    HAPI_PDG_STATE_COOKING = 1
    HAPI_PDG_STATE_MAX = 2

    HAPI_PDG_STATE_MAX_READY_STATE = 0


class PDG_EventType(enum.IntEnum):
    """Equivalent of HAPI's HAPI_PDG_EventType
    """
    # An empty, undefined event.  Should be ignored.
    HAPI_PDG_EVENT_NULL = 0

    # Sent when a new work item is added by a node
    HAPI_PDG_EVENT_WORKITEM_ADD = 1
    # Sent when a work item is deleted from a node
    HAPI_PDG_EVENT_WORKITEM_REMOVE = 2
    # Sent when a work item's state changes
    HAPI_PDG_EVENT_WORKITEM_STATE_CHANGE = 3

    # Sent when a work item has a dependency added
    HAPI_PDG_EVENT_WORKITEM_ADD_DEP = 4
    # Sent when a dependency is removed from a work item
    HAPI_PDG_EVENT_WORKITEM_REMOVE_DEP = 5

    # Sent from dynamic work items that generate from a cooked item
    HAPI_PDG_EVENT_WORKITEM_ADD_PARENT = 6
    # Sent when the parent item for a work item is deleted
    HAPI_PDG_EVENT_WORKITEM_REMOVE_PARENT = 7

    # A node event that indicates that node is about to have all its work items cleared
    HAPI_PDG_EVENT_NODE_CLEAR = 8

    # Sent when an error is issued by the node
    HAPI_PDG_EVENT_COOK_ERROR = 9
    # Sent when an warning is issued by the node
    HAPI_PDG_EVENT_COOK_WARNING = 10

    # Sent for each node in the graph, when a cook completes
    HAPI_PDG_EVENT_COOK_COMPLETE = 11

    # A node event indicating that one more items in the node will be dirtied
    HAPI_PDG_EVENT_DIRTY_START = 12
    # A node event indicating that the node has finished dirtying items
    HAPI_PDG_EVENT_DIRTY_STOP = 13

    # A event indicating that the entire graph is about to be dirtied
    HAPI_PDG_EVENT_DIRTY_ALL = 14

    # A work item event that indicates the item has been selected in the TOPs UI
    HAPI_PDG_EVENT_UI_SELECT = 15

    # Sent when a new node is created
    HAPI_PDG_EVENT_NODE_CREATE = 16
    # Sent when a node was removed from the graph
    HAPI_PDG_EVENT_NODE_REMOVE = 17
    # Sent when a node was renamed
    HAPI_PDG_EVENT_NODE_RENAME = 18
    # Sent when a node was connected to another node
    HAPI_PDG_EVENT_NODE_CONNECT = 19
    # Sent when a node is disconnected from another node
    HAPI_PDG_EVENT_NODE_DISCONNECT = 20

    # Sent when an int attribute value is modified on a work item
    HAPI_PDG_EVENT_WORKITEM_SET_INT = 21
    # Sent when a float attribute value is modified on a work item
    HAPI_PDG_EVENT_WORKITEM_SET_FLOAT = 22
    # Sent when a string attribute value is modified on a work item
    HAPI_PDG_EVENT_WORKITEM_SET_STRING = 23
    # Sent when a file attribute value is modified on a work item
    HAPI_PDG_EVENT_WORKITEM_SET_FILE = 24
    # Sent when a Python object attribute value is modified on a work item
    HAPI_PDG_EVENT_WORKITEM_SET_PYOBJECT = 25
    # Sent when a geometry attribute value is modified on a work item
    HAPI_PDG_EVENT_WORKITEM_SET_GEOMETRY = 26
    # Deprecated
    HAPI_PDG_EVENT_WORKITEM_MERGE = 27
    # Sent when an output file is added to a work item
    HAPI_PDG_EVENT_WORKITEM_RESULT = 28

    # Sent when a work items priority is changed
    HAPI_PDG_EVENT_WORKITEM_PRIORITY = 29
    # Sent for each node in the graph, when a cook starts
    HAPI_PDG_EVENT_COOK_START = 30
    # Deprecated
    HAPI_PDG_EVENT_WORKITEM_ADD_STATIC_ANCESTOR = 31
    # Deprecated
    HAPI_PDG_EVENT_WORKITEM_REMOVE_STATIC_ANCESTOR = 32

    # Deprecated
    HAPI_PDG_EVENT_NODE_PROGRESS_UPDATE = 33
    # Deprecated
    HAPI_PDG_EVENT_BATCH_ITEM_INITIALIZED = 34
    # A special enum that represents the OR of all event types
    HAPI_PDG_EVENT_ALL = 35
    # A special enum that represents the OR of both the `CookError` and `CookWarning` events
    HAPI_PDG_EVENT_LOG = 36

    # Sent when a new scheduler is added to the graph
    HAPI_PDG_EVENT_SCHEDULER_ADDED = 37
    # Sent when a scheduler is removed from the graph
    HAPI_PDG_EVENT_SCHEDULER_REMOVED = 38
    # Sent when the scheduler assigned to a node is changed
    HAPI_PDG_EVENT_SET_SCHEDULER = 39
    # Deprecated
    HAPI_PDG_EVENT_SERVICE_MANAGER_ALL = 40

    HAPI_PDG_CONTEXT_EVENTS = 41


class PDG_WorkitemState(enum.IntEnum):
    """Equivalent of HAPI's HAPI_PDG_WorkitemState
    """
    HAPI_PDG_WORKITEM_UNDEFINED = 0
    HAPI_PDG_WORKITEM_UNCOOKED = 1
    HAPI_PDG_WORKITEM_WAITING = 2
    HAPI_PDG_WORKITEM_SCHEDULED = 3
    HAPI_PDG_WORKITEM_COOKING = 4
    HAPI_PDG_WORKITEM_COOKED_SUCCESS = 5
    HAPI_PDG_WORKITEM_COOKED_CACHE = 6
    HAPI_PDG_WORKITEM_COOKED_FAIL = 7
    HAPI_PDG_WORKITEM_COOKED_CANCEL = 8
    HAPI_PDG_WORKITEM_DIRTY = 9


class InputCurveMethod(enum.IntEnum):
    """wrapper of HAPI_InputCurveMethod
    """
    HAPI_CURVEMETHOD_INVALID = -1,
    HAPI_CURVEMETHOD_CVS = 0,
    HAPI_CURVEMETHOD_BREAKPOINTS = 1,
    HAPI_CURVEMETHOD_MAX = 2


class InputCurveParameterization(enum.IntEnum):
    """wrapper of HAPI_InputCurveParameterization
    """
    HAPI_CURVEPARAMETERIZATION_INVALID = -1,
    HAPI_CURVEPARAMETERIZATION_UNIFORM = 0,
    HAPI_CURVEPARAMETERIZATION_CHORD = 1,
    HAPI_CURVEPARAMETERIZATION_CENTRIPETAL = 2,
    HAPI_CURVEPARAMETERIZATION_MAX= 3

# Python -----------------------------------------------------------------

class SessionConnectionState(enum.IntEnum):
    """[summary]
    """
    NOT_CONNECTED = 0
    CONNECTED = 1
    FAILED_TO_CONNECT = 2


#####################################################################################################
# Main API Structs
#####################################################################################################
# kivlin, fix np.dtype mistake.
NP_TYPE_VALID = [np.dtype('int32'), np.dtype('int64'), np.dtype('float32'), np.dtype('float64'), np.dtype('bytes_')]
NP_TYPE_TO_HSTORAGE_TYPE = {
    np.dtype('int32'): StorageType.INT,
    np.dtype('int64'): StorageType.INT64,
    np.dtype('float32'): StorageType.FLOAT,
    np.dtype('float64'): StorageType.FLOAT64,
    np.dtype('bytes_'): StorageType.STRING}


# GENERICS -----------------------------------------------------------------

class Transform(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_Transform
    """
    _fields_ = [('position', c_float * 3),
                ('rotationQuaternion', c_float * 4),
                ('scale', c_float * 3),
                ('shear', c_float * 3),
                ('rstorder', c_int32)]
    _map = {
        "rstorder": RSTOrder
    }

    def __init__(self):
        super(Transform, self).__init__()
        self.position[0] = 0
        self.position[1] = 0
        self.position[2] = 0
        self.rotationQuaternion[0] = 0
        self.rotationQuaternion[1] = 0
        self.rotationQuaternion[2] = 0
        self.rotationQuaternion[3] = 1
        self.scale[0] = 1
        self.scale[1] = 1
        self.scale[2] = 1
        self.shear[0] = 0
        self.shear[1] = 0
        self.shear[2] = 0
        self.rstorder = RSTOrder.HAPI_RSTORDER_DEFAULT

    def __json__(self):
        json_data = {}
        # _fields_
        json_data[self._fields_[0][0]] = [self.position[0], self.position[1], self.position[2]]
        json_data[self._fields_[1][0]] = [self.rotationQuaternion[0], self.rotationQuaternion[1],
                                          self.rotationQuaternion[2], self.rotationQuaternion[3]]
        json_data[self._fields_[2][0]] = [self.scale[0], self.scale[1], self.scale[2]]
        json_data[self._fields_[3][0]] = [self.shear[0], self.shear[1], self.shear[2]]
        json_data[self._fields_[4][0]] = self.rstorder
        return json_data


class TransformEuler(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_TransformEuler
    """
    _fields_ = [('position', c_float * 3),
                ('rotationQuaternion', c_float * 4),
                ('scale', c_float * 3),
                ('shear', c_float * 3),
                ('rotationOrder', c_int32),
                ('rstorder', c_int32)]
    _map = {
        "rotationOrder": XYZOrder,
        "rstorder": RSTOrder
    }

    def __init__(self):
        super(TransformEuler, self).__init__()
        self.position[0] = 0
        self.position[1] = 0
        self.position[2] = 0
        self.rotationQuaternion[0] = 0
        self.rotationQuaternion[1] = 0
        self.rotationQuaternion[2] = 0
        self.rotationQuaternion[3] = 1
        self.scale[0] = 1
        self.scale[1] = 1
        self.scale[2] = 1
        self.shear[0] = 0
        self.shear[1] = 0
        self.shear[2] = 0
        self.rotationorder = XYZOrder.HAPI_XYZORDER_DEFAULT
        self.rstorder = RSTOrder.HAPI_RSTORDER_DEFAULT

    def __json__(self):
        json_data = {}
        # _fields_
        json_data[self._fields_[0][0]] = [self.position[0], self.position[1], self.position[2]]
        json_data[self._fields_[1][0]] = [self.rotationQuaternion[0], self.rotationQuaternion[1],
                                          self.rotationQuaternion[2], self.rotationQuaternion[3]]
        json_data[self._fields_[2][0]] = [self.scale[0], self.scale[1], self.scale[2]]
        json_data[self._fields_[3][0]] = [self.shear[0], self.shear[1], self.shear[2]]
        json_data[self._fields_[4][0]] = self.rotationOrder
        json_data[self._fields_[5][0]] = self.rstorder
        return json_data


# SESSIONS -----------------------------------------------------------------

class Session(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_Session
    """
    _fields_ = [('type', c_int),
                ('id', c_int64)]
    _map = {
        "type": SessionType
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.type
        json_data[self._fields_[1][0]] = self.id
        return json_data


class ThriftServerOptions(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_ThriftServerOptions
    """
    _fields_ = [('autoClose', c_bool),
                ('timeoutMs', c_float),
                ('verbosity', c_int)]

    _map = {
        "verbosity": StatusVerbosity
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.autoClose
        json_data[self._fields_[1][0]] = self.timeoutMs
        json_data[self._fields_[2][0]] = self.verbosity
        return json_data


# TIME ---------------------------------------------------------------------

class TimelineOptions(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_TimelineOptions
    """
    _fields_ = [('fps', c_float),
                ('startTime', c_float),
                ('endTime', c_float)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.fps
        json_data[self._fields_[1][0]] = self.startTime
        json_data[self._fields_[2][0]] = self.endTime
        return json_data


# ASSETS -------------------------------------------------------------------

class AssetInfo(Structure):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_AssetInfo
    """
    _fields_ = [('nodeId', c_int32),
                ('objectNodeId', c_int32),
                ('hasEverCooked', c_bool),
                ('nameSH', c_int32),
                ('labelSH', c_int32),
                ('filePathSH', c_int32),
                ('versionSH', c_int32),
                ('fullOpNameSH', c_int32),
                ('helpTextSH', c_int32),
                ('helpURLSH', c_int32),
                ('objectCount', c_int32),
                ('handleCount', c_int32),
                ('transformInputCount', c_int32),
                ('geoInputCount', c_int32),
                ('geoOutputCount', c_int32),
                ('haveObjectsChanged', c_int32),
                ('haveMaterialsChanged', c_int32)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.nodeId
        json_data[self._fields_[1][0]] = self.objectNodeId
        json_data[self._fields_[2][0]] = self.hasEverCooked
        json_data[self._fields_[3][0]] = self.nameSH
        json_data[self._fields_[4][0]] = self.labelSH
        json_data[self._fields_[5][0]] = self.filePathSH
        json_data[self._fields_[6][0]] = self.versionSH
        json_data[self._fields_[7][0]] = self.fullOpNameSH
        json_data[self._fields_[8][0]] = self.helpTextSH
        json_data[self._fields_[9][0]] = self.helpURLSH
        json_data[self._fields_[10][0]] = self.objectCount
        json_data[self._fields_[11][0]] = self.handleCount
        json_data[self._fields_[12][0]] = self.transformInputCount
        json_data[self._fields_[13][0]] = self.geoInputCount
        json_data[self._fields_[14][0]] = self.geoOutputCount
        json_data[self._fields_[15][0]] = self.haveObjectsChanged
        json_data[self._fields_[16][0]] = self.haveMaterialsChanged
        return json_data


class CookOptions(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_CookOptions
    """
    _fields_ = [('splitGeosByGroup', c_bool),
                ('splitGroupSH', c_int32),
                ('splitGeosByAttribute', c_bool),
                ('splitAttrSH', c_int32),
                ('maxVerticesPerPrimitive', c_int32),
                ('refineCurveToLinear', c_bool),
                ('curveRefineLOD', c_float),
                ('clearErrorsAndWarnings', c_bool),
                ('cookTemplatedGeos', c_bool),
                ('splitPointsByVertexAttributes', c_bool),
                ('packedPrimInstancingMode', c_int32),
                ('handleBoxPartTypes', c_bool),
                ('handleSpherePartTypes', c_bool),
                ('checkPartChanges', c_bool),
                ('cacheMeshTopology', c_bool),
                ('preferOutputNodes', c_bool),
                ('extraFlags', c_int32)]
    _map = {
        'packedPrimInstancingMode': PackedPrimInstancingMode
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.splitGeosByGroup
        json_data[self._fields_[1][0]] = self.splitGeosByAttribute
        json_data[self._fields_[2][0]] = self.splitAttrSH
        json_data[self._fields_[3][0]] = self.maxVerticesPerPrimitive
        json_data[self._fields_[4][0]] = self.refineCurveToLinear
        json_data[self._fields_[5][0]] = self.curveRefineLOD
        json_data[self._fields_[6][0]] = self.clearErrorsAndWarnings
        json_data[self._fields_[7][0]] = self.cookTemplatedGeos
        json_data[self._fields_[8][0]] = self.splitPointsByVertexAttributes
        json_data[self._fields_[9][0]] = self.packedPrimInstancingMode
        json_data[self._fields_[10][0]] = self.handleBoxPartTypes
        json_data[self._fields_[11][0]] = self.handleSpherePartTypes
        json_data[self._fields_[12][0]] = self.checkPartChanges
        json_data[self._fields_[13][0]] = self.cacheMeshTopology
        json_data[self._fields_[14][0]] = self.preferOutputNodes
        json_data[self._fields_[15][0]] = self.extraFlags
        return json_data


# NODES --------------------------------------------------------------------

class NodeInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_NodeInfo
    """
    _fields_ = [('id', c_int32),
                ('parentId', c_int32),
                ('nameSH', c_int32),
                ('type', c_int),
                ('isValid', c_bool),
                ('totalCookCount', c_int32),
                ('uniqueHoudiniNodeId', c_int32),
                ('internalNodePathSH', c_int32),
                ('parmCount', c_int32),
                ('parmIntValueCount', c_int32),
                ('parmFloatValueCount', c_int32),
                ('parmStringValueCount', c_int32),
                ('parmChoiceCount', c_int32),
                ('childNodeCount', c_int32),
                ('inputCount', c_int32),
                ('outputCount', c_int32),
                ('createdPostAssetLoad', c_bool),
                ('isTimeDependent', c_bool)]
    _map = {
        "type": NodeType
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.id
        json_data[self._fields_[1][0]] = self.parentId
        json_data[self._fields_[2][0]] = self.nameSH
        json_data[self._fields_[3][0]] = self.type
        json_data[self._fields_[4][0]] = self.isValid
        json_data[self._fields_[5][0]] = self.totalCookCount
        json_data[self._fields_[6][0]] = self.uniqueHoudiniNodeId
        json_data[self._fields_[7][0]] = self.internalNodePathSH
        json_data[self._fields_[8][0]] = self.parmCount
        json_data[self._fields_[9][0]] = self.parmIntValueCount
        json_data[self._fields_[10][0]] = self.parmFloatValueCount
        json_data[self._fields_[11][0]] = self.parmStringValueCount
        json_data[self._fields_[12][0]] = self.parmChoiceCount
        json_data[self._fields_[13][0]] = self.childNodeCount
        json_data[self._fields_[14][0]] = self.inputCount
        json_data[self._fields_[15][0]] = self.outputCount
        json_data[self._fields_[16][0]] = self.createdPostAssetLoad
        json_data[self._fields_[17][0]] = self.isTimeDependent
        return json_data


# PARAMETERS ---------------------------------------------------------------

class ParmInfo(StructureWithEnums):
    """Equivalent of HAPI's HAPI_ParmInfo
    """
    _fields_ = [('id', c_int32),
                ('parentId', c_int32),
                ('childIndex', c_int32),
                ('type', c_int),
                ('scriptType', c_int),
                ('typeInfoSH', c_int32),
                ('permissions', c_int32),
                ('tagCount', c_int32),
                ('size', c_int32),
                ('choiceListType', c_int32),
                ('choiceCount', c_int32),
                ('nameSH', c_int32),
                ('labelSH', c_int32),
                ('templateNameSH', c_int32),
                ('helpSH', c_int32),
                ('hasMin', c_bool),
                ('hasMax', c_bool),
                ('hasUIMin', c_bool),
                ('hasUIMax', c_bool),
                ('min', c_float),
                ('max', c_float),
                ('UIMin', c_float),
                ('UIMax', c_float),
                ('invisible', c_bool),
                ('disabled', c_bool),
                ('spare', c_bool),
                ('joinNext', c_bool),
                ('labelNone', c_bool),
                ('intValuesIndex', c_int32),
                ('floatValuesIndex', c_int32),
                ('stringValuesIndex', c_int32),
                ('choiceIndex', c_int32),
                ('inputNodeType', c_int32),
                ('inputNodeFlag', c_int32),
                ('isChildOfMultiParm', c_bool),
                ('instanceNum', c_int32),
                ('instanceLength', c_int32),
                ('instanceCount', c_int32),
                ('instanceStartOffset', c_int32),
                ('rampType', c_int32),
                ('visibilityConditionSH', c_int32),
                ('disabledConditionSH', c_int32),
                ('useMenuItemTokenAsValue', c_bool)]
    _map = {
        "type": ParmType,
        "scriptType": PrmScriptType,
        "permissions": Permissions,
        "choiceListType": ChoiceListType,
        "inputNodeType": NodeType,
        "inputNodeFlag": NodeFlags,
        "rampType": RampType
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.id
        json_data[self._fields_[1][0]] = self.parentId
        json_data[self._fields_[2][0]] = self.childIndex
        json_data[self._fields_[3][0]] = self.type
        json_data[self._fields_[4][0]] = self.scriptType
        json_data[self._fields_[5][0]] = self.typeInfoSH
        json_data[self._fields_[6][0]] = self.permissions
        json_data[self._fields_[7][0]] = self.tagCount
        json_data[self._fields_[8][0]] = self.size
        json_data[self._fields_[9][0]] = self.choiceListType
        json_data[self._fields_[10][0]] = self.choiceCount
        json_data[self._fields_[11][0]] = self.nameSH
        json_data[self._fields_[12][0]] = self.labelSH
        json_data[self._fields_[13][0]] = self.templateNameSH
        json_data[self._fields_[14][0]] = self.helpSH
        json_data[self._fields_[15][0]] = self.hasMin
        json_data[self._fields_[16][0]] = self.hasMax
        json_data[self._fields_[17][0]] = self.hasUIMin
        json_data[self._fields_[18][0]] = self.hasUIMax
        json_data[self._fields_[19][0]] = self.min
        json_data[self._fields_[20][0]] = self.max
        json_data[self._fields_[21][0]] = self.UIMin
        json_data[self._fields_[22][0]] = self.UIMax
        json_data[self._fields_[23][0]] = self.invisible
        json_data[self._fields_[24][0]] = self.disabled
        json_data[self._fields_[25][0]] = self.spare
        json_data[self._fields_[26][0]] = self.joinNext
        json_data[self._fields_[27][0]] = self.labelNone
        json_data[self._fields_[28][0]] = self.intValuesIndex
        json_data[self._fields_[29][0]] = self.floatValuesIndex
        json_data[self._fields_[30][0]] = self.stringValuesIndex
        json_data[self._fields_[31][0]] = self.choiceIndex
        json_data[self._fields_[32][0]] = self.inputNodeType
        json_data[self._fields_[33][0]] = self.inputNodeFlag
        json_data[self._fields_[34][0]] = self.isChildOfMultiParm
        json_data[self._fields_[35][0]] = self.instanceNum
        json_data[self._fields_[36][0]] = self.instanceLength
        json_data[self._fields_[37][0]] = self.instanceCount
        json_data[self._fields_[38][0]] = self.instanceStartOffset
        json_data[self._fields_[39][0]] = self.rampType
        json_data[self._fields_[40][0]] = self.visibilityConditionSH
        json_data[self._fields_[41][0]] = self.disabledConditionSH
        json_data[self._fields_[42][0]] = self.useMenuItemTokenAsValue
        return json_data

    def is_int(self):
        """If this attribute is int type

        Returns:
            bool: If this attribute is int type
        """
        return (ParmType.INT_START <= self.type <= ParmType.INT_END) \
               or self.type == ParmType.MULTIPARMLIST \
               or self.type == ParmType.FOLDERLIST_RADIO

    def is_float(self):
        """If this attribute is float type

        Returns:
            bool: If this attribute is float type
        """
        return ParmType.FLOAT_START <= self.type <= ParmType.FLOAT_END

    def is_string(self):
        """If this attribute is string type

        Returns:
            bool: If this attribute is string type
        """
        return (ParmType.STRING_START <= self.type <= ParmType.STRING_END) \
               or self.type == ParmType.LABEL \
               or self.type == ParmType.PATH_FILE_DIR

    def is_path(self):
        """If this attribute is path type

        Returns:
            bool: If this attribute is path type
        """
        return (ParmType.PATH_START <= self.type <= ParmType.PATH_END) \
               or self.type == ParmType.PATH_FILE_DIR

    def is_node(self):
        """If this attribute is node type

        Returns:
            bool: If this attribute is node type
        """
        return ParmType.NODE_START <= self.type <= ParmType.NODE_END

    def is_non_value(self):
        """If this attribute is non-value

        Returns:
            bool: If this attribute is non-value
        """
        return ParmType.NONVALUE_START <= self.type <= ParmType.NONVALUE_END


class ParmChoiceInfo(StructureWithEnums):
    """Equivalent of HAPI's HAPI_ParmChoiceInfo
    """
    _fields_ = [
        ('parentParmId', c_int32),
        ('labelSH', c_int32),
        ('valueSH', c_int32)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.parentParmId
        json_data[self._fields_[1][0]] = self.labelSH
        json_data[self._fields_[2][0]] = self.valueSH
        return json_data


# HANDLES ------------------------------------------------------------------

class HandleInfo(StructureWithEnums):
    """Equivalent of HAPI's HAPI_HandleInfo
    """
    _fields_ = [
        ('nameSH', c_int32),
        ('typeNameSH', c_int32),
        ('bindingsCount', c_int32)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.nameSH
        json_data[self._fields_[1][0]] = self.typeNameSH
        json_data[self._fields_[2][0]] = self.bindingsCount
        return json_data


class HAPI_HandleBindingInfo(StructureWithEnums):
    """Equivalent of HAPI's HAPI_HAPI_HandleBindingInfo
    """
    _fields_ = [
        ('handleParmNameSH', c_int32),
        ('assetParmNameSH', c_int32),
        ('assetParmId', c_int32),
        ('assetParmIndex', c_int32)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.handleParmNameSH
        json_data[self._fields_[1][0]] = self.assetParmNameSH
        json_data[self._fields_[2][0]] = self.assetParmId
        json_data[self._fields_[3][0]] = self.assetParmIndex
        return json_data


# OBJECTS ------------------------------------------------------------------

class ObjectInfo(Structure):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_ObjectInfo
    """
    _fields_ = [('nameSH', c_int32),
                ('objectInstancePathSH', c_int32),
                ('hasTransformChanged', c_bool),
                ('haveGeosChanged', c_bool),
                ('isVisible', c_bool),
                ('isInstancer', c_bool),
                ('isInstanced', c_bool),
                ('geoCount', c_int32),
                ('nodeId', c_int32),
                ('objectToInstanceId', c_int32)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.nameSH
        json_data[self._fields_[1][0]] = self.objectInstancePathSH
        json_data[self._fields_[2][0]] = self.hasTransformChanged
        json_data[self._fields_[3][0]] = self.haveGeosChanged
        json_data[self._fields_[4][0]] = self.isVisible
        json_data[self._fields_[5][0]] = self.isInstancer
        json_data[self._fields_[6][0]] = self.isInstanced
        json_data[self._fields_[7][0]] = self.geoCount
        json_data[self._fields_[8][0]] = self.nodeId
        json_data[self._fields_[9][0]] = self.objectToInstanceId
        return json_data


# GEOMETRY -----------------------------------------------------------------

class GeoInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_GeoInfo
    """
    _fields_ = [('type', c_int32),
                ('nameSH', c_int32),
                ('nodeId', c_int32),
                ('isEditable', c_bool),
                ('isTemplated', c_bool),
                ('isDisplayGeo', c_bool),
                ('hasGeoChanged', c_bool),
                ('hasMaterialChanged', c_bool),
                ('pointGroupCount', c_int32),
                ('primitiveGroupCount', c_int32),
                ('edgeGroupCount', c_int32),
                ('partCount', c_int32)]
    _map = {
        "type": HGeoType
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.type
        json_data[self._fields_[1][0]] = self.nameSH
        json_data[self._fields_[2][0]] = self.nodeId
        json_data[self._fields_[3][0]] = self.isEditable
        json_data[self._fields_[4][0]] = self.isTemplated
        json_data[self._fields_[5][0]] = self.isDisplayGeo
        json_data[self._fields_[6][0]] = self.hasGeoChanged
        json_data[self._fields_[7][0]] = self.hasMaterialChanged
        json_data[self._fields_[8][0]] = self.pointGroupCount
        json_data[self._fields_[9][0]] = self.primitiveGroupCount
        json_data[self._fields_[10][0]] = self.edgeGroupCount
        json_data[self._fields_[11][0]] = self.partCount
        return json_data


class PartInfo(StructureWithEnums):
    """Equivalent of HAPI's HAPI_PartInfo
    """
    _fields_ = [('id', c_int32),
                ('nameSH', c_int32),
                ('type', c_int32),
                ('faceCount', c_int32),
                ('vertexCount', c_int32),
                ('pointCount', c_int32),
                ('attributeCounts', c_int32 * 4),
                ('isInstanced', c_bool),
                ('instancedPartCount', c_int32),
                ('instanceCount', c_int32),
                ('hasChanged', c_bool)]
    _map = {
        "type": PartType
    }

    def __init__(self):
        """Init
        """
        super(PartInfo, self).__init__()
        self.attributeCounts[0] = 0
        self.attributeCounts[1] = 0
        self.attributeCounts[2] = 0
        self.attributeCounts[3] = 0

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.id
        json_data[self._fields_[1][0]] = self.nameSH
        json_data[self._fields_[2][0]] = self.type
        json_data[self._fields_[3][0]] = self.faceCount
        json_data[self._fields_[4][0]] = self.vertexCount
        json_data[self._fields_[5][0]] = self.pointCount
        json_data[self._fields_[7][0]] = self.isInstanced
        json_data[self._fields_[8][0]] = self.instancedPartCount
        json_data[self._fields_[9][0]] = self.instanceCount
        json_data[self._fields_[10][0]] = self.hasChanged
        return json_data

    @property
    def point_attrib_count(self):
        """Get point attribute count

        Returns:
            int: point attribute count
        """
        return self.attributeCounts[AttributeOwner.POINT]

    @point_attrib_count.setter
    def point_attrib_count(self, value):
        """Set point attribute count

        Args:
            value (int): point attribute count
        """
        self.attributeCounts[AttributeOwner.POINT] = value

    @property
    def vertex_attrib_count(self):
        """Get vertex attribute count

        Returns:
            int: vertex attribute count
        """
        return self.attributeCounts[AttributeOwner.VERTEX]

    @vertex_attrib_count.setter
    def vertex_attrib_count(self, value):
        """Set vertex attribute count

        Args:
            value (int): vertex attribute count
        """
        self.attributeCounts[AttributeOwner.VERTEX] = value

    @property
    def prim_attrib_count(self):
        """Get prim attribute count

        Returns:
            int: prim attribute count
        """
        return self.attributeCounts[AttributeOwner.PRIM]

    @prim_attrib_count.setter
    def prim_attrib_count(self, value):
        """Set prim attribute count

        Args:
            value (int): prim attribute count
        """
        self.attributeCounts[AttributeOwner.PRIM] = value

    @property
    def detail_attrib_count(self):
        """Get detail attribute count

        Returns:
            int: detail attribute count
        """
        return self.attributeCounts[AttributeOwner.DETAIL]

    @detail_attrib_count.setter
    def detail_attrib_count(self, value):
        """Set detail attribute count

        Args:
            value (int): detail attribute count
        """
        self.attributeCounts[AttributeOwner.DETAIL] = value


class AttributeInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_AttributeInfo
    """
    _fields_ = [('exists', c_bool),
                ('owner', c_int32),
                ('storage', c_int32),
                ('originalOwner', c_int32),
                ('count', c_int32),
                ('tupleSize', c_int32),
                ('totalArrayElements', c_int64),
                ('typeInfo', c_int32)]
    _map = {
        "owner": AttributeOwner,
        "storage": StorageType,
        "originalOwner": AttributeOwner,
        "typeInfo": AttributeTypeInfo
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.exists
        json_data[self._fields_[1][0]] = self.owner
        json_data[self._fields_[2][0]] = self.storage
        json_data[self._fields_[3][0]] = self.originalOwner
        json_data[self._fields_[4][0]] = self.count
        json_data[self._fields_[5][0]] = self.tupleSize
        json_data[self._fields_[6][0]] = self.totalArrayElements
        json_data[self._fields_[7][0]] = self.typeInfo
        return json_data


# MATERIALS ----------------------------------------------------------------

class MaterialInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_MaterialInfo
    """
    _fields_ = [('nodeId', c_int32),
                ('exists', c_bool),
                ('hasChanged', c_bool)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.nodeId
        json_data[self._fields_[1][0]] = self.exists
        json_data[self._fields_[2][0]] = self.hasChanged
        return json_data


class ImageFileFormat(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_ImageFileFormat
    """
    _fields_ = [('nameSH', c_int32),
                ('descriptionSH', c_int32),
                ('defaultExtensionSH', c_int32)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.nameSH
        json_data[self._fields_[1][0]] = self.descriptionSH
        json_data[self._fields_[2][0]] = self.defaultExtensionSH
        return json_data


class ImageInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_ImageInfo
    """
    _fields_ = [('imageFileFormatNameSH', c_int32),
                ('xRes', c_int32),
                ('yRes', c_int32),
                ('dataFormat', c_int32),
                ('interleaved', c_bool),
                ('packing', c_int32),
                ('gamma', c_double)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.imageFileFormatNameSH
        json_data[self._fields_[1][0]] = self.xRes
        json_data[self._fields_[2][0]] = self.yRes
        json_data[self._fields_[3][0]] = self.dataFormat
        json_data[self._fields_[4][0]] = self.interleaved
        json_data[self._fields_[5][0]] = self.packing
        json_data[self._fields_[6][0]] = self.gamma
        return json_data


# ANIMATION ----------------------------------------------------------------

class Keyframe(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_Keyframe
    """
    _fields_ = [('time', c_float),
                ('value', c_float),
                ('inTangent', c_float),
                ('outTangent', c_float)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.time
        json_data[self._fields_[1][0]] = self.value
        json_data[self._fields_[2][0]] = self.inTangent
        json_data[self._fields_[3][0]] = self.outTangent
        return json_data


# VOLUMES ------------------------------------------------------------------

class VolumeInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_VolumeInfo
    """
    _fields_ = [('nameSH', c_int32),
                ('type', c_int32),
                ('xLength', c_int32),
                ('yLength', c_int32),
                ('zLength', c_int32),
                ('minX', c_int32),
                ('minY', c_int32),
                ('minZ', c_int32),
                ('tupleSize', c_int32),
                ('storage', c_int32),
                ('tileSize', c_int32),
                ('transform', Transform),
                ('hasTaper', c_bool),
                ('xTaper', c_float),
                ('yTaper', c_float)]
    _map = {
        "type": VolumeType,
        "storage": StorageType,
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.nameSH
        json_data[self._fields_[1][0]] = self.type
        json_data[self._fields_[2][0]] = self.xLength
        json_data[self._fields_[3][0]] = self.yLength
        json_data[self._fields_[4][0]] = self.zLength
        json_data[self._fields_[5][0]] = self.minX
        json_data[self._fields_[6][0]] = self.minY
        json_data[self._fields_[7][0]] = self.minZ
        json_data[self._fields_[8][0]] = self.tupleSize
        json_data[self._fields_[9][0]] = self.storage
        json_data[self._fields_[10][0]] = self.tileSize
        json_data[self._fields_[11][0]] = self.transform.__json__()
        json_data[self._fields_[12][0]] = self.hasTaper
        json_data[self._fields_[13][0]] = self.xTaper
        json_data[self._fields_[14][0]] = self.yTaper
        return json_data


class VolumeTileInfo(Structure):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_VolumeTileInfo
    """
    _fields_ = [('minX', c_int32),
                ('minY', c_int32),
                ('minZ', c_int32),
                ('isValid', c_bool)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.minX
        json_data[self._fields_[1][0]] = self.minY
        json_data[self._fields_[2][0]] = self.minZ
        json_data[self._fields_[3][0]] = self.isValid
        return json_data


class VolumeVisualInfo(Structure):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_VolumeVisualInfo
    """
    _fields_ = [('type', c_int32),
                ('iso', c_float),
                ('density', c_float)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.type
        json_data[self._fields_[1][0]] = self.iso
        json_data[self._fields_[2][0]] = self.density
        return json_data


# CURVES -------------------------------------------------------------------

class CurveInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_CurveInfo
    """
    _fields_ = [('curveType', c_int32),
                ('curveCount', c_int32),
                ('vertexCount', c_int32),
                ('knotCount', c_int32),
                ('isPeriodic', c_bool),
                ('isRational', c_bool),
                ('order', c_int32),
                ('hasKnots', c_bool),
                ('isClosed', c_bool)]
    _map = {
        "curveType": CurveType
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.curveType
        json_data[self._fields_[1][0]] = self.curveCount
        json_data[self._fields_[2][0]] = self.vertexCount
        json_data[self._fields_[3][0]] = self.knotCount
        json_data[self._fields_[4][0]] = self.isPeriodic
        json_data[self._fields_[5][0]] = self.isRational
        json_data[self._fields_[6][0]] = self.order
        json_data[self._fields_[7][0]] = self.hasKnots
        json_data[self._fields_[8][0]] = self.isClosed
        return json_data


class InputCurveInfo(StructureWithEnums):
    """Wrapper of HAPI_InputCurveInfo
    """
    _fields_ = [('curveType', c_int32),
                ('order', c_int32),
                ('closed', c_bool),
                ('reverse', c_bool),
                ('inputMethod', c_int32),
                ('breakpointParameterization', c_int32)]
    _map = {
        "curveType": CurveType,
        "inputMethod": InputCurveMethod,
        "breakpointParameterization": InputCurveParameterization
    }

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.curveType
        json_data[self._fields_[1][0]] = self.order
        json_data[self._fields_[2][0]] = self.closed
        json_data[self._fields_[3][0]] = self.reverse
        json_data[self._fields_[4][0]] = self.inputMethod
        json_data[self._fields_[5][0]] = self.breakpointParameterization
        return json_data


# BASIC PRIMITIVES ---------------------------------------------------------

class BoxInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_BoxInfo
    """
    _fields_ = [('center', c_float * 3),
                ('size', c_float * 3),
                ('rotation', c_float * 3)]

    def __init__(self):
        super(BoxInfo, self).__init__()
        self.center[0] = 0
        self.center[1] = 0
        self.center[2] = 0
        self.size[0] = 1
        self.size[1] = 1
        self.size[2] = 1
        self.rotation[0] = 0
        self.rotation[1] = 0
        self.rotation[2] = 0

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = [self.center[0], self.center[1], self.center[2]]
        json_data[self._fields_[1][0]] = [self.size[0], self.size[1], self.size[2]]
        json_data[self._fields_[2][0]] = [self.rotation[0], self.rotation[1], self.rotation[2]]
        return json_data


class SphereInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_SphereInfo
    """
    _fields_ = [('center', c_float * 3),
                ('radius', c_float)]

    def __init__(self):
        super(SphereInfo, self).__init__()
        self.center[0] = 0
        self.center[1] = 0
        self.center[2] = 0
        self.radius = 1

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = [self.center[0], self.center[1], self.center[2]]
        json_data[self._fields_[1][0]] = self.radius
        return json_data


# PDG Structs --------------------------------------------------------------

class PDG_EventInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_PDG_EventInfo
    """
    _fields_ = [('nodeId', c_int32),
                ('workitemId', c_int32),
                ('dependencyId', c_int32),
                ('currentState', c_int32),
                ('lastState', c_int32),
                ('eventType', c_int32),
                ('msgSH', c_int32)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.nodeId
        json_data[self._fields_[1][0]] = self.workitemId
        json_data[self._fields_[2][0]] = self.dependencyId
        json_data[self._fields_[3][0]] = self.currentState
        json_data[self._fields_[4][0]] = self.lastState
        json_data[self._fields_[5][0]] = self.eventType
        json_data[self._fields_[6][0]] = self.msgSH
        return json_data


class PDG_WorkItemInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_PDG_WorkitemInfo
    """
    _fields_ = [('index', c_int32),
                ('numResults', c_int32),
                ('nameSH', c_int32)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.index
        json_data[self._fields_[1][0]] = self.numResults
        json_data[self._fields_[2][0]] = self.nameSH
        return json_data

class PDG_WorkItemOutputFile(StructureWithEnums):
    """Wrapper of HAPI_PDG_WorkItemOutputFile

    Data for a PDG output file
    """
    _fields_ = [('filePathSH', c_int),
                ('tagSH', c_int),
                ('hash', c_int64)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.filePathSH
        json_data[self._fields_[1][0]] = self.tagSH
        json_data[self._fields_[2][0]] = self.hash
        return json_data

class PDG_WorkItemResultInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_PDG_WorkItemResultInfo
    """
    _fields_ = [('resultSH', c_int32),
                ('resultTagSH', c_int32),
                ('resultHash', c_int64)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.resultSH
        json_data[self._fields_[1][0]] = self.resultTagSH
        json_data[self._fields_[2][0]] = self.resultHash
        return json_data


# SESSIONSYNC --------------------------------------------------------------

class Viewport(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_Viewport
    """
    _fields_ = [('position', c_float * 3),
                ('rotationQuaternion', c_float * 4),
                ('offset', c_float)]

    def __init__(self):
        super(Transform, self).__init__()
        self.position[0] = 0
        self.position[1] = 0
        self.position[2] = 0
        self.rotationQuaternion[0] = 0
        self.rotationQuaternion[1] = 0
        self.rotationQuaternion[2] = 0
        self.rotationQuaternion[3] = 1
        self.offset = 0

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = [self.position[0], self.position[1], self.position[2]]
        json_data[self._fields_[1][0]] = [self.rotationQuaternion[0], self.rotationQuaternion[1],
                                          self.rotationQuaternion[2], self.rotationQuaternion[3]]
        json_data[self._fields_[2][0]] = self.offset
        return json_data


class SessionSyncInfo(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_SessionSyncInfo
    """
    _fields_ = [('cookUsingHoudiniTime', c_bool),
                ('syncViewport', c_bool)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.cookUsingHoudiniTime
        json_data[self._fields_[1][0]] = self.syncViewport
        return json_data


class CompositorOptions(StructureWithEnums):  # pylint: disable=too-few-public-methods
    """Equivalent of HAPI's HAPI_CompositorOptions
    """
    _fields_ = [('maximumResolutionX', c_int32),
                ('maximumResolutionY', c_int32)]

    def __json__(self):
        json_data = {}
        json_data[self._fields_[0][0]] = self.maximumResolutionX
        json_data[self._fields_[1][0]] = self.maximumResolutionY
        return json_data


""""
todo : 



/// Configuration options for Houdini's compositing context
struct HAPI_API HAPI_CompositorOptions
{
    /// Specifies the maximum allowed width of an image in the compositor
    int maximumResolutionX;

    /// Specifies the maximum allowed height of an image in the compositor
    int maximumResolutionY;
};
HAPI_C_STRUCT_TYPEDEF( HAPI_CompositorOptions )
"""
