#!/usr/bin/env python

""" 
   Copyright (C) 2003-2005 PimenTech SARL (http://www.pimentech.net)

   Pimengest2 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.

   Pimengest2 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 library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.	
"""

import sys
import os
import getopt
import re
import psycopg # Module from http://initd.org/software/initd/psycopg
from stat import ST_MTIME
from os.path import exists
from string import index, join
import locale

locale.setlocale(locale.LC_TIME, 'fr_FR')

def euro_round(sum):
	return round(float(sum)-0.001, 2)

def euro_round_fr(sum):
	txt = "%.2f" % euro_round(sum)
	l = txt[0:-3]
	l = list(l)
	l.reverse()
	i = 0
	ret = []
	while i < len(l):
		l2 = l[i:i+3]
		l2.reverse()
		ret .append(''.join(l2))
		i += 3
	ret.reverse()
	return '~'.join(ret) + ',' + txt[-2:]
	
class genpdf:
	BUFFER = ''
	BUFFER_HEADER = ''
	BUFFER_ARTICLES = '%# articles_from_genpdf'
	BUFFER_PRESTA = "%# prestas_from_genpdf"
	BUFFER_DESCRIPTION_PRESTA = ''
	UID = 0
	WITH_HEADER = 0
	FILEDIR = ''
	DEBUG_INFO = ''
	
	def __init__(self, uid, with_header, verbose, filedir):
		self.UID=uid
		self.WITH_HEADER=with_header
		self.VERBOSE=verbose
		self.FILEDIR=filedir

	def init_template(self, latexdir, template_file):
		try:
			file=open(latexdir + "/" + template_file, 'r')
		except:
			print "Error : no tex file " +template_file+ " found on "+ latexdir +"\n"
			sys.exit(-1)
		else:
			self.BUFFER=file.read()
			file.close()

	def init_header(self, latexdir, header_file):
		if self.WITH_HEADER:
			try:
				file=open(latexdir + "/" + header_file, 'r')
			except:
				print "Error : no tex file " +header_file+ " found on "+ latexdir +"\n"
				sys.exit(-1)
			else:
				self.BUFFER_HEADER=file.read()
				file.close()			


	def replace_values(self, affichage, latexdir, template_file):
		"""Replace values from token list to buffers.
		If a header is given, all buffer_header is inserted in buffer."""

		self.tokens['ENTETE_FILE'] = "template_entete.tex"
		# Ici entete EPS
		if self.tokens['FICHIER_PIED'] != "~":
			sys.stderr.write("[detect] " + self.tokens['FICHIER_PIED'] + "\n")

			self.tokens['ENTETE_FILE'] = "template_entete_img.tex"
			file1 = self.tokens['FICHIER_PIED']
			file2 = self.tokens['FICHIER_LOGO']
			for file, token in ((file1, "FICHIER_PIED"), (file2, 'FICHIER_LOGO')):
				if check_output(self.tokens[token]):
					try:
						file.index('.')
						list=file.split('.')
						core, extention = join(list[0:-1], '.'), list[-1]
					except:
						self.tokens['ENTETE_FILE'] = "template_entete.tex"
					else:
						if extention != "eps":
							if check_output("%s.%s" % (core, "eps")):
								m_time1=os.stat(file)[ST_MTIME]
								m_time2=os.stat("%s.eps" % core)[ST_MTIME]
								if  m_time2<m_time1:
									try:
										self.conversion(core)
										self.tokens[token] = "%s.%s" % (core, "eps")
									except:
										self.tokens['ENTETE_FILE'] = "template_entete.tex"
							else:
								try:
									self.convertion(core)
									self.tokens[token] = "%s.%s" % (core, "eps")
								except:
									self.tokens['ENTETE_FILE'] = "template_entete.tex"
				else:
					self.tokens['ENTETE_FILE'] = "template_entete.tex"
				
		# Ici entete dynnamique : token = FICHIER_LOGO
		elif self.tokens["FICHIER_LOGO"]!="~" and self.tokens['ENTETE_FILE'] == "template_entete.tex":
			sys.stderr.write("[detect] template d'entete : template_entete.tex\n")
			if check_output(self.tokens['FICHIER_LOGO']):
				file = self.tokens["FICHIER_LOGO"]
				try:
					file.index('.')
					list=file.split('.')
					core, extention = join(list[0:-1], '.'), list[-1]
				except:
					self.tokens["FICHIER_LOGO"]="{{"
				else:
					if extention=="eps":
						self.tokens["FICHIER_LOGO"]=" \\fontsize{6.5pt}{19.2pt}\\selectfont{\\includegraphics[width=4.7cm]{%s}" % (self.tokens["FICHIER_LOGO"])
					else:
						if check_output("%s.%s" % (core, "eps")):
							m_time1=os.stat(file)[ST_MTIME]
							m_time2=os.stat("%s.eps" % core)[ST_MTIME]
							if  m_time2>=m_time1:
								self.tokens["FICHIER_LOGO"]= "\\fontsize{6.5pt}{19.2pt}\\selectfont{\\includegraphics[width=4.7cm]{%s.%s}" % (core, "eps")
							else:
								try:
									self.convertion(core)
								except:
									self.tokens["FICHIER_LOGO"]="{{"
						else:
							try:
								self.convertion(core)
							except:
								self.tokens["FICHIER_LOGO"]="{{"
			else:
				self.tokens["FICHIER_LOGO"]="{{"
		else:
			self.tokens["FICHIER_LOGO"]="{{"
					

		self.tokens["DESCRIPTION_PRESTATION"] = self.BUFFER_DESCRIPTION_PRESTA
		
		self.init_template(latexdir, template_file)
		self.init_header(latexdir, self.tokens['ENTETE_FILE'])
		for token in ("FICHIER_LOGO", "FICHIER_PIED", ):
			self.BUFFER_HEADER = self.BUFFER_HEADER.replace('<TMPL '+token+'>', self.tokens[token], 1)
			
		if self.WITH_HEADER:
			self.BUFFER = self.BUFFER.replace('<TMPL ENTETE>', self.BUFFER_HEADER, 1)

		if affichage:
			self.tokens["ARTICLES"]=self.BUFFER_ARTICLES
			self.tokens["PRESTAS"]=self.BUFFER_PRESTA
			#optionnel
			self.tokens["ARTICLES2"]=self.BUFFER_ARTICLES.replace('Article', 'Description')

			
		if self.VERBOSE:
			print self.tokens
			
		for token, str in self.tokens.items():
			if str == None:
				str = ""
			str = TeXfilter(str)
			self.BUFFER = self.BUFFER.replace('<TMPL '+token+'>', str, 1)

	def has_remise(self, type):
		if type == 'article':
			req = self.query_article % self.UID
			rang = 6
		elif type == 'presta':
			req = self.query_presta % self.UID
			rang = 3
		else:
			return 0
		self.curs.execute(req)
		if self.curs.rowcount == 0:
			return 0
		res = self.curs.fetchall()
		for r in res:
			if r[rang]:
				return 1
		return 0
		
	def get_articles_prestas(self, devise, montant_init=0):
		total_ht=0
		total_ttc=0

		has_remise_article = self.has_remise('article')
		has_remise_presta = self.has_remise('presta')
		
		template_article_head= r"""
\begin{small}
\begin{flushright}
\tablehead{
\hline
"""
		if has_remise_article:
			template_article_head += r"\bf Article & \bf Réf. & \bf Remise & \bf Qtt & \bf Px Unit. HT & \bf TVA & \bf Mtt HT\\" + "\n"
		else:
			template_article_head += r"\bf Article & \bf Réf. & \bf Qtt & \bf Px Unit. HT & \bf TVA & \bf Mtt HT\\" + "\n"
			
		template_article_head += r"""
\hline}
\tabletail{\hline}
"""
		
		if has_remise_article:
			template_article_head += r"\begin{supertabular}[bbbbbbb]{|p{7.5cm}||>{\PBS\centering}b{1.5cm}|>{\PBS\centering}b{1cm}|>{\PBS\centering}b{1cm}|>{\PBS\raggedleft}b{2cm}|>{\PBS\raggedleft}b{1cm}|>{\PBS\raggedleft}b{1.5cm}|}"+"\n"
		else:
			template_article_head += r"\begin{supertabular}[bbbbbb]{|p{8.5cm}||>{\PBS\centering}b{1.5cm}|>{\PBS\centering}b{1cm}|>{\PBS\raggedleft}b{2cm}|>{\PBS\raggedleft}b{1cm}|>{\PBS\raggedleft}b{1.5cm}|}"+"\n"

		template_presta_head= r"""
\begin{small}
\begin{flushright}
\tablehead{
\hline
"""
		if has_remise_presta:
			template_presta_head += r"""
\bf Prestation & \bf Réf. & \bf Description & \bf Remise & \bf TVA & \bf Mtt HT\\
\hline}
\tabletail{\hline}
\begin{supertabular}[bbbbbb]{|p{4.4cm}||>{\PBS\centering}b{1cm}|p{7cm}|>{\PBS\raggedleft}b{1cm}|>{\PBS\raggedleft}b{1cm}|>{\PBS\raggedleft}b{2cm}|}
"""
			
		else:
			template_presta_head += r"""
\bf Prestation & \bf Réf. & \bf Description & \bf TVA & \bf Mtt HT\\
\hline}
\tabletail{\hline}
\begin{supertabular}[bbbbb]{|p{5.4cm}||>{\PBS\centering}b{1cm}|p{7cm}|>{\PBS\raggedleft}b{1cm}|>{\PBS\raggedleft}b{2cm}|}
"""
			
		template_foot= r"""
\end{supertabular}
\end{flushright}
\end{small}
"""

		# ARTICLES
		req = self.query_article % self.UID
		self.curs.execute(req)

		if self.curs.rowcount>0:
			self.BUFFER_ARTICLES=template_article_head
			
			i=1
			for i in range(self.curs.rowcount):
				res=self.curs.dictfetchone()
				total_ht += res['ca_ht']
				total_ttc += res['ca_ttc']
				
				if res['declinaison'] != '':
					if res['code']:
						ref = '-' + res['declinaison']
					else:
						ref = res['declinaison']
				else:
					ref=''

				if not has_remise_article:
					res['remise'] = ""
				elif not res['remise']:
					res['remise'] = " ~ & "
				else:
					res['remise'] = "%.1f %% & " % res['remise']

				if not res['description']:
					res['description'] = ""
				else:
					res['description'] = " (" + res['description'] + ") "

				if res['ca_ht']==0 and res['ca_ttc']==0:
					tva=0
				else:
					add_tva(res['ca_ht'], res['ca_ttc'])
					tva = (res['ca_ttc'] - res['ca_ht']) / res['ca_ht'] * 100
				self.BUFFER_ARTICLES += res['nom'] + res['description'] + ' & '+ '%s %s & %s %d & %s %s & %.1f %% & %s %s\\\\\n'\
									   % (res['code'] or "", ref, res['remise'], res['quantite'], euro_round_fr(res['ca_ht']/res['quantite']), devise, tva, euro_round_fr(res['ca_ht']), devise)

			self.BUFFER_ARTICLES += template_foot

		# PRESTATIONS
		req = self.query_presta % self.UID
		
		self.curs.execute(req)
		
		if self.curs.rowcount>0:
			self.BUFFER_PRESTA=template_presta_head
			
			i=1
			for i in range(self.curs.rowcount):
				res=self.curs.dictfetchone()
				if not has_remise_presta:
					res['remise'] = ""
				elif not res['remise']:
					res['remise'] = " ~ & "
				else:
					res['remise'] = "%.1f %% & " % res['remise']
					
				total_ht+=res['montant_ht']
				total_ttc+=res['montant_ttc']
				if not res['montant_ht']:
					tva = 0
				else:
					add_tva(res['montant_ht'], res['montant_ttc'])
					tva=(res['montant_ttc'] - res['montant_ht']) / res['montant_ht'] * 100
				self.BUFFER_PRESTA += '%s & %s & \\footnotesize %s & %s %.1f%% & %s %s\\\\\n'\
									   % (res['prestation'] or 'prestation', res['uid'], res['description'] or '~', res['remise'], tva, euro_round_fr(res['montant_ht']), devise)

				# optionnel : description des prestas à part
				if res['prestation']!=None and res['prestation']!='':
					self.BUFFER_DESCRIPTION_PRESTA += "{\\bf %s} - " % res['prestation']
				if res['description']!=None and res['description']!='':
					self.BUFFER_DESCRIPTION_PRESTA += "%s\\\\" % res['description']

			if self.BUFFER_DESCRIPTION_PRESTA != "":
				 self.BUFFER_DESCRIPTION_PRESTA = "\\\\\n{\\bf Descriptif des prestations}\\\\" + self.BUFFER_DESCRIPTION_PRESTA
				 
			self.BUFFER_PRESTA += template_foot
		
		return (total_ht, total_ttc)

	def convertion(self, core):
		out=os.system('convert %s %s.%s > /dev/null 2>&1' % (self.tokens["FICHIER_LOGO"], core, "eps"))
		if out==0:
			self.tokens["FICHIER_LOGO"]= "\\fontsize{6.5pt}{19.2pt}\\selectfont{\\includegraphics[width=4.7cm]{%s.%s}" % (core, "eps")
		else:
			raise 'CONVERT ERROR'
		
		
	def savetexfile(self, output):
		"""Save the buffer in a file in 'output' directory."""
		
		try:
			file = open(output+self.UID+'.tex', 'w')
			#file.write(TeXfilter(self.BUFFER))
			file.write(self.BUFFER)
			file.close()
		except:
			print "Error save TeX file on %s" % output+self.UID+'.tex'
			sys.exit(-1)

		
	def getConnection(self, DBNAME, DBUSER, DBPWD, DBHOST, DBPORT):
		"""Object connection with database.
		It loads the good 'getinfo' according to 'mode'"""
		
		self.con=psycopg.connect("dbname=%s user=%s password=%s host=%s port=%s" % (DBNAME, DBUSER, DBPWD, DBHOST, DBPORT))
		self.curs=self.con.cursor()
		self.con.autocommit()


	def toPDF(self, outputdir, outputfile):
		debug_file=outputdir + "/pimengest2_debug"
		os.chdir(outputdir)
		true_output="%s%s" % (outputfile, self.UID)
		log(debug_file, "\n---\nLATEX SOURCE\n---\n")
		tex_file=open("%s.tex" % true_output, 'r')
		log(debug_file, tex_file)
		log(debug_file, "\n---\nLATEX OUTPUT\n---\n")
		cmd="latex -interaction=nonstopmode %s.tex >> %s 2>&1" % (true_output, debug_file)
		os.system(cmd)
		
		if self.VERBOSE:
			print cmd
		try:
			del(tex_file)
			os.system("latex -interaction=nonstopmode %s.tex > /dev/null 2>&1" % true_output)
		except:
			sys.exit(-1)
		try:
			cmd="dvipdf %s.dvi >> %s 2>&1" % (true_output, debug_file)
			log(debug_file, "\n---\nDVIPDF\n---\n")
			os.system(cmd)
			if self.VERBOSE:
				print cmd
			os.system("rm -rf %s.dvi %s.aux %s.log %s.tex" % (true_output, true_output, true_output, true_output))
		except:
			try:
				cmd="dvips %s.dvi >> %s 2>&1" % (true_output, debug_file)
				log(debug_file, "\n---\nDVIPS\n---\n")
				os.system(cmd)
				if self.VERBOSE:
					print cmd
				cmd="ps2pdf %s.ps >> %s 2>&1"  % (true_output, debug_file)
				log(debug_file, "\n---\nPS2PDF\n---\n")
				os.system(cmd)
				if self.VERBOSE:
					print cmd
				os.system("rm -rf %s.ps > /dev/null 2>&1" % true_output)
			except:
				sys.exit(-1)

		return "%s.pdf" % true_output

def TeXfilter(str):
	for pat, rep in TeXfilter.comp:
		str = pat.sub(rep, str)
	str = str.replace('<-', ' $\\leftarrow$ ')
	str = str.replace('->', ' $\\rightarrow$ ')
	return str
TeXfilter.comp = ((re.compile(r'(?<!\\)_'), r'\_') , (re.compile(r'%(?!#)'), r'\%'))

def add_tva(montant_ht, montant_ttc=0):
	sys.stderr.write(" HT=%s - TTC=%s\n" % (montant_ht, montant_ttc))
	if montant_ttc==0:
		for t in add_tva.taux:
			add_tva.taux[t] *= montant_ht/100
	else:
		ratio = "%.1f" % ((montant_ttc - montant_ht)*100 / montant_ht)
		if not add_tva.taux.has_key(ratio):
			add_tva.taux[ratio] = 0
		add_tva.taux[ratio] += montant_ht
		
add_tva.taux = {}

def log(strfile, msg):
	if not exists(strfile):
		file=open(strfile, 'w+')
	else:
		file=open(strfile, 'a')
		
	if type(msg)==type(''):
		file.write(msg)
		file.write("\n---\n")
	elif type(msg)==type(file):
		file.write(msg.read())
		file.write("\n---\n")
	file.close()
	del(file)

def usage(*args):
	sys.stdout = sys.stderr
	for msg in args: print msg
	sys.exit(-1)

def check_output(output_dir):
	if not exists(output_dir):
		return 0
	else:
		return 1
		
def extract_base(str):
	ret = {'host':'localhost', 'port':'5432'}
	base = str.split('/')
	for str in base:
		f, v = str.split(':')
		if f=='u' : ret['user']=v
		elif f=='d' : ret['base']=v
		elif f=='P' : ret['pass']=v
		elif f=='p' : ret['port']=v
		elif f=='h' : ret['host']=v
	if not ret.has_key('user') or not ret.has_key('pass') or not ret.has_key('base'):
		return 0
	else:
		return ret

	
def get_options():
	"""
	genpdf.py makes a pdf with a latex template and pimengest2 database informations

	* genfacture.py
	* gendevis.py
	* genlettre.py
	
	usage : genXXX.py -u DBUID -l latexdir -f filedir --database=\"database info\"
	        [--without-header | -e header_file] [--without-tab] [--without-pdf] [-t template] [-d outdir]
			
	-u : database uid
	--database=\"u:user/P:pass/d:dbname[/h:host/p:port]\"
	-l : latex template dir
	-f : file dir (from clients' uploads)
	---------------
	--with-header : with header output. header file optional (in src/latex directory)
	--without-tab : don't print the 'article+presta' tabular
	--without-pdf : debug option (does not load toPDF function)
	-t : alternative latex template
	-d : output directory, default is '/tmp/pdf'
	-v : verbose
	-h : help
	"""

	try:
		opts, args = getopt.getopt(sys.argv[1:], 'ht:d:e:m:u:vl:f:', ['without-header', 'without-tab', 'without-pdf', 'database='])
	except getopt.error, msg:
		usage(msg)

	options={'WITH_ENTETE':1, 'WITH_PDF':1, 'UID':'', 'TEMPLATE':'', 'OUTDIR':'/tmp/pdf', 'LATEXDIR':'', 'FILEDIR':'', 'VERBOSE':0, 'AFFICHAGE_TAB':1, 'DATABASE':''}
	
	for o, a in opts:
		if o == '-u': options['UID']=a
		elif o == '-l': options['LATEXDIR']=a
		elif o == '-f': options['FILEDIR']=a
		elif o == '--database': options['DATABASE']=a;
		elif o == '--without-header':  options['WITH_ENTETE']=0
		elif o == '--without-tab': options['AFFICHAGE_TAB']=0
		elif o == '--without-pdf': options['WITH_PDF']=0
		elif o == '-h': usage(get_options.__doc__)
		elif o == '-t': options['TEMPLATE']=a
		elif o == '-d': options['OUTDIR']=a
		elif o == '-v': options['VERBOSE']=1


	if options['DATABASE']=='' or options['LATEXDIR']=='' or options['FILEDIR']=='':
		usage(get_options.__doc__)

		
	if not exists(options['LATEXDIR']) and options['WITH_ENTETE']==1:
		print " *** Can't find %s ***\n" % options['LATEXDIR']
		usage(get_options.__doc__)
		
	if options['UID']=='':
		usage(get_options.__doc__)

	return options

if __name__ == '__main__':
	print get_options()

