from .coord import coord2, coord2_property
from . import transformable
from .transforms.translation import gds_translation
from .transforms.rotation import gds_rotation
from . import shape_info
from .. import constants

from ..properties.descriptor import restricted_property, function_property
from ..properties.restrictions import restrict_type
from ..properties.processors import processor_typecast
from ..properties.initializer import strong_property_initializer

__all__=["gds_vector", "transformation_from_vector", "vector_from_two_points", "vector_property", "vector_match_transform"]


class gds_vector(strong_property_initializer, transformable.gds_transformable):
    """ positioned vector, consisting of a point and an angle """
    position = coord2_property(default = (0.0, 0.0))
    def __init__(self, position, angle, **kwargs):
        super(gds_vector, self).__init__(
            position = position,
            angle= angle,
            **kwargs
            )

    def get_x(self):
        return self.position.x
    x = property(get_x)
    
    def get_y(self):
        return self.position.y
    y = property(get_y)

    def get_angle_rad(self):
        return constants.DEG2RAD * self.__angle__
    def set_angle_rad(self, value):
        self.__angle__ = (constants.RAD2DEG * value)%360.0
    angle_rad = function_property(get_angle_rad, set_angle_rad)
    
    def get_angle_deg(self):
        return self.__angle__
    def set_angle_deg(self, value):
        self.__angle__ = value % 360.0
    angle_deg = function_property(get_angle_deg, set_angle_deg)
    angle = angle_deg
    
    def cos(self):
        return cos(constants.DEG2RAD*self.__angle__)
    def sin(self):
        return sin(constants.DEG2RAD*self.__angle__)
    def tan(self):
        return tan(constants.DEG2RAD*self.__angle__)
    
    def flip(self):
        #gives port in other direction
        return gds_vector(self.position, (self.__angle__ + 180.0 ) % 360.0)

    def __getitem__(self, key):
        # behave like a coordinate for e.g. size_info
        if key == 0:
            return self.position[0]
        if key == 1:
            return self.position[1]
        else:
            raise IndexError("gds_vector supports only subscription[0] and [1], not " + str(key))

    def __eq__(self, other):
        if not isinstance(other, gds_vector): return False
        return self.position==other.position and (self.angle_deg == other.angle_deg)
    
    def __neq__(self, other):
        return self.position!=other.position or (self.angle_deg != other.angle_deg)

    def __repr__(self):
        return "<Vector (%f, %f), a=%f>" %(self.x, self.y, self.angle_deg)


def transformation_from_vector(vector):
    return gds_rotation((0.0, 0.0), vector.angle_deg) + gds_translation(vector.position)

def vector_from_two_points(point1, point2):
    return gds_vector(point1, shape_info.angle_deg(point2, point1))

def vector_property(internal_member_name = None, restriction = None, preprocess = None, **kwargs):
    R = restrict_type(gds_vector) & restriction
    return restricted_property(internal_member_name, restriction = R, **kwargs )


def vector_match_transform(vector1, vector2):
    """ returns transformation to realign vectort 1 to match position and angle with vector 2 """
    return gds_translation(vector2.position - vector1.position) + gds_rotation(vector2.position, vector2.angle_deg - vector1.angle_deg + 180.0)  
