#!/usr/bin/env python
# -*- coding: utf-8 -*-
# $Id: AsyncRequest.py 9634 2016-04-13 08:13:53Z Eric $
#
# Copyright (c) 2013 Nuwa Information Co., Ltd, All Rights Reserved.
#
# Licensed under the Proprietary License,
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at our web site.
#
# See the License for the specific language governing permissions and
# limitations under the License.
#
# $Author: Eric $
# $Date: 2016-04-13 16:13:53 +0800 (Wed, 13 Apr 2016) $
# $Revision: 9634 $

import cPickle as pickle

try:
    import lzma # Python 3.3
except ImportError:
    import pylzma as lzma

from celery import Celery

from Iuno.browser import tasks
from Iuno.browser import Config
from Iuno.browser.Request import Request, Response

class AsyncRequest(Request):
    """
    Asynchronous request to browser.
    This is a abstract interface for all browser implementations.
    """

    def __init__(self, *args, **kws):
        """
        Constructor.
        
        @param *args Arguments, see Request.__init__.
        @param **kws Keyword arguments, see Request.__init__.
        """
        super(AsyncRequest, self).__init__(*args, **kws)
        
        self.engine = self.__class__.__module__.split('.')[-2]
        if not self.configFile:
            self.config.update(Config.load(engine=self.engine))
            
        config = Config.load()
        
        self.celery = Celery('tasks')
        self.celery.conf.update({
            'BROKER_URL': 'amqp://{user}:{password}'
                          '@{host}:{port}{vHost}'.format(
                              user=self.config.get('brokerUser', 'celery'),
                              password=self.config.get('brokerPassword', ''),
                              host=self.config.get('brokerHost', 'localhost'),
                              port=int(self.config.get('brokerPort', '5672')),
                              vHost=self.config.get('brokerVHost', '/'),                         
                          ),
            'CELERY_RESULT_BACKEND': 'redis://:{password}'
                                     '@{host}:{port}'.format(
                                      password=self.config.get(
                                                        'redisPassword', ''),
                                      host=self.config.get(
                                                    'redisHost', 'localhost'),
                                      port=int(self.config.get(
                                                        'redisPort', '6379')),
                                    ),
            'CELERY_TASK_SERIALIZER': 'pickle',
            'CELERY_RESULT_SERIALIZER': 'pickle',
            'CELERY_ACCEPT_CONTENT': ['pickle'],
        })

    def _send(self):        
        queue = self.config.get('queue', 'browser')
        send = self.celery.task(queue=queue)(tasks.send)
        asyncResult = send.delay(self, self.engine)
        return AsyncResponse(asyncResult)

class AsyncResponse(Response):
    """
    Asynchronous wrapper for Response object. It will fetch response object 
    from queue only when response's attribute is accessed.
    """

    def __init__(self, result):
        """
        Constructor.

        @param result AsyncResult that celery responsed.
        """
        self.__result = result
        self.__cache = None

    def __getattribute__(self, name):
        c = object.__getattribute__(self, '_AsyncResponse__cache')
        if c:
            return getattr(c, name)
        else:
            async = object.__getattribute__(self, '_AsyncResponse__result')
            response = async.get()
            response.content = lzma.decompress(response.content)
            response.snapshot = lzma.decompress(response.snapshot)
            
            object.__setattr__(self, '_AsyncResponse__cache', response)
            return getattr(response, name)
