# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Flags and helpers for the compute backend-buckets commands."""

from __future__ import absolute_import
from __future__ import unicode_literals
from googlecloudsdk.calliope import actions as calliope_actions
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.compute import completers as compute_completers
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.disks import flags as disks_flags
from googlecloudsdk.command_lib.util import completers

_SOURCE_DISK_DETAILED_HELP = """\
        A source disk to create the image from. The value for this option can be
        the name of a disk with the zone specified via ``--source-disk-zone''
        flag.
"""
_SOURCE_SNAPSHOT_DETAILED_HELP = """\
        A source snapshot to create the image from. The value for this option
        can be the name of a snapshot within the same project as the destination
        image.
"""
_REPLACEMENT_DISK_DETAILED_HELP = """\
       Specifies a Compute Engine image as a replacement for the image
       being phased out. Users of the deprecated image will be
       advised to switch to this replacement. For example, *--replacement
       example-image* or *--replacement
       projects/google/global/images/example-image*.

       This flag value is purely informational and is not validated in any way.
       """

_SOURCE_DISK_ZONE_EXPLANATION = compute_flags.ZONE_PROPERTY_EXPLANATION

LIST_FORMAT = """\
    table(
      name,
      selfLink.map().scope(projects).segment(0):label=PROJECT,
      family,
      deprecated.state:label=DEPRECATED,
      status
    )"""


class ImagesCompleter(compute_completers.ListCommandCompleter):

  def __init__(self, **kwargs):
    super(ImagesCompleter, self).__init__(
        collection='compute.images',
        list_command='compute images list --uri',
        **kwargs)


class SearchImagesCompleter(completers.ResourceSearchCompleter):

  def __init__(self, **kwargs):
    super(SearchImagesCompleter, self).__init__(
        collection='compute.images',
        **kwargs)


def MakeDiskImageArg(plural=False, required=True, name='image_name'):
  return compute_flags.ResourceArgument(
      resource_name='disk image',
      name=name,
      completer=ImagesCompleter,
      plural=plural,
      required=required,
      global_collection='compute.images')


def MakeForceCreateArg():
  return base.Argument(
      '--force-create',
      action=calliope_actions.DeprecationAction(
          flag_name='force-create',
          warn='Flag force-create is deprecated. Use --force instead.',
          error='Flag force-create is removed. Use --force instead.',
          action='store_true'),
      default=False,
      help="""\
          DEPRECATED, use --force instead.
          By default, image creation fails when it is created from a disk that
          is attached to a running instance. When this flag is used, image
          creation from disk will proceed even if the disk is in use.
          """)


def MakeForceArg():
  return base.Argument(
      '--force',
      action='store_true',
      default=False,
      help="""\
          By default, image creation fails when it is created from a disk that
          is attached to a running instance. When this flag is used, image
          creation from disk will proceed even if the disk is in use.
          """)


REPLACEMENT_DISK_IMAGE_ARG = compute_flags.ResourceArgument(
    resource_name='disk image',
    name='--replacement',
    completer=ImagesCompleter,
    global_collection='compute.images',
    required=False,
    short_help='Specifies a Compute Engine image as a replacement.',
    detailed_help=_REPLACEMENT_DISK_DETAILED_HELP)

SOURCE_DISK_ARG = compute_flags.ResourceArgument(
    resource_name='source disk',
    name='--source-disk',
    completer=compute_completers.DisksCompleter,
    zonal_collection='compute.disks',
    short_help='The deprecation state to set on the image.',
    detailed_help=_SOURCE_DISK_DETAILED_HELP,
    zone_explanation=_SOURCE_DISK_ZONE_EXPLANATION,
    required=False)

SOURCE_IMAGE_ARG = compute_flags.ResourceArgument(
    resource_name='source image',
    name='--source-image',
    completer=ImagesCompleter,
    global_collection='compute.images',
    short_help='An existing Compute Engine image from which to import.',
    required=False)

SOURCE_SNAPSHOT_ARG = compute_flags.ResourceArgument(
    resource_name='snapshot',
    name='--source-snapshot',
    completer=disks_flags.SnapshotsCompleter,
    required=False,
    global_collection='compute.snapshots',
    short_help='A source snapshot used to create an image.',
    detailed_help=_SOURCE_SNAPSHOT_DETAILED_HELP,
)


def AddCommonArgs(parser):
  """Add common image creation args."""
  parser.add_argument(
      '--description',
      help=('An optional, textual description for the image being created.'))

  parser.add_argument(
      '--family',
      help=('The family of the image. When creating an instance or disk, '
            'specifying a family will cause the latest non-deprecated image '
            'in the family to be used.')
  )

  parser.add_argument(
      '--licenses',
      type=arg_parsers.ArgList(),
      help='Comma-separated list of URIs to license resources.')


def AddCommonSourcesArgs(parser, sources_group):
  """Add common args for specifying the source for image creation."""
  sources_group.add_argument(
      '--source-uri',
      help="""\
      The full Google Cloud Storage URI where the disk image is stored.
      This file must be a gzip-compressed tarball whose name ends in
      ``.tar.gz''.
      """)

  SOURCE_DISK_ARG.AddArgument(parser, mutex_group=sources_group)


def AddCloningImagesArgs(parser, sources_group):
  """Add args to support image cloning."""
  sources_group.add_argument(
      '--source-image',
      help="""\
      The name of an image to clone. May be used with
      ``--source-image-project'' to clone an image in a different
      project.
      """)

  sources_group.add_argument(
      '--source-image-family',
      help="""\
      The family of the source image. This will cause the latest non-
      deprecated image in the family to be used as the source image.
      May be used with ``--source-image-project'' to refer to an image
      family in a different project.
      """)

  parser.add_argument(
      '--source-image-project',
      help="""\
      The project name of the source image. Must also specify either
      ``--source-image'' or ``--source-image-family'' when using
      this flag.
      """)


def AddCreatingImageFromSnapshotArgs(parser, sources_group):
  """Add args to support creating image from snapshot."""
  SOURCE_SNAPSHOT_ARG.AddArgument(parser, mutex_group=sources_group)


def ValidateSourceArgs(args, sources):
  """Validate that there is one, and only one, source for creating an image."""
  sources_error_message = 'Please specify a source for image creation.'

  # Get the list of source arguments
  source_arg_list = [getattr(args, s.replace('-', '_')) for s in sources]
  # Count the number of source arguments that are specified.
  source_arg_count = sum(bool(a) for a in source_arg_list)

  source_arg_names = ['--' + s for s in sources]

  if source_arg_count > 1:
    raise exceptions.ConflictingArgumentsException(*source_arg_names)

  if source_arg_count < 1:
    raise exceptions.MinimumArgumentException(source_arg_names,
                                              sources_error_message)
