#!/usr/bin/python
# vim: set fileencoding=utf-8 :
""" Jabber ad-hoc command interface for cabbies
"""
import xmpp
from xmpp.protocol import *


import sys, os
sys.path.insert(1, os.path.join(sys.path[0], '../..'))
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from django.conf import settings
sys.path.insert(1, settings.PROJECT_PATH)
from taxi.models import *


options = {
	'JID': 'katrin-bot@jabber.ru/msi',
	'Password': '******',
}

class TaxiAdHoc(xmpp.commands.Command_Handler_Prototype, object):
	def __init__(self, jid=''):
		xmpp.commands.Command_Handler_Prototype.__init__(self,jid)
		self.initial = {
			'execute': self.initialForm
		}

	def initialForm(self, conn, request):
		sessionid = self.getSessionID()
		self.sessions[sessionid] = {
			'jid':request.getFrom(),
			'data':{'type':None}
		}
		cabby_qs = Cabby.objects.filter(
				jabber='%s@%s' % (request.getFrom().getNode(), request.getFrom().getDomain()),
				)
		if cabby_qs.count():
			self.cabby = cabby_qs[0]
		else:
			self.cabby = None
			self.cancel(conn, request)

		request.getTag(name="command").setAttr('sessionid', sessionid)
	def cancel(self, conn, request):
		sessionid = request.getTagAttr('command','sessionid')

		reply = request.buildReply('result')
		reply.addChild(
			name='command',
			namespace=NS_COMMANDS,
			attrs={
				'node':request.getTagAttr('command','node'),
				'sessionid':sessionid,
				'status':'cancelled'})
		self._owner.send(reply)
		try:
			del self.sessions[sessionid]
		except:
			pass
		raise xmpp.NodeProcessed


class SetStatus(TaxiAdHoc):
	name = 'select_status'
	description = u'Выбор статуса'
	def initialForm(self, conn, request):
		super(type(self), self).initialForm(conn, request)
		return self.selectStatusForm(conn, request)
			
	def selectStatusForm(self, conn, request):
		sessionid = request.getTagAttr('command','sessionid')
		session = self.sessions[sessionid]

		session['actions'] = {
			'cancel': self.cancel,
			'next': self.selectStatusFormAccept,
			'execute': self.selectStatusFormAccept,
		}

		xmpp_cs  = [[cs[1],cs[0]] for cs in CABBY_STATUS]
		statustypefield = xmpp.DataField(
			name='statustype',
			desc='Status',
			value=session['data']['type'],
			options = xmpp_cs,
			typ='list-single',
			required=1)
		statustypefield.setAttr('label', 'Cabby status')

		form = xmpp.DataForm(
			title=u'Выбор статуса',
			data=[
				u'Выберите статус',
				statustypefield])

		reply = request.buildReply('result')
		replypayload = [
			xmpp.Node('actions',
				attrs={'execute':'next'},
				payload=[xmpp.Node('next')]),
			form]
		reply.addChild(
			name='command',
			namespace=NS_COMMANDS,
			attrs={
				'node':request.getTagAttr('command','node'),
				'sessionid':sessionid,
				'status':'executing'},
			payload=replypayload)
		self._owner.send(reply)	# Question: self._owner or conn?
		raise xmpp.NodeProcessed

	def selectStatusFormAccept(self, conn, request):
		sessionid = request.getTagAttr('command','sessionid')
		session = self.sessions[sessionid]

		# load the form
		node = request.getTag(name='command').getTag(name='x',namespace=NS_DATA)
		form = xmpp.DataForm(node=node)

		# retrieve the data
		status_id = form.getField('statustype').getValue()
		session['data']['type'] = status_id
		
		self.cabby.status = status_id
		self.cabby.save()
		form = xmpp.DataForm(
			typ='result',
			data=[u'Статус \'%s\' применен' % dict(CABBY_STATUS)[int(status_id)]])

		reply = request.buildReply('result')
		reply.addChild(
			name='command',
			namespace=NS_COMMANDS,
			attrs={
				'node':request.getTagAttr('command','node'),
				'sessionid':sessionid,
				'status':'completed'},
			payload=[form])

		self._owner.send(reply)

		del self.sessions[sessionid]
		raise xmpp.NodeProcessed

class GetBalance(TaxiAdHoc):
	name = 'get_balance'
	description = u'Узнать баланс'
	def initialForm(self, conn, request):
		super(type(self), self).initialForm(conn, request)
		return self.getBalanceFormAccept(conn, request)
			
	def getBalanceFormAccept(self, conn, request):
		sessionid = request.getTagAttr('command','sessionid')
		session = self.sessions[sessionid]

		# load the form
		node = request.getTag(name='command').getTag(name='x',namespace=NS_DATA)
		form = xmpp.DataForm(node=node)

		# retrieve the data
		balance_str = u'Ваш баланс %s' % self.cabby.balance

		session['data']['balance'] = balance_str

		form = xmpp.DataForm(
			typ='result',
			data=[balance_str])

		reply = request.buildReply('result')
		reply.addChild(
			name='command',
			namespace=NS_COMMANDS,
			attrs={
				'node':request.getTagAttr('command','node'),
				'sessionid':sessionid,
				'status':'completed'},
			payload=[form])

		self._owner.send(reply)

		del self.sessions[sessionid]
		raise xmpp.NodeProcessed

class GetCurrentTransfer(TaxiAdHoc):
	name = 'get_current_transfer'
	description = u'Текущая поездка'
	def initialForm(self, conn, request):
		super(type(self), self).initialForm(conn, request)
		return self.showCurrentTransferForm(conn, request)
			
	def showCurrentTransferForm(self, conn, request):
		sessionid = request.getTagAttr('command','sessionid')
		session = self.sessions[sessionid]

		transfer_set = ServiceTaxiStat.objects.filter(
				status = 2, # Выполнение
				cabby = self.cabby)
		if not transfer_set.count():
			return self.cancel(conn, request)
		transfer = transfer_set[0]

		form = xmpp.DataForm(
			typ='result',
			data=[
u'''№ %s
Cтоимость: %s
Адрес посадки: %s
Адрес доставки: %s''' % (transfer.id, transfer.cost, transfer.get_full_addr_in(), transfer.get_full_addr_out())])

		reply = request.buildReply('result')
		reply.addChild(
			name='command',
			namespace=NS_COMMANDS,
			attrs={
				'node':request.getTagAttr('command','node'),
				'sessionid':sessionid,
				'status':'completed'},
			payload=[form])

		self._owner.send(reply)

		del self.sessions[sessionid]
		raise xmpp.NodeProcessed



class ConnectionError: pass
class AuthorizationError: pass
class NotImplemented: pass

class Bot:
	def __init__(self, JID, Password):
		# connect...
		jid = xmpp.JID(JID)
		self.connection = xmpp.Client(jid.getDomain(), debug=['always', 'browser', 'testcommand'])

		result = self.connection.connect()

		if result is None:
			raise ConnectionError

		# authorize
		result = self.connection.auth(jid.getNode(), Password)

		if result is None:
			raise AuthorizationError

		# plugins
		# disco - needed by commands

		# warning: case of "plugin" method names are important!
		# to attach a command to Commands class, use .plugin()
		# to attach anything to Client class, use .PlugIn()
		self.disco = xmpp.browser.Browser()
		self.disco.PlugIn(self.connection)
		self.disco.setDiscoHandler({
			'info': {
				'ids': [{
					'category': 'client',
					'type': 'pc',
					'name': 'Bot'
					}],
				'features': [NS_DISCO_INFO],
				}
			})

		self.commands = xmpp.commands.Commands(self.disco)
		self.commands.PlugIn(self.connection)

		self.command_selectstatus = SetStatus()
		self.command_selectstatus.plugin(self.commands)

		self.command_getbalance = GetBalance()
		self.command_getbalance.plugin(self.commands)
		
		self.command_getcurrenttransfer = GetCurrentTransfer()
		self.command_getcurrenttransfer.plugin(self.commands)
		# presence
		self.connection.sendInitPresence(requestRoster=0)

	def loop(self):
		""" Do nothing except handling new xmpp stanzas. """
		try:
			while self.connection.Process(1):
				pass
		except KeyboardInterrupt:
			pass

bot = Bot(**options)
bot.loop()
