// ---------------------------------------------------------------------
//
// xml_server.cxx, a part of flamp
//
// Copyflampht (C) 2023
// Dave Freese, W1HKJ
//
// This library 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 3 of the License, or
// (at your option) any later version.
//
// This library 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 the program; if not, write to the
//
//  Free Software Foundation, Inc.
//  51 Franklin Street, Fifth Floor
//  Boston, MA  02110-1301 USA.
//
// ---------------------------------------------------------------------
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <fcntl.h>
#include <vector>
#include <pthread.h>

#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Enumerations.H>

#include "flamp.h"
#include "flamp_dialog.h"
#include "dialogs.h"
#include "XmlRpc.h"

// The server
using namespace XmlRpc;

XmlRpcServer flamp_server;

//------------------------------------------------------------------------------
// Set fskio transmit std::string
//------------------------------------------------------------------------------

extern void FSK_add(std::string);
static std::string fskio_text;

class flamp_create_script : public XmlRpcServerMethod {
public:

	flamp_create_script(XmlRpcServer* s) : XmlRpcServerMethod("flamp.create_script", s) {}

		void execute(XmlRpcValue& params, XmlRpcValue& result) { 
			std::string pathname = (std::string)params[0];
			std::string text = (std::string)params[1];

			if (xml_create_script(pathname, text))
				result = 1;
			else
				result = 0;
	}

	std::string help() { return std::string("sends text using fskio DTR/RTS keying"); }

} flamp_create_script(&flamp_server);

//------------------------------------------------------------------------------
/** ********************************************************
 *
 ***********************************************************/
 
bool queue_sent = false;
void send_queue(void*)
{
	if(transmitting) {
		abort_request();
		return;
	}

	if (tx_queue->size() == 0) {
		return;
	}

	transmit_queued(true, false);
	queue_sent = true;
}

class flamp_transmit_queue : public XmlRpcServerMethod {
public:
	flamp_transmit_queue (XmlRpcServer* s) : XmlRpcServerMethod("flamp.transmit_queue", s) {}

	void execute(XmlRpcValue& params, XmlRpcValue& result) { 

		queue_sent = false;
		Fl::awake(send_queue);
		result = queue_sent;
	}
	std::string help() { return std::string("transmit queued messages"); }

} flamp_transmit_queue(&flamp_server);


//------------------------------------------------------------------------------

std::string exec_script_name;

void do_xml_execute_script(void *)
{
	xml_execute_script(exec_script_name);
}

class flamp_execute_script : public XmlRpcServerMethod {
public:
	flamp_execute_script (XmlRpcServer* s) : XmlRpcServerMethod("flamp.execute_script", s) {}

	void execute(XmlRpcValue& params, XmlRpcValue& result) { 

		exec_script_name = (std::string)(params[0]);

		Fl::awake(do_xml_execute_script);

		result = 1;

	}
	std::string help() { return std::string("execute script 'pathname'"); }

} flamp_execute_script(&flamp_server);


struct MLIST {
	std::string name; std::string signature; std::string help;
} mlist[] = {
	{ "flamp.create_script",   "i:s", "create script 'pathname', 'script_text'" },
	{ "flamp.execute_script",  "n:s", "execute script 'pathname'"},
	{ "flamp.transmit_queue",  "n:i", "transmit queued messages"}
};

class flamp_list_methods : public XmlRpcServerMethod {
public:
	flamp_list_methods(XmlRpcServer *s) : XmlRpcServerMethod("flamp.list_methods", s) {}

	void execute(XmlRpcValue& params, XmlRpcValue& result) { 
		std::vector<XmlRpcValue> methods;
		for (size_t n = 0; n < sizeof(mlist) / sizeof(*mlist); ++n) {
			XmlRpcValue::ValueStruct item;
			item["name"]      = mlist[n].name;
			item["signature"] = mlist[n].signature;
			item["help"]      = mlist[n].help;
			methods.push_back(item);
		}

		result = methods;
	}

	std::string help() { return std::string("get flamp methods"); }
} flamp_list_methods(&flamp_server);

//------------------------------------------------------------------------------
// support thread xmlrpc clients
//------------------------------------------------------------------------------

pthread_t *xml_thread = 0;

static bool run_server = false;

void * xml_thread_loop(void *d)
{
	run_server = true;
	for(;;) {
		if (!run_server) break;
		flamp_server.work(-1.0);
	}
	return NULL;
}

void start_server(int port)
{
//	XmlRpc::setVerbosity(progStatus.rpc_level);

// Create the server socket on the specified port
	flamp_server.bindAndListen(port);

// Enable introspection
	flamp_server.enableIntrospection(true);

	xml_thread = new pthread_t;
	if (pthread_create(xml_thread, NULL, xml_thread_loop, NULL)) {
		perror("pthread_create");
		clean_shutdown();
	}
}

void exit_server()
{
	flamp_server.exit();
	run_server = false;
}

void set_server_port(int port)
{
	flamp_server.bindAndListen(port);
}

std::string print_xmlhelp()
{
	static std::string pstr;
	pstr.clear();
	std::string line;
	size_t f1_len = 0;
	for (size_t n = 0; n < sizeof(mlist) / sizeof(*mlist); ++n) {
		if (mlist[n].name.length() > f1_len) f1_len = mlist[n].name.length();
	}
	for (size_t n = 0; n < sizeof(mlist) / sizeof(*mlist); ++n) {
		line.clear();
		line.assign(mlist[n].name);
		line.append(f1_len + 2 - line.length(), ' ');
		line.append(mlist[n].signature);
		line.append("  ");
		line.append(mlist[n].help);
		line.append("\n");
		pstr.append(line);
	}
	return pstr;
}

