#!/usr/bin/env python
# Author:  Lisandro Dalcin
# Contact: dalcinl@gmail.com
"""
Open a new browser window to visualize a PETSc XML log file.
"""
import os
import sys
import posixpath
import argparse
import webbrowser
try:
    from urllib.request import urlopen
    from http.server import HTTPServer
    from http.server import HTTPStatus
    from http.server import SimpleHTTPRequestHandler
except ImportError:
    import urllib2
    import contextlib
    from SocketServer import TCPServer
    from SimpleHTTPServer import SimpleHTTPRequestHandler

    @contextlib.contextmanager
    def urlopen(*args, **kwargs):
        url = urllib2.urlopen(*args, **kwargs)
        try:
            yield url
        finally:
            url.close()

    class HTTPStatus:
        OK = 200
        NOT_FOUND = 404

    class HTTPServer(TCPServer):
        def __enter__(self):
            return self
        def __exit__(self, *args):
            self.server_close()


xmlfile = 'log.xml'
xslfile = 'performance_xml2html.xsl'

def read_xmlfile():
    with open(xmlfile, 'rb') as f:
        return f.read()

def read_xslfile():
    petscdir = os.environ.get('PETSC_DIR')
    if petscdir:
        filepath = os.path.join('share', 'petsc', 'xml', xslfile)
        filename = os.path.join(petscdir, filepath)
        if os.path.isfile(filename):
            with open(filename, 'rb') as f:
                return f.read()
    giturl = "https://gitlab.com/petsc/petsc/raw/release/"
    filepath = posixpath.join('share', 'petsc', 'xml', xslfile)
    with urlopen(giturl + filepath) as f:
        return f.read()

class Handler(SimpleHTTPRequestHandler):

    def log_message(self, format, *args):
        pass

    def send_not_found(self):
        self.send_error(HTTPStatus.NOT_FOUND)

    def send_data(self, data, ctype):
        self.send_response(HTTPStatus.OK)
        self.send_header("Content-type", ctype)
        self.send_header("Content-Length", len(data))
        self.end_headers()
        self.wfile.write(data)

    def do_GET(self):
        path = self.path[1:]
        if path == posixpath.basename(xmlfile):
            try:
                cdata = read_xmlfile()
            except (OSError, IOError):
                self.send_not_found()
            else:
                ctype = self.guess_type(path)
                self.send_data(cdata, ctype)
        elif path == xslfile:
            cdata = read_xslfile()
            ctype = self.guess_type(path)
            self.send_data(cdata, ctype)
        else:
            self.send_not_found()


parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-b', '--bind', default='', type=str,
                    help='Specify bind address', metavar='ADDRESS')
parser.add_argument('-p', '--port', default=0, type=int,
                    help='Specify port', metavar='PORT')
parser.add_argument('--browser', default=None, type=str,
                    help='Specify browser', metavar='BROWSER')
parser.add_argument('-n', '--new', dest='new_win',
                    action='store_const', default=0, const=1,
                    help='Open in new window if possible')
parser.add_argument('-t', '--tab', dest='new_win',
                    action='store_const', default=0, const=2,
                    help='Open in new tab if possible')
parser.add_argument('logfile', type=str, metavar='LOGFILE',
                    help="PETSc XML log filename")
args = parser.parse_args()

xmlfile = args.logfile

server_address = (args.bind, args.port)
with HTTPServer(server_address, Handler) as httpd:
    host, port = httpd.socket.getsockname()
    path = os.path.basename(xmlfile)
    url = "http://{}:{}/{}".format(host, port, path)
    webbrowser.get(args.browser).open(url, args.new_win)
    try:
        httpd.handle_request()  # serve xmlfile
        httpd.handle_request()  # serve xslfile
    except KeyboardInterrupt:
        sys.exit(0)
