#!/usr/bin/env python

'''
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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.
'''

import optparse
import os
import sys

from ambari_commons.ambari_service import AmbariService
from ambari_commons.exceptions import FatalException
from ambari_commons.os_utils import remove_file
from ambari_commons.os_windows import SvcStatusCallback, WinServiceController
from ambari_metrics_collector.serviceConfiguration import get_properties, get_value_from_properties, DEBUG_MODE_KEY, \
  SUSPEND_START_MODE_KEY, PID_OUT_FILE, SERVER_OUT_FILE_KEY, SERVER_OUT_FILE, SERVICE_USERNAME_KEY, SERVICE_PASSWORD_KEY, \
  DEFAULT_CONF_DIR, EMBEDDED_HBASE_MASTER_SERVICE
from embedded_hbase_service import EmbeddedHBaseService
from main import server_process_main


class AMCollectorService(AmbariService):
  AmbariService._svc_name_ = "AmbariMetricsCollector"
  AmbariService._svc_display_name_ = "Ambari Metrics Collector"
  AmbariService._svc_description_ = "Ambari Metrics Collector Service"

  AmbariService._AdjustServiceVersion()

  # Adds the necessary script dir(s) to the Python's modules path.
  # Modify this as the deployed product's dir structure changes.
  def _adjustPythonPath(self, current_dir):
    python_path = os.path.join(current_dir, "sbin")
    sys.path.insert(0, python_path)
    pass

  @classmethod
  def Install(cls, startupMode = "auto", username = None, password = None, interactive = False,
              perfMonIni = None, perfMonDll = None):
    script_path = os.path.dirname(__file__.replace('/', os.sep))
    classPath = os.path.join(script_path, cls.__module__) + "." + cls.__name__

    return AmbariService.Install(classPath, startupMode, username, password, interactive,
                                                    perfMonIni, perfMonDll)

  def SvcDoRun(self):
    scmStatus = SvcStatusCallback(self)

    properties = get_properties()
    self.options.debug = get_value_from_properties(properties, DEBUG_MODE_KEY, self.options.debug)
    self.options.suspend_start = get_value_from_properties(properties, SUSPEND_START_MODE_KEY, self.options.suspend_start)

    self.redirect_output_streams()

    childProc = server_process_main(self.options, scmStatus)

    if not self._StopOrWaitForChildProcessToFinish(childProc):
      return

    remove_file(PID_OUT_FILE)
    pass

  def _InitOptionsParser(self):
    return init_options_parser()

  def redirect_output_streams(self):
    properties = get_properties()

    outFilePath = properties[SERVER_OUT_FILE_KEY]
    if (outFilePath is None or outFilePath == ""):
      outFilePath = SERVER_OUT_FILE

    self._RedirectOutputStreamsToFile(outFilePath)
    pass

def ctrlHandler(ctrlType):
  AMCollectorService.DefCtrlCHandler()
  return True

def svcsetup():
  AMCollectorService.set_ctrl_c_handler(ctrlHandler)

  # we don't save password between 'setup' runs, so we can't run Install every time. We run 'setup' only if user and
  # password provided or if service not installed
  if (SERVICE_USERNAME_KEY in os.environ and SERVICE_PASSWORD_KEY in os.environ):
    EmbeddedHBaseService.Install(username=os.environ[SERVICE_USERNAME_KEY], password=os.environ[SERVICE_PASSWORD_KEY])
    AMCollectorService.Install(username=os.environ[SERVICE_USERNAME_KEY], password=os.environ[SERVICE_PASSWORD_KEY])
  else:
    EmbeddedHBaseService.Install()
    AMCollectorService.Install()
  pass

#
# Starts the Ambari Metrics Collector. The server can start as a service or standalone process.
# args:
#  options.is_process = True - start the server as a process. For now, there is no restrictions for the number of
#     server instances that can run like this.
#  options.is_process = False - start the server in normal mode, as a Windows service. If the Ambari Metrics Collector
#     is not registered as a service, the function fails. By default, only one instance of the service can
#     possibly run.
#
def start(options):
  AMCollectorService.set_ctrl_c_handler(ctrlHandler)

  if options.is_process:
    #Run as a normal process. Invoke the ServiceMain directly.
    childProc = server_process_main(options)

    childProc.wait()

    remove_file(PID_OUT_FILE)
  else:
    AMCollectorService.Start()

#
# Stops the Ambari Metrics Collector. Ineffective when the server is started as a standalone process.
#
def stop():
  AMCollectorService.Stop()

#
# Prints the Ambari Metrics Collector service status.
#
def svcstatus(options):
  options.exit_message = None

  statusStr = AMCollectorService.QueryStatus()
  print "Ambari Metrics Collector is " + statusStr


def setup(options):
  svcsetup()

def init_options_parser():
  parser = optparse.OptionParser(usage="usage: %prog action [options]", )
  parser.add_option('--config', dest="conf_dir",
                    default=DEFAULT_CONF_DIR,
                    help="Configuration files directory")
  parser.add_option('--debug', action="store_true", dest='debug', default=False,
                    help="Start ambari-metrics-collector in debug mode")
  parser.add_option('--suspend-start', action="store_true", dest='suspend_start', default=False,
                    help="Freeze ambari-metrics-collector Java process at startup in debug mode")
  parser.add_option('--process', action="store_true", dest='is_process', default=False,
                    help="Start ambari-metrics-collector as a process, not as a service")
  parser.add_option('--noembedded', action="store_true", dest='no_embedded_hbase', default=False,
                    help="Don't attempt to start the HBASE services. Expect them to be already installed and running.")

  # --help reserved for help
  return parser


def init_service_debug(options):
  if options.debug:
    sys.frozen = 'windows_exe'  # Fake py2exe so we can debug


def ensure_hdp_service_soft_dependencies():
  ret = WinServiceController.EnsureServiceIsStarted(EMBEDDED_HBASE_MASTER_SERVICE)
  if ret != 0:
    err = 'ERROR: Cannot start service "{0}". Error = {1}'.format(EMBEDDED_HBASE_MASTER_SERVICE, ret)
    raise FatalException(1, err)
