///////////////////////////////////////////////////////////////////////////////
//                                                                             
//  Copyright (C) 2008-2012  Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>     
//                                                                             
//  See accompanying file COPYING.TXT file for licensing details.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_SERVICE_H
#define CPPCMS_SERVICE_H

#include <cppcms/defs.h>
#include <booster/noncopyable.h>
#include <booster/hold_ptr.h>
#include <booster/function.h>
#include <locale>
#include <booster/auto_ptr_inc.h>
#include <cppcms/locale_fwd.h>
#include <cppcms/json.h>

namespace booster {
	namespace aio {
		class io_service;
	}
}

///
/// \brief This is the namespace where all CppCMS functionality is placed
///
namespace cppcms {
	namespace plugin {
		class scope;
	}
	namespace impl {
		struct cached_settings;
		class service;
		namespace cgi {
			class acceptor;
		}
	}

	class applications_pool;
	class thread_pool;
	class session_pool;
	class cache_pool;
	class forwarder; 
	
	namespace json {
		class value;
	}
	namespace views {
		class manager;
	}

	///
	/// \brief This class represent the central event loop of the CppCMS applications.
	///
	/// This is the central class that is responsible for management of CppCMS services: management of HTTP requests and
	/// responses, sessions, cache and much more services. It is the central class that runs during execution of any CppCMS
	/// service.
	///

	class CPPCMS_API service : public booster::noncopyable
	{
	public:
		///
		/// Load configuration settings from the command line parameters. This object can be passed
		/// to service(json::value const &v) constructor allowing to alter these settings before
		/// creating the actual service object.
		///
		static json::value load_settings(int argc,char *argv[]);
		///
		/// Create a new service, passing all configuration settings via json::value instead of parsing command line parameters.
		///
		service(json::value const &v);
		///
		/// Parse command line parameters, get the configuration file and additional options and create the service.
		///
		/// Note for Windows users: argv is assumed to be UTF-8 encoded strings, if you want pass non-ascii or "wide" parameters
		/// you need convert them from UTF-16 to UTF-8. For example you can use booster::nowide::convert functions.
		///
		service(int argc,char *argv[]);
		///
		/// Destroy the service - the last class to go down.
		///
		/// Note, if you have asynchronous applications that are not owned the service class they must be destroyed before it
		///
		~service();

		///
		/// Start the central even loop of CppCMS service. By default, it also install signal handlers on POSIX platforms
		/// to handle SIGINT, SIGTERM and SIGUSR1 signals or uses SetConsoleCtrlHandler on Windows platforms waiting on
		/// C, BREAK, CLOSE and SHUTDOWN events.
		///
		/// This even call service::shutdown function that stops the main event loop and shutdowns the service properly.
		///
		/// If you want to disable these handlers, you may set service.disable_global_exit_handling option to true.
		///
		void run();

		///
		/// Stop the service event loop. This member function is both thread and signal safe.
		///
		void shutdown();

		///
		/// Get the configuration setting the service was created with.
		///
		json::value const &settings();
		
		///
		/// Get a cppcms::applications_pool instance of this service
		///
		cppcms::applications_pool &applications_pool();
		///
		/// Get a cppcms::thread_pool instance of this service
		///
		cppcms::thread_pool &thread_pool();
		///
		/// Get a cppcms::session_pool instance of this service, never used directly by user level applications 
		///
		cppcms::session_pool &session_pool();
		///
		/// Get the cppcms::views::manager instance
		///
		cppcms::views::manager &views_pool();
		///
		/// Get the cppcms::cache_pool instance of this service, never used directly by user level applications
		///
		cppcms::cache_pool &cache_pool();
		///
		/// Get cppcms::forwarder instance of this service
		///
		cppcms::forwarder &forwarder();

		///
		/// Get locale::generator instance of this service
		///
		locale::generator const &generator();
		///
		/// Get the default locale for this service.
		///
		std::locale locale();
		///
		/// Get a locale by \a name, shortcut to generator().get(name);
		///
		std::locale locale(std::string const &name);


		///
		/// Get low level central event loop of the CppCMS service that allows you to connect asynchronous application with generic
		/// asynchronous sockets API or create any asynchronous TCP/IP servers over it.
		///
		booster::aio::io_service &get_io_service();

		///
		/// Post an execution handler \a handler to the event loop queue. This member function is thread safe allowing 
		/// safe communication between event loop thread (where all asynchronous applications run) and any other threads.
		///
		void post(booster::function<void()> const &handler);

		///
		/// Execute handler after forking processes (on POSIX platforms). This is useful when you want to start various asynchronous
		/// applications or services in separate processes.
		///
		void after_fork(booster::function<void()> const &handler);
		
		///
		/// Get the size of thread pool each of CppCMS processes will be running.
		///
		int threads_no();

		///
		/// Get the number of forked processes used by the service. Always 0 on Windows and Cygwin.
		///
		int procs_no();

		///
		/// Get current process identification number. Note, this is not getpid() function.
		///
		/// When CppCMS service manages preforked process pool, each process gets its own id starting from 1 to procs_no() when
		/// the parent supervisor process gets an id 0. If one of the forked processes crash, it is replaced with a new process
		/// with same id.
		///
		/// So if an application want to run certain activity that can't be executed in multiple processes it can setup an after_fork
		/// handle that would check the process id and start this activity.
		///
		/// Under Windows and Cygwin it is always 0.
		///
		int process_id();


		///
		/// Get plugin scope ownd by the cppcms::service
		///
		plugin::scope &plugins();

		/// \cond INTERNAL
		
		// internal functions never call it directly

		cppcms::impl::service &impl();

		impl::cached_settings const &cached_settings();
		
		
		/// \endcond

	private:
		void setup();
		std::auto_ptr<cppcms::impl::cgi::acceptor> setup_acceptor(json::value const &,int,int shift=0);
		void stop();
		void start_acceptor(bool after_fork=false);
		void setup_exit_handling();
		bool prefork();
		void run_prepare();
		void after_fork_exec();
		void run_acceptor();
		void run_event_loop();
		#ifdef CPPCMS_WIN32
		void run_win_console();
		#endif
		#ifdef CPPCMS_WIN_NATIVE
		void win_service_prepare();
		void win_service_exec();
		void run_win_service();
		#endif
		booster::hold_ptr<impl::service> impl_;
	};

} //




#endif
