# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""A servlet for project and component owners to view and edit components."""
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import

import logging
import time

import ezt

from features import filterrules_helpers
from framework import framework_helpers
from framework import framework_views
from framework import permissions
from framework import servlet
from framework import timestr
from framework import urls
from gae_ts_mon import flask_handlers
from tracker import component_helpers
from tracker import tracker_bizobj
from tracker import tracker_constants
from tracker import tracker_views


class ComponentDetail(servlet.Servlet):
  """Servlets allowing project owners to view and edit a component."""

  _MAIN_TAB_MODE = servlet.Servlet.MAIN_TAB_PROCESS
  _PAGE_TEMPLATE = 'tracker/component-detail-page.ezt'

  def _GetComponentDef(self, mr):
    """Get the config and component definition to be viewed or edited."""
    if not mr.component_path:
      self.abort(404, 'component not specified')
    config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
    component_def = tracker_bizobj.FindComponentDef(mr.component_path, config)
    if not component_def:
      self.abort(404, 'component not found')
    return config, component_def

  def AssertBasePermission(self, mr):
    """Check whether the user has any permission to visit this page.

    Args:
      mr: commonly used info parsed from the request.
    """
    super(ComponentDetail, self).AssertBasePermission(mr)
    _config, component_def = self._GetComponentDef(mr)

    # TODO(jrobbins): optional restrictions on viewing fields by component.

    allow_view = permissions.CanViewComponentDef(
        mr.auth.effective_ids, mr.perms, mr.project, component_def)
    if not allow_view:
      raise permissions.PermissionException(
          'User is not allowed to view this component')

  def GatherPageData(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.
    """
    config, component_def = self._GetComponentDef(mr)
    users_by_id = framework_views.MakeAllUserViews(
        mr.cnxn, self.services.user,
        component_def.admin_ids, component_def.cc_ids)
    component_def_view = tracker_views.ComponentDefView(
        mr.cnxn, self.services, component_def, users_by_id)
    initial_admins = [users_by_id[uid].email for uid in component_def.admin_ids]
    initial_cc = [users_by_id[uid].email for uid in component_def.cc_ids]
    initial_labels = [
        self.services.config.LookupLabel(mr.cnxn, mr.project_id, label_id)
        for label_id in component_def.label_ids]

    creator, created = self._GetUserViewAndFormattedTime(
        mr, component_def.creator_id, component_def.created)
    modifier, modified = self._GetUserViewAndFormattedTime(
        mr, component_def.modifier_id, component_def.modified)

    allow_edit = permissions.CanEditComponentDef(
        mr, self.services, component_def, config)

    subcomponents = tracker_bizobj.FindDescendantComponents(
        config, component_def)
    templates = self.services.template.TemplatesWithComponent(
        mr.cnxn, component_def.component_id)
    allow_delete = allow_edit and not subcomponents and not templates

    return {
        'admin_tab_mode': servlet.Servlet.PROCESS_TAB_COMPONENTS,
        'component_def': component_def_view,
        'initial_leaf_name': component_def_view.leaf_name,
        'initial_docstring': component_def.docstring,
        'initial_deprecated': ezt.boolean(component_def.deprecated),
        'initial_admins': initial_admins,
        'initial_cc': initial_cc,
        'initial_labels': initial_labels,
        'allow_edit': ezt.boolean(allow_edit),
        'allow_delete': ezt.boolean(allow_delete),
        'subcomponents': subcomponents,
        'templates': templates,
        'creator': creator,
        'created': created,
        'modifier': modifier,
        'modified': modified,
    }

  def ProcessFormData(self, mr, post_data):
    """Validate and store the contents of the issues tracker admin page.

    Args:
      mr: commonly used info parsed from the request.
      post_data: HTML form data from the request.

    Returns:
      String URL to redirect the user to, or None if response was already sent.
    """
    config, component_def = self._GetComponentDef(mr)
    allow_edit = permissions.CanEditComponentDef(
        mr, self.services, component_def, config)
    if not allow_edit:
      raise permissions.PermissionException(
          'User is not allowed to edit or delete this component')

    if 'deletecomponent' in post_data:
      allow_delete = not tracker_bizobj.FindDescendantComponents(
          config, component_def)
      if not allow_delete:
        raise permissions.PermissionException(
            'User tried to delete component that had subcomponents')
      return self._ProcessDeleteComponent(mr, component_def)

    else:
      return self._ProcessEditComponent(mr, post_data, config, component_def)


  def _ProcessDeleteComponent(self, mr, component_def):
    """The user wants to delete the specified custom field definition."""
    self.services.issue.DeleteComponentReferences(
        mr.cnxn, component_def.component_id)
    self.services.config.DeleteComponentDef(
        mr.cnxn, mr.project_id, component_def.component_id)
    return framework_helpers.FormatAbsoluteURL(
        mr, urls.ADMIN_COMPONENTS, deleted=1, ts=int(time.time()))

  def _GetUserViewAndFormattedTime(self, mr, user_id, timestamp):
    formatted_time = (timestr.FormatAbsoluteDate(timestamp)
                      if timestamp else None)
    user = self.services.user.GetUser(mr.cnxn, user_id) if user_id else None
    user_view = None
    if user:
      user_view = framework_views.UserView(user)
      viewing_self = mr.auth.user_id == user_id
      # Do not obscure email if current user is a site admin. Do not obscure
      # email if current user is the same as the creator. For all other
      # cases do whatever obscure_email setting for the user is.
      email_obscured = (not(mr.auth.user_pb.is_site_admin or viewing_self)
                        and user_view.obscure_email)
      if not email_obscured:
        user_view.RevealEmail()

    return user_view, formatted_time

  def _ProcessEditComponent(self, mr, post_data, config, component_def):
    """The user wants to edit this component definition."""
    parsed = component_helpers.ParseComponentRequest(
        mr, post_data, self.services)

    if not tracker_constants.COMPONENT_NAME_RE.match(parsed.leaf_name):
      mr.errors.leaf_name = 'Invalid component name'

    original_path = component_def.path
    if mr.component_path and '>' in mr.component_path:
      parent_path = mr.component_path[:mr.component_path.rindex('>')]
      new_path = '%s>%s' % (parent_path, parsed.leaf_name)
    else:
      new_path = parsed.leaf_name

    conflict = tracker_bizobj.FindComponentDef(new_path, config)
    if conflict and conflict.component_id != component_def.component_id:
      mr.errors.leaf_name = 'That name is already in use.'

    creator, created = self._GetUserViewAndFormattedTime(
        mr, component_def.creator_id, component_def.created)
    modifier, modified = self._GetUserViewAndFormattedTime(
        mr, component_def.modifier_id, component_def.modified)

    if mr.errors.AnyErrors():
      self.PleaseCorrect(
          mr, initial_leaf_name=parsed.leaf_name,
          initial_docstring=parsed.docstring,
          initial_deprecated=ezt.boolean(parsed.deprecated),
          initial_admins=parsed.admin_usernames,
          initial_cc=parsed.cc_usernames,
          initial_labels=parsed.label_strs,
          created=created,
          creator=creator,
          modified=modified,
          modifier=modifier,
      )
      return None

    new_modified = int(time.time())
    new_modifier_id = self.services.user.LookupUserID(
        mr.cnxn, mr.auth.email, autocreate=False)
    self.services.config.UpdateComponentDef(
        mr.cnxn, mr.project_id, component_def.component_id,
        path=new_path, docstring=parsed.docstring, deprecated=parsed.deprecated,
        admin_ids=parsed.admin_ids, cc_ids=parsed.cc_ids, modified=new_modified,
        modifier_id=new_modifier_id, label_ids=parsed.label_ids)

    update_rule = False
    if new_path != original_path:
      update_rule = True
      # If the name changed then update all of its subcomponents as well.
      subcomponent_ids = tracker_bizobj.FindMatchingComponentIDs(
          original_path, config, exact=False)
      for subcomponent_id in subcomponent_ids:
        if subcomponent_id == component_def.component_id:
          continue
        subcomponent_def = tracker_bizobj.FindComponentDefByID(
            subcomponent_id, config)
        subcomponent_new_path = subcomponent_def.path.replace(
            original_path, new_path, 1)
        self.services.config.UpdateComponentDef(
            mr.cnxn, mr.project_id, subcomponent_def.component_id,
            path=subcomponent_new_path)

    if (set(parsed.cc_ids) != set(component_def.cc_ids) or
        set(parsed.label_ids) != set(component_def.label_ids)):
      update_rule = True
    if update_rule:
      filterrules_helpers.RecomputeAllDerivedFields(
          mr.cnxn, self.services, mr.project, config)

    return framework_helpers.FormatAbsoluteURL(
        mr, urls.COMPONENT_DETAIL,
        component=new_path, saved=1, ts=int(time.time()))

  def GetComponentDetailPage(self, **kwargs):
    return self.handler(**kwargs)

  def PostComponentDetailPage(self, **kwargs):
    return self.handler(**kwargs)
