import math
import numpy as np
import pandas as pd
import colorsys

lbstoN = 4.44822

def absolute(request):
    urls = {
        'ABSOLUTE_ROOT': request.build_absolute_uri('/')[:-1].strip("/"),
        'ABSOLUTE_ROOT_URL': request.build_absolute_uri('/').strip("/"),
        'PATH':request.build_absolute_uri(),
    }

    return urls

def trcolors(r1,g1,b1,r2,g2,b2):
    r1 = r1/255.
    r2 = r2/255.
    g1 = g1/255.
    g2 = g2/255.
    b2 = b2/255.
    b1 = b1/255.
    h1,s1,v1 = colorsys.rgb_to_hsv(r1,g1,b1)
    h2,s2,v2 = colorsys.rgb_to_hsv(r2,g2,b2)

    
    return 360*h1,360*(h2-h1),s1,(s2-s1),v1,(v2-v1)

palettes = {
  'monochrome_blue':(207,-4,0.06,0.89,1.0,-0.38),
  'gold_sunset':(47,-31,.26,-0.12,0.94,-0.5),
  'blue_red':(207,-200,.85,0,.74,-.24),
  'blue_green':(207,-120,.85,0,.75,.25),
  'cyan_green':(192,-50,.08,.65,.98,-.34),
  'cyan_purple':trcolors(237,248,251,136,65,157),
  'green_blue':trcolors(240,249,232,8,104,172),
  'orange_red':trcolors(254,240,217,179,0,0),
  'cyan_blue':trcolors(241,238,246,4,90,141),
  'cyan_green':trcolors(246,239,247,1,108,89),
  'cyan_magenta':trcolors(241,238,246,152,0,67),
  'beige_magenta':trcolors(254,235,226,122,1,119),
  'yellow_green':trcolors(255,255,204,0,104,55),
  'yellow_blue':trcolors(255,255,205,37,52,148),
  'autumn':trcolors(255,255,212,153,52,4),
  'yellow_red':trcolors(255,255,178,189,0,39)
}


def range_to_color_hex(groupcols,palette='monochrome_blue'):

  try:
    plt = palettes[palette]
  except KeyErro:
    plt = palettes['monochrome_blue']
    
  rgb = [colorsys.hsv_to_rgb((plt[0]+plt[1]*x)/360.,
                             plt[2]+plt[3]*x,
                             plt[4]+plt[5]*x) for x in groupcols]

  RGB = [(int(255.*r),int(255.*g),int(255.*b)) for (r, g, b) in rgb]
  colors = ["#%02x%02x%02x" % (r, g, b) for (r, g, b) in RGB]
  
  return colors

def str2bool(v):
  return v.lower() in ("yes", "true", "t", "1")

def uniqify(seq, idfun=None): 
   # order preserving
   if idfun is None:
       def idfun(x): return x
   seen = {}
   result = []
   for item in seq:
       marker = idfun(item)
       # in old Python versions:
       # if seen.has_key(marker)
       # but in new ones:
       if marker in seen: continue
       seen[marker] = 1
       result.append(item)
   return result

def serialize_list(value,token=','):
    assert(isinstance(value, list) or isinstance(value, tuple) or isinstance(value,np.ndarray))
    return token.join([unicode(s) for s in value])

def deserialize_list(value,token=','):
    if isinstance(value, list):
        return value
    elif isinstance(value, np.ndarray):
        return value
    return value.split(token)

def geo_distance(lat1,lon1,lat2,lon2):
    """ Approximate distance and bearing between two points
    defined by lat1,lon1 and lat2,lon2
    This is a slight underestimate but is close enough for our purposes,
    We're never moving more than 10 meters between trackpoints

    Bearing calculation fails if one of the points is a pole. 
    (Hey, from the North pole you can walk South, East, North and end up 
    on the same spot!)
    
    """
    
    # radius of our earth in km --> should be moved to settings if
    # rowing takes off on other planets
    R = 6373.0

    # pi
    pi = math.pi

    lat1 = math.radians(lat1)
    lat2 = math.radians(lat2)
    lon1 = math.radians(lon1)
    lon2 = math.radians(lon2)

    dlon = lon2 - lon1
    dlat = lat2 - lat1

    a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))

    distance = R * c

    tc1 = atan2(sin(lon2-lon1)*cos(lat2),
		cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1))

    tc1 = tc1 % (2*pi)

    bearing = math.degrees(tc1)

    return [distance,bearing]


def isbreakthrough(delta,cpvalues,p0,p1,p2,p3,ratio):
  pwr = abs(p0)/(1+(delta/abs(p2)))
  pwr += abs(p1)/(1+(delta/abs(p3)))

  pwr *= ratio

  delta = delta.values
  cpvalues = cpvalues.values

  res = np.sum(cpvalues>pwr)

  btdf = pd.DataFrame(
    {
      'delta':delta[cpvalues>pwr],
      'cpvalues':cpvalues[cpvalues>pwr],
      'pwr':pwr[cpvalues>pwr],
    }
  )


  btdf.sort_values('delta',axis=0,inplace=True)

  
  return res>1,btdf
