#! /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 Log
import Opcoes
import rpm
import os
import re
import md5
import MySQLdb
import MySQLdb.cursors
import sys
import Ambiente
import Opcoes

class Diretorio(object):
	"""
	Classe que lista todos arquivos e diretorios de um determinado caminho
	"""
	def __init__(self, diretorio):
		self.diretorio = diretorio
		self.listaDiretorio = []
		self.listaNomeArquivo = []

	def lista(self):
		"""
		Retorna uma lista com os arquivos e diretorios
		"""
		if not os.path.isdir(self.diretorio):																			# Verifica se o caminho passado e' um diretorio
			return None
		else:
			self.__lista(self.diretorio)
			return self.listaNomeArquivo, self.listaDiretorio

	def __lista(self, diretorio):
		"""
		Retorna uma lista de arquivos e diretorios do diretorio corrente
		"""
		try:
			os.chdir(os.path.join(os.getcwd(), diretorio))
			novo_diretorio = os.getcwd()
			arquivos = os.listdir(novo_diretorio)
		except:
			return None
			
		for i in xrange(len(arquivos)):
			if os.path.isdir(arquivos[i]):																# Verifica se a entrada e' um diretorio
				self.__lista(arquivos[i])																		# Diretorio encontrado, recursao para ele
			else:
				if re.search('.rpm$', arquivos[i]) != None:											# Filtra somentes arquivos .rpm
					self.listaDiretorio.append(self.diretorio + "/" + diretorio + "/")	# Adiciona entrada na lista
					self.listaNomeArquivo.append(arquivos[i])
				continue																								# Arquivo encontrado, proxima entrada
		os.chdir("..")



class Repositorio(object):
	"""
	Classe que gerencia o repositorio de softwares
	"""

	def __init__(self, caminhoRepositorio=None):
		
		self.db = Ambiente.db
		
		# Inicia Log do Repositorio
		#self.log = Log.Log("Repositorio")
		#self.log = self.log.get()
		self.log = Ambiente.log
		
		opcoes = Opcoes.Opcoes()
		
		if caminhoRepositorio != None:
			self.caminhoRepositorio = caminhoRepositorio
		else:
			#opcoes = opcoes.ler('Repositorio')
			#self.caminhoRepositorio  =  opcoes['caminho']
			self.caminhoRepositorio = "repositorio"



	def caminho(self, caminhoRepositorio=None):
		if caminhoRepositorio != None:
			self.caminhoRepositorio = caminhoRepositorio
		return self.caminhoRepositorio


	def informacao(self, md5):
		"""
		Retorna todas as informacoes de um determinado software
		Entrada: md5 (assinatura md5 do software)
		Saida:
			OK: Informacoes do software
			Falha: retorna 'None'
		"""
		try:
			self.db.execute("""SELECT * FROM softwares WHERE md5=%s""",  (md5))
			return self.db.fetchone()
		except MySQLdb.Error, e:
			self.log.error("%d: %s" % (e.args[0], e.args[1]))
			return -1


	def total(self):
		try:
			self.db.execute("SELECT count(*) as numSoftwares FROM softwares")
			return self.db.fetchone()
		except MySQLdb.Error, e:
			mysql_erro = "%d: %s" % (e.args[0], e.args[1])
			self.log.error(mysql_erro)
			return -1
		except Exception:
			erro = "ao totalizar o numero de softwares"
			self.log.error(erro)
			return -1


	def tamanho(self):
		try:
			self.db.execute("SELECT sum(tamanho) as tam FROM softwares")
			return self.db.fetchone()
		except MySQLdb.Error, e:
			mysql_erro = "%d: %s" % (e.args[0], e.args[1])
			self.log.error(mysql_erro)
			return -1
		except Exception:
			erro = "ao somar tamanho dos softwares"
			self.log.error(erro)
			return -1


	def remove(self, md5=None):
		"""
		Remove software da base de dados
		Entrada: md5 (assinatura md5 do software)
		Retorno:
			 1: concluido com sucesso
			None: falha na remocao
		"""
		try:
			if md5 == None:
				self.db.execute("DELETE FROM softwares")
			else:
				self.db.execute("DELETE FROM softwares where md5 = %s", md5)
			return 1
		except MySQLdb.Error, e:
			self.log.error("%d: %s" % (e.args[0], e.args[1]))
			return None



	def inseri(self, dicNovoSoftware):
		"""
		Inseri ou atualiza um novo software na base de dados
		Entrada: dicNovoSoftware = Dicionario com os campos de cadastro 
		Retorno: 
			 1: concluido com sucesso
			-1: parametro invalido (nao eh do tipo dicionario)
			-2: falta paramentro (md5)
			None: falha na insercao
		"""
		if isinstance(dicNovoSoftware, dict) != True:
			return -1
		if dicNovoSoftware["md5"] == None:
			return -2
		
		try:
			self.db.execute("REPLACE INTO softwares \
				(nome, md5, versao, tamanho, liberacao, descricao, \
				plataforma, localizacao, grupo, nomeArquivo) \
				values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
				(dicNovoSoftware["nome"], dicNovoSoftware["md5"], dicNovoSoftware["versao"], dicNovoSoftware["tamanho"],
				dicNovoSoftware["liberacao"], dicNovoSoftware["descricao"], dicNovoSoftware["plataforma"], 
				dicNovoSoftware["localizacao"], dicNovoSoftware["grupo"], dicNovoSoftware["nomeArquivo"]))
			return 1
		except MySQLdb.Error, e:
			mysql_erro = "%d: %s" % (e.args[0], e.args[1])
			self.log.error(mysql_erro)
			return mysql_erro
		except Exception:
			erro = "ao adicionar software no repositorio"
			self.log.error(erro)
			return erro



	def atualiza(self):
		"""
		Atualiza repositorio de softwares
		Retorno: 
			 1: concluido com sucesso
			None: falha na atualizacao
		"""
		self.remove()
		dir = Diretorio(self.caminhoRepositorio)
		arquivos, caminhoArquivos = dir.lista()
		if arquivos == None:
			self.log.error("Caminho para repositorio invalido: " + self.caminhoRepositorio)
			return None
			
		for index in xrange(len(arquivos)):
			try:
				ts = rpm.ts()
				arq = os.getcwd() + "/" + caminhoArquivos[index] + "/" + arquivos[index]

				fdno = os.open(arq, os.O_RDONLY)
				hdr = ts.hdrFromFdno(fdno)
				os.close(fdno)
				
				fdno = open(arq, 'rb')
				assinatura = md5.new(fdno.read())
				fdno.close()
				sw = {}
				sw["md5"] = assinatura.hexdigest()
				sw["nome"] = hdr[rpm.RPMTAG_NAME]
				sw["versao"] = hdr[rpm.RPMTAG_VERSION]
				sw["liberacao"] = hdr[rpm.RPMTAG_RELEASE]
				sw["tamanho"] = int(hdr[rpm.RPMTAG_SIZE])
				sw["plataforma"] = hdr[rpm.RPMTAG_PLATFORM]
				sw["descricao"] = hdr[rpm.RPMTAG_SUMMARY]
				sw["localizacao"] = caminhoArquivos[index]
				sw["nomeArquivo"] = arquivos[index]
				sw["grupo"] = hdr[rpm.RPMTAG_GROUP]
				self.inseri(sw)
			except Exception:
				self.log.error("ao atualizar repositorio de softwares. ")
				raise
				return -1
		return 1

	
	def informacao(self, md5=None):
		"""
		Retorna todas as informacoes de um determinado software
		"""
		try:
			if md5 == None:
				self.db.execute("""SELECT md5 FROM softwares""")
				return self.db.fetchall()
			else:
				self.db.execute("""SELECT * FROM softwares WHERE md5=%s """,  (md5))
				return self.db.fetchone()
		except MySQLdb.Error, e:
			mysql_erro = "%d: %s" % (e.args[0], e.args[1])
			self.log.error(mysql_erro)
			return mysql_erro
		except Exception:
			erro = "ao buscar informacao de uma acao: %s" % agente_mac_address
			self.log.error(erro)
			return -1


	def grupo(self, grupo=None):
		"""
		Retorna informacoes de um determinado software
		"""
		try:
			if grupo == None:
				self.db.execute("""SELECT distinct grupo FROM softwares""")
				return self.db.fetchall()
			else:
				self.db.execute("""SELECT * FROM softwares WHERE grupo=%s """,  (grupo))
				return self.db.fetchall()
		except MySQLdb.Error, e:
			mysql_erro = "%d: %s" % (e.args[0], e.args[1])
			self.log.error(mysql_erro)
			return mysql_erro
		except Exception:
			erro = "ao buscar informacao de uma acao: %s" % agente_mac_address
			self.log.error(erro)
			return -1
			

	def exporta(self):
		"""
		Retorna todas as informacoes de um determinado software
		"""
		try:
			if md5 == None:
				self.db.execute("""SELECT * FROM softwares""")
			return self.db.fetchall()
		except MySQLdb.Error, e:
			mysql_erro = "%d: %s" % (e.args[0], e.args[1])
			self.log.error(mysql_erro)
			return mysql_erro
		except Exception:
			erro = "ao buscar informacao de uma acao: %s" % agente_mac_address
			self.log.error(erro)
			return -1