#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""XMPP webapp handler classes.

This module provides handler classes for XMPP bots, including both basic
messaging functionality and a command handler for commands such as "/foo bar"
"""



import logging
from google.appengine.api import xmpp
from google.appengine.ext import webapp


class BaseHandler(webapp.RequestHandler):
  """A webapp baseclass for XMPP handlers.

  Implements a straightforward message delivery pattern. When a message is
  received, message_received is called with a Message object that encapsulates
  the relevant details. Users can reply using the standard XMPP API, or the
  convenient .reply() method on the Message object.
  """

  def message_received(self, message):
    """Called when a message is sent to the XMPP bot.

    Args:
      message: Message: The message that was sent by the user.
    """
    raise NotImplementedError()

  def handle_exception(self, exception, debug_mode):
    """Called if this handler throws an exception during execution.

    Args:
      exception: the exception that was thrown
      debug_mode: True if the web application is running in debug mode
    """
    super(BaseHandler, self).handle_exception(exception, debug_mode)
    if self.xmpp_message:
      self.xmpp_message.reply('Oops. Something went wrong.')

  def post(self):
    try:
      self.xmpp_message = xmpp.Message(self.request.POST)
    except xmpp.InvalidMessageError, e:
      logging.error("Invalid XMPP request: Missing required field %s", e[0])
      return
    self.message_received(self.xmpp_message)


class CommandHandlerMixin(object):
  """A command handler for XMPP bots.

  Implements a command handler pattern. XMPP messages are processed by calling
  message_received. Message objects handled by this class are annotated with
  'command' and 'arg' fields. On receipt of a message starting with a forward
  or backward slash, the handler calls a method named after the command - eg,
  if the user sends "/foo bar", the handler will call foo_command(message).
  If no handler method matches, unhandled_command is called. The default behaviour
  of unhandled_command is to send the message "Unknown command" back to
  the sender.

  If the user sends a message not prefixed with a slash,
  text_message(message) is called.
  """

  def unhandled_command(self, message):
    """Called when an unknown command is sent to the XMPP bot.

    Args:
      message: Message: The message that was sent by the user.
    """
    message.reply('Unknown command')

  def text_message(self, message):
    """Called when a message not prefixed by a /command is sent to the XMPP bot.

    Args:
      message: Message: The message that was sent by the user.
    """
    pass

  def message_received(self, message):
    """Called when a message is sent to the XMPP bot.

    Args:
      message: Message: The message that was sent by the user.
    """
    if message.command:
      handler_name = '%s_command' % (message.command,)
      handler = getattr(self, handler_name, None)
      if handler:
        handler(message)
      else:
        self.unhandled_command(message)
    else:
      self.text_message(message)


class CommandHandler(CommandHandlerMixin, BaseHandler):
  """A webapp implementation of CommandHandlerMixin."""
  pass
