/*
 * Sai server
 *
 * Copyright (C) 2019 - 2025 Andy Green <andy@warmcat.com>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation:
 *  version 2.1 of the License.
 *
 *  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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA  02110-1301  USA
 *
 * The same ws interface is connected-to by builders (on path /builder), and
 * provides the query transport for browsers (on path /browse).
 *
 * There's a single server slite3 database containing events, and a separate
 * sqlite3 database file for each event, it only contains tasks and logs for
 * the event and can be deleted when the event record associated with it is
 * deleted.  This is to keep is scalable when there may be thousands of events
 * and related tasks and logs stored.
 */

#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <fcntl.h>

#include "s-private.h"

int
sql3_get_integer_cb(void *user, int cols, char **values, char **name)
{
	unsigned int *pui = (unsigned int *)user;

	if (cols < 1 || !values[0])
		*pui = 0;
	else
		*pui = (unsigned int)atoi(values[0]);

	return 0;
}

int
sql3_get_string_cb(void *user, int cols, char **values, char **name)
{
	char *p = (char *)user;

	p[0] = '\0';
	if (cols < 1 || !values[0])
		return 0;

	lws_strncpy(p, values[0], 33);

	return 0;
}

void
sai_task_uuid_to_event_uuid(char *event_uuid33, const char *task_uuid65)
{
	memcpy(event_uuid33, task_uuid65, 32);
	event_uuid33[32] = '\0';
}



int
sai_detach_builder(struct lws_dll2 *d, void *user)
{
	lws_dll2_remove(d);

	return 0;
}

int
sai_detach_resource(struct lws_dll2 *d, void *user)
{
	lws_dll2_remove(d);

	return 0;
}

int
sai_destroy_resource_wellknown(struct lws_dll2 *d, void *user)
{
	sai_resource_wellknown_t *rwk =
			lws_container_of(d, sai_resource_wellknown_t, list);

	/*
	 * Just detach everything listed on this well-known resource...
	 * everything listed here is ultimately owned by a pss and will be
	 * destroyed when that goes down
	 */

	lws_dll2_foreach_safe(&rwk->owner_queued, NULL, sai_detach_resource);
	lws_dll2_foreach_safe(&rwk->owner_leased, NULL, sai_detach_resource);

	lws_dll2_remove(d);

	free(rwk);

	return 0;
}

int
sai_pcon_destroy_cb(struct lws_dll2 *d, void *user)
{
	sai_power_controller_t *pc = lws_container_of(d, sai_power_controller_t, list);

	lws_dll2_remove(d);

	/* Also need to clear the child lists */
	lws_dll2_foreach_safe(&pc->controlled_builders_owner, NULL, sai_detach_builder);

	/* We don't free pc because it's usually in an lwsac, but if it's from db it might be malloced.
	 * In s-power.c usage, it's lwsac.
	 * Wait, s-sai.c uses 'server->pdb' which is sqlite.
	 * The in-memory structure 'sai_power_managed_builders_t' is what we are likely destroying here if we are cleaning up ephemeral state.
	 *
	 * However, 'server' struct in 's-private.h' doesn't seem to have a list of live PCONs.
	 * We should check s-private.h to see if we added one.
	 * If not, we might be relying on the database + transient messages.
	 */

	return 0;
}

void
sais_server_destroy(struct vhd *vhd, sais_t *server)
{
	lwsl_notice("%s: server %p\n", __func__, server);
	if (server)
		lws_dll2_foreach_safe(&server->builder_owner, NULL,
				      sai_detach_builder);

	sai_event_db_close_all_now(&vhd->sqlite3_cache);

	lws_struct_sq3_close(&server->pdb);

	lws_dll2_foreach_safe(&server->resource_wellknown_owner, NULL,
			      sai_destroy_resource_wellknown);
}