#!/usr/bin/python
# -*- coding: utf-8 -*-

# This file is part of Cockpit.
#
# Copyright (C) 2015 Red Hat, Inc.
#
# Cockpit is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Cockpit 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Cockpit; If not, see <http://www.gnu.org/licenses/>.

import contextlib
import datetime
import tempfile
import os
import shutil
import subprocess
import sys
import HTMLParser

master_repo = 'cockpit-project/cockpit'
bug_status_output = "%s/hubbot/bug_status.html" % os.environ['HOME']

location_blacklist = [
    "./pkg/base1/jquery.js",
    "./pkg/kubernetes/angular.js",
    "./tools/qunit.js",
    "./test/sizzle.js",
    "./doc/guide/gtk-doc.xsl"
]

class IDParser(HTMLParser.HTMLParser):
    def __init__(self, id):
        self.id = id
        self.result = None
        self.in_tag = False
        self.depth = {}
        self.html = None
        self.watch_startpos = False
        HTMLParser.HTMLParser.__init__(self)

    def loads(self, html):
        self.html = html
        self.feed(html)
        self.close()

    def handle_starttag(self, tag, attrs):
        attrs = dict(attrs)
        if self.in_tag:
            self.find_startpos(None)
        if 'id' in attrs and attrs['id'] == self.id:
            self.result = [tag]
            self.in_tag = True
            self.watch_startpos = True
        if self.in_tag:
            if not tag in self.depth: self.depth[tag] = 0
            self.depth[tag] += 1

    def handle_endtag(self, tag):
        if self.in_tag:
            if tag in self.depth: self.depth[tag] -= 1
            if self.depth[self.result[0]] == 0:
                self.in_tag = False
                self.result.append(self.getpos())

    def find_startpos(self, x):
        if self.watch_startpos:
            self.watch_startpos = False
            self.result.append(self.getpos())
    handle_entityref = handle_charref = handle_data = handle_comment = handle_decl = handle_pi = unknown_decl = find_startpos

    def get_result(self):
        if self.result == None:
            return None
        if len(self.result) != 3:
            return None
        lines = self.html.split('\n')
        lines = lines[self.result[1][0]-1:self.result[2][0]]
        lines[0] = lines[0][self.result[1][1]:]
        if len(lines) == 1:
            lines[-1] = lines[-1][:self.result[2][1]-self.result[1][1]]
        lines[-1] = lines[-1][:self.result[2][1]]
        return '\n'.join(lines).strip()

def get_element_by_id(id, html):
    """ return tag reference by id in html """
    parser = IDParser(id)
    parser.loads(html)
    return parser.get_result()


@contextlib.contextmanager
def tempdir(prefix='tmp'):
    """A context manager for creating and then deleting a temporary directory."""
    tmpdir = tempfile.mkdtemp(prefix=prefix)
    try:
        yield tmpdir
    finally:
        shutil.rmtree(tmpdir)


def cmd(*args):
    print "+", " ".join(list(args))
    subprocess.check_call(list(args), stdout=sys.stdout, stderr=sys.stderr)

def git(*args):
    cmd("git", *args)

def bug_details(bug_entry):
    bug = { 'location': bug_entry[0],
            'url': bug_entry[1] }
    print "looking up bug %s" % (bug['url'])
    try:
        html = subprocess.check_output ([ "curl", "-s", bug['url'] ])
        bug['status'] = get_element_by_id("static_bug_status", html) or "Unknown"
        bug['description'] = get_element_by_id("short_desc_nonedit_display", html) or bug_entry[1]
    except:
        bug['status'] = "(failed)"
        bug['description'] = "(failed)"
    return bug

def print_bugs(title, bugs):
    if not bugs:
        return """
      <div class="container">
      <h2>%s</h2>
      <p>No entries.</p>
      </div><!-- /.container -->
""" % (title)
    text = """
    <div class="container">

      <h2>%s</h2>
      <table class="table">
        <thead>
          <tr>
            <th>Location</th>
            <th>Description</th>
            <th>Status</th>
          </tr>
        </thead>
        <tbody>
""" % (title)
    for bug in bugs:
        text = text + """
          <tr>
            <td>%(location)s</td>
            <td><a href="%(url)s">%(description)s</a></td>
            <td>%(status)s</td>
          </tr>""" % (bug)
    text = text + """
        </tbody>
      </table>
    </div><!-- /.container -->
"""
    return text

def publish_bugs(dest_filename, bugs):
    header = """<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <meta name="description" content="">
    <meta name="author" content="Cockpit Project">
    <!--<link rel="icon" href="../../favicon.ico">-->

    <title>Cockpit - Bugzilla Status</title>

    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">

    <!-- Optional theme -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>

  <body>
    <h1>Status at: %s UTC</h1>
""" % (datetime.datetime.utcnow())
    footer = """
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Latest compiled and minified JavaScript -->
    <!--<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>-->
  </body>
</html>
"""
    with open(dest_filename, "w") as out_file:
        out_file.write(header + print_bugs('Bugs', bugs) + footer)

with tempdir() as working_directory:
    os.chdir(working_directory)
    # checkout current master in a temp directory
    git("init")
    git("fetch", "https://github.com/%s.git" % master_repo, "master")
    git("checkout", "FETCH_HEAD")

    # get bugzilla links
    uniq = subprocess.Popen(["uniq"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    grep = subprocess.Popen([ "grep", "-rEo", "(http|https)://(bugzilla|bugs)[\da-z./?A-Z0-9\D=_-]*", "." ], stdout=uniq.stdin)
    data = uniq.communicate()[0].split("\n")
    grep.wait()

    bugs = map(lambda b: bug_details(b),
               filter(lambda e: len(e) is 2 and e[1] and not e[0] in location_blacklist,
                      map(lambda e: e.split(":", 1), data)))
    publish_bugs(bug_status_output, bugs)
