# w.c.s. - web application for online forms
# Copyright (C) 2005-2013  Entr'ouvert
#
# 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 2 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/>.

import json
import threading
import time

from django.http import HttpResponseBadRequest, HttpResponseRedirect
from django.utils.six.moves.urllib import parse as urllib

from quixote import get_publisher
from quixote.errors import RequestError
from .qommon.publisher import ImmediateRedirectException
from .qommon.http_response import HTTPResponse
from .compat import CompatHTTPRequest, CompatWcsPublisher


class PublisherInitialisationMiddleware(object):
    '''Initializes the publisher according to the request server name.'''
    def process_request(self, request):
        pub = get_publisher()
        if not pub:
            pub = CompatWcsPublisher.create_publisher()
        compat_request = CompatHTTPRequest(request)
        request.t0 = compat_request.t0 = time.time()
        try:
            pub.init_publish(compat_request)
        except ImmediateRedirectException as e:
            return HttpResponseRedirect(e.location)

        pub._set_request(compat_request)
        try:
            pub.parse_request(compat_request)
        except RequestError as e:
            if compat_request.is_json():
                return HttpResponseBadRequest(json.dumps(
                    {'err': 1, 'err_class': e.title, 'err_desc': e.public_msg}),
                    content_type='application/json')
            else:
                return HttpResponseBadRequest(str(e))

        request._publisher = pub

        # handle session_var_<xxx> in query strings, add them to session and
        # redirect to same URL without the parameters
        if compat_request.get_method() == 'GET' and compat_request.form:
            query_string_allowed_vars = pub.get_site_option(
                    'query_string_allowed_vars') or ''
            query_string_allowed_vars = [x.strip() for x in
                    query_string_allowed_vars.split(',')]
            had_session_variables = False
            session_variables = {}
            for k, v in list(compat_request.form.items()):
                if k.startswith('session_var_'):
                    had_session_variables = True
                    session_variable = str(k[len('session_var_'):])
                    # only add variable to session if it's a string, this
                    # handles the case of repeated parameters producing a
                    # list of values (by ignoring those parameters altogether).
                    if session_variable in query_string_allowed_vars and (
                            isinstance(v, str)):
                        session_variables[session_variable] = v
                    del compat_request.form[k]
            if had_session_variables:
                pub.start_request() # creates session
                compat_request.session.add_extra_variables(**session_variables)
                pub.finish_successful_request() # commits session
                new_query_string = ''
                if compat_request.form:
                    new_query_string = '?' + urllib.urlencode(compat_request.form)
                response = HttpResponseRedirect(compat_request.get_path() + new_query_string)
                for name, value in compat_request.response.generate_headers():
                    if name == 'Content-Length':
                        continue
                    response[name] = value
                return response

    def process_response(self, request, response):
        pub = get_publisher()
        if pub:
            pub.cleanup()
        return response


class AfterJobsMiddleware(object):
    ASYNC = True

    def process_response(self, request, response):
        if hasattr(response, 'after_jobs') and response.after_jobs:
            http_response = HTTPResponse()
            http_response.after_jobs = response.after_jobs
            if self.ASYNC:
                threading.Thread(target=http_response.process_after_jobs).start()
            else:
                http_response.process_after_jobs()
        return response
