##############################################################################
#
# Copyright (c) 2004 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 time, os

import netsvc
import report,sql_db,tools


def graph_get(cr, graph, wkf_id, nested=False, workitem={}):
	import pydot
	cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,))
	nodes = cr.dictfetchall()
	activities = {}
	actfrom = {}
	actto = {}
	for n in nodes:
		activities[n['id']] = n
		if n['subflow_id'] and nested:
			cr.execute('select * from wkf where id=%d', (n['subflow_id'],))
			wkfinfo = cr.dictfetchone()
			graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize=10, label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv'])
			(s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem)
			graph.add_subgraph(graph2)
			actfrom[n['id']] = s2
			actto[n['id']] = s1
		else:
			args = {}
			if n['flow_start'] or n['flow_stop']:
				args['style']='filled'
				args['color']='lightgrey'
			args['label']=n['name']
			if n['subflow_id']:
				args['shape'] = 'box'
			if n['id'] in workitem:
				args['label']+='\\nx '+str(workitem[n['id']])
				args['color'] = "red"
			graph.add_node(pydot.Node(n['id'], **args))
			actfrom[n['id']] = (n['id'],{})
			actto[n['id']] = (n['id'],{})
	cr.execute('select * from wkf_transition where act_from in ('+','.join(map(lambda x: str(x['id']),nodes))+')')
	transitions = cr.dictfetchall()
	for t in transitions:
		args = {}
		args['label'] = str(t['condition'])
		if t['signal']:
			args['label'] += '\\n'+str(t['signal'])
			args['style'] = 'bold'

		if activities[t['act_from']]['split_mode']=='AND':
			args['arrowtail']='box'
		elif str(activities[t['act_from']]['split_mode'])=='OR ':
			args['arrowtail']='inv'

		if activities[t['act_to']]['join_mode']=='AND':
			args['arrowhead']='crow'

		activity_from = actfrom[t['act_from']][1].get(t['signal'], actfrom[t['act_from']][0])
		activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0])
		graph.add_edge(pydot.Edge( activity_from ,activity_to, fontsize=8, **args))
	nodes = cr.dictfetchall()
	cr.execute('select id from wkf_activity where flow_start=True and wkf_id=%d limit 1', (wkf_id,))
	start = cr.fetchone()[0]
	cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%d", (wkf_id,))
	stop = cr.fetchall()
	stop = (stop[0][1], dict(stop))
	return ((start,{}),stop)


def graph_instance_get(cr, graph, inst_id, nested=False):
	workitems = {}
	cr.execute('select * from wkf_instance where id=%d', (inst_id,))
	inst = cr.dictfetchone()

	def workitem_get(instance):
		cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%d group by act_id', (instance,))
		workitems = dict(cr.fetchall())

		cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,))
		for (subflow_id,) in cr.fetchall():
			workitems.update(workitem_get(subflow_id))
		return workitems
	graph_get(cr, graph, inst['wkf_id'], nested, workitem_get(inst_id))

#
# TODO: pas clean: concurrent !!!
#

class report_graph_instance(object):
	def __init__(self, uid, ids, data):
		try:
			import pydot
		except Exception,e:
			print 'Import Error for pydot, you will not be able to render workflows'
			print 'Consider Installing PyDot or dependencies: http://dkbza.org/pydot.html'
			raise e
		self.done = False

		try:
			cr = sql_db.db.cursor()
			cr.execute('select * from wkf where osv=%s limit 1', (data['model'],))
			wkfinfo = cr.dictfetchone()
			cr.execute('select id from wkf_instance where res_id=%d and wkf_id=%d order by state limit 1', (data['id'],wkfinfo['id']))
			inst_id = cr.fetchone()[0]

			graph = pydot.Dot(fontsize=16, label="\\n\\nWorkflow: %s\\n OSV: %s" % (wkfinfo['name'],wkfinfo['osv']))
			graph_instance_get(cr, graph, inst_id, data.get('nested', False))
			ps_string = graph.create_ps(prog='dot')
		except:
			# string is in PS, like the success message would have been
			ps_string = '''%PS-Adobe-3.0
/inch {72 mul} def
/Times-Roman findfont 50 scalefont setfont
1.5 inch 15 inch moveto
(No workflow available) show
showpage'''
		input, output = os.popen2('ps2pdf -sPAPERSIZE=a3 - -')
		input.write(ps_string)
		input.close()
		self.result = output.read()
		output.close()
		cr.close()
		self.done = True

	def is_done(self):
		return self.done

	def get(self):
		if self.done:
			return self.result
		else:
			return None

class report_graph(report.interface.report_int):
	def __init__(self, name, table):
		report.interface.report_int.__init__(self, name)
		self.table = table

	def result(self):
		if self.obj.is_done():
			return (True, self.obj.get(), 'pdf')
		else:
			return (False, False, False)

	def create(self, uid, ids, data, context={}):
		self.obj = report_graph_instance(uid, ids, data)
		return (self.obj.get(), 'pdf')

report_graph('report.workflow.instance.graph', 'ir.workflow')
