# -*- encoding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#                    Fabien Pinckaers <fp@tiny.Be>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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 base64, os, string

import netsvc
import sql_db, security, ir, tools
import logging

import threading, thread

import time

logging.basicConfig()

#TODO: use translation system
def _(str):
	return str

class common(netsvc.Service):
	def __init__(self,name="common"):
		netsvc.Service.__init__(self,name)
		self.joinGroup("web-services")
		self.exportMethod(self.ir_get)
		self.exportMethod(self.ir_set)
		self.exportMethod(self.ir_del)
		self.exportMethod(self.about)
		self.exportMethod(self.login)

	def ir_set(self, uid, password, keys, args, name, value, replace=True, isobject=False):
		security.check(uid, password)
		cr = sql_db.db.cursor()
		res = ir.ir_set(cr,uid, keys, args, name, value, replace, isobject)
		cr.commit()
		cr.close()
		return res

	def ir_del(self, uid, password, id):
		security.check(uid, password)
		cr = sql_db.db.cursor()
		res = ir.ir_del(cr,uid, id)
		cr.commit()
		cr.close()
		return res

	def ir_get(self, uid, password, keys, args=[], meta=None, context={}):
		security.check(uid, password)
		cr = sql_db.db.cursor()
		res = ir.ir_get(cr,uid, keys, args, meta, context)
		cr.commit()
		cr.close()
		return res

	def login(self, login, password):
		logger = netsvc.Logger()
		cr = sql_db.db.cursor()
#FIXME: this is a temporary fix for the crash on login/password with non ASCII chars. 
#We should fix this in a better way (ie somewhere else)
		cr.execute('select id from res_users where login=%s and password=%s', (login.encode('utf-8'), password.encode('utf-8')))
		res = cr.fetchone()
		msg = res and 'successful login' or 'bad login or password'
		logger.notifyChannel("web-service", netsvc.LOG_INFO, '%s from %s' % (msg, login))
		cr.close()
		return (res and res[0]) or False

	def about(self):
		return tools.version_string + _('''

Tiny ERP is an ERP+CRM program for small and medium businesses.

The whole source code is distributed under the terms of the
GNU Public Licence.

(c) 2003-TODAY, Fabien Pinckaers - Tiny sprl''')
common()

class objects_proxy(netsvc.Service):
	def __init__(self, name="object"):
		netsvc.Service.__init__(self,name)
		self.joinGroup('web-services')
		self.exportMethod(self.execute)
		self.exportMethod(self.exec_workflow)
		self.exportMethod(self.obj_list)
		
	def exec_workflow(self, uid, passwd, object, method, id):
		security.check(uid, passwd)
		service = netsvc.LocalService("object_proxy")
		res = service.exec_workflow(uid, object, method, id)
		return res
		
	def execute(self, uid, passwd, object, method, *args):
		security.check(uid, passwd)
		service = netsvc.LocalService("object_proxy")
		res = service.execute(uid, object, method, *args)
		return res

	def obj_list(self, uid, passwd):
		security.check(uid, passwd)
		service = netsvc.LocalService("object_proxy")
		res = service.obj_list()
		return res
objects_proxy()


#
# Wizard ID: 1
#    - None = end of wizard
#
# Wizard Type: 'form'
#    - form
#    - print
#
# Wizard datas: {}
# TODO: change local request to OSE request/reply pattern
#
class wizard(netsvc.Service):
	def __init__(self, name='wizard'):
		netsvc.Service.__init__(self,name)
		self.joinGroup('web-services')
		self.exportMethod(self.execute)
		self.exportMethod(self.create)
		self.id = 0
		self.wiz_datas = {}
		self.wiz_name = {}
		self.wiz_uid = {}

	def _execute(self, uid, wiz_id, datas, action, context):
		self.wiz_datas[wiz_id].update(datas)
		wiz = netsvc.LocalService('wizard.'+self.wiz_name[wiz_id])
		return wiz.execute(uid, self.wiz_datas[wiz_id], action, context)

	def create(self, uid, passwd, wiz_name, datas={}):
		security.check(uid, passwd)
#FIXME: this is not thread-safe
		self.id += 1
		self.wiz_datas[self.id] = {}
		self.wiz_name[self.id] = wiz_name
		self.wiz_uid[self.id] = uid
		return self.id

	def execute(self, uid, passwd, wiz_id, datas, action='init', context={}):
		security.check(uid, passwd)

		if wiz_id in self.wiz_uid:
			if self.wiz_uid[wiz_id] == uid:
				return self._execute(uid, wiz_id, datas, action, context)
			else:
				raise 'AccessDenied'
		else:
			raise 'WizardNotFound'
wizard()

#
# TODO: set a maximum report number per user to avoid DOS attacks
#
# Report state:
#     False -> True
#
class report_spool(netsvc.Service):
	def __init__(self, name='report'):
		netsvc.Service.__init__(self, name)
		self.joinGroup('web-services')
		self.exportMethod(self.report)
		self.exportMethod(self.report_get)
		self._reports = {}
		self.id = 0
		self.id_protect = threading.Semaphore()

	def report(self, uid, passwd, object, ids, datas={}, context={}):
		security.check(uid, passwd)
		
		self.id_protect.acquire()
		self.id += 1
		id = self.id
		self.id_protect.release()

		self._reports[id] = {'uid': uid, 'result': False, 'state': False}

		def go(id, uid, ids, datas, context):
			obj = netsvc.LocalService('report.'+object)
			(result, format) = obj.create(uid, ids, datas, context)
			self._reports[id]['result'] = result
			self._reports[id]['format'] = format
			self._reports[id]['state'] = True
			return True

		thread.start_new_thread(go, (id, uid, ids, datas, context))
		return id

	def _check_report(self, report_id):
		result = self._reports[report_id]
		res = {'state': result['state']}
		if res['state']:
			if tools.config['reportgz']:
				import zlib
				res2 = zlib.compress(result['result'])
				res['code'] = 'zlib'
			else:
				#CHECKME: why is this needed???
				if isinstance(result['result'], unicode):
					res2 = result['result'].encode('latin1', 'replace')
				else:
					res2 = result['result']
			res['result'] = base64.encodestring(res2)
			res['format'] = result['format']
			del self._reports[report_id]
		return res

	def report_get(self, uid, passwd, report_id):
		security.check(uid, passwd)

		if report_id in self._reports:
			if self._reports[report_id]['uid'] == uid:
				return self._check_report(report_id)
			else:
				raise 'AccessDenied'
		else:
			raise 'ReportNotFound'

report_spool()

# vim:noexpandtab
