/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - sch-rnd (executable)
 *  Copyright (C) 2022 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022)
 *
 *  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.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/sch-rnd
 *    contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html
 *    mailing list: http://www.repo.hu/projects/sch-rnd/contact.html
 */

/* Emergency and backup saves */

#include <libcschem/config.h>

#include <ctype.h>

#include <librnd/core/error.h>
#include <librnd/core/compat_misc.h>
#include <librnd/core/globalconst.h>
#include <librnd/hid/hid.h>
#include <librnd/core/paths.h>
#include <librnd/core/conf_multi.h>

#include <libcschem/concrete.h>
#include <libcschem/plug_io.h>

#include "conf_core.h"

#include "emergency.h"

static const char *valid_emergency_name(void)
{
	static const char *stock = "SCH.%ld-%ld.save";
	const char *s;
	int lds = 0;

	for(s = conf_core.rc.emergency_name; *s != '\0'; s++) {
		if (*s == '%') {
			s++;
			while(isdigit(*s)) s++;
			if ((s[0] == 'l') && (s[1] == 'd')) {
				lds++;
				s++;
			}
			else {
				fprintf(stderr, "Invalid conf_core.rc.emergency_name: format string other than %%ld\n");
				return stock;
			}
		}
	}

	if (lds > 2) {
		fprintf(stderr, "Invalid conf_core.rc.emergency_name: more than two %%ld's \n");
		return stock;
	}

	return conf_core.rc.emergency_name;
}

void sch_rnd_save_in_tmp(csch_sheet_t *sheet)
{
	char filename[RND_PATH_MAX];

	/* memory might have been released before this function is called */
	if ((sheet != NULL) && sheet->changed && (conf_core.rc.emergency_name != NULL) && (*conf_core.rc.emergency_name != '\0')) {
		const char *fmt = "lihata";
		int res;

		sprintf(filename, valid_emergency_name(), (long int)rnd_getpid(), sheet->uid);
		rnd_message(RND_MSG_INFO, "Trying to save your sheet in '%s'\n", filename);
		res = csch_save_sheet(sheet, filename, fmt);
		if (res != 0)
			rnd_message(RND_MSG_INFO, " (failed)\n");
	}
}

void sch_rnd_save_all_in_tmp(void)
{
	rnd_design_t *dsg;

	for(dsg = gdl_first(&rnd_designs); dsg != NULL; dsg = dsg->link.next)
		sch_rnd_save_in_tmp((csch_sheet_t *)dsg);
}


/* front-end for pcb_save_in_tmp() to makes sure it is only called once */
static rnd_bool dont_save_any_more = rnd_false;
void sch_rnd_emergency_save(void)
{
	if (!dont_save_any_more) {
		dont_save_any_more = rnd_true;
		sch_rnd_save_all_in_tmp();
	}
}

void sch_rnd_disable_emergency_save(void)
{
	dont_save_any_more = rnd_true;
}


/*** Timed backup (autosave) ***/

static rnd_hidval_t backup_timer;

/*
 * If the backup interval is > 0 then set another timer.  Otherwise
 * we do nothing and it is up to the GUI to call sch_rnd_enable_autosave()
 * after setting conf_core.rc.backup_interval > 0 again.
 */
static void backup_cb(rnd_hidval_t data)
{
	backup_timer.ptr = NULL;
	sch_rnd_backup_all();
	if (conf_core.rc.backup_interval > 0 && rnd_gui->add_timer)
		backup_timer = rnd_gui->add_timer(rnd_gui, backup_cb, 1000 * conf_core.rc.backup_interval, data);
}

void sch_rnd_enable_autosave(void)
{
	rnd_hidval_t x;

	x.ptr = NULL;

	/* If we already have a timer going, then cancel it out */
	if (backup_timer.ptr != NULL && rnd_gui->stop_timer)
		rnd_gui->stop_timer(rnd_gui, backup_timer);

	backup_timer.ptr = NULL;
	/* Start up a new timer */
	if ((conf_core.rc.backup_interval > 0) && (rnd_gui->add_timer != NULL))
		backup_timer = rnd_gui->add_timer(rnd_gui, backup_cb, 1000 * conf_core.rc.backup_interval, x);
}

/* Saves the board in a backup file using the name configured in conf_core.rc.backup_name */
void sch_rnd_backup(csch_sheet_t *sheet)
{
	char *filename = NULL;
	const char *fmt = "lihata";

	if ((sheet->hidlib.fullpath == NULL) || (sheet->hidlib.fullpath[0] == '<'))
		return; /* do not make backups of <none> */

	filename = rnd_build_fn(&sheet->hidlib, conf_core.rc.backup_name);
	if (filename == NULL) {
		fprintf(stderr, "sch_rnd_backup(): can't build file name for a backup\n");
		exit(1);
	}

	csch_save_sheet_backup(sheet, filename, fmt);

	free(filename);
}

void sch_rnd_backup_all(void)
{
	rnd_design_t *dsg;
	for(dsg = gdl_first(&rnd_designs); dsg != NULL; dsg = dsg->link.next)
		sch_rnd_backup((csch_sheet_t *)dsg);
}
