/*****************************************************************************\
*                                                                             *
*  Name   : service_controller                                                *
*  Author : Chris Koeritz                                                     *
*                                                                             *
*******************************************************************************
* Copyright (c) 2000-$now By Author.  This program is free software; you can  *
* redistribute it and/or modify it under the terms of the GNU General Public  *
* License as published by the Free Software Foundation; either version 2 of   *
* the License or (at your option) any later version.  This is online at:      *
*     http://www.fsf.org/copyleft/gpl.html                                    *
* Please send any updates to: fred@gruntose.com                               *
\*****************************************************************************/

#include <basis/istring.h>
#include <loggers/console_logger.h>
#include <opsystem/application_shell.h>
#include <opsystem/filename.h>
#include <data_struct/static_memory_gremlin.h>
#include <service_ext/service_control.h>

const int SERVICE_SHUTDOWN_DELAY = 4 * SECOND_ms;
  // this is the interval we pause between stopping a service and restarting
  // it.  apparently the fact that windows returns from the stop call doesn't
  // mean the process is gone yet.

class service_controller : public application_shell
{
public:
  service_controller() : application_shell(class_name()) {}

  virtual int execute();

  IMPLEMENT_CLASS_NAME("service_controller");

  int instruct();
    // print the instructions.
};

////////////////////////////////////////////////////////////////////////////

int service_controller::instruct()
{
  log(filename(__argv[0]).rootname() + " Usage:");
  log("\
This program provides control over services in MS-Win32 operating systems.\n\
The first parameter must be \"start\", \"stop\", \"restart\", \"manual\", or\n\
\"automatic\".  This specifies how to control the service.  The second\n\
parameter is the name of the service.  This must be identical to the service\n\
name registered with the operating system.  The start, stop and restart\n\
flags operate on the running state of a service.  The manual and automatic\n\
flags simply change the service launch configuration.\n\
\n\
Example:\n\
\tservice_controller restart app_launcher\n");
  return 1;
}

int service_controller::execute()
{
  SET_DEFAULT_CONSOLE_LOGGER;
  if (__argc < 3) return instruct();

  istring control_word(__argv[1]);
  control_word.to_lower();

  istring service_name(__argv[2]);
  service_name.to_lower();

  service_control ctl;

  if (control_word == "stop")
    return !(ctl.control_service(service_name, false, false)
        == service_control::OKAY);
  else if (control_word == "start")
    return !(ctl.control_service(service_name, true, false)
        == service_control::OKAY);
  else if (control_word == "restart") {
    // stop it and then restart.  we don't worry too much if it wasn't stopped,
    // since it might not have been started in the first place.
    ctl.control_service(service_name, false, true);
//argh!  no, we should be waiting until the app actually is gone.
    portable::sleep_ms(SERVICE_SHUTDOWN_DELAY);
    return !(ctl.control_service(service_name, true, false)
        == service_control::OKAY);
  } else if (control_word == "manual") {
    return !(ctl.reconfigure_service(service_name, service_control::MANUAL)
        == service_control::OKAY);
  } else if (control_word == "automatic") {
    return !(ctl.reconfigure_service(service_name, service_control::AUTOMATIC)
        == service_control::OKAY);
  } else return instruct();
}

////////////////////////////////////////////////////////////////////////////

HOOPLE_MAIN(service_controller, )

#ifdef __BUILD_STATIC_APPLICATION__
  // static dependencies found by buildor_gen_deps.sh:
  #include <basis/array.cpp>
  #include <basis/byte_array.cpp>
  #include <basis/callstack_tracker.cpp>
  #include <basis/chaos.cpp>
  #include <basis/convert_utf.cpp>
  #include <basis/definitions.cpp>
  #include <basis/earth_time.cpp>
  #include <basis/guards.cpp>
  #include <basis/istring.cpp>
  #include <basis/log_base.cpp>
  #include <basis/memory_checker.cpp>
  #include <basis/mutex.cpp>
  #include <basis/object_base.cpp>
  #include <basis/outcome.cpp>
  #include <basis/packable.cpp>
  #include <basis/portable.cpp>
  #include <basis/sequence.cpp>
  #include <basis/set.cpp>
  #include <basis/utility.cpp>
  #include <basis/version_record.cpp>
  #include <data_struct/amorph.cpp>
  #include <data_struct/bit_vector.cpp>
  #include <data_struct/byte_hasher.cpp>
  #include <data_struct/configurator.cpp>
  #include <data_struct/hash_table.cpp>
  #include <data_struct/pointer_hash.cpp>
  #include <data_struct/stack.cpp>
  #include <data_struct/static_memory_gremlin.cpp>
  #include <data_struct/string_hash.cpp>
  #include <data_struct/string_hasher.cpp>
  #include <data_struct/string_table.cpp>
  #include <data_struct/symbol_table.cpp>
  #include <data_struct/table_configurator.cpp>
  #include <loggers/console_logger.cpp>
  #include <loggers/file_logger.cpp>
  #include <loggers/locked_logger.cpp>
  #include <loggers/null_logger.cpp>
  #include <loggers/program_wide_logger.cpp>
  #include <opsystem/application_base.cpp>
  #include <opsystem/application_shell.cpp>
  #include <opsystem/byte_filer.cpp>
  #include <opsystem/command_line.cpp>
  #include <opsystem/critical_events.cpp>
  #include <opsystem/directory.cpp>
  #include <opsystem/filename.cpp>
  #include <opsystem/ini_config.cpp>
  #include <opsystem/ini_parser.cpp>
  #include <opsystem/path_configuration.cpp>
  #include <opsystem/rendezvous.cpp>
  #include <service_ext/service_control.cpp>
  #include <textual/byte_format.cpp>
  #include <textual/parser_bits.cpp>
  #include <textual/string_manipulation.cpp>
  #include <textual/tokenizer.cpp>
#endif // __BUILD_STATIC_APPLICATION__

