#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# AWL simulator - Server interface
#
# Copyright 2013-2019 Michael Buesch <m@bues.ch>
#
# 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 program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

from __future__ import division, absolute_import, print_function, unicode_literals

import sys
import getopt
from socket import AF_INET, AF_INET6

from awlsim_loader.common import *
from awlsim_loader.core import *
from awlsim_loader.coreclient import *
from awlsim_loader.coreserver import *
import awlsim_loader.cython_helper as cython_helper


def usage():
	print("awlsim-server version %s" % VERSION_STRING)
	print("")
	print("Usage: awlsim-server [OPTIONS] <project.awlpro>")
	print("")
	print("<project.awlpro> is an optional project file that will be loaded.")
	print("If -w is also given, all project changes are written back to that file.")
	print("")
	print("Options:")
	print(" -l|--listen HOST[:PORT] Listen on the specified HOST:PORT")
	print("                         Defaults to %s:%d" %\
		  (AwlSimServer.DEFAULT_HOST, AwlSimServer.DEFAULT_PORT))
	print("                         The special values 'all', 'any' or an empty host")
	print("                         can be used to listen on any interface.")
	print(" -4|--force-ipv4         Force the use of IPv4.")
	print(" -6|--force-ipv6         Force the use of IPv6.")
	print(" -B|--background         Fork a background process")
	print(" -w|--rw-project         Enable project file writing")
	print(" -S|--allow-shutdown     Allow remote system shutdown")
	print(" -L|--loglevel LVL       Set the log level:")
	print("                         0: Log nothing")
	print("                         1: Log errors")
	print("                         2: Log errors and warnings")
	print("                         3: Log errors, warnings and info messages (default)")
	print("                         4: Verbose logging")
	print("                         5: Extremely verbose logging")

def main():
	global opt_listen
	global opt_background

	opt_project = None
	opt_rwProject = False
	opt_listen = (AwlSimServer.DEFAULT_HOST, AwlSimServer.DEFAULT_PORT)
	opt_family = None
	opt_background = False
	opt_allowShutdown = False
	opt_loglevel = Logging.LOG_INFO

	try:
		(opts, args) = getopt.getopt(sys.argv[1:],
			"hl:46BwSL:",
			[ "help", "listen=", "force-ipv4", "force-ipv6",
			  "background", "rw-project", "allow-shutdown",
			  "loglevel=", ])
	except getopt.GetoptError as e:
		printError(str(e))
		usage()
		return ExitCodes.EXIT_ERR_CMDLINE
	for (o, v) in opts:
		if o in ("-h", "--help"):
			usage()
			return ExitCodes.EXIT_OK
		if o in ("-l", "--listen"):
			try:
				host, port = parseNetAddress(v)
				if not host.strip() or\
				   host in {"any", "all"}:
					host = ""
				if port is None:
					port = AwlSimServer.DEFAULT_PORT
				opt_listen = (host, port)
			except AwlSimError as e:
				printError("-l|--listen: %s" % e.message)
				sys.exit(1)
		if o in ("-4", "--force-ipv4"):
			opt_family = AF_INET
		if o in ("-6", "--force-ipv6"):
			opt_family = AF_INET6
		if o in ("-B", "--background"):
			opt_background = True
		if o in ("-w", "--rw-project"):
			opt_rwProject = True
		if o in ("-S", "--allow-shutdown"):
			opt_allowShutdown = True
		if o in ("-L", "--loglevel"):
			try:
				opt_loglevel = int(v)
			except ValueError:
				printError("-L|--loglevel: Invalid log level")
				sys.exit(1)
	if len(args) not in (0, 1):
		usage()
		return ExitCodes.EXIT_ERR_CMDLINE
	if args:
		opt_project = args[0]

	exitCode = ExitCodes.EXIT_OK
	try:
		Logging.setLoglevel(opt_loglevel)

		commandMask = 0
		if opt_allowShutdown:
			commandMask |= AwlSimServer.CMDMSK_SHUTDOWN

		if opt_background:
			interpreter = sys.executable
			assert(interpreter)
			serverProcess = AwlSimServer.start(listenHost=opt_listen[0],
							   listenPort=opt_listen[1],
							   listenFamily=opt_family,
							   forkInterpreter=interpreter,
							   commandMask=commandMask,
							   projectFile=opt_project,
							   projectWriteBack=opt_rwProject)
			printInfo("Started awlsim server process (PID: %d)" %\
				  serverProcess.pid)
		else:
			if cython_helper.shouldUseCython():
				printInfo("*** Using accelerated CYTHON core "
					  "(AWLSIM_CYTHON environment variable is set)")

			exitCode = AwlSimServer.start(listenHost=opt_listen[0],
						      listenPort=opt_listen[1],
						      listenFamily=opt_family,
						      forkInterpreter=None,
						      commandMask=commandMask,
						      projectFile=opt_project,
						      projectWriteBack=opt_rwProject)
	except AwlSimError as e:
		printError(e.getReport())
		return ExitCodes.EXIT_ERR_SIM

	return exitCode

if __name__ == "__main__":
	sys.exit(main())
