# 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

"""Classes for users to create a new project."""
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import


import logging
from six import string_types
import ezt

import settings
from businesslogic import work_env
from framework import exceptions, flaskservlet
from framework import filecontent
from framework import framework_helpers
from framework import gcs_helpers
from framework import jsonfeed
from framework import permissions
from framework import servlet
from framework import urls
from project import project_constants
from project import project_helpers
from project import project_views
from services import project_svc
from tracker import tracker_bizobj
from tracker import tracker_views


_MSG_PROJECT_NAME_NOT_AVAIL = 'That project name is not available.'
_MSG_MISSING_PROJECT_NAME = 'Missing project name'
_MSG_INVALID_PROJECT_NAME = 'Invalid project name'
_MSG_MISSING_PROJECT_SUMMARY = 'Missing project summary'


class ProjectCreate(flaskservlet.FlaskServlet):
  """Shows a page with a simple form to create a project."""

  _PAGE_TEMPLATE = 'sitewide/project-create-page.ezt'

  def AssertBasePermission(self, mr):
    """Assert that the user has the permissions needed to view this page."""
    super(ProjectCreate, self).AssertBasePermission(mr)

    if not permissions.CanCreateProject(mr.perms):
      raise permissions.PermissionException(
          'User is not allowed to create a project')

  def GatherPageData(self, _mr):
    """Build up a dictionary of data values to use when rendering the page."""
    available_access_levels = project_helpers.BuildProjectAccessOptions(None)
    offer_access_level = len(available_access_levels) > 1
    if settings.default_access_level:
      access_view = project_views.ProjectAccessView(
          settings.default_access_level)
    else:
      access_view = None

    return {
        'initial_name': '',
        'initial_summary': '',
        'initial_description': '',
        'initial_project_home': '',
        'initial_docs_url': '',
        'initial_source_url': '',
        'initial_logo_gcs_id': '',
        'initial_logo_file_name': '',
        'logo_view': tracker_views.LogoView(None),
        'labels': [],
        'max_project_name_length': project_constants.MAX_PROJECT_NAME_LENGTH,
        'offer_access_level': ezt.boolean(offer_access_level),
        'initial_access': access_view,
        'available_access_levels': available_access_levels,
    }

  def ProcessFormData(self, mr, post_data):
    """Process the posted form."""
    # 1. Parse and validate user input.
    # Project name is taken from post_data because we are creating it.
    project_name = post_data.get('projectname')
    if not project_name:
      mr.errors.projectname = _MSG_MISSING_PROJECT_NAME
    elif not project_helpers.IsValidProjectName(project_name):
      mr.errors.projectname = _MSG_INVALID_PROJECT_NAME

    summary = post_data.get('summary')
    if not summary:
      mr.errors.summary = _MSG_MISSING_PROJECT_SUMMARY
    description = post_data.get('description', '')

    access = project_helpers.ParseProjectAccess(None, post_data.get('access'))
    home_page = post_data.get('project_home')
    if home_page and not (
        home_page.startswith('http://') or home_page.startswith('https://')):
      mr.errors.project_home = 'Home page link must start with http(s)://'
    docs_url = post_data.get('docs_url')
    if docs_url and not (
        docs_url.startswith('http:') or docs_url.startswith('https:')):
      mr.errors.docs_url = 'Documentation link must start with http: or https:'

    # These are not specified on via the ProjectCreate form,
    # the user must edit the project after creation to set them.
    committer_ids = []
    contributor_ids = []

    # Validate that provided logo is supported.
    logo_provided = 'logo' in post_data and not isinstance(
        post_data['logo'], string_types)
    if logo_provided:
      item = post_data['logo']
      try:
        gcs_helpers.CheckMimeTypeResizable(
            filecontent.GuessContentTypeFromFilename(item.filename))
      except gcs_helpers.UnsupportedMimeType, e:
        mr.errors.logo = e.message

    # 2. Call services layer to save changes.
    if not mr.errors.AnyErrors():
      with work_env.WorkEnv(mr, self.services) as we:
        try:
          project_id = we.CreateProject(
              project_name, [mr.auth.user_id],
              committer_ids, contributor_ids, summary, description,
              access=access, home_page=home_page, docs_url=docs_url)

          config = tracker_bizobj.MakeDefaultProjectIssueConfig(project_id)
          self.services.config.StoreConfig(mr.cnxn, config)
          # Note: No need to store any canned queries or rules yet.
          self.services.issue.InitializeLocalID(mr.cnxn, project_id)

          # Update project with  logo if specified.
          if logo_provided:
            item = post_data['logo']
            logo_file_name = item.filename
            logo_gcs_id = gcs_helpers.StoreLogoInGCS(
                logo_file_name, item.value, project_id)
            we.UpdateProject(
                project_id, logo_gcs_id=logo_gcs_id,
                logo_file_name=logo_file_name)

        except exceptions.ProjectAlreadyExists:
          mr.errors.projectname = _MSG_PROJECT_NAME_NOT_AVAIL

    # 3. Determine the next page in the UI flow.
    if mr.errors.AnyErrors():
      access_view = project_views.ProjectAccessView(access)
      self.PleaseCorrect(
          mr, initial_summary=summary, initial_description=description,
          initial_name=project_name, initial_access=access_view)
    else:
      # Go to the new project's introduction page.
      return framework_helpers.FormatAbsoluteURL(
          mr, urls.ADMIN_INTRO, project_name=project_name)

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

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