import pygame
import math

class Compass():
    def __init__(self, font_size, size):
        pygame.font.init()
        self.textColor = pygame.Color("white")
        self.backgroundColor = pygame.Color("White")
        self.needleColor = pygame.Color("black")

        self.font = pygame.font.Font(pygame.font.get_default_font(), font_size)

        self.surface = pygame.Surface(size, pygame.SRCALPHA)
        self.size = size
        
        self.x = 0
        self.y = 0

        self.backgroundSurface = None


    def setX(self, x):
        self.x = x
    def getX(self):
        return self.x

    def setY(self, y):
        self.y = y
    def getY(self):
        return self.y

    def get(self):
        return self.surface

    def setTextColor(self, color):
        try:
            self.textColor = pygame.Color(color)
        except:
            self.textColor = pygame.Color("black")

    def setBackgroundColor(self, color):
        try:
            self.backgroundColor = pygame.Color(color)
        except:
            self.backgroundColor = pygame.Color("white")

    def setNeedleColor(self, color):
        try:
            self.needleColor = pygame.Color(color)
        except:
            self.needleColor = pygame.Color("black")

    def update(self, value):
        raise NotImplementedError()


class MiddleNeedle(Compass):
    def update(self, value):
        radius = min(self.size[0]//2, self.size[1]//2)
        pygame.draw.circle( self.surface, self.backgroundColor, (self.size[0]//2, self.size[1]//2), radius)

 
        arrow = pygame.Surface( ((self.size[0]//100*60)//2, self.size[1]//100*60), pygame.SRCALPHA )

        polygon_list = [
            ( arrow.get_width()//2, 0 ), #Middle top
            ( 0, arrow.get_height() ), #bottom left
            ( arrow.get_width()//2, (arrow.get_height()-arrow.get_height()//100*30) ), #middle pos
            ( arrow.get_width(), arrow.get_height() ), #bottom right
            ]

        pygame.draw.polygon(arrow, self.needleColor, polygon_list)
        arrow = pygame.transform.rotate( arrow, value )
        self.surface.blit( arrow, ( (self.size[0]//2)-(arrow.get_width()//2), (self.size[1]//2)-(arrow.get_height()//2)))

        text = self.font.render("N", True, self.textColor)
        self.surface.blit( text, ( (self.size[0]//2) - (text.get_width()//2), int(self.size[1]/100*10) - text.get_height()//2 ) )

        text = self.font.render("W", True, self.textColor)
        self.surface.blit( text, ( int(self.size[0]/100*10) - (text.get_width()//2), (self.size[1]//2) - (text.get_height()//2) ) )

        text = self.font.render("O", True, self.textColor)
        self.surface.blit( text, ( int(self.size[0]/100*90)- (text.get_width()//2), (self.size[1]//2) - (text.get_height()//2) ) )
        
        text = self.font.render("S", True, self.textColor)
        self.surface.blit( text, ( (self.size[0]//2) - (text.get_width()//2), int(self.size[1]/100*90) - text.get_height()//2 ) )


class OuterNeedle(Compass):
    def update(self, value):
        radius = min(self.size[0]//2, self.size[1]//2)
        pygame.draw.circle( self.surface, self.backgroundColor, (self.size[0]//2, self.size[1]//2), radius)


        if self.backgroundSurface:
            self.surface.blit( self.backgroundSurface, (0,0) )

        if self.lineLength is None:
            self.lineLength = 5

        # 0 is down -> +90
        # alpha = 2 * arcsin (s / 2r); s is bottom line
        alpha = 2 * math.asin( self.lineLength / (2*radius) )
        value = math.radians(value) + math.pi/2 #put 0 to bottom
        bottom_left =   self.getPos(value +alpha/2, radius)
        bottom_left = ( int(bottom_left[0] + radius), bottom_left[1]+radius) #offset to screen middle
        bottom_right =  self.getPos(value -alpha/2, radius)
        bottom_right = ( int(bottom_right[0] + radius), bottom_right[1]+radius)
        height_of_segment = self.lineLength/2 * math.tan( alpha / 4 )
        height_of_triangle = math.sqrt(3) /2 * self.lineLength
        top = self.getPos(value, radius-height_of_segment-height_of_triangle)
        top = ( int(top[0] + radius), top[1]+radius )
        points = [ bottom_left, top, bottom_right ]

        pygame.draw.lines( self.surface, self.needleColor, False, points,3)

        text = self.font.render("N", True, self.textColor)
        self.surface.blit( text, ( (self.size[0]//2) - (text.get_width()//2), int(self.size[1]/100*10) - text.get_height()//2 ) )

        text = self.font.render("W", True, self.textColor)
        self.surface.blit( text, ( int(self.size[0]/100*10) - (text.get_width()//2), (self.size[1]//2) - (text.get_height()//2) ) )

        text = self.font.render("O", True, self.textColor)
        self.surface.blit( text, ( int(self.size[0]/100*90)- (text.get_width()//2), (self.size[1]//2) - (text.get_height()//2) ) )
        
        text = self.font.render("S", True, self.textColor)
        self.surface.blit( text, ( (self.size[0]//2) - (text.get_width()//2), int(self.size[1]/100*90) - text.get_height()//2 ) )

    def getPos(self, alpha, radius):
        return ( int( radius * math.cos(alpha) ), int( radius * math.sin(alpha) ) )
    
    def setLineLength(self, length):
        self.lineLength = length

    def setBackgroundSurface(self, surface):
        self.backgroundSurface = surface

