# 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

"""Issue Tracker code to serve out issue attachments.

Summary of page classes:
  AttachmentPage: Serve the content of an attachment w/ the appropriate
                  MIME type.
  IssueAttachmentDeletion: Form handler for deleting attachments.
"""
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import

import base64
import logging
import os
import re
from six.moves import urllib

from google.appengine.api import app_identity
from google.appengine.api import images

from framework import exceptions
from framework import flaskservlet
from framework import framework_constants
from framework import framework_helpers
from framework import gcs_helpers
from framework import permissions
from framework import servlet
from framework import urls
from tracker import attachment_helpers
from tracker import tracker_helpers
from tracker import tracker_views


# This will likely appear blank or as a broken image icon in the browser.
NO_PREVIEW_ICON = ''
NO_PREVIEW_MIME_TYPE = 'image/png'


class AttachmentPage(servlet.Servlet):
  """AttachmentPage serves issue attachments."""

  def GatherPageData(self, mr):
    """Parse the attachment ID from the request and serve its content.

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

    Returns: dict of values used by EZT for rendering the page.
    """
    if mr.signed_aid != attachment_helpers.SignAttachmentID(mr.aid):
      self.abort(400, 'Please reload the issue page')

    try:
      attachment, _issue = tracker_helpers.GetAttachmentIfAllowed(
          mr, self.services)
    except exceptions.NoSuchIssueException:
      self.abort(404, 'issue not found')
    except exceptions.NoSuchAttachmentException:
      self.abort(404, 'attachment not found')
    except exceptions.NoSuchCommentException:
      self.abort(404, 'comment not found')

    if not attachment.gcs_object_id:
      self.abort(404, 'attachment data not found')

    bucket_name = app_identity.get_default_gcs_bucket_name()

    gcs_object_id = attachment.gcs_object_id

    logging.info('attachment id %d is %s', mr.aid, gcs_object_id)

    # By default GCS will return images and attachments displayable inline.
    if mr.thumb:
      # Thumbnails are stored in a separate obj always displayed inline.
      gcs_object_id = gcs_object_id + '-thumbnail'
    elif not mr.inline:
      # Downloads are stored in a separate obj with disposiiton set.
      filename = attachment.filename
      if not framework_constants.FILENAME_RE.match(filename):
        logging.info('bad file name: %s' % attachment.attachment_id)
        filename = 'attachment-%d.dat' % attachment.attachment_id
      if gcs_helpers.MaybeCreateDownload(
          bucket_name, gcs_object_id, filename):
        gcs_object_id = gcs_object_id + '-download'

    url = gcs_helpers.SignUrl(bucket_name, gcs_object_id)
    self.redirect(url, abort=True)

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