# coding=utf-8
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import absolute_import, division, print_function, unicode_literals

import http.server
import itertools
import json
import logging
import mimetypes
import os
import pkgutil
import re
from builtins import object, range, str, zip
from collections import namedtuple
from datetime import date, datetime
from textwrap import dedent

import pystache
from future.moves.urllib.parse import parse_qs, urlencode, urlsplit, urlunparse

from pants.base.build_environment import get_buildroot
from pants.base.mustache import MustacheRenderer
from pants.base.run_info import RunInfo
from pants.pantsd.process_manager import ProcessManager
from pants.stats.statsdb import StatsDBFactory


logger = logging.getLogger(__name__)

# Google Prettyprint plugin files.
PPP_RE = re.compile("""^lang-.*\.js$""")


class PantsHandler(http.server.BaseHTTPRequestHandler):
  """A handler that demultiplexes various pants reporting URLs."""

  def __init__(self, settings, renderer, request, client_address, server):
    self._settings = settings  # An instance of ReportingServer.Settings.
    self._root = self._settings.root
    self._renderer = renderer
    self._client_address = client_address
    # The underlying handlers for specific URL prefixes.
    self._GET_handlers = [
      ('/runs/', self._handle_runs),  # Show list of known pants runs.
      ('/run/', self._handle_run),  # Show a report for a single pants run.
      ('/stats/', self._handle_stats),  # Show a stats analytics page.
      ('/statsdata/', self._handle_statsdata),  # Get JSON stats data.
      ('/browse/', self._handle_browse),  # Browse filesystem under build root.
      ('/content/', self._handle_content),  # Show content of file.
      ('/assets/', self._handle_assets),  # Statically serve assets (css, js etc.)
      ('/poll', self._handle_poll),  # Handle poll requests for raw file content.
      ('/latestrunid', self._handle_latest_runid),  # Return id of latest pants run.
      ('/favicon.ico', self._handle_favicon)  # Return favicon.
    ]
    # Note: BaseHTTPServer.BaseHTTPRequestHandler is an old-style class, so we must
    # invoke its __init__ like this.
    # TODO: Replace this entirely with a proper server as part of the pants daemon.
    http.server.BaseHTTPRequestHandler.__init__(self, request, client_address, server)

  def do_GET(self):
    """GET method implementation for BaseHTTPRequestHandler."""
    if not self._client_allowed():
      return

    try:
      (_, _, path, query, _) = urlsplit(self.path)
      params = parse_qs(query)
      # Give each handler a chance to respond.
      for prefix, handler in self._GET_handlers:
        if self._maybe_handle(prefix, handler, path, params):
          return
      # If no path specified, default to showing the list of all runs.
      if path == '/':
        self._handle_runs('', {})
        return

      self._send_content('Invalid GET request {}'.format(self.path), 'text/html', code=400)
    except (IOError, ValueError):
      pass  # Printing these errors gets annoying, and there's nothing to do about them anyway.
      #sys.stderr.write('Invalid GET request {}'.format(self.path))

  def _handle_runs(self, relpath, params):
    """Show a listing of all pants runs since the last clean-all."""
    runs_by_day = self._partition_runs_by_day()
    args = self._default_template_args('run_list.html')
    args['runs_by_day'] = runs_by_day