from .. import constants
from .. import settings
from .fonts import TEXT_FONT_DEFAULT, TEXT_FONTS
from .font import gds_font, font_property
from ..geometry.shape import gds_shape
from ..geometry import size_info

from .elements import gds_layer_element, gds_compound_element
from ..properties.restrictions import __property_restriction__
from ..properties.predefined import string_property, length_property, int_property, RESTRICT_NONNEGATIVE
from ..properties.descriptor import restricted_property
from ..geometry.coord import coord2_property
import string

__all__ = ["gds_polygon_text_element",
           "gds_label_element",
           "el_text",
           "el_label",
           "el_polygon_text",
           "alignment_property",
           "RESTRICT_ALIGNMENT"]


class restrict_alignment(__property_restriction__):
    """ restrict to a 2-tuple for text alignment """
    def validate(self, value, obj = None):
        if len(value) == 2:
            if not value[0] in constants.TEXT_ALIGNS_HORIZONTAL: return False
            if not value[1] in constants.TEXT_ALIGNS_VERTICAL: return False
            return True
        return False

    def __repr__(self):
        return  "Alignment restriction" 

RESTRICT_ALIGNMENT = restrict_alignment()

def alignment_property(internal_member_name= None, restriction = None,  **kwargs):
    R = RESTRICT_ALIGNMENT & restriction
    return restricted_property(internal_member_name, restriction = R, **kwargs)

#----------------------------------------------------------------------------
# Text
#----------------------------------------------------------------------------
class gds_text_element(gds_layer_element):
    text = string_property(required = True)
    coordinate = coord2_property(default = (0.0, 0.0))
    alignment = alignment_property(default = (constants.TEXT_ALIGN_CENTER, constants.TEXT_ALIGN_TOP) )
    height = length_property(default = 20.0)
    font = font_property(default = TEXT_FONT_DEFAULT)
    def __init__(self, layer,  text, coordinate = (0.0,0.0), alignment = (constants.TEXT_ALIGN_CENTER, constants.TEXT_ALIGN_TOP) , font = TEXT_FONT_DEFAULT, height = 20.0, transformation = None, **kwargs):
        super(gds_text_element, self).__init__(layer = layer, 
                                               text = text, 
                                               coordinate = coordinate, 
                                               alignment = alignment, 
                                               font = font, 
                                               height = height, 
                                               transformation = transformation, 
                                               **kwargs)
    def get_h_alignment(self):
        return self.alignment[0]
    h_alignment = property(get_h_alignment)

    def get_v_alignment(self):
        return self.alignment[1]
    v_alignment = property(get_v_alignment)

    def is_empty(self):
        return (len(string.strip(self.text)) == 0) or (self.height == 0)


#----------------------------------------------------------------------------
# Polygon Text
#----------------------------------------------------------------------------

class gds_polygon_text_element(gds_compound_element, gds_text_element):
    #def __init__(self, layer,  text, coordinate = (0.0,0.0), alignment = (constants.TEXT_ALIGN_CENTER, constants.TEXT_ALIGN_TOP) , font = TEXT_FONT_DEFAULT, height = 20.0, transformation = None):
            #gds_text_element.__init__(self,layer,  text, coordinate, alignment, font, height, transformation)
            #gds_compound_element.__init__(self, [], transformation)

    def __calc__(self):
        # TO DO: include full transformation!!!
        #angle = self.transformation.rotation

        #if isinstance(self.font, int):
                #if self.font < 0 or self.font >= len(TEXT_FONTS):
                        #print >> sys.stderr, "Warning: Font " + str(font) + " is not available."
                        #font = 0
                #F = TEXT_FONTS[self.font]
        #elif isinstance(self.font, gds_font):
                #F = self.font

        F = self.font
        text = self.text.upper()

        #determine start position
        letter_height = self.height
        letter_spacing = letter_height * F.spacing
        line_width =  letter_height * F.line_width
        letter_width = letter_height * (F.letter_width() + F.spacing)
        text_width = letter_width * len(text) - letter_spacing

        #ca = cos(angle*DEG2RAD)
        #sa = sin(angle*DEG2RAD)

        if self.h_alignment == constants.TEXT_ALIGN_RIGHT:
            x0 = - text_width
        elif self.h_alignment == constants.TEXT_ALIGN_CENTER:
            x0 = - text_width/2.0
        else:
            x0 = 0.0

        if self.v_alignment == constants.TEXT_ALIGN_BOTTOM:
            y0 = 0.0
        elif self.v_alignment == constants.TEXT_ALIGN_MIDDLE:
            y0 = - letter_height/2.0
        else:
            y0 = -letter_height

        #xpos = x0 * ca - y0 * sa
        #ypos = x0 * sa + y0 * ca
        xpos = x0
        ypos = y0


        xpos += self.coordinate[0]
        ypos += self.coordinate[1]
        for c in text:
            self += F.elements_character(self.layer, c, letter_height, (xpos, ypos), angle = 0.0)
            xpos += letter_width #* ca
            #ypos += letter_width * sa

    def __copy__(self):
        return gds_polygon_text_element(self.layer, self.text, self.coordinate, (self.h_alignment, self.v_alignment), self.font, self.height, self.transformation)

    def __deepcopy__(self, memo):
        return gds_polygon_text_element(self.layer, self.text, self.coordinate, (self.h_alignment, self.v_alignment), copy.deepcopy(self.font), self.height, copy.deepcopy(self.transformation))


def el_polygon_text (layer,  text, coordinate = (0.0,0.0), alignment = (constants.TEXT_ALIGN_CENTER, constants.TEXT_ALIGN_TOP) , font = TEXT_FONT_DEFAULT, height = 20.0, transformation = None):
    return gds_polygon_text_element(layer = layer,  
                                    text = text, 
                                    coordinate = coordinate, 
                                    alignment = alignment, 
                                    font = font, 
                                    height = height, 
                                    transformation = transformation)
#----------------------------------------------------------------------------
# Label text
#----------------------------------------------------------------------------
class gds_label_element(gds_text_element):
    #def __init__(self,layer,  text, coordinate = (0.0,0.0), alignment = (constants.TEXT_ALIGN_CENTER, constants.TEXT_ALIGN_TOP) , font = TEXT_FONT_DEFAULT, height = 20.0, transformation = None):
            #gds_text_element.__init__(self, layer, text, coordinate, alignment, font, height, transformation)

    font = int_property(restriction = RESTRICT_NONNEGATIVE, required= True)
            
    def size_info(self):
        text_width = len(self.text) * self.height
        if self.h_alignment == constants.TEXT_ALIGN_RIGHT:
            L = self.coordinate[0] - text_width
        elif self.h_alignment == constants.TEXT_ALIGN_CENTER:
            L = self.coordinate[0] - text_width/2.0
        else:
            L = self.coordinate[0]
        R = L + text_width

        if self.v_alignment == constants.TEXT_ALIGN_BOTTOM:
            B = self.coordinate[1]
        elif self.v_alignment == constants.TEXT_ALIGN_MIDDLE:
            B = self.coordinate[1]- self.height/2.0
        else:
            B = self.coordinate[1] - self.height
        T = B + self.height
        return size_info.size_info_from_numpyarray((gds_shape([(L,B), (L,T), (R, B), (R,T)], True).transform(self.transformation)).__points__)

    def __copy__(self):
        return gds_label_element(self.layer, self.text, self.coordinate, (self.h_alignment, self.v_alignment), self.font, self.height, self.transformation)

    def __deepcopy__(self, memo):
        return gds_label_element(self.layer, self.text, self.coordinate, (self.h_alignment, self.v_alignment), copy.deepcopy(self.font), self.height, copy.deepcopy(self.transformation))

    def flat_copy(self, level = -1):
        return self.__copy__()


def el_label (layer,  text, coordinate = (0.0,0.0), alignment = (constants.TEXT_ALIGN_CENTER, constants.TEXT_ALIGN_TOP) , font = TEXT_FONT_DEFAULT, height = 20.0, transformation = None):
    return gds_label_element(layer,  text, coordinate, alignment, font, height, transformation)


#----------------------------------------------------------------------------
# EL-text function 
#----------------------------------------------------------------------------
def el_text (layer,  text, coordinate = (0.0,0.0), alignment = (constants.TEXT_ALIGN_CENTER, constants.TEXT_ALIGN_TOP) , font = TEXT_FONT_DEFAULT, height = 20.0, transformation = None):
    S = settings.get_text_style() 
    if  S == constants.TEXT_STYLE_LABELS:
        ret = el_label (layer,  text, coordinate, alignment, font, height, transformation)
    elif S == constants.TEXT_STYLE_POLYGONS:
        ret = el_polygon_text (layer,  text, coordinate, alignment, font, height, transformation)
    return ret
