import os
import io
import csv
import traceback
from datetime import datetime
from flask import current_app
from webinterface import db
from webinterface.models.gtfs_static import Agencia, Servicio, Paradero, Parada, Ruta, Linea

def parse_time(strinput):
	try:
		h, m, s = strinput.split(":")
		h = int(h)
		d = 0
		while h > 23:
			d += 1
			h -= 24

		return datetime.strptime("{}:{}:{}".format(h,m,s), '%H:%M:%S').time(), d
	except:
		current_app.logger.debug('Traceback {}'.format(traceback.format_exc()))
		current_app.logger.warning("Hora incorrecta => {}".format(strinput))
		return datetime.strptime("01:01:01", '%H:%M:%S').time(), 0


def parse_paraderoid(strinput):
	primerodenero2022 = 44562

	if strinput.find("-") > 0:
		current_app.logger.error("Error en el dato de la parada: {}".format(strinput))
		try:
			whatdate= datetime.strptime('{}-{}'.format(strinput, 2022), '%d-%b-%Y').date()
			idparadero = primerodenero2022 + whatdate.timetuple().tm_yday
			current_app.logger.warning("Calculado el Identificador en base al año 2022 => {}".format(idparadero))
			return idparadero
		except:
			return 0
	else:
		return int(strinput)


def completa_dataset():
	iparaderos = 0
	for paradero in Paradero.query.all():
		iparaderos += 1
		cparadero = 0
		lparadas = 0
		sparadas = 0
		dparadas = 0
		lineas = []
		lparada = []

		for parada in Parada.query.filter(Parada.paraderoid==paradero.id).all():
			cparadero += 1
			if cparadero % 1000 == 0:
				current_app.logger.debug("Paradero {}, {} detenciones. {} lineas".format(iparaderos, cparadero, len(lineas)))

			elemento = (parada.servicio.lineaid, parada.servicio.direccionid)

			if parada.servicio.dotw == 'S':
				sparadas += 1
			elif parada.servicio.dotw == 'D':
				dparadas += 1
			else:
				lparadas += 1

			if elemento in lineas:
				continue

			lineas.append(elemento)
			if parada.servicio.direccionid:
				lparada.append("{} ({} ida)".format(parada.servicio.linea.codigo, parada.secuencia))
			else:
				lparada.append("{} ({} regreso)".format(parada.servicio.linea.codigo, parada.secuencia))

		lparada.sort()
		paradero.recorridos = " - ".join(lparada)
		paradero.paradas = 5*lparadas+sparadas+dparadas
		paradero.resumen = "{} paradas a la semana, {} lineas".format(paradero.paradas, len(lineas))
		paradero.paradasl = lparadas
		paradero.paradass = sparadas
		paradero.paradasd = dparadas
		paradero.lineas = len(lineas)
		current_app.logger.info("Paradero {}, {} detenciones a la semana en {} lineas".format(iparaderos, paradero.paradas, len(lineas)))
		if iparaderos % 10 == 0:
			db.session.commit()

	db.session.commit()

def agrega_paraderos():
	from bs4 import BeautifulSoup
	from zipfile import ZipFile

#	print(os.getcwd())

	current_app.logger.info("Archivo de paraderos, kmz")
	with ZipFile('webinterface/models/datos/PARADEROS_FORMALES.kmz', 'r') as kmz:
		kml = kmz.open(kmz.filelist[0].filename, 'r').read()

	soup = BeautifulSoup(kml, 'xml')
	existen = 0
	nuevo = 0


	for paradero in soup.find_all("kml:Placemark"):
		if (existen+nuevo) % 1000 == 0:
			current_app.logger.debug("Leidos {} paraderos existentes y {} nuevos".format(existen, nuevo))


		lat = int(paradero.find("kml:SimpleData", {"name": "LATITUDE"}).text)/1000000
		lng = int(paradero.find("kml:SimpleData", {"name": "LONGITUDE"}).text)/1000000

		codigo = paradero.find("kml:SimpleData", {"name": "CODIGO_INT"}).text
		comuna = paradero.find("kml:SimpleData", {"name": "COMUNA"}).text
		recorridos = paradero.find("kml:SimpleData", {"name": "RECORRIDOS"}).text
		tamano = paradero.find("kml:SimpleData", {"name": "SUPERFICIE"}).text
		capacidad = paradero.find("kml:SimpleData", {"name": "CAPACIDAD"}).text
		materialpiso = paradero.find("kml:SimpleData", {"name": "RADIER_MAT"}).text
		materialpared = paradero.find("kml:SimpleData", {"name": "PARED_POS2"}).text
		materialtecho = paradero.find("kml:SimpleData", {"name": "TECHUMBRE2"}).text


		match = None

		for radio in [0.00000001, 0.00000002, 0.00000003, 0.00000004, 0.00000005, 0.000000075, 0.0000001, 0.0000002]:
			match = Paradero.query.filter(((Paradero.latitud-lat)*(Paradero.latitud-lat)+(Paradero.longitud-lng)*(Paradero.longitud-lng)) < radio).first()

			if match is not None:
				break

		if match is None:
			nuevo += 1
			nombre = "{} cerca {}".format(paradero.find("kml:SimpleData", {"name": "NOMBRE_DE_"}).text, paradero.find("kml:SimpleData", {"name": "CALLE_CERC"}).text)
			match = Paradero(id=codigo, codigo=codigo, nombre=nombre, latitud=lat, longitud=lng)
			db.session.add(match)
			db.session.commit()
		else:
			existen += 1

		match.codigo 		= codigo
		match.comuna 		= comuna
		match.recorridos2	= recorridos
		match.tamano 		= tamano
		match.capacidad		= capacidad
		match.techo			= materialtecho
		match.pared			= materialpared
		match.piso 			= materialpiso
		db.session.commit()

	current_app.logger.info("Cargados {} paraderos existentes y {} nuevos".format(existen, nuevo))





def load_dataset():
	from bs4 import BeautifulSoup
	from zipfile import ZipFile

	with ZipFile('GC.zip', 'r') as dataset:
		current_app.logger.debug("Abriendo archivo GC.zip")

		#Carga las agencias:
		with io.TextIOWrapper(dataset.open('agency.txt'), encoding='utf8') as agencias_csv:
			current_app.logger.debug("Leyendo agency.txt")
			agencias = csv.reader(agencias_csv, delimiter=',')
			elementos = 0

			for item in agencias:
				if elementos > 0:
					agencia = Agencia.query.filter(Agencia.id==item[0]).one_or_none()

					if agencia is None:
						agencia = Agencia(id=item[0], nombre=item[1], url=item[2], fono=item[5])
						db.session.add(agencia)
					else:
						agencia.nombre 	= item[1]
						agencia.url 	= item[2]
						agencia.fono 	= item[3]

				elementos += 1

			db.session.commit()
			current_app.logger.info("Se cargaron {} agencias".format(elementos))


		#Carga las agencias
		with io.TextIOWrapper(dataset.open('stops.txt'), encoding='utf8') as paraderos_csv:
			current_app.logger.debug("Leyendo stops.txt")
			paraderos = csv.reader(paraderos_csv, delimiter=',')
			elementos = 0

			for item in paraderos:
				if elementos > 0:

					idparadero = item[0]

					paradero = Paradero.query.filter(Paradero.id==idparadero).one_or_none()
					if len(item[1]) > 0:
						codigo = item[1]
					else:
						codigo = None

					if paradero is None:

						paradero = Paradero(id=idparadero, codigo=codigo, nombre=item[2], latitud=item[4], longitud=item[5])
						db.session.add(paradero)
					else:
						paradero.codigo 	= codigo
						paradero.nombre 	= item[2]
						paradero.latitud 	= item[4]
						paradero.longitud	= item[5]

				elementos += 1
				if elementos % 1000 == 0:
					current_app.logger.info("Se han cargado {} elementos".format(elementos))

			db.session.commit()
			current_app.logger.info("Se cargaron {} paradas".format(elementos))


		with io.TextIOWrapper(dataset.open('routes.txt'), encoding='utf8') as lineas_csv:
			current_app.logger.debug("Leyendo routes.txt")
			lineas = csv.reader(lineas_csv, delimiter=',')
			elementos = 0

			for item in lineas:
				if elementos > 0:
					variante = Linea.query.filter(Linea.id==item[0]).one_or_none()

					if variante is None:
						variante = Linea(id=item[0], agenciaid=item[1], codigo=item[2], nombre=item[3], color=item[7])
						db.session.add(variante)
					else:
						variante.agenciaid = item[1]
						variante.codigo    = item[2]
						variante.nombre	   = item[3]
						variante.color	   = item[7]

				elementos += 1
				if elementos % 1000 == 0:
					current_app.logger.info("Se han cargado {} elementos".format(elementos))

			db.session.commit()
			current_app.logger.info("Se cargaron {} Linea".format(elementos))


		with io.TextIOWrapper(dataset.open('trips.txt'), encoding='utf8') as rutas_csv:
			current_app.logger.debug("Leyendo Servicios.txt")
			rutas = csv.reader(rutas_csv, delimiter=',')
			elementos = 0

			for item in rutas:
				if elementos > 0:

					itinerario = Servicio.query.filter(Servicio.id==item[2], Servicio.lineaid==item[0]).one_or_none()

					if itinerario is None:
						itinerario = Servicio(id=item[2], lineaid=item[0], direccionid=item[5], destino=item[3],  dotw=item[1], rutaid=item[7])
						db.session.add(itinerario)
					else:
						itinerario.destino 		= item[3]
						itinerario.direccionid 	= item[5]
						itinerario.rutaid 		= item[7]
						itinerario.dotw 		= item[1]

				elementos += 1
				if elementos % 1000 == 0:
					db.session.commit()
					current_app.logger.info("Se han cargado {} elementos".format(elementos))

			db.session.commit()
			current_app.logger.info("Se cargaron {} servicios".format(elementos))

		with io.TextIOWrapper(dataset.open('shapes.txt'), encoding='utf8') as shapes_csv:
			current_app.logger.debug("Leyendo rutas.txt")
			shapes = csv.reader(shapes_csv, delimiter=',')
			elementos = 0

			for item in shapes:
				if elementos > 0:
					shape = Ruta.query.filter(Ruta.rutaid==item[0], Ruta.secuencia==item[3]).one_or_none()

					if shape is None:
						shape = Ruta(rutaid=item[0], secuencia=item[3], latitud=item[1], longitud=item[2])
						db.session.add(shape)
					else:
						shape.latitud = item[1]
						shape.longitud = item[2]

				elementos += 1
				if elementos % 1000 == 0:
					db.session.commit()
					current_app.logger.info("Se han cargado {} elementos".format(elementos))


			db.session.commit()
			current_app.logger.info("Se cargaron {} puntos".format(elementos))

		with io.TextIOWrapper(dataset.open('stop_times.txt'), encoding='utf8') as paradas_csv:
			current_app.logger.debug("Leyendo paradas.txt")
			paradas = csv.reader(paradas_csv, delimiter=',')
			elementos = 0

			for item in paradas:
				if elementos > 0:
					idparadero = item[3]

					parada = Parada.query.filter(Parada.servicioid==item[0], Parada.paraderoid==idparadero, Parada.secuencia==item[4]).one_or_none()
					llegada, _ = parse_time(item[1])
					salida, otrodia = parse_time(item[2])

					if parada is None:
						parada = Parada(servicioid=item[0], paraderoid=idparadero, secuencia=item[4], tipo=item[8], llegada=llegada, salida=salida, otrodia=otrodia)
						db.session.add(parada)
					else:
						parada.llegada = llegada
						parada.salida = salida
						parada.otrodia = otrodia
						parada.tipo = item[8]

				elementos += 1
				if elementos % 1000 == 0:
					db.session.commit()
					current_app.logger.info("Se han cargado {} elementos".format(elementos))

			db.session.commit()
			current_app.logger.info("Se cargaron {} paradas".format(elementos))
