# Copyright (c) 2019-2020 Manfred Moitzi
# License: MIT License
from typing import TYPE_CHECKING
from ezdxf.lldxf import validator
from ezdxf.lldxf.attributes import (
    DXFAttr, DXFAttributes, DefSubclass, XType, RETURN_DEFAULT,
    group_code_mapping
)
from ezdxf.lldxf.const import SUBCLASS_MARKER
from ezdxf.math import NULLVEC, X_AXIS, Z_AXIS
from .spline import Spline, acdb_spline
from .dxfentity import base_class, SubclassProcessor
from .dxfgfx import acdb_entity
from .factory import register_entity

if TYPE_CHECKING:
    from ezdxf.eztypes import TagWriter, DXFNamespace, Matrix44

__all__ = ['Helix']

acdb_helix = DefSubclass('AcDbHelix', {
    'major_release_number': DXFAttr(90, default=29),
    'maintenance_release_number': DXFAttr(91, default=63),
    'axis_base_point': DXFAttr(10, xtype=XType.point3d, default=NULLVEC),
    'start_point': DXFAttr(
        11, xtype=XType.point3d, default=X_AXIS,
        validator=validator.is_not_null_vector,
        fixer=RETURN_DEFAULT,
    ),
    'axis_vector': DXFAttr(
        12, xtype=XType.point3d, default=Z_AXIS,
        validator=validator.is_not_null_vector,
        fixer=RETURN_DEFAULT,
    ),
    'radius': DXFAttr(40, default=1),
    'turns': DXFAttr(41, default=1),
    'turn_height': DXFAttr(42, default=1),

    # Handedness:
    # 0 = left
    # 1 = right
    'handedness': DXFAttr(
        290, default=1,
        validator=validator.is_integer_bool,
        fixer=RETURN_DEFAULT,
    ),

    # Constrain type:
    # 0 = Constrain turn height
    # 1 = Constrain turns
    # 2 = Constrain height
    'constrain': DXFAttr(
        280, default=1,
        validator=validator.is_in_integer_range(0, 3),
        fixer=RETURN_DEFAULT,
    ),
})
acdb_helix_group_codes = group_code_mapping(acdb_helix)


@register_entity
class Helix(Spline):
    """ DXF HELIX entity """
    DXFTYPE = 'HELIX'
    DXFATTRIBS = DXFAttributes(base_class, acdb_entity, acdb_spline, acdb_helix)

    def load_dxf_attribs(
            self, processor: SubclassProcessor = None) -> 'DXFNamespace':
        dxf = super().load_dxf_attribs(processor)
        if processor:
            processor.fast_load_dxfattribs(
                dxf, acdb_helix_group_codes, 3, recover=True)
        return dxf

    def export_entity(self, tagwriter: 'TagWriter') -> None:
        """ Export entity specific data as DXF tags. """
        super().export_entity(tagwriter)
        tagwriter.write_tag2(SUBCLASS_MARKER, acdb_helix.name)
        self.dxf.export_dxf_attribs(tagwriter, [
            'major_release_number', 'maintenance_release_number',
            'axis_base_point', 'start_point', 'axis_vector', 'radius', 'turns',
            'turn_height', 'handedness', 'constrain'

        ])

    def transform(self, m: 'Matrix44') -> 'Helix':
        """ Transform the HELIX entity by transformation matrix `m` inplace. """
        super().transform(m)
        self.dxf.axis_base_point = m.transform(self.dxf.axis_base_point)
        self.dxf.axis_vector = m.transform_direction(self.dxf.axis_vector)
        self.dxf.start_point = m.transform(self.dxf.start_point)
        self.dxf.radius = m.transform_direction(
            (self.dxf.radius, 0, 0)).magnitude
        return self
