from ..transform import gds_reversible_transform
from ..coord import coord2, coord2_property
from ...properties.descriptor import set_function_property
from numpy import array
__all__ = ["gds_stretch"]

class gds_stretch(gds_reversible_transform):
    """ non-homothetic scaling """
    def __init__(self, stretch_center = (0.0, 0.0), stretch_factor = (1.0, 1.0), **kwargs):
        super(gds_stretch, self).__init__(
            stretch_center = stretch_center,
            stretch_factor = stretch_factor,
            **kwargs)

    stretch_center = coord2_property(default = (0.0, 0.0))
    
    def set_stretch_factor(self, value):
        if isinstance(value, coord2):
            self.__stretch_factor__ = value
        else:
            self.__stretch_factor__= coord2(value[0], value[1])
        if self.__stretch_factor__[0] == 0.0 or self.__stretch_factor__[1] == 0.0:
            raise AttributeError("Error: Stretch factor cannot be zero in gds_stretch transform")
    stretch_factor = set_function_property("__stretch_factor__", set_stretch_factor, required = True)
    """ stretch factor (x, y) """

    def apply_to_coord(self, coord):
        """ apply transformation to coordinate """
        return coord2(self.__stretch_factor__[0] * coord[0] + (1- self.__stretch_factor__[0]) * self.stretch_center[0],
                      self.__stretch_factor__[1] * coord[1] + (1- self.__stretch_factor__[1]) * self.stretch_center[1])

    def reverse_on_coord(self, coord):
        """ apply reverse transformation to coordinate """
        return coord2(1.0/self.__stretch_factor__[0] * coord[0] + (1- 1.0/self.__stretch_factor__[0]) * self.stretch_center[0],
                      1.0/self.__stretch_factor__[1] * coord[1] + (1- 1.0/self.__stretch_factor__[1]) * self.stretch_center[1])
    
    def apply_to_array(self, coords):
        """ apply transformation to numpy array"""
        coords  *= array([self.stretch_factor.x, self.stretch_factor.y])
        coords += array([(1- self.__stretch_factor__.x) * self.stretch_center.x, (1- self.__stretch_factor__.y) * self.stretch_center.y])
        return coords


    def reverse_on_array(self, coords):
        """ internal use: applies reverse transformation to a numpy array """
        coords  *= array([1.0/self.stretch_factor.x, 1.0/self.stretch_factor.y])
        coords += array([(1- 1.0/self.__stretch_factor__.x) * self.stretch_center.x, (1- 1.0/self.__stretch_factor__.y) * self.stretch_center.y])
        return coords
    
    def is_identity(self):
        """ returns True if the transformation does nothing """
        return ((self.stretch_factor.x == 1.0) and
                (self.stretch_factor.y == 1.0))

    def is_isometric(self):
        """ returns True if the transformation conserves angles and distances"""
        return ((self.stretch_factor.x == 1.0) and
                (self.stretch_factor.y == 1.0))

    def is_homothetic(self):
        """ returns True if the transformation conserves angles """
        return self.stretch_factor.x == self.stretch_factor.y


def shape_scale(shape, scaling=(1.0, 1.0), scale_center=(0.0, 0.0)):
    """ legacy: apply a magnification to a shape """
    from .magnification import gds_magnification
    if scaling[0] == scaling[1]:
        return gds_magnification(scale_center, scaling[0])(shape)
    else:
        return gds_stretch(scale_center, scaling)(shape)
