# Copyright (c) 2011 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import BaseHTTPServer

import cgi
import codecs
import datetime
import json
import mimetypes
import os.path
import shutil
import threading
import time
import wsgiref.handlers
import BaseHTTPServer


class ReflectionHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    STATIC_FILE_EXTENSIONS = ['.js', '.css', '.html']
    # Subclasses should override.
    STATIC_FILE_DIRECTORY = None

    # Setting this flag to True causes the server to send
    #   Access-Control-Allow-Origin: *
    # with every response.
    allow_cross_origin_requests = False

    def do_GET(self):
        self._handle_request()

    def do_POST(self):
        self._handle_request()

    def do_HEAD(self):
        self._handle_request()

    def read_entity_body(self):
        length = int(self.headers.getheader('content-length'))
        return self.rfile.read(length)

    def _read_entity_body_as_json(self):
        return json.loads(self.read_entity_body())

    def _handle_request(self):
        # The query attribute is used in subclasses. If we want to set it in the constructor,
        # we have to override the superclass constructor, although the docs
        # (https://docs.python.org/2/library/basehttpserver.html) say "Subclasses should
        # not need to override or extend the __init__() method."
        # pylint: disable=attribute-defined-outside-init
        if '?' in self.path:
            path, query_string = self.path.split('?', 1)
            self.query = cgi.parse_qs(query_string)
        else:
            path = self.path
            self.query = {}
        function_or_file_name = path[1:] or 'index.html'

        _, extension = os.path.splitext(function_or_file_name)
        if extension in self.STATIC_FILE_EXTENSIONS:
            self._serve_static_file(function_or_file_name)
            return

        function_name = function_or_file_name.replace('.', '_')
        if not hasattr(self, function_name):
            self.send_error(404, 'Unknown function %s' % function_name)
            return
        if function_name[0] == '_':
            self.send_error(401, 'Not allowed to invoke private or protected methods')
            return
        function = getattr(self, function_name)
        function()

    def _serve_static_file(self, static_path):
        self._serve_file(os.path.join(self.STATIC_FILE_DIRECTORY, static_path))

    def quitquitquit(self):
        self._serve_text('Server quit.\n')
        # Shutdown has to happen on another thread from the server's thread,
        # otherwise there's a deadlock.
        threading.Thread(target=self.server.shutdown).start()

    def _send_access_control_header(self):
        if self.allow_cross_origin_requests:
            self.send_header('Access-Control-Allow-Origin', '*')

    def _serve_text(self, text):
        self.send_response(200)
        self._send_access_control_header()
        self.send_header('Content-type', 'text/plain')
        self.end_headers()
        self.wfile.write(text)

    def _serve_json(self, json_object):
        self.send_response(200)
        self._send_access_control_header()
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        json.dump(json_object, self.wfile)

    def _serve_file(self, file_path, cacheable_seconds=0, headers_only=False):
        if not os.path.exists(file_path):
            self.send_error(404, 'File not found')
            return
        with codecs.open(file_path, 'rb') as static_file:
            self.send_response(200)
            self._send_access_control_header()
            self.send_header('Content-Length', os.path.getsize(file_path))
            mime_type, _ = mimetypes.guess_type(file_path)
            if mime_type:
                self.send_header('Content-type', mime_type)

            if cacheable_seconds:
                expires_time = (datetime.datetime.now() +
                                datetime.timedelta(0, cacheable_seconds))
                expires_formatted = wsgiref.handlers.format_date_time(
                    time.mktime(expires_time.timetuple()))
                self.send_header('Expires', expires_formatted)
            self.end_headers()

            if not headers_only:
                shutil.copyfileobj(static_file, self.wfile)

    def _serve_xml(self, xml):
        self.send_response(200)
        self._send_access_control_header()
        self.send_header('Content-type', 'text/xml')
        self.end_headers()
        xml = xml.encode('utf-8')
        self.wfile.write(xml)
