from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

# All the Courses related methods

# Python
from django.utils import timezone
from datetime import datetime
from datetime import timedelta
import time
from django.db import IntegrityError
import uuid
from django.conf import settings

import geocoder

from matplotlib import path
import xml.etree.ElementTree as et

from xml.etree.ElementTree import Element, SubElement, Comment, tostring
from xml.dom import minidom

def prettify(elem):
    """Return a pretty-printed XML string for the Element.
    """
    rough_string = tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="  ")

import pandas as pd
import numpy as np
from timezonefinder import TimezoneFinder

import rowers.dataprep as dataprep
from rowers.utils import geo_distance

ns = {'opengis': 'http://www.opengis.net/kml/2.2'}

xmlns_uris_dict = {'gx': 'http://www.google.com/kml/ext/2.2',
                   'kml': 'http://www.google.com/kml/ext/2.2',
                   'atom': "http://www.w3.org/2005/Atom",
                   '': "http://www.opengis.net/kml/2.2"}


from rowers.models import (
    Rower, Workout,
    GeoPoint,GeoPolygon, GeoCourse,
    course_length,course_coord_center,course_coord_maxmin,
    polygon_coord_center,PlannedSession,
    polygon_to_path,coordinate_in_path
    )


from rowers.courseutils import coursetime_paths, coursetime_first,time_in_path


def crewnerdcourse(doc):
    courses = []
    for course in doc:
        name = course.findall('.//opengis:name',ns)[0].text
        try:
            description = course.findall('.//opengis:description',ns)[0].text
        except IndexError:
            description = ''

        polygonpms = course.findall('.//opengis:Placemark[opengis:Polygon]',ns)
        polygons = get_polygons(polygonpms)

        courses.append({
            'name':name,
            'description':description,
            'polygons':polygons
            })
        
    return courses

def get_polygons(polygonpms):
    polygons = []
    for pm in polygonpms:
        name = pm.findall('.//opengis:name',ns)[0].text
        coordinates = pm.findall('.//opengis:coordinates',ns)
        if coordinates:
            cc = coordinates[0].text
        else:
            cc = ''

        pointstring = cc.split()

        points = []
        for s in pointstring:
            coordinates = s.split(',')
            points.append({
                'longitude':float(coordinates[0]),
                'latitude':float(coordinates[1]),
                })

        polygons.append({
            'name':name,
            'points':points
            })


    return polygons
    

def coursetokml(course):
    top = Element('kml')
    for prefix, uri in xmlns_uris_dict.items():
        if prefix != '':
            top.attrib['xmlns:' + prefix] = uri
        else:
            top.attrib['xmlns'] = uri
            
    document = SubElement(top,'Document')
    name = SubElement(document, 'name')
    name.text = 'Courses.kml'
    folder = SubElement(document,'Folder')
    foldername = SubElement(folder,'name')
    foldername.text = 'Courses'
    folder2 = SubElement(folder,'Folder')
    coursename = SubElement(folder2,'name')
    coursename.text = course.name
    open = SubElement(folder2,'open')
    open.text = '1'
    
    polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")

    polygonsxml = []
    
    for polygon in polygons:
        placemark = SubElement(folder2,'Placemark')
        polygonname = SubElement(placemark,'name')
        polygonname.text = polygon.name
        p = SubElement(placemark,'Polygon')
        tessellate = SubElement(p,'tessellate')
        tessellate.text = '1'
        boundary = SubElement(p,'outerBoundaryIs')
        ring = SubElement(boundary,'LinearRing')
        coordinates = SubElement(ring,'coordinates')
        coordinates.text = ''
        points = GeoPoint.objects.filter(polygon=polygon).order_by("order_in_poly")
        for point in points:
            coordinates.text += '{lon},{lat},0 '.format(
                lat = point.latitude,
                lon = point.longitude,
                )
        coordinates.text += '{lon},{lat},0'.format(
            lat = points[0].latitude,
            lon = points[0].longitude,
            )

    return prettify(top)

def kmltocourse(f):
    doc = et.parse(f)
    courses = doc.findall('.//opengis:Folder[opengis:Placemark]',ns)

    if not courses:
        courses = doc.findall('.//opengis:Placemark',ns)

    if courses:
        return crewnerdcourse(courses)
    
    polygonpms = doc.findall('.//opengis:Placemark[opengis:Polygon]',ns)

    return get_polygons(polygonpms)




def createcourse(
        manager,name,polygons,notes=''):

    c = GeoCourse(manager=manager,name=name,notes=notes)
    c.save()

    i = 0
    for p in polygons:
        pp = GeoPolygon(course=c,order_in_course=i,name=p['name'])
        pp.save()
        j = 0
        for point in p['points']:
            if i==0 and j==0:
                latitude = point['latitude']
                longitude = point['longitude']
                g = geocoder.google([latitude,longitude],method='reverse')
                if g.ok:
                    address = g.raw['address_components']
                    country = 'unknown'
                    for a in address:
                        if 'country' in a['types']:
                            country = a['long_name']
                else:
                    country = 'unknown'
                c.country = country
                c.save()
            obj = GeoPoint(
                latitude = point['latitude'],
                longitude = point['longitude'],
                polygon = pp,
                order_in_poly = j
                )
            obj.save()
            j += 1
        i += 1

    c.distance = int(course_length(c))
    c.save()

    return c


def get_time_course(ws,course):
    coursetimeseconds = 0.0
    coursecompleted = False

    w = ws[0]
    columns = ['time',' latitude',' longitude','cum_dist']
    rowdata = dataprep.getsmallrowdata_db(
        columns,
        ids = [w.id],
        doclean=False,
        workstrokesonly=False
    )

    rowdata.rename(columns = {
        ' latitude':'latitude',
        ' longitude':'longitude',
        }, inplace=True)


    rowdata['time'] = rowdata['time']/1000.

    rowdata.fillna(method='backfill',inplace=True)

    rowdata['time'] = rowdata['time']-rowdata.ix[0,'time']
    # we may want to expand the time (interpolate)
    rowdata['dt'] = rowdata['time'].apply(
        lambda x: timedelta(seconds=x)
        )
    rowdata = rowdata.resample('100ms',on='dt').mean()
    rowdata = rowdata.interpolate()

    # create path
    polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
    paths = []
    for polygon in polygons:
        path = polygon_to_path(polygon)
        paths.append(path)


        
        
    (
        coursetimeseconds,
        coursemeters,
        coursecompleted,
        
    ) = coursetime_paths(rowdata,paths)
    (
        coursetimefirst,
        coursemetersfirst,
        firstcompleted
    ) = coursetime_first(
        rowdata,paths)

    coursetimeseconds = coursetimeseconds-coursetimefirst
    coursemeters = coursemeters-coursemetersfirst
    
    return coursetimeseconds,coursemeters,coursecompleted

def replacecourse(course1,course2):
    ps = PlannedSession.objects.filter(course=course1)
    for p in ps:
        p.course = course2
        p.save()

    course1.delete()

    return 1
