from math import radians, sin, cos, asin, sqrt
from sqlalchemy.types import TypeDecorator, String


class Location(TypeDecorator):
    impl = String
    cache_ok = True

    def __init__(self, latitude=None, longitude=None):
        self.latitude = latitude
        self.longitude = longitude

    def process_bind_param(self, value, dialect):
        if value:
            return str(value)

    def process_result_value(self, value, dialect):
        if value:
            return Location(* map(float, value.split(",")))

    def load_dialect_impl(self, dialect):
        # Provide the implementation for the specified dialect
        return dialect.type_descriptor(String)

    def distance(self, other):
        R = 6371

        d_lat = radians(self.latitude - other.latitude) 
        d_lon = radians(self.longitude - other.longitude)

        a = sin(d_lat/2) * sin(d_lat/2) +\
            sin(d_lon/2) * sin(d_lon/2) * cos(radians(self.latitude)) * cos(radians(other.latitude))
        
        c = 2 * asin(sqrt(a))
        d = R * c

        return d
    
    def get_cooldown(self, other):
        distance = self.distance(other)

        if distance <= 2:
            return 1
        elif distance <= 5:
            return 2
        elif distance <= 7:
            return 5
        elif distance <= 10:
            return 7
        elif distance <= 12:
            return 8
        elif distance <= 18:
            return 10
        elif distance <= 26:
            return 15
        elif distance <= 42:
            return 19
        elif distance <= 65:
            return 22
        elif distance <= 81:
            return 25
        elif distance <= 100:
            return 35
        elif distance <= 220:
            return 40
        elif distance <= 250:
            return 45
        elif distance <= 350:
            return 51
        elif distance <= 375:
            return 54
        elif distance <= 460:
            return 62
        elif distance <= 500:
            return 65
        elif distance <= 565:
            return 69
        elif distance <= 700:
            return 78
        elif distance <= 800:
            return 84
        elif distance <= 900:
            return 92
        elif distance <= 1000:
            return 99
        elif distance <= 1100:
            return 107
        elif distance <= 1200:
            return 114
        elif distance <= 1300:
            return 117
        else:
            return 120

    def __str__(self):
        return str(self.latitude) + "," + str(self.longitude)

    def __repr__(self):
        return str(self.latitude) + "," + str(self.longitude)