# -*- coding: latin-1 -*-
""" 
   Copyright (C) 2001-2004 PimenTech SARL (http://www.pimentech.net)

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library 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.	
"""

__version__='$Revision: 1.170 $'[11:-2]


from Globals import HTMLFile	  
from Globals import MessageDialog
from OFS.Folder import *
from DateTime import *

from string import *
from cStringIO import StringIO
import traceback

from Products.PimenTechLibCommon.map import *
from Products.PimenTechLibCommon.dbp import *
from Products.PimenTechLibCommon.row import *
from Products.PimenTechLibCommon.age import *

import htmlentitydefs
import re

# this pattern matches substrings of reserved and non-ASCII characters
#
pattern_all = re.compile(r"[&<>\"\x80-\xff]+")
pattern = re.compile(r"[\x80-\xff]+")
# create character map
entity_map = {}
for i in range(256):
	entity_map[chr(i)] = "&%d;" % i
for entity, char in htmlentitydefs.entitydefs.items():
	if entity_map.has_key(char):
		entity_map[char] = "&%s;" % entity

def escape_entity(m, get=entity_map.get):
	return join(map(get, m.group()), "")

def escape_html(string):
	return pattern.sub(escape_entity, string)

def escape_all_html(string):
	return pattern_all.sub(escape_entity, string)

compiled = re.compile(r'<.*?>')

def html_to_txt(msg):
	"convertie du html en ascii"
	msg = msg.replace(r'<br>', '\n')
	msg = compiled.sub('', msg)
	msg = msg.replace(r'&gt;', '>')
	msg = msg.replace(r'&lt;', '<')
	msg = msg.replace(r'&amp;', '&')
	msg = msg.replace(r'&nbsp;', ' ')
	msg = msg.replace(r'&eacute;', 'é')
	msg = msg.replace(r'&egrave;', 'è')
	msg = msg.replace(r'&ecirc;', 'ê')
	msg = msg.replace(r'&agrave;', 'à')
	return msg

def implementedSQLConnectionIDs(self):
	"""
	Find SQL database connections in the current folder and above
	This function return a list of ids.
	Shameless stolen (with little modifications) from SQL.py
	"""

	ids={}
	have_id=ids.has_key
	StringType=type('')

	while self is not None:
		if hasattr(self, 'objectValues'):
			for o in self.objectValues():
				if (hasattr(o,'_isAnSQLConnection') and o._isAnSQLConnection
					and hasattr(o,'id')):
					id=o.id
					if type(id) is not StringType: id=id()
					if not have_id(id):
						if hasattr(o,'title_and_id'): o=o.title_and_id()
						else: o=id
						ids[id]=id
		if hasattr(self, 'aq_parent'): self=self.aq_parent
		else: self=None

	ids=map(lambda item: (item[1], item[0]), ids.items())
	ids.sort()
	return ids


def manage_addAppRoot(self, id, connection_id, REQUEST=None):
	"Add a AppRoot to a folder."
	cr = AppRoot(id, connection_id)
	self._setObject(id, cr)
	if REQUEST is not None:
		return self.manage_main(self, REQUEST)

try:
	manage_addAppRootForm = HTMLFile('dtml/appRootAdd', globals())
except:
	pass

class AppRoot(DBP, Map):
	"""
	AppRoot Class
	"""
	
	meta_type = 'AppRoot'

	try:
		#manage_options = Folder.manage_options
		my_manage_tabs = HTMLFile('dtml/my_manage_tabs', globals())
	except:
		pass

	dict_uid_nom = {}
	dict_uid_nom_html = {}
	dict_nom_uid = {}

	def __init__(self, id, connection_id):
		Map.__init__(self, id)
		self.conn = None	 
		self.connection_id = connection_id


	def escape_html(self, string):
		"Rempace les caractères accentués par des entités"
		return pattern.sub(escape_entity, string)
	
	def reset_cache(self):
		"reset dictionnary cache"
		self.dict_uid_nom = {}
		self.dict_uid_nom_html = {}
		self.dict_nom_uid = {}
		
	def root_app(self):
		"Utilise pour retrouver la racine de l'appli"
		return self

	def load_table(self, tablename, indefini='indefini'):
		"Charge une table entité dans les dico dict_uid_nom et dic_nom_uid"
		self.dict_nom_uid[tablename] = {}
		self.dict_uid_nom[tablename] = {}	
		self.dict_uid_nom_html[tablename] = {}	
		for (uid, nom) in self.fetch("select uid, nom from %s" % tablename):
			self.dict_nom_uid[tablename][nom] = uid
			self.dict_uid_nom[tablename][uid] = nom
			self.dict_uid_nom_html[tablename][uid] = escape_html(nom)
		self.dict_nom_uid[tablename][indefini] = 0
		self.dict_uid_nom[tablename][0] = indefini
		self.dict_uid_nom_html[tablename][0] = indefini
		self._p_changed = 1

	def get_nom(self, tablename, uid=1):
		"Renvoie le nom"
		if uid is None:
			return ''
		if not self.dict_uid_nom.has_key(tablename):
			self.load_table(tablename)
		return self.dict_uid_nom[tablename].get(uid, 'Erreur')

	def get_nom_html(self, tablename, uid=1):
		"Renvoie le nom"
		if uid is None:
			return ''
		if not self.dict_uid_nom_html.has_key(tablename):
			self.load_table(tablename)
		return self.dict_uid_nom_html[tablename].get(uid, 'Erreur')

	def get_uid(self, tablename, nom):
		"Renvoie l'uid.."
		if not self.dict_nom_uid.has_key(tablename):
			self.load_table(tablename)
		return self.dict_nom_uid[tablename][nom]

	def get_new_uid(self):
		res = self.fetch("select nextval('object_uid_seq')")
		return int(res[0][0])


	def view_table(self, name):
		"pour debug"
		if self.dict_uid_nom.has_key(name):
			return `self.dict_uid_nom[name]`
		return "yapa"

	def zope_class(self, meta_type):
		"""
		return a reference to zope 'instance class' corresponding to
		meta_type :
		obj = zope_class('Folder')('an_id')
		is equivalent to
		from OFS.Folder import Folder
		obj = Folder('an_id')
		"""
		meta_types = []
		for d in self.all_meta_types():
			cur_meta_type = d['name']
			if meta_type == cur_meta_type:
				return d['instance']
			meta_types.append(cur_meta_type)
		raise "meta_type '%s' unknown :<br>\n%s" % (meta_type, meta_types)

	def _set_property(self, name, value, type='string'):
		"""
		shortcut to PropertyManager methods.
		_set_property do a setattr and fill the _property dict,
		usable in manage_propertiesForm tab
		"""
		if self.hasProperty(name):
			self._updateProperty(name, value)
		else:
			self._setProperty(name, value, type)

	def get_users(self, node):
		"Liste des utilisateurs présents ds l'aquisition"
		users = []
		for object in node.aq_chain:
			if hasattr(object, 'acl_users'):
				users += object['acl_users'].getUsers()
		return users
	
	def set_user(self, acl_users, login, pwd, roles, domains=0):
		"Ajoute un utilisateur"
		if acl_users.getUser(login):
			return acl_users._changeUser(login, pwd, pwd, roles, domains)
		else:
			return acl_users._addUser(login, pwd, pwd, roles, domains)

	def del_user(self, acl_users, login):
		"Supprime un utilisateur"
		acl_users._delUsers((login,))

	def html_select(self, tablename, input_name, default_value=0):
		"Construit une liste de sélection HTML"
		str = '<select name="%s:int">\n' % input_name
		if not default_value:
			default_value = 0
		if not self.dict_uid_nom_html.has_key(tablename):
			self.load_table(tablename)
		uids = self.dict_uid_nom_html[tablename].keys()
		uids.sort()
		for uid in uids:
			if default_value == uid:
				selected = ' selected'
			else:
				selected = ''
			str += '<option value="%s"%s>%s</option>\n' % (uid, selected, self.dict_uid_nom_html[tablename][uid])
		return '%s\n</select>' % str

	def xhtml_select(self, tablename, input_name, default_value=0):
		"Construit une liste de sélection HTML"
		str = '<select name="%s:int">\n' % input_name
		if not default_value:
			default_value = 0
		if not self.dict_uid_nom_html.has_key(tablename):
			self.load_table(tablename)
		uids = self.dict_uid_nom_html[tablename].keys()
		uids.sort()
		for uid in uids:
			if default_value == uid:
				selected = ' selected="selected"'
			else:
				selected = ''
			str += '<option value="%s"%s>%s</option>\n' % (uid, selected, self.dict_uid_nom[tablename][uid])
		return '%s\n</select>' % str

	def date_dict(self, dict):
		"Renvoie une date à partir du dico"
		return DateTime(dict.get('annee',0), dict.get('mois', 0), dict.get('jour', 0),
						dict.get('heure', 0), dict.get('minute', 0), dict.get('seconde', 0))

	def dateEditHTML(self, date_default, name, checked=None):
		"""
		Renvoie un select HTML avec la date passée en paramètre préselectionnée
		checked None  =>  no checkbox
		checked 0  =>  empty checkbox
		checked 1  =>  checked checkbox
		"""
		output_html = ''

		if checked is not None:
			output_html = '<input type="checkbox" name="date_%s.check:record" value="%s" onclick="actionClick()"' % (name, name)
			if checked:
				output_html += " checked"
			output_html += '>\n'
		txt_option_sel = '<option value="%d" selected="selected">%d</option>\n'
		txt_option = '<option value="%d">%d</option>\n'
		# jour
		output_html += '<select name="date_%s.jour:record:int">\n' % name
		for jour in range(1,32):
			if jour == date_default.day():
				output_html += txt_option_sel % (jour, jour)
			else:
				output_html += txt_option % (jour, jour)
		output_html += '</select>/\n'
		# mois
		output_html += '<select name="date_%s.mois:record:int">\n' % name
		for mois in range(1,13):
			if mois == date_default.month():
				output_html += txt_option_sel % (mois, mois)
			else:
				output_html += txt_option % (mois, mois)
		output_html += '</select>/\n'
		# annee
		this_year = DateTime().year() - 2
		output_html += '<select name="date_%s.annee:record:int">\n' % name
		for annee in range(this_year, this_year + 7):
			if annee == date_default.year():
				output_html += txt_option_sel % (annee, annee)
			else:
				output_html += txt_option % (annee, annee)
		output_html += '</select>\n'
		return output_html
		
	def dateNowMoinsToHTML(self, jours_avant, name):
		"Renvoie un select HTML avec la date du jour moins N jours préselectionnée"
		return self.dateEditHTML(DateTime() - jours_avant, name, 0)
	
	def datetimeEditHTML(self, date_default, name, checked=None):
		"Renvoie un select HTML avec la date et une heure préselectionnées"
		
		txt_option_sel = '<option value="%d" selected="selected">%d</option>\n'
		txt_option = '<option value="%d">%d</option>\n'

		output_html = self.dateEditHTML(date_default, name, checked)
		output_html += ' - '
		# hour
		output_html += '<select name="date_%s.heure:record:int">\n' % name
		for heure in range(0,24):
			if heure == date_default.hour():
				output_html += txt_option_sel % (heure, heure)
			else:
				output_html += txt_option % (heure, heure)
		output_html += '</select>H\n'

		# minute
		output_html += '<select name="date_%s.minute:record:int">\n' % name
		for minute in range(0,60,5):
			if minute == date_default.minute():
				output_html += txt_option_sel % (minute, minute)
			else:
				output_html += txt_option % (minute, minute)
		output_html += '</select>\n'

		return output_html

	def datetimeNowMoinsToHTML(self, hours_before, name, checked=0):
		"Renvoie un select HTML avec la date du jour moins N heures"
		return self.datetimeEditHTML(DateTime() - (1.0/24)*hours_before, name, checked)

	def datetimeDiffToHTML(self, day, day_ref, name, checked=1, lang='fr'):
		"Cacul la différence entre"

		txt_option_sel = '<option value="%d" selected="selected">%s</option>\n'
		txt_option = '<option value="%d">%s</option>\n'	

		if lang=='en':
			time_c = en_time
		else:
			time_c = fr_time

		diff = Age(day, 1, day_ref)
		age = diff.getAge()[diff.getFirst()-1]

		# activate
		output_html = '<input type="checkbox" name="datediff_%s.check:record" value="%s" onclick="actionClick()"' % (name, name)
		if checked:
			output_html += " checked"
		output_html += '>\n'
		
		# num
		output_html += '<input type="text" size="2" name="datediff_%s.num:record:int" value="%s" />\n' % (name, age)
		
		# unit
		output_html += '<select name="datediff_%s.unit:record:int" onclick="actionClick()">\n' % name
		for i in range(len(time_c)):
			# RESTRICT TO day, hour, minute
			if i in [2, 3, 4]:
				if i == diff.getFirst()-1:
					output_html += txt_option_sel % (i, time_c[i][0])
				else:
					output_html += txt_option % (i, time_c[i][0])
		output_html += '</select>\n'
		
		return output_html

	def datetimeDiffDefaultToHTML(self, name, lang='fr'):
		"valeur par defaut de datetimeDiffToHTML"
		txt_option_sel = '<option value="%d" selected="selected">%s</option>\n'
		txt_option = '<option value="%d">%s</option>\n'
		
		if lang=='en':
			time_c = en_time
		else:
			time_c = fr_time

		output_html = '<input type="checkbox" name="datediff_%s.check:record" value="%s" onclick="actionClick()">' % (name, name)
		output_html += '<input type="text" size="2" name="datediff_%s.num:record:int" value="%s" />\n' % (name, 1)
		output_html += '<select name="datediff_%s.unit:record:int" onclick="actionClick()">\n' % name
		for i in range(len(time_c)):
			# RESTRICT TO day, hour, minute
			if i in [2, 3, 4]:
				if i == 3: #hour
					output_html += txt_option_sel % (i, time_c[i][0])
				else:
					output_html += txt_option % (i, time_c[i][0])
		output_html += '</select>\n'
		
		return output_html
	
	def datetimeDiffExploit(self, date_ref, num, unit):
		"exploit values of datetimeDiffToHTML return DateTime object"
		year = date_ref.year()
		month = date_ref.month()
		day = date_ref.day()
		hour = date_ref.hour()
		minute = date_ref.minute()
		second = date_ref.second()

		# RESTRICT TO day, hour, minute
		year_less = month_less = hour_less = day_less = 0
		
		if unit == 4:
			minute = date_ref.minute()-num
			num = 0
			while minute < 0:
				minute += 60
				hour_less += 1
		if unit == 3 or hour_less:
			hour = date_ref.hour() - num - hour_less
			num = 0
			while hour < 0:
				hour += 24
				day_less += 1
		if unit == 2 or day_less:
			day = date_ref.day() - num - day_less
			num = 0
			while day <= 0:
				month -= 1 #month before
				if is_bissextile(year):
					day += day_month_bis[month-1]
				else:
					day += day_month[month-1]
		while month <= 0:
			month += 12
			year_less += 1
		year -= year_less
			
		return DateTime(year, month, day, hour, minute, second)
	
	def add_row(self, container, uid, table_name, id=None):
		"Add a row to container and fill it with pg values"
		if id is None:
			id = table_name
		try:
			row = Row(id, table_name, uid)
		except:
			fp = StringIO()
			traceback.print_exc(file=fp)
			error = fp.getvalue()
			self.Log.error(error)
			self.rollback_connection()
			raise """Erreur :<br>\n%s<br> (L'administrateur vient d'être prévenu de cette erreur)""" % error
			return None
		container[id] = row
		return container[id].update()

	def create_row(self, container, uid, table_name, id=None):
		if id is None:
			id = table_name
		row = Row(id, table_name, uid)
		container[id] = row
		container[id].create() # insert en base avec uid row.id
		
	def rangeHTML(self, name, value, begin, end, inter=1):
		"Renvoie un select HTML d'entier dans l'intervalle [begin..end]"
		
		txt_option_sel = '<option value="%d" selected="selected">%d</option>\n'
		txt_option = '<option value="%d">%d</option>\n'
		
		output_html = '<select name="%s:int">\n' % name
		for i in range(begin, end, inter):
			if i==value:
				output_html += txt_option_sel % (i, i)
			else:
				output_html += txt_option % (i, i)
		output_html += '</select>\n'
		return output_html

