#!/usr/bin/env python
# -*- coding: utf-8 -*-

from models	import *

from django.db import IntegrityError
from django.core.exceptions import ObjectDoesNotExist

from datetime import datetime, timedelta, tzinfo, date
import time

from calendar import monthrange

from string import Formatter

from ponto.models import Comentario


###################################### 
#	    FUNÇÕES GERAIS
###################################### 


def puxar_informacoes_henry(lista_funcionarios):
	
	# Arquivo com as saídas do Henry;
	arquivo = open("/mnt/henry/MeusArquivosSaida/Registros.txt.txt", 'r')

	# Ler todas as linhas do arquivo e fecha-o em seguida;
	conteudo_arquivo = arquivo.readlines()
	arquivo.close()
	
	formato = "%d/%m/%Y %H:%M:%S"
		
	for linha in conteudo_arquivo:
		
		# Matrícula com oito dígitos.
		matricula = linha.split(" ")[-1].rstrip()[12:20]
		
		# Compara matrícula do funcionário com a do arquivo.
		for funcionario in lista_funcionarios:
			
			if funcionario.matricula in matricula:
								
				# Data no formato 'DD/MM/AAAA'.
				data = linha.split(" ")[-3]
				
				# Hora no formato '00:00:00'.
				hora = linha.split(" ")[-2]
				
				data_hora = datetime.strptime("%s %s" %(data, hora), formato)
				
				batida_ponto = BatidaPonto()
		
				batida_ponto.funcionario = funcionario
				batida_ponto.momento_batidaponto = data_hora
				
				try:
					batida_ponto.save()
				except IntegrityError:
					pass
										

# Sincroniza informações do Henry com o banco de dados

def sincronizar():
	
	lista_funcionarios = Funcionario.objects.all()
	
	if lista_funcionarios:
		puxar_informacoes_henry(lista_funcionarios)
		
		nova_sincronizacao = Sincronizacao()
		agora = datetime.now()
		nova_sincronizacao.data_hora = agora
		nova_sincronizacao.save()
		
		return True
	else:
		return False
		
		
######################################
# 	  OUTRAS FUNÇÕES ÚTEIS
######################################
	
def strfdelta(tdelta, fmt):
    f = Formatter()
    d = {}
    l = {'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
    k = map( lambda x: x[1], list(f.parse(fmt)))
    rem = int(tdelta.total_seconds())

    for i in ('D', 'H', 'M', 'S'):
        if i in k and i in l.keys():
            d[i], rem = divmod(rem, l[i])

    return f.format(fmt, **d)

###################################### 
#	  FUNÇÕES QUE GERAM RELATÓRIOS	
###################################### 	

class ResumoDiario():
	
	def __init__(self, data, horas):
		self.data = data
		self.horas = horas
		
		
	def horas_formatadas(self):
				
		return strfdelta(self.horas, "{H:02}:{M:02}:{S:02}")
		
	
	def data_formatada(self):
		
		return self.data.strftime("%d/%m/%Y")
		
	
		
		
def organizar_batidasponto(batidas_do_dia, data):
	
#	intervalo_almoco = datetime(data.year, data.month, data.day, 12, 30)
	
	quantidade_batidas_do_dia = len(batidas_do_dia)
	
	batida_entrada_manha = None
	batida_saida_manha = None
	batida_entrada_tarde = None
	batida_saida_tarde = None
	
	if quantidade_batidas_do_dia >= 1:
		batida_entrada_manha = batidas_do_dia[0].momento_batidaponto	
	if quantidade_batidas_do_dia >= 2:
		batida_saida_manha = batidas_do_dia[1].momento_batidaponto
	if quantidade_batidas_do_dia >= 3:
		batida_entrada_tarde = batidas_do_dia[2].momento_batidaponto
	if quantidade_batidas_do_dia >= 4:
		batida_saida_tarde = batidas_do_dia[3].momento_batidaponto

	
	"""
	
	if quantidade_batidas_do_dia > 1:
		
		batidas_antes_intervalo_almoco = []
		batidas_depois_intervalo_almoco = []
			
		for bd in batidas_do_dia:
			
			if bd.momento_batidaponto < intervalo_almoco:
				batidas_antes_intervalo_almoco.append(bd.momento_batidaponto)
			else:
				batidas_depois_intervalo_almoco.append(bd.momento_batidaponto)
				
		
		batidas_antes_intervalo_almoco.sort()
		batidas_depois_intervalo_almoco.sort()
		
		if len(batidas_antes_intervalo_almoco) == 1:
			batida_entrada_manha = batidas_antes_intervalo_almoco[0]
		elif len(batidas_antes_intervalo_almoco) > 1:
			batida_entrada_manha = batidas_antes_intervalo_almoco[0]
			batida_saida_manha = batidas_antes_intervalo_almoco[-1]
			
			
		if len(batidas_depois_intervalo_almoco) == 1:
			batida_entrada_tarde = batidas_depois_intervalo_almoco[0]
		elif len(batidas_depois_intervalo_almoco) > 1:
			batida_entrada_tarde = batidas_depois_intervalo_almoco[0]
			batida_saida_tarde = batidas_depois_intervalo_almoco[-1]
	"""
		
	"""
		if quantidade_batidas_do_dia == 1:
			pass
			
		elif quantidade_batidas_do_dia == 2:
			

			if batidas_do_dia[0].momento_batidaponto < intervalo_almoco and batidas_do_dia[-1].momento_batidaponto < intervalo_almoco:	
				
				batida_entrada_manha = batidas_do_dia[0]
				batida_saida_manha = batidas_do_dia[-1]
				
			elif batidas_do_dia[0].momento_batidaponto > intervalo_almoco and batidas_do_dia[-1].momento_batidaponto > intervalo_almoco:			
				
				
				batida_entrada_tarde = batidas_do_dia[0]
				batida_saida_tarde = batidas_do_dia[-1]

			else:
				pass
				
		
		elif quantidade_batidas_do_dia == 3:
			
			if batidas_do_dia[0].momento_batidaponto < intervalo_almoco and batidas_do_dia[1].momento_batidaponto < intervalo_almoco:
				batida_entrada_manha = batidas_do_dia[0]
				batida_saida_manha = batidas_do_dia[1]
				
			elif batidas_do_dia[0].momento_batidaponto > intervalo_almoco and batidas_do_dia[1].momento_batidaponto > intervalo_almoco:
				batida_entrada_tarde = batidas_do_dia[0]
				batida_saida_tarde = batidas_do_dia[1]
				
			elif batidas_do_dia[1].momento_batidaponto < intervalo_almoco and batidas_do_dia[2].momento_batidaponto < intervalo_almoco:
				batida_entrada_manha = batidas_do_dia[1]
				batida_saida_manha = batidas_do_dia[2]
				
			elif batidas_do_dia[1].momento_batidaponto > intervalo_almoco and batidas_do_dia[2].momento_batidaponto > intervalo_almoco:
				batida_entrada_tarde = batidas_do_dia[1]
				batida_saida_tarde = batidas_do_dia[2]	
				
			else:
				pass
			
			
		else:
			
			batidas_antes_intervalo_almoco = []
			batidas_depois_intervalo_almoco = []
			
			for bd in batidas_do_dias:
				
				if bd.momento_batidaponto < intervalo_almoco:
					batidas_antes_intervalo_almoco.append(bd)
				else:
					batidas_depois_intervalo_almoco.append(bd)
				
			
			if batidas_do_dia[0].momento_batidaponto < intervalo_almoco 
			batida_entrada_manha = batidas_do_dia[0]
			batida_saida_tarde = batidas_do_dia[-1]
			for i in range(quantidade_batidas_do_dia):
				if batidas_do_dia[i].momento_batidaponto >= intervalo_almoco:
					batida_saida_manha = batidas_do_dia[i-1]
					batida_entrada_tarde = batidas_do_dia[i]
					break
	"""
		
	return batida_entrada_manha, batida_saida_manha, batida_entrada_tarde, batida_saida_tarde

		
def calcular_horas_trabalhadas_dia(funcionario, data):
		
	batidas_do_dia = list(BatidaPonto.objects.filter(funcionario=funcionario, momento_batidaponto__day=data.day, momento_batidaponto__month=data.month, momento_batidaponto__year=data.year).order_by('momento_batidaponto'))
	
	tempo_total_dia = timedelta(0,0)
		
	batida_entrada_manha, batida_saida_manha, batida_entrada_tarde, batida_saida_tarde = organizar_batidasponto(batidas_do_dia, data)
	
	if batida_entrada_manha and batida_saida_manha:
		
		# Para limitar o horário de entrada
				
		horario_entrada = batida_entrada_manha.time()
		
		if horario_entrada < funcionario.horario_inicial_entrada:
			batida_entrada_manha = datetime.combine(data, funcionario.horario_inicial_entrada)
		
		horas_trabalhadas_manha = batida_saida_manha - batida_entrada_manha
		tempo_total_dia += horas_trabalhadas_manha
			
	if batida_entrada_tarde and batida_saida_tarde:
		
		# Para limitar o horário de saída
				
		horario_saida = batida_saida_tarde.time()
		
		if horario_saida > funcionario.horario_final_saida:
			batida_saida_tarde = datetime.combine(data, funcionario.horario_final_saida)
			
		horas_trabalhadas_tarde = batida_saida_tarde - batida_entrada_tarde
		tempo_total_dia += horas_trabalhadas_tarde
		
	
	try:
		
		comentario = Comentario.objects.get(funcionario=funcionario, data=data)
		
		if comentario.aprovado:
			
			tempo_gasto = comentario.tempo_gasto
			
			horas = tempo_gasto.hour
			minutos = tempo_gasto.minute
			segundos = tempo_gasto.second
			
			tempo_gasto_timedelta = timedelta(0,segundos,0,0,minutos,horas,0)
			
			tempo_total_dia += tempo_gasto_timedelta
	
	except ObjectDoesNotExist:
		
		pass
			

	"""
	if(quantidade_batidas_do_dia%2==0):
		for i in range(0, quantidade_batidas_do_dia, 2):
			hora_menor = batidas_do_dia[i].momento_batidaponto
			hora_maior = batidas_do_dia[i+1].momento_batidaponto
			tempo_parcial = hora_maior - hora_menor
			tempo_total_dia += tempo_parcial
			
	else:
		for i in range(0, quantidade_batidas_do_dia-1, 2):
			hora_menor = batidas_do_dia[i].momento_batidaponto
			hora_maior = batidas_do_dia[i+1].momento_batidaponto
			tempo_parcial = hora_maior - hora_menor
			tempo_total_dia += tempo_parcial
	"""
	

	return tempo_total_dia		
	
	
	
def horas_trabalhadas_dia(funcionario):
	
	resumos = []
	
	primeira_batidaponto = None
	
	try:
		primeira_batidaponto = BatidaPonto.objects.filter(funcionario=funcionario).earliest('momento_batidaponto')
	except ObjectDoesNotExist:
		pass
		
	if primeira_batidaponto:
		
		primeira_data = primeira_batidaponto.momento_batidaponto
		data_atual = datetime.now()
		
		diferenca_datas = data_atual - primeira_data
		quantidade_dias = diferenca_datas.days
	
		data_temp = primeira_data
		
		while data_temp.date() <= data_atual.date():
						
			horas_dia = calcular_horas_trabalhadas_dia(funcionario, data_temp)
			
			resumo = ResumoDiario(data_temp.date(), horas_dia)
			
			resumos.append(resumo)
			
			data_temp += timedelta(days=1)
			
	
	return resumos
	
	
class ResumoSemanal():
	
	def __init__(self, domingo, horas):
		
		self.domingo = domingo
		self.horas = horas
		
	def horas_formatadas(self):
		
		return strfdelta(self.horas, "{H:02}:{M:02}:{S:02}")
		
		
	def semana_formatada(self):
		
		meses  = ("Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro")
		
		domingo = self.domingo
		sexta_feira = self.domingo + timedelta(days=6)
		
		dia_domingo = "%d" %(domingo.day)
		dia_sexta = "%d" %(sexta_feira.day)
		
		if domingo.day < 10:
			dia_domingo = "0%d" %(domingo.day)
			
		if sexta_feira.day < 10:
			dia_sexta = "0%d" %(sexta_feira.day)
		
		
		semana = "De %s de %s de %d a %s de %s de %d" %(dia_domingo, meses[domingo.month -1], domingo.year, dia_sexta, meses[sexta_feira.month -1], sexta_feira.year)
		
		return semana

	
def calcular_horas_trabalhadas_semana(funcionario, domingo):

	tempo_total_semana = timedelta(0,0)
	
	data_temp = domingo
	
	for i in range(7):
		tempo_total_semana += calcular_horas_trabalhadas_dia(funcionario, data_temp)
		data_temp += timedelta(days=1)

	# Retorna o tempo total da semana.
	return tempo_total_semana
	
	
def horas_trabalhadas_semana(funcionario):
	
	resumos = []
	primeira_batidaponto = None
	
	try:
		primeira_batidaponto = BatidaPonto.objects.filter(funcionario=funcionario).earliest('momento_batidaponto')
	except ObjectDoesNotExist:
		pass		
		
	if primeira_batidaponto:
		
		primeira_data = primeira_batidaponto.momento_batidaponto
		data_atual = datetime.now()
		
		dia_semana = primeira_data.weekday()
		
		# Caso não seja uma domingo, ele voltará alguns dias até encontrá-la.
		while dia_semana != 6:
			primeira_data -= timedelta(days=1)
			dia_semana = primeira_data.weekday()
		
		data_atual = datetime.now()
		data_temp = primeira_data
				
		while data_temp.date() < data_atual.date():
			
			horas_trabalhadas = calcular_horas_trabalhadas_semana(funcionario, data_temp)
			
			resumo_semanal = ResumoSemanal(data_temp.date(), horas_trabalhadas)
			
			resumos.append(resumo_semanal)
	
			data_temp += timedelta(days=7)	
		
	return resumos
	

def horas_trabalhadas_semana_durante_mes(funcionario, mes, ano):
	
	limites_mes = monthrange(ano, mes)
	
	primeiro_dia_mes = date(ano, mes, limites_mes[0])
	ultimo_dia_mes = date(ano, mes, limites_mes[1])
	
	primeira_data = primeiro_dia_mes
	
	resumos = []
	
	dia_semana = primeira_data.weekday()
	
	# Caso não seja uma domingo, ele voltará alguns dias até encontrá-la.
	
	while dia_semana != 6:
		primeira_data -= timedelta(days=1)
		dia_semana = primeira_data.weekday()

	data_temp = primeira_data
			
	while data_temp < ultimo_dia_mes:
		
		horas_trabalhadas = calcular_horas_trabalhadas_semana(funcionario, data_temp)
		
		resumo_semanal = ResumoSemanal(data_temp, horas_trabalhadas)
		
		resumos.append(resumo_semanal)

		data_temp += timedelta(days=7)	
		
	return resumos
	
def horas_trabalhadas_datas(funcionario, datas):
	
	resumos = []

	tempo_total = timedelta(0,0)

	for data in datas:	
		tempo_total += calcular_horas_trabalhadas_dia(funcionario,data)
		
	return strfdelta(tempo_total, "{H:02}:{M:02}:{S:02}")
		

class RelatorioDiario():
	
	def __init__(self, data, tempo_total_dia, batida_entrada_manha, batida_saida_manha, batida_entrada_tarde, batida_saida_tarde):
		self.data = data
		self.tempo_total_dia = tempo_total_dia
		
		if batida_entrada_manha:
			self.batida_entrada_manha = batida_entrada_manha.strftime("%H:%M:%S")
		if batida_saida_manha:
			self.batida_saida_manha =  batida_saida_manha.strftime("%H:%M:%S")
		if batida_entrada_tarde:
			self.batida_entrada_tarde = batida_entrada_tarde.strftime("%H:%M:%S")
		if batida_saida_tarde:
			self.batida_saida_tarde = batida_saida_tarde.strftime("%H:%M:%S")
		
		

def gerar_relatorio_mensal(funcionario, mes, ano):
		
	fim_do_mes = monthrange(ano, mes)[1]
	relatorios_diarios = []
	
	# Percorre todos os dias do mês.	
	for dia in range(1,fim_do_mes+1,1):
			
		batidas_formatadas = []
		data = date(ano, mes, dia)
		data_formatada = data.strftime("%d/%m/%Y")
		
		tempo_total_dia = calcular_horas_trabalhadas_dia(funcionario, data)
		
		tempo_total_dia_formatado = strfdelta(tempo_total_dia, "{H:02}:{M:02}:{S:02}")
		
		batidas_ponto_dia = list(BatidaPonto.objects.filter(funcionario=funcionario, momento_batidaponto__month=mes, momento_batidaponto__day=dia, momento_batidaponto__year=ano))

		batida_entrada_manha, batida_saida_manha, batida_entrada_tarde, batida_saida_tarde = organizar_batidasponto(batidas_ponto_dia , data)
		
		#for bp in batidas_ponto_dia:
		#	batidas_formatadas.append(bp.momento_batidaponto.strftime("%H:%M:%S"))
			
		relatorio_diario = RelatorioDiario(data_formatada, tempo_total_dia_formatado, batida_entrada_manha, batida_saida_manha, batida_entrada_tarde, batida_saida_tarde)
		relatorios_diarios.append(relatorio_diario)
		
	return relatorios_diarios
