#
#

# Copyright (C) 2014 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""Job filter rule commands"""

# pylint: disable=W0401,W0614
# W0401: Wildcard import ganeti.cli
# W0614: Unused import %s from wildcard import (since we need cli)

from ganeti.cli import *
from ganeti import constants
from ganeti import utils


#: default list of fields for L{ListFilters}
_LIST_DEF_FIELDS = ["uuid", "watermark", "priority",
                    "predicates", "action", "reason_trail"]


def AddFilter(opts, args):
  """Add a job filter rule.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code

  """
  assert args == []

  reason = []
  if opts.reason:
    reason = [(constants.OPCODE_REASON_SRC_USER,
               opts.reason,
               utils.EpochNano())]

  cl = GetClient()
  result = cl.ReplaceFilter(None, opts.priority, opts.predicates, opts.action,
                            reason)

  print(result)  # Prints the UUID of the replaced/created filter


def ListFilters(opts, args):
  """List job filter rules and their properties.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: filters to list, or empty for all
  @rtype: int
  @return: the desired exit code

  """
  desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
  cl = GetClient()
  return GenericList(constants.QR_FILTER, desired_fields, args, None,
                     opts.separator, not opts.no_headers,
                     verbose=opts.verbose, cl=cl, namefield="uuid")


def ListFilterFields(opts, args):
  """List filter rule fields.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: fields to list, or empty for all
  @rtype: int
  @return: the desired exit code

  """
  cl = GetClient()
  return GenericListFields(constants.QR_FILTER, args, opts.separator,
                           not opts.no_headers, cl=cl)


def ReplaceFilter(opts, args):
  """Replaces a job filter rule with the given UUID, or creates it, if it
  doesn't exist already.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: should contain only one element, the UUID of the filter

  @rtype: int
  @return: the desired exit code

  """
  (uuid,) = args

  reason = []
  if opts.reason:
    reason = [(constants.OPCODE_REASON_SRC_USER,
               opts.reason,
               utils.EpochNano())]

  cl = GetClient()
  result = cl.ReplaceFilter(uuid,
                            priority=opts.priority,
                            predicates=opts.predicates,
                            action=opts.action,
                            reason=reason)

  print(result)  # Prints the UUID of the replaced/created filter
  return 0


def ShowFilter(_, args):
  """Show filter rule details.

  @type args: list
  @param args: should either be an empty list, in which case
      we show information about all filters, or should contain
      a list of filter UUIDs to be queried for information
  @rtype: int
  @return: the desired exit code

  """
  cl = GetClient()
  result = cl.QueryFilters(fields=["uuid", "watermark", "priority",
                                   "predicates", "action", "reason_trail"],
                           uuids=args)

  for (uuid, watermark, priority, predicates, action, reason_trail) in result:
    ToStdout("UUID: %s", uuid)
    ToStdout("  Watermark: %s", watermark)
    ToStdout("  Priority: %s", priority)
    ToStdout("  Predicates: %s", predicates)
    ToStdout("  Action: %s", action)
    ToStdout("  Reason trail: %s", reason_trail)

  return 0


def DeleteFilter(_, args):
  """Remove a job filter rule.

  @type args: list
  @param args: a list of length 1 with the UUID of the filter to remove
  @rtype: int
  @return: the desired exit code

  """
  (uuid,) = args
  cl = GetClient()
  result = cl.DeleteFilter(uuid)
  assert result is None
  return 0


FILTER_PRIORITY_OPT = \
    cli_option("--priority",
               dest="priority", action="store", default=0, type="int",
               help="Priority for filter processing")

FILTER_PREDICATES_OPT = \
    cli_option("--predicates",
               dest="predicates", action="store", default=[], type="json",
               help="List of predicates in the Ganeti query language,"
                    " given as a JSON list.")

FILTER_ACTION_OPT = \
    cli_option("--action",
               dest="action", action="store", default="CONTINUE",
               type="filteraction",
               help="The effect of the filter. Can be one of 'ACCEPT',"
                    " 'PAUSE', 'REJECT', 'CONTINUE' and '[RATE_LIMIT, n]',"
                    " where n is a positive integer.")


commands = {
  "add": (
    AddFilter, ARGS_NONE,
    [FILTER_PRIORITY_OPT, FILTER_PREDICATES_OPT, FILTER_ACTION_OPT],
    "",
    "Adds a new filter rule"),
  "list": (
    ListFilters, ARGS_MANY_FILTERS,
    [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT],
    "[<filter-uuid>...]",
    "Lists the job filter rules. The available fields can be shown"
    " using the \"list-fields\" command (see the man page for details)."
    " The default list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
  "list-fields": (
    ListFilterFields, [ArgUnknown()],
    [NOHDR_OPT, SEP_OPT],
    "[<fields>...]",
    "Lists all available fields for filters"),
  "info": (
    ShowFilter, ARGS_MANY_FILTERS,
    [],
    "[<filter-uuid>...]",
    "Shows information about the filter(s)"),
  "replace": (
    ReplaceFilter, ARGS_ONE_FILTER,
    [FILTER_PRIORITY_OPT, FILTER_PREDICATES_OPT, FILTER_ACTION_OPT],
    "<filter-uuid>",
    "Replaces a filter"),
  "delete": (
    DeleteFilter, ARGS_ONE_FILTER,
    [],
    "<filter-uuid>",
    "Removes a filter"),
}


def Main():
  return GenericMain(commands)
