# -*- coding: latin-1 -*-
""" 
   Copyright (C) 1999-2006 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.	
"""

from Products.PimenTechLibCommon.map import *
from Products.PimenTechLibCommon.sqlcommon import *

import sys
from string import *
from cStringIO import StringIO

from Globals import HTMLFile
from Globals import MessageDialog
from OFS.SimpleItem import SimpleItem
from DateTime import DateTime

const_dateTime = DateTime()

def manage_addRow(self, id, tablename, uid, REQUEST=None):
	"Add a Row to a folder."
	row = Row(id, tablename, uid)
	self._setObject(id, row)
	if REQUEST is not None:
		return self.manage_main(self, REQUEST)

try:
	manage_addRowForm = HTMLFile('dtml/rowAdd', globals()) 
except:
	pass

class CommonRow:
	""" This a abstract class for Row and VRow
	* id : row label
	* map : {key : value} of the row
	* tablename : name of the table. must be present in pgmlgraph
	* pgmlgraph : mus be present in aq
	"""

	meta_type = None

	def __init__(self, id, tablename, uid=None, approot=None):
		self.id = id 
		self.tablename = tablename
		if uid is None:
			self.uid = int(id)
		else:
			self.uid = int("%s" % uid)
		if approot is None:
			self.approot = self
		else:
			self.approot = approot # for VRow
			
		self.title = '%s(%s)' % (self.tablename, self.uid)
		self._to_be_commited = 0

	def __getitem__(self, key):
		try:
			return self.data[key]
		except: # trash man
			self.update()
		
		return self.data[key]

	def _names_values_quoted(self, fields_overload={}):
		"""
		Retourne la chaine prop1='val1',...,propn='valn'
		(pour construire l'update)
		"""
		ovrld_keys = fields_overload.keys()
		res = ''
		for key in self.approot.pgmlgraph[self.tablename].object.get_fields():
			if key in ovrld_keys:
				value = fields_overload[key]
			else:
				value = self[key]
			if type(value) == type(const_dateTime):
				value = "%s" % value	
				if len(value)!=10:
					value = value[:-6] # vire GMT+2 (pb posgresql)					
			#if value is not None:
			res += "%s=%s," % (key, sqlFilter(value))
		return res[:-1]

	def set_from_form(self, REQUEST):
		"set_from_form."
		for key,value in REQUEST.form.items():
			if self.has_key(key):
				self[key] = value
		self.commit()
		REQUEST.RESPONSE.redirect('manage_main')

	def update(self, REQUEST=None):
		"maj à partir de pg"
		curs = self.approot.get_cursor()
		sel_fields = self.approot.pgmlgraph[self.tablename].object.get_fields()
		curs.execute("select %s from %s where uid=%s" % (join(sel_fields,','), self.tablename, self.uid))
		if curs.rowcount == 0:
			self.approot.error("table %s : uid %s does not exists" % (self.tablename, self.uid))
		elif curs.rowcount > 1:
			self.approot.warning("table %s : %s rows for uid %s" % (self.tablename, curs.rowcount, self.uid))
		for key, value in curs.dictfetchone().items():
			#self.approot.message("%s (Row)%s.update() : self[%s]=%s" % (self.meta_type, self.getId(), key, value))
			self[key] = value
			
		self._p_changed = 1
		self._to_be_commited = 0
		
		if REQUEST is not None:
			return MessageDialog(
				title = 'Modification effectuée',
				message = "Les paramètres ont été modifiés avec succès.",
				action = 'index_html',
				)

	def _copy(self, ref, dict_option, REQUEST, tablename=None):
		" duplication in postgresql "
		tablename = tablename or self.tablename

		dict_values = {}
		for key in self.approot.pgmlgraph[tablename].object.get_fields():
			if key not in ('uid', 'datecrea', 'datemodif', 'authcrea', 'authmodif', 'codecrea', 'codemodif'):
				if key == 'zid':
					try:
						int(self['zid'])
						dict_values['zid'] = ref
						continue
					except:
						pass
				dict_values[key] = self[key]
				
		for key, value in dict_option.items():
			dict_values[key] = value
		dict_values['uid'] = ref
		dict_values['codecrea'] = self._get_code_log()
		dict_values['datecrea'] = DateTime()
		dict_values['authcrea'] = self.approot.get_ref_author(REQUEST)
		dict_values['frozen'] = 1
		query = '%s;' % sql_insert(tablename, dict_values)
		self.message('copy query = %s' % query)
		curs = self.approot.get_cursor()
		self.approot.exec_vital_sql(query, curs)

		# update ref_object history
		self['ref_object'] = int(ref)

	def pg_differs(self, REQUEST=None):
		"returns 1 if pg values != zodb values"
		curs = self.approot.get_cursor()
		sel_fields = self.approot.pgmlgraph[self.tablename].object.get_fields()
		curs.execute("select %s from %s where uid=%s" % (join(sel_fields,','), self.tablename, self.uid))
		if curs.rowcount == 0:
			self.approot.error("table %s : uid %s does not exists" % (self.tablename, self.uid))
		elif curs.rowcount > 1:
			self.approot.warning("table %s : %s rows for uid %s" % (self.tablename, curs.rowcount, self.uid))
		for key, value in curs.dictfetchone().items():
			self.approot.message("%s (Row)%s.update() : self[%s]=%s" % (self.meta_type, self.getId(), key, value))
			if self[key] != value:
				return 1
		return 0

	def commit(self, fields_overload={}):
		"commit en base"
		if not self._to_be_commited:
			return
		curs = self.approot.get_cursor()
		query = "update %s set %s where uid=%s" % (self.tablename, self._names_values_quoted(fields_overload), self.uid)
		res = self.approot.exec_vital_sql(query, curs)
		if curs.rowcount != 1:
			self.approot.error('update error : %s rows affected for query :\n%s' % (curs.rowcount, query))
			return None
		else:
			self.approot.notice("row.commit : %s" % query)

		self.approot._to_be_commited = 0
		return res

	def insert(self):
		"insert (quand creation depuis l'interface)"
		if self.approot.fetch("select uid from %s where uid=%s" % (self.tablename, self.uid)):
			error = "%s uid %s deja en base" % (self.tablename, self.uid)
			self.approot.error(error)
			raise error
		query = "insert into %s (uid) values (%s);" % (self.tablename, self.uid)
		self.approot.exec_vital_sql(query)
		# init row fields
		for key in self.approot.pgmlgraph[self.tablename].object.get_fields():
			if not self.has_key(key):
				default = self.approot.pgmlgraph[self.tablename].object.get_field(key)['default']
				if default == 'now()' and self.approot.pgmlgraph[self.tablename].object.get_field(key)['type'] in ('date', 'timestamp'):
						self[key] = DateTime()
				else:
					self[key] = unSqlFilter(default)

	def create(self):
		"DEPRECATED : use update or insert methode"
		if not self.approot.fetch("select uid from %s where uid=%s" % (self.tablename, self.uid)):
			self.approot.insert()
		self.approot.update()
		
	def check_field(self, key):
		"check the existence of a field for a table in pgml file"
		if not self.approot.pgmlgraph[self.tablename].object.get_field(key):
			raise "champ %s inconnu dans la table %s pour le pgml" % (key, self.tablename)
		
class Row(CommonRow, PDictMap):
	" Persistent Row "

	meta_type = 'Row'

	# for zope2.6 / python 2.1
	__PDictMap_init = PDictMap.__init__
	__CommonRow_init = CommonRow.__init__

	def __init__(self, id, tablename, uid=None):
		self.__PDictMap_init(id)
		self.__CommonRow_init(id, tablename, uid, None)
	
	def __setitem__(self, key, value):		
		self.check_field(key)		
		PDictMap.__setitem__(self, key, value)
		self._to_be_commited = 1
		
	
class VRow(CommonRow, DictMap):
	" Volatile Row "

	meta_type = 'VRow'

	def __init__(self, id, approot, tablename, uid=None, props = {}):
		DictMap.__init__(self, id)
		CommonRow.__init__(self, id, tablename, uid, approot)

		for key, value in props.items():
			if key != 'uid':
				self[key] = value

	def __setitem__(self, key, value):
		self.check_field(key)		
		DictMap.__setitem__(self, key, value)
		self._to_be_commited = 1
		
	def insert(self, REQUEST):
		CommonRow.insert(self)
		self['codecrea'] = self._get_code_log()
		self['datecrea'] = DateTime()
		self['authcrea'] = self.approot.get_ref_author(REQUEST)
		self['zid'] = self.getId()
		return CommonRow.commit(self)

	def commit(self, REQUEST, fields_overload={}):
		self['codemodif'] = self._get_code_log()
		self['datemodif'] = DateTime()
		self['authmodif'] = self.approot.get_ref_author(REQUEST)
		return CommonRow.commit(self, fields_overload)



class PRow(Row):
	" A better Row object but depends of database model "

	map_setitem = DictMap.__setitem__
	row_commit = Row.commit
	row_insert = Row.insert
	type_string = type('')

	def __setitem__(self, key, value):
		"""
		 * check if key exits
		 * cast the value for int and float or set None
		 * check datetime type
		"""
		self.check_field(key)
		if value != None:
			pg_type = self.approot.pgmlgraph[self.tablename].object.get_field(key)['type']
			if value == '' and pg_type != self.type_string:
				value = None
			elif pg_type in ('int', 'int4'):
				value = int(value)
			elif pg_type in ('float', 'float8'):
				value = float(value)
			elif pg_type in ('date', 'timestamp'):
				if type(value) != type(const_dateTime):
					raise "Error : %s found on field %s (DateTime expected)" % (type(value), key)
		self.map_setitem(key, value)
		self._to_be_commited = 1
		
	def insert(self):
		self.row_insert()
		self['codecrea'] = self._get_code_log()
		self['datecrea'] = DateTime()
		self['authcrea'] = self.get_ref_author(self.getOwner().getUserName())
		self['zid'] = self.aq_parent.getId()
		return self.row_commit()

	def commit(self, REQUEST, fields_overload={}):
		self['codemodif'] = self._get_code_log()
		self['datemodif'] = DateTime()
		self['authmodif'] = self.get_ref_author(REQUEST)
		return self.row_commit(fields_overload)



