# Copyright 2014 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can
# be found in the LICENSE file.
"""This module defines the vtctl client interface.
"""

import logging

# mapping from protocol to python class. The protocol matches the string
# used by vtctlclient as a -vtctl_client_protocol parameter.
vtctl_client_conn_classes = dict()


def register_conn_class(protocol, c):
  """Used by implementations to register themselves.

  Args:
    protocol: short string to document the protocol.
    c: class to register.
  """
  vtctl_client_conn_classes[protocol] = c


def connect(protocol, *pargs, **kargs):
  """connect will return a dialed VtctlClient connection to a vtctl server.

  Args:
    protocol: the registered protocol to use.
    *pargs: passed to the registered protocol __init__ method.
    **kargs: passed to the registered protocol __init__ method.

  Returns:
    A dialed VtctlClient.

  Raises:
    Exception: if the protocol is unknown.
  """
  if protocol not in vtctl_client_conn_classes:
    raise Exception('Unknown vtclient protocol', protocol)
  conn = vtctl_client_conn_classes[protocol](*pargs, **kargs)
  conn.dial()
  return conn


class Event(object):
  """Event is streamed by VtctlClient.

  Eventually, we will just use the proto3 definition for logutil.proto/Event.
  """

  INFO = 0
  WARNING = 1
  ERROR = 2
  CONSOLE = 3

  def __init__(self, time, level, file, line, value):
    self.time = time
    self.level = level
    self.file = file
    self.line = line
    self.value = value


class VtctlClient(object):
  """VtctlClient is the interface for the vtctl client implementations.

  All implementations must implement all these methods.
  If something goes wrong with the connection, this object will be thrown out.
  """

  def __init__(self, addr, timeout):
    """Initialize a vtctl connection.

    Args:
      addr: server address. Can be protocol dependent.
      timeout: connection timeout (float, in seconds).
    """
    pass

  def dial(self):
    """Dial to the server. If successful, call close() to close the connection.
    """
    pass

  def close(self):
    """Close the connection. This object may be re-used again by calling dial().
    """
    pass

  def is_closed(self):
    """Checks the connection status.

    Returns:
      True if this connection is closed.
    """
    pass

  def execute_vtctl_command(self, args, action_timeout=30.0, lock_timeout=5.0):
    """Executes a remote command on the vtctl server.

    Args:
      args: Command line to run.
      action_timeout: total timeout for the action (float, in seconds).
      lock_timeout: timeout for locking topology (float, in seconds).

    Returns:
      This is a generator method that yields Event objects.
    """
    pass


def execute_vtctl_command(client, args, action_timeout=30.0,
                          lock_timeout=5.0, info_to_debug=False):
  """This is a helper method that executes a remote vtctl command.

  It logs the output to the logging module, and returns the console output.

  Args:
    client: VtctlClient object to use.
    args: Command line to run.
    action_timeout: total timeout for the action (float, in seconds).
    lock_timeout: timeout for locking topology (float, in seconds).
    info_to_debug: if set, changes the info messages to debug.

  Returns:
    The console output of the action.
  """

  console_result = ''
  for e in client.execute_vtctl_command(args, action_timeout=action_timeout,
                                        lock_timeout=lock_timeout):
    if e.level == Event.INFO:
      if info_to_debug:
        logging.debug('%s', e.value)
      else:
        logging.info('%s', e.value)
    elif e.level == Event.WARNING:
      logging.warning('%s', e.value)
    elif e.level == Event.ERROR:
      logging.error('%s', e.value)
    elif e.level == Event.CONSOLE:
      console_result += e.value

  return console_result
