"""
    SleekXMPP: The Sleek XMPP Library
    Copyright (C) 2010 Nathanael C. Fritz
    This file is part of SleekXMPP.
    
    See the file LICENSE for copying permission.
"""
from __future__ import with_statement
from . import base
import logging
from xml.etree import cElementTree as ET
import time

class xep_0050(base.base_plugin):
	"""
	XEP-0050 Ad-Hoc Commands
	"""
	
	def plugin_init(self):
		self.xep = '0050'
		self.description = 'Ad-Hoc Commands'
		self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='__None__'/></iq>" % self.xmpp.default_ns, self.handler_command, name='Ad-Hoc None')
		self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='execute'/></iq>" % self.xmpp.default_ns, self.handler_command, name='Ad-Hoc Execute')
		self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='next'/></iq>" % self.xmpp.default_ns, self.handler_command_next, name='Ad-Hoc Next', threaded=True)
		self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='cancel'/></iq>" % self.xmpp.default_ns, self.handler_command_cancel, name='Ad-Hoc Cancel')
		self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='complete'/></iq>" % self.xmpp.default_ns, self.handler_command_complete, name='Ad-Hoc Complete')
		self.commands = {}
		self.sessions = {}
		self.sd = self.xmpp.plugin['xep_0030']
	
	def post_init(self):
		base.base_plugin.post_init(self)
		self.sd.add_feature('http://jabber.org/protocol/commands')

	def addCommand(self, node, name, form, pointer=None, multi=False):
		self.sd.add_item(None, name, 'http://jabber.org/protocol/commands', node)
		self.sd.add_identity('automation', 'command-node', name, node)
		self.sd.add_feature('http://jabber.org/protocol/commands', node)
		self.sd.add_feature('jabber:x:data', node)
		self.commands[node] = (name, form, pointer, multi)
	
	def getNewSession(self):
		return str(time.time()) + '-' + self.xmpp.getNewId()
	
	def handler_command(self, xml):
		in_command = xml.find('{http://jabber.org/protocol/commands}command')
		sessionid = in_command.get('sessionid', None)
		node = in_command.get('node')
		sessionid = self.getNewSession()
		name, form, pointer, multi = self.commands[node]
		self.sessions[sessionid] = {}
		self.sessions[sessionid]['jid'] = xml.get('from')
		self.sessions[sessionid]['to'] = xml.get('to')
		self.sessions[sessionid]['past'] = [(form, None)]
		self.sessions[sessionid]['next'] = pointer
		npointer = pointer
		if multi:
			actions = ['next']
			status = 'executing'
		else:
			if pointer is None:
				status = 'completed'
				actions = []
			else:
				status = 'executing'
				actions = ['complete']
		self.xmpp.send(self.makeCommand(xml.attrib['from'], in_command.attrib['node'], form=form, id=xml.attrib['id'], sessionid=sessionid, status=status, actions=actions))
	
	def handler_command_complete(self, xml):
		in_command = xml.find('{http://jabber.org/protocol/commands}command')
		sessionid = in_command.get('sessionid', None)
		pointer = self.sessions[sessionid]['next']
		results = self.xmpp.plugin['old_0004'].makeForm('result')
		results.fromXML(in_command.find('{jabber:x:data}x'))
		pointer(results,sessionid)
		self.xmpp.send(self.makeCommand(xml.attrib['from'], in_command.attrib['node'], form=None, id=xml.attrib['id'], sessionid=sessionid, status='completed', actions=[]))
		del self.sessions[in_command.get('sessionid')]
		
	
	def handler_command_next(self, xml):
		in_command = xml.find('{http://jabber.org/protocol/commands}command')
		sessionid = in_command.get('sessionid', None)
		pointer = self.sessions[sessionid]['next']
		results = self.xmpp.plugin['old_0004'].makeForm('result')
		results.fromXML(in_command.find('{jabber:x:data}x'))
		form, npointer, next = pointer(results,sessionid)
		self.sessions[sessionid]['next'] = npointer
		self.sessions[sessionid]['past'].append((form, pointer))
		actions = []
		actions.append('prev')
		if npointer is None:
			status = 'completed'
		else:
			status = 'executing'
			if next:
				actions.append('next')
			else:
				actions.append('complete')
		self.xmpp.send(self.makeCommand(xml.attrib['from'], in_command.attrib['node'], form=form, id=xml.attrib['id'], sessionid=sessionid, status=status, actions=actions))
		
	def handler_command_cancel(self, xml):
		command = xml.find('{http://jabber.org/protocol/commands}command')
		try:
			del self.sessions[command.get('sessionid')]
		except:
			pass
		self.xmpp.send(self.makeCommand(xml.attrib['from'], command.attrib['node'], id=xml.attrib['id'], sessionid=command.attrib['sessionid'], status='canceled'))

	def makeCommand(self, to, node, id=None, form=None, sessionid=None, status='executing', actions=[]):
		if not id:
			id = self.xmpp.getNewId()
		iq = self.xmpp.makeIqResult(id)
		iq.attrib['from'] = self.xmpp.fulljid
		iq.attrib['to'] = to
		command = ET.Element('{http://jabber.org/protocol/commands}command')
		command.attrib['node'] = node
		command.attrib['status'] = status
		xmlactions = ET.Element('actions')
		for action in actions:
			xmlactions.append(ET.Element(action))
		if xmlactions:
			command.append(xmlactions)
		if not sessionid:
			sessionid = self.getNewSession()
		else:
			iq.attrib['from'] = self.sessions[sessionid]['to']
		command.attrib['sessionid'] = sessionid
		if form is not None:
			if hasattr(form,'getXML'):
				form = form.getXML()
			command.append(form)
		iq.append(command)
		return iq