# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# This module contains code for running an HTTP server to view build info.

from __future__ import absolute_import, unicode_literals

import BaseHTTPServer
import json
import os

import requests


class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_GET(self):
        s = self.server.wrapper
        p = self.path

        if p == '/list':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json; charset=utf-8')
            self.end_headers()

            keys = sorted(s.json_files.keys())
            json.dump({'files': keys}, self.wfile)
            return

        if p.startswith('/resources/'):
            key = p[len('/resources/'):]

            if key not in s.json_files:
                self.send_error(404)
                return

            self.send_response(200)
            self.send_header('Content-Type', 'application/json; charset=utf-8')
            self.end_headers()

            self.wfile.write(s.json_files[key])
            return

        if p == '/':
            p = '/index.html'

        self.serve_docroot(s.doc_root, p[1:])

    def do_POST(self):
        if self.path == '/shutdown':
            self.server.wrapper.do_shutdown = True
            self.send_response(200)
            return

        self.send_error(404)

    def serve_docroot(self, root, path):
        local_path = os.path.normpath(os.path.join(root, path))

        # Cheap security. This doesn't resolve symlinks, etc. But, it should be
        # acceptable since this server only runs locally.
        if not local_path.startswith(root):
            self.send_error(404)

        if not os.path.exists(local_path):
            self.send_error(404)
            return

        if os.path.isdir(local_path):
            self.send_error(500)
            return

        self.send_response(200)
        ct = 'text/plain'
        if path.endswith('.html'):
            ct = 'text/html'

        self.send_header('Content-Type', ct)
        self.end_headers()

        with open(local_path, 'rb') as fh:
            self.wfile.write(fh.read())


class BuildViewerServer(object):
    def __init__(self, address='localhost', port=0):
        # TODO use pkg_resources to obtain HTML resources.
        pkg_dir = os.path.dirname(os.path.abspath(__file__))
        doc_root = os.path.join(pkg_dir, 'resources', 'html-build-viewer')
        assert os.path.isdir(doc_root)

        self.doc_root = doc_root
        self.json_files = {}

        self.server = BaseHTTPServer.HTTPServer((address, port), HTTPHandler)
        self.server.wrapper = self
        self.do_shutdown = False

    @property
    def url(self):
        hostname, port = self.server.server_address
        return 'http://%s:%d/' % (hostname, port)

    def add_resource_json_file(self, key, path):
        """Register a resource JSON file with the server.

        The file will be made available under the name/key specified."""
        with open(path, 'rb') as fh:
            self.json_files[key] = fh.read()

    def add_resource_json_url(self, key, url):
        """Register a resource JSON file at a URL."""
        r = requests.get(url)
        if r.status_code != 200:
            raise Exception('Non-200 HTTP response code')
        self.json_files[key] = r.text

    def run(self):
        while not self.do_shutdown:
            self.server.handle_request()
