import gk_transformable
from gk_property_descriptor import *
import math

# base class (can also be used for 3-D coords, etc.
class gds_coord(gk_transformable.gds_transformable):
    pass

class coord2(gds_coord):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __getitem__(self, index):
        if index == 0: return self.x
        if index == 1: return self.y
        raise IndexError("coord2 type only supports index 0 and 1")
    
    def __setitem__(self, index, value):
        if index == 0: 
            self.x = value
        elif index ==1: 
            self.y = value
        else:
            raise IndexError("coord2 type only supports index 0 and 1")
        return

    def __iter__(self):
        for index in range(2):
            yield self[index]

    def transform(self, transformation):
        C = transformation.apply_to_coord(self)
        self.x = C.x
        self.y = C.y
        return self
    
    def transform_copy(self, transformation):
        return transformation.apply_to_coord(coord2(self.x, self.y))
    
    def move(self, position):
        self.x += position[0] # compatibility with tuples used for quick notation
        self.y += position[1] # compatibility with tuples used for quick notation
        return self
    
    def move_copy(self, position):
        return coord2(self.x + position[0], self.y + position[1])

    def snap_to_grid(grid = None, unit= None):
            if grid == None:
                    grid = get_grid()
            if unit == None:
                    unit = get_unit()
            self.__points__ *= (unit/grid)
            round(self.__points__,0,self__points__)
            self.__points__ *= (grid/unit)
    def __str__(self):
        return "("+str(self.x) + "," + str(self.y) + ")"

    def __eq__(self, other):
        return (self[0] == other[0]) and (self[1] == other[1])
    def __ne__(self, other):
        return (self[0] != other[0]) or (self[1] != other[1])

    def distance(self, other):
        return sqrt((other[0]-self.x)**2 + (other[1]-self.y)**2)

    def angle_deg(self, other=(0.0, 0.0)):
        return RAD2DEG*self.angle_rad(other)

    def angle_rad(self, other=(0.0, 0.0)):
        return atan2(self.y - other[1], self.x - other[0])
    
    def __iadd__(self, other):
        self.x += other[0]
        self.y += other[1]
        
    def __add__(self, other):
        return coord2 (self.x + other[0], self.y + other[1])
    
    def __isub__(self, other):
        self.x -= other[0]
        self.y -= other[1]
        
    def __sub__(self, other):
        return coord2 (self.x - other[0], self.y - other[1])
    
    def __neg__(self):
        return coord2 (-self.x, -self.y)
    
    
    def __imul__(self, other):
        self.x *= other
        self.y *= other
        return self
    
    def __mul__(self, other):
        return coord2(self.x * other, self.y * other)
    def __rmul__(self, other):
        return coord2(self.x * other, self.y * other)
    
    def __repr__(self):
        return "C2(%f, %f)" % (self.x, self.y)
        
        
class processor_coord2(processor_typecast):
    def __init__(self):
        processor_typecast.__init__(self, coord2)
    def process(self, value, obj = None):
        if isinstance(value, tuple):
            return coord2(value[0], value[1])
        else:
            return processor_typecast.process(self, value, obj)

def coord2_property(internal_member_name, restriction = None, preprocess = None, **kwargs):
    R = restrict_type(coord2) & restriction
    P = processor_coord2() + preprocess
    return restricted_property_descriptor(internal_member_name, restriction = R, preprocess = P )
