#! /usr/bin/python
# -*- coding: iso-8859-1 -*-

#####################################################
#    Copyright (C) 2006 by Cesar Kallas   	
#    cesarkallas@soulivre.org   
#    http://cesarkallas.soulivre.org
#                                                                          
#    This program is free software; you can redistribute it and#or modify  
#    it under the terms of the GNU General Public License as published by 
#    the Free Software Foundation; either version 2 of the License, or     
#    (at your option) any later version.                                   
#                                                                          
#    This program is distributed in the hope that it will be useful,       
#    but WITHOUT ANY WARRANTY; without even the implied warranty of        
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         
#    GNU General Public License for more details.                          
#                                                                          
#    You should have received a copy of the GNU General Public License     
#    along with this program; if not, write to the                         
#    Free Software Foundation, Inc.,                                       
#    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             
#####################################################

import Ambiente
import Opcoes
import Log
import Acoes
import Agentes
import socket
import thread
import string


class Servidor(object):
	"""
	Classe que gerenciar o servidor conecta gerente
	"""
	def __init__(self):
		# Le as opcoes de inicializacao
		opcoes = Opcoes.Opcoes()
		servidorOpcoes = opcoes.ler('Servidor')
		
		# Inicia Log do Repositorio
		#self.log = Log.Log("Servidor")
		#self.log = self.log.get()
		self.log = Ambiente.log
		
		self.porta = servidorOpcoes["porta"]
		
		servidorOpcoes = opcoes.ler('Repositorio')
		self.repositorio = servidorOpcoes["caminho"]
		
		if self.porta == None:
			self.porta = 15000
			
		self.porta = int(self.porta)
		
		self.agentes = Agentes.Agentes()

		
	def iniciar(self):
		"""
		Inicia servidor
		"""
		
		# Cria mutex para variaveis que vao ser editas pelas threads 
		self.vlock = thread.allocate_lock()
		self.vlockLog = thread.allocate_lock()
		
		# Cria novo servidor tcp
		try:
			skt_servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)		# Cria socket TCP
			skt_servidor.bind(('', self.porta))														# Faz a ligacao dele com a porta passada por parametro
			skt_servidor.listen(5)																								# Numero de hand-shakes (pedidos de conexoes simultaneas)
			self.log.info("Servidor online: porta: %s" % self.porta)
			# Seta que o servidor esta online
			self.vlock.acquire()
			Ambiente.servidorOnline = 1
			self.vlock.release()
			while(1):
				# Escuta novas conexoes, cada nova conexao sera tratada por uma thread da funcao trataCliente
				(skt_cliente, skt_cliente_endereco) = skt_servidor.accept()
				if Ambiente.servidorOnline != 1:
					break
				self.log.info("Servidor: novo agente conectado: %s:%s" % (skt_cliente_endereco[0], skt_cliente_endereco[1]))
				thread.start_new_thread(self.trataCliente, (skt_cliente, skt_cliente_endereco))
		except socket.error, e:
			if e.args[0] == 98:
				self.log.error("Servidor: porta TCP em uso: %s" % self.porta)
				return -1
		except Exception:
			self.log.error("Servidor: ao criar um novo servidor-tcp")
			raise
		skt_servidor.close()
		self.log.info("Servidor offline")


	def trataCliente(self, skt_cliente, skt_cliente_endereco):
		"""
		Trata pedido de conexao do cliente
		Entradas:
			skt_cliente: socket cliente conectado
			skt_cliente_endereco: endereco do cliente conectado
		"""
		skt_cliente.settimeout(None)
		
		# Edita numero de clientes conectaos
		self.vlock.acquire()
		Ambiente.agentesConectados += 1
		self.vlock.release()
		
		try:
			while 1:
				msg = string.lower(skt_cliente.recv(1024))
				print msg
				if len(msg) < 25:
					skt_cliente.sendall("900:requisicao desconhecida\n")
					break
				
				# Verifica se o agente esta cadastrado
				agente = self.agentes.informacao(msg[0:17])
				if agente == -1:
					skt_cliente.sendall("901:agente inexistente\n")
					self.vlockLog.acquire()
					self.log.error("Servidor: agente inexistente: " + msg[0:17])
					self.vlockLog.release()
					break
				if agente == None:
					skt_cliente.sendall("901:agente inexistente\n")
					self.vlockLog.acquire()
					self.log.error("Servidor: agente inexistente: " + msg[0:17])
					self.vlockLog.release()
					break

				if msg[18:25] == "retorno":
					break
					
				elif msg[18:26] == "consulta":
					# Retorna acoes agendadas para o agente
					print "consulta cliente: ", msg[0:17]
					
					# Instancia acoes do agente com o mac address passado pelo cliente
					acoes = Acoes.Acoes(msg[0:17])
						
					# Gera xml com as acoes
					md5ArquivoXml = acoes.exporta("agendada")
					if md5ArquivoXml == -1:
						skt_cliente.sendall("902:falha ao gerar arquivo xml\n")
						self.vlockLog.acquire()
						self.log.error("Servidor: falha ao gerar arquivo xml do agente: " + msg[0:17])
						self.vlockLog.release()
						break
						
					if md5ArquivoXml == -2:
						skt_cliente.sendall("101:sem atualizacoes disponiveis\n")
						self.vlockLog.acquire()
						self.log.error("Servidor: sem atualizacoes disponiveis para o agente: " + msg[0:17])
						self.vlockLog.release()
						break
						
					else:
						# Envia assinatura do arquivo a ser transferido
						skt_cliente.sendall("100:" + md5ArquivoXml)
						resposta = skt_cliente.recv(1024)
						if resposta != "IniciarTransferencia":
							print "erro na resposta"
							return -1
							
						# Envia xml
						try:
							macAddress = str(msg[0:17])
							macAddress = macAddress.replace(":", "")
							arquivoXml = open("acoes/" + macAddress + ".xml", 'rb')
							while True:
								bytes = arquivoXml.read(1024)
								if not bytes:
									break
								transfer = skt_cliente.sendall(bytes)
								#assert transfer == len(bytes)
							arquivoXml.close()
							skt_cliente.close()
							self.vlockLog.acquire()
							self.log.info("Servidor: atualizacao enviada com sucesso para: " + msg[0:17])
							self.vlockLog.release()
						except Exception:
							self.vlockLog.acquire()
							self.log.error("Servidor: falha ao enviar acao para: " + msg[0:17])
							self.vlockLog.release()
							raise
					break
				else:
					print msg
					break
					
		except Exception:
			skt_cliente.close()
			raise
			
		self.vlock.acquire()
		Ambiente.agentesConectados -= 1
		self.vlock.release()
