# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd

"""Servlet to export a project's config in JSON format.
"""
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import

import logging
import time

import ezt

from framework import flaskservlet
from framework import permissions
from framework import jsonfeed
from framework import servlet
from project import project_helpers
from tracker import tracker_bizobj


class ProjectExport(servlet.Servlet):
  """Only site admins can export a project"""

  _PAGE_TEMPLATE = 'project/project-export-page.ezt'
  _MAIN_TAB_MODE = flaskservlet.FlaskServlet.MAIN_TAB_ADMIN

  def AssertBasePermission(self, mr):
    """Make sure that the logged in user has permission to view this page."""
    super(ProjectExport, self).AssertBasePermission(mr)
    if not mr.auth.user_pb.is_site_admin:
      raise permissions.PermissionException(
          'Only site admins may export project configuration')

  def GatherPageData(self, mr):
    """Build up a dictionary of data values to use when rendering the page."""

    return {
        'admin_tab_mode': None,
        'page_perms': self.MakePagePerms(mr, None, permissions.CREATE_ISSUE),
    }

  # def GetProjectExportPage(self, **kwargs):
  #   return self.handler(**kwargs)


# TODO(https://crbug.com/monorail/10936): Use FlaskJsonFeed
class ProjectExportJSON(jsonfeed.JsonFeed):
  """ProjectExportJSON shows all configuration for a Project in JSON form."""

  # Pretty-print the JSON output.
  JSON_INDENT = 4

  def AssertBasePermission(self, mr):
    """Make sure that the logged in user has permission to view this page."""
    super(ProjectExportJSON, self).AssertBasePermission(mr)
    if not mr.auth.user_pb.is_site_admin:
      raise permissions.PermissionException(
          'Only site admins may export project configuration')

  def HandleRequest(self, mr):
    """Build up a dictionary of data values to use when rendering the page.

    Args:
      mr: commonly used info parsed from the request.

    Returns:
      Dict of values used by EZT for rendering the page.
    """
    project = self.services.project.GetProject(mr.cnxn, mr.project.project_id)
    user_id_set = project_helpers.UsersInvolvedInProject(project)

    config = self.services.config.GetProjectConfig(
        mr.cnxn, mr.project.project_id)
    templates = self.services.template.GetProjectTemplates(
        mr.cnxn, config.project_id)
    involved_users = self.services.config.UsersInvolvedInConfig(
        config, templates)
    user_id_set.update(involved_users)

    # The value 0 indicates "no user", e.g., that an issue has no owner.
    # We don't need to create a User row to represent that.
    user_id_set.discard(0)
    email_dict = self.services.user.LookupUserEmails(mr.cnxn, user_id_set)

    project_json = self._MakeProjectJSON(project, email_dict)
    config_json = self._MakeConfigJSON(config, email_dict, templates)

    json_data = {
        'metadata': {
            'version': 1,
            'when': int(time.time()),
            'who': mr.auth.email,
        },
        'project': project_json,
        'config': config_json,
        # This list could be derived from the others, but we provide it for
        # ease of processing.
        'emails': list(email_dict.values()),
    }
    return json_data

  def _MakeProjectJSON(self, project, email_dict):
    project_json = {
      'name': project.project_name,
      'summary': project.summary,
      'description': project.description,
      'state': project.state.name,
      'access': project.access.name,
      'owners': [email_dict.get(user) for user in project.owner_ids],
      'committers': [email_dict.get(user) for user in project.committer_ids],
      'contributors': [
          email_dict.get(user) for user in project.contributor_ids],
      'perms': [self._MakePermJSON(perm, email_dict)
                for perm in project.extra_perms],
      'issue_notify_address': project.issue_notify_address,
      'attachment_bytes': project.attachment_bytes_used,
      'attachment_quota': project.attachment_quota,
      'recent_activity': project.recent_activity,
      'process_inbound_email': project.process_inbound_email,
      'only_owners_remove_restrictions':
          project.only_owners_remove_restrictions,
      'only_owners_see_contributors': project.only_owners_see_contributors,
      'revision_url_format': project.revision_url_format,
      'read_only_reason': project.read_only_reason,
    }
    return project_json

  def _MakePermJSON(self, perm, email_dict):
    perm_json = {
      'member': email_dict.get(perm.member_id),
      'perms': [p for p in perm.perms],
    }
    return perm_json

  def _MakeConfigJSON(self, config, email_dict, project_templates):
    config_json = {
      'statuses':
          [self._MakeStatusJSON(status)
           for status in config.well_known_statuses],
      'statuses_offer_merge':
          [status for status in config.statuses_offer_merge],
      'labels':
          [self._MakeLabelJSON(label) for label in config.well_known_labels],
      'exclusive_label_prefixes':
          [label for label in config.exclusive_label_prefixes],
      # TODO(http://crbug.com/monorail/7217): Export the project's FieldDefs.
      'components':
          [self._MakeComponentJSON(component, email_dict)
           for component in config.component_defs],
      'templates':
          [self._MakeTemplateJSON(template, email_dict)
           for template in project_templates],
      'developer_template': config.default_template_for_developers,
      'user_template': config.default_template_for_users,
      'list_cols': config.default_col_spec,
      'list_spec': config.default_sort_spec,
      'grid_x': config.default_x_attr,
      'grid_y': config.default_y_attr,
      'only_known_values': config.restrict_to_known,
    }
    if config.custom_issue_entry_url:
      config_json.update({'issue_entry_url': config.custom_issue_entry_url})
    return config_json

  def _MakeTemplateJSON(self, template, email_dict):
    template_json = {
      'name': template.name,
      'summary': template.summary,
      'content': template.content,
      'summary_must_be_edited': template.summary_must_be_edited,
      'owner': email_dict.get(template.owner_id),
      'status': template.status,
      'labels': [label for label in template.labels],
      # TODO(http://crbug.com/monorail/7217): Export the template's Fields.
      'members_only': template.members_only,
      'owner_defaults_to_member': template.owner_defaults_to_member,
      'component_required': template.component_required,
      'admins': [email_dict(user) for user in template.admin_ids],
    }
    return template_json

  def _MakeStatusJSON(self, status):
    status_json = {
      'status': status.status,
      'open': status.means_open,
      'docstring': status.status_docstring,
    }
    return status_json

  def _MakeLabelJSON(self, label):
    label_json = {
      'label': label.label,
      'docstring': label.label_docstring,
    }
    return label_json

  def _MakeComponentJSON(self, component, email_dict):
    component_json = {
      'path': component.path,
      'docstring': component.docstring,
      'admins': [email_dict.get(user) for user in component.admin_ids],
      'ccs': [email_dict.get(user) for user in component.cc_ids],
    }
    return component_json

  # def GetProjectExportJSONPage(self, **kwargs):
  #   return self.handler(**kwargs)

  # def PostProjectExportJSONPage(self, **kwargs):
  #   return self.handler(**kwargs)