# -*- coding: utf-8 -*-
# Copyright (C) 2000-2006  Juan David Ibáñez Palomar <jdavid@itaapy.com>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.

"""
This is a hotfix, it dynamically applies several patches to Zope.
"""

# Import from the Standard Library
import logging
import os
from thread import allocate_lock, get_ident

# Import from itools
from .itools.i18n import AcceptLanguageType

# Import from Zope
import Globals
from ZPublisher import Publish
from ZPublisher.HTTPRequest import HTTPRequest


# Flag
patch = False
Z_DEBUG_MODE = os.environ.get('Z_DEBUG_MODE') == '1'


logger = logging.getLogger('Localizer')


# PATCH 1: Global Request
#
# The original purpose was to get the request object from places where the
# acquisition was disabled (within the __of__ method for example). It was
# inspired by the Tim McLaughlin's GlobalGetRequest proposal, see
# http://dev.zope.org/Wikis/DevSite/Proposals/GlobalGetRequest
#
# Currently it keeps a Context instance, which wraps the request object,
# but also other things, like the user's session, as it is required by
# the ikaaro CMS.
#
# The request objects are stored in a dictionary in the Publish module,
# whose keys are the thread id.
#
# Also, we keep the get_request method in the Globals module for backwards
# compatibility (with TranslationService for example).

_requests = {}
_requests_lock = allocate_lock()


def get_request():
    """Get a request object"""
    return _requests.get(get_ident(), None)


def new_publish(request, module_name, after_list, debug=0,
                zope_publish=Publish.publish):
    # Get the process id
    ident = get_ident()

    # Add the request object to the global dictionnary
    _requests_lock.acquire()
    try:
        _requests[ident] = request
    finally:
        _requests_lock.release()

    # Call the old publish
    try:
        # Publish
        x = zope_publish(request, module_name, after_list, debug)
    finally:
        # Remove the request object.
        # When conflicts occur the "publish" method is called again,
        # recursively. In this situation the "_requests dictionary would
        # be cleaned in the innermost call, hence outer calls find the
        # request does not exist anymore. For this reason we check first
        # wether the request is there or not.
        if ident in _requests:
            _requests_lock.acquire()
            try:
                del _requests[ident]
            finally:
                _requests_lock.release()

    return x


if patch is False:
    logger.info('Install "Globals.get_request".')

    # Apply the patch
    Publish.publish = new_publish

    # First import (it's not a refresh operation).
    # We need to apply the patches.
    patch = True

    # Add to Globals for backwards compatibility
    Globals.get_request = get_request



# PATCH 2: Accept
#
# Adds the variable AcceptLanguage to the REQUEST.  It provides a higher
# level interface than HTTP_ACCEPT_LANGUAGE.

# Apply the patch
def new_processInputs(self):
    HTTPRequest.old_processInputs(self)

    request = self

    # Set the AcceptLanguage variable
    # Initialize with the browser configuration
    accept_language = request['HTTP_ACCEPT_LANGUAGE']
    # Patches for user agents that don't support correctly the protocol
    user_agent = request['HTTP_USER_AGENT']
    if user_agent.startswith('Mozilla/4') and user_agent.find('MSIE') == -1:
        # Netscape 4.x
        q = 1.0
        langs = []
        for lang in [ x.strip() for x in accept_language.split(',') ]:
            langs.append('%s;q=%f' % (lang, q))
            q = q/2
        accept_language = ','.join(langs)

    accept_language = AcceptLanguageType.decode(accept_language)
    self.other['AcceptLanguage'] = accept_language


if patch:
    HTTPRequest.old_processInputs = HTTPRequest.processInputs
    HTTPRequest.processInputs = new_processInputs