   /****************************************************************
    Copyright (C) 1986-2000 by

    F6FBB - Jean-Paul ROUBELAT
    6, rue George Sand
    31120 - Roquettes - France
	jpr@f6fbb.org

    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Parts of code have been taken from many other softwares.
    Thanks for the help.
    ****************************************************************/

/*
 * THEMES.C
 *
 * Gestion des themes de bulletins
 */

#include <serv.h>

#define READ_OK(st)	((st.status != 'K') && (st.status != 'A') && (st.status != 'H'))

#define MAX_THEMES	32

static int themes_read (int verbose);

static void error_file (void);
static void libere_theme (void);
static void prompt_themes (void);
static void trans_num (void);

void valide_themes (unsigned, bullist *);

typedef char NomTh[7];

typedef struct
{
	char nom[11];
	char nb_themes;
	NomTh *lthemes;
	int nb_bull;
}
Theme;

static int tot_themes;
static int nolig;

static Theme *theme_liste = NULL;

void end_themes (void)
{
	if (theme_liste)
		libere_theme ();
}

#define CADENCE 5;

void scan_themes (void)
{
#ifdef __FBBDOS__
	fen *fen_ptr;

#endif
	unsigned offset = 0;
	int nb = 0;
	long last_num = 0L;
	bloc_mess *bptr = tete_dir;
	bullist ligne;


	deb_io ();
#ifdef __FBBDOS__
#ifdef ENGLISH
	fen_ptr = open_win (10, 5, 50, 8, INIT, "Themas");
#else
	fen_ptr = open_win (10, 5, 50, 8, INIT, "Themes");
#endif
#endif

	ouvre_dir ();

	while (bptr)
	{
		if (bptr->st_mess[offset].noenr)
		{
			++nb;
			read_dir (bptr->st_mess[offset].noenr, &ligne);

			if ((ligne.type == 'B') && (READ_OK (ligne)))
			{
				valide_themes (bptr->st_mess[offset].noenr, &ligne);
			}
			if ((nb % 100) == 0)
			{
#if defined(__WINDOWS__) || defined(__LINUX__)
				char buf[80];

				sprintf (buf, "%ld", bptr->st_mess[offset].nmess);
				InitText (buf);
#endif
#ifdef __FBBDOS__
				cprintf ("%ld\r", bptr->st_mess[offset].nmess);
#endif
			}
			last_num = bptr->st_mess[offset].nmess;
		}

		if (++offset == T_BLOC_MESS)
		{
			bptr = bptr->suiv;
			offset = 0;
		}
	}

#if defined(__WINDOWS__) || defined(__LINUX__)
	{
		char buf[80];

		sprintf (buf, "%ld", last_num);
		InitText (buf);
	}
#else
	cprintf ("%ld\r", last_num);
#endif

	ferme_dir ();

#ifdef __FBBDOS__
	attend_caractere (2);
	close_win (fen_ptr);
#endif
	fin_io ();
}

int theme_existe (char *theme, char liste[MAX_THEMES][11])
{
	int i;

	for (i = 0; i < tot_themes; i++)
	{
		if (strcmp (theme, liste[i]) == 0)
			return (1);
	}
	return (0);
}

void load_themes (void)
{
	int i, nb;
	FILE *fptr;
	char *ptr;
	char buffer[258];
	NomTh tmp_nom[100];
	NomTh *pnom;
	struct stat st;
	char nom_themes[MAX_THEMES][11];

	if ((stat (c_disque ("THEMES.SYS"), &st) == 0) && (st.st_mtime == t_thm))
		return;

	t_thm = st.st_mtime;

	if (theme_liste)
	{
		libere_theme ();
		theme_liste = NULL;
	}

	nolig = 0;
	tot_themes = 0;

	fptr = fopen (c_disque ("THEMES.SYS"), "rt");
	if (fptr == NULL)
	{
		return;
	}

	while (fgets (buffer, 257, fptr))
	{
		++nolig;
		ptr = strtok (buffer, " \t");
		if ((ptr == NULL) || (*ptr == '#'))
			continue;

		if (theme_existe (ptr, nom_themes))
		{
			fclose (fptr);
			error_file ();
			tot_themes = 0;
			return;
		}

		n_cpy (10, nom_themes[tot_themes], ptr);

		++tot_themes;

		if (tot_themes == MAX_THEMES)
			break;
	}

	if (tot_themes == 0)
	{
		fclose (fptr);
		return;
	}

	theme_liste = (Theme *) m_alloue (tot_themes * sizeof (Theme));

	rewind (fptr);

	tot_themes = 0;

	while (fgets (buffer, 257, fptr))
	{
		sup_ln (buffer);
		ptr = strtok (buffer, " \t");
		if ((ptr == NULL) || (*ptr == '#'))
			continue;

		n_cpy (10, theme_liste[tot_themes].nom, ptr);

		nb = 0;
		while ((ptr = strtok (NULL, " \t")) != NULL)
		{
			n_cpy (6, tmp_nom[nb], ptr);
			++nb;
		}
		if (nb)
			pnom = (NomTh *) m_alloue (nb * sizeof (NomTh));
		else
			pnom = NULL;
		for (i = 0; i < nb; i++)
			strcpy (pnom[i], tmp_nom[i]);
		theme_liste[tot_themes].lthemes = pnom;
		theme_liste[tot_themes].nb_themes = nb;
		theme_liste[tot_themes].nb_bull = 0;

		++tot_themes;
		if (tot_themes == MAX_THEMES)
			break;
	}

/*
   if (tot_themes)
   {
   for (i = 0 ; i < tot_themes ; i++)
   {
   cprintf("%s ", theme_liste[i].nom);
   if (((i+1) % 8) == 0)
   cprintf("\r\n");
   }
   cprintf("\r\n");
   }
 */
	fclose (fptr);

	/*
	   cprintf("3rd pass ... ");

	   for (i = 0 ; i < tot_themes ; i++)
	   {
	   cprintf("%2d:%-10s %-4d", i, theme_liste[i].nom, theme_liste[i].nb_bull);
	   if ((i+1) % 4 == 0)
	   cprintf("\r\n");
	   else
	   cprintf("  ");
	   }
	 */

	scan_themes ();
}

void valide_themes (unsigned noenr, bullist * pbul)
{
	int i, j;
	long val = 1L;
	long masque = 0L;

	if (theme_liste == NULL)
		return;

	for (i = 1; i < tot_themes; i++)
	{
		for (j = 0; j < theme_liste[i].nb_themes; j++)
		{
			if (strmatch (pbul->desti, theme_liste[i].lthemes[j]))
			{
				++theme_liste[i].nb_bull;
				masque |= val;
				break;
			}
		}
		val <<= 1L;
	}
	if (pbul->theme != masque)
	{
		pbul->theme = masque;
		if (noenr != 0)
			write_dir (noenr, pbul);
	}
	if (masque == 0L)
	{
		++theme_liste[0].nb_bull;
	}
}

static void libere_theme (void)
{
	int i;

	if (theme_liste == NULL)
		return;

	for (i = 0; i < NBVOIES; i++)
	{
		if ((svoie[i]->niv1 == N_THEMES) && (svoie[i]->niv2 != 0))
		{
			selvoie (i);
			pvoie->finf.theme = 0;
			prompt_themes ();
		}
	}

	for (i = 0; i < tot_themes; i++)
	{
		if (theme_liste[i].nb_themes)
		{
			m_libere (theme_liste[i].lthemes,
					  theme_liste[i].nb_themes * sizeof (NomTh));
		}
	}
	m_libere (theme_liste, tot_themes * sizeof (Theme));
	theme_liste = NULL;
	tot_themes = 0;
}

char *cur_theme (int voie)
{
	return (theme_liste[(int)svoie[voie]->finf.theme].nom);
}

int nbull_theme (int voie)
{
	return (theme_liste[(int)svoie[voie]->finf.theme].nb_bull);
}

static void prompt_themes (void)
{
	maj_niv (N_THEMES, 0, 0);

	pvoie->sr_mem = 0;

	texte (T_THE + 2);
}

static void list_topics (void)
{
	int i;
	char s[100];
	int numero = pvoie->finf.theme;

	for (i = 0; i < theme_liste[numero].nb_themes; i++)
	{
		sprintf (s, " %-6s", theme_liste[numero].lthemes[i]);
		out (s, strlen (s));

		if ((i + 1) % 8 == 0)
			cr ();
	}
	if (i % 8)
		cr ();
}

static void display_themes (void)
{
	int i;
	char s[100];

	for (i = 0; i < tot_themes; i++)
	{
		sprintf (s, "%2d:%-10s %-4d", i, theme_liste[i].nom, theme_liste[i].nb_bull);
		out (s, strlen (s));
		if ((i + 1) % 4 == 0)
			cr ();
		else
			out ("  ", 1);
	}
	if (i % 4)
		cr ();

	prompt_themes ();
}

static char *ltitre (int mode, bullist * pbul)	/* Mode = 1 pour LS */
{
	/*  int lg = (mode) ? 80 : 36 ; */
	int lg = 80;
	static char buf[100];

	if (pvoie->typlist)
	{
		sprintf (buf, "%-12s ", pbul->bid);
		if (mode)
			strn_cpy (lg, buf + 13, pbul->titre);
		else
			n_cpy (lg, buf + 13, pbul->titre);
	}
	else
	{
		if (mode)
			strn_cpy (lg, buf, pbul->titre);
		else
			n_cpy (lg, buf, pbul->titre);
	}
	return (buf);
}

static void alloue_list_numeros (void)
{
	if (pvoie->ptemp)
	{
		m_libere ((char *) pvoie->ptemp, pvoie->psiz);
		pvoie->ptemp = NULL;
		pvoie->psiz = 0;
	}

	pvoie->psiz = pvoie->temp2 * sizeof (long);

	pvoie->ptemp = m_alloue (pvoie->psiz);
}

static void aff_ligne (int numero, bullist * ligne)
{
	char *ptr;

	*ptmes = *ligne;

	if (*(ligne->bbsv))
		sprintf (varx[0], "@%-6s", bbs_via (ligne->bbsv));
	else
		strcpy (varx[0], "       ");
	var_cpy (1, ltitre (0, ligne));
	ptmes->numero = (long) numero;

	ptr = var_txt (langue[vlang]->plang[T_THE + 1 - 1]);
	if (strlen (ptr) > 80)
	{
		ptr[79] = '\r';
		ptr[80] = '\0';
	}
	outs (ptr, strlen (ptr));
}

static int entete_theme (void)
{
	return (texte (T_THE + 0));
}

static int themes_bloc_liste (void)
{
	long b_theme;
	long *num_list;
	int retour = 1;
	int num_lig = 0;
	int max_lig;
	unsigned offset = pvoie->recliste.offset;
	bloc_mess *bptr = pvoie->recliste.ptemp;
	bullist ligne;

	num_list = (long *) pvoie->ptemp;
	if ((num_list == NULL) || (pvoie->psiz == 0))
		return (retour);

	pvoie->sr_mem = pvoie->seq = FALSE;

	if (pvoie->finf.theme)
		b_theme = 1L << (pvoie->finf.theme - 1);
	else
		b_theme = 0L;

	max_lig = pvoie->psiz / sizeof (long);

	num_lig = max_lig - pvoie->temp2;

	ouvre_dir ();

	while (bptr)
	{

		/* Pb debordement du tableau ! */
		if (num_lig >= max_lig)
		{
			retour = 2;
			break;
		}

		if (!pvoie->reverse)
			--offset;

		if (bptr->st_mess[offset].noenr)
		{
			read_dir (bptr->st_mess[offset].noenr, &ligne);

			if ((ligne.type == 'B') && (READ_OK (ligne)))
			{
				if (((b_theme) && (ligne.theme & b_theme)) || ((b_theme == 0L) && (ligne.theme == 0L)))
				{
					if (pvoie->temp1)
					{
						pvoie->temp2 -= entete_theme ();
						pvoie->temp1 = 0;
					}
					num_list[num_lig++] = ligne.numero;
					aff_ligne (num_lig, &ligne);
					--pvoie->temp2;
				}
			}
			if (pvoie->temp2 == 0)
			{
				retour = 2;
				break;
			}
		}

		if (pvoie->reverse)
		{
			if (++offset == T_BLOC_MESS)
			{
				bptr = bptr->suiv;
				offset = 0;
			}
		}
		else
		{
			if (offset == 0)
			{
				bptr = prec_dir (bptr);
				offset = T_BLOC_MESS;
			}
		}

		if (pvoie->memoc >= MAXMEM)
		{
			pvoie->sr_mem = TRUE;
			retour = 0;
			break;
		}
		if (trait_time > MAXTACHE)
		{
			pvoie->seq = TRUE;
			retour = 0;
			break;
		}

	}

	ferme_dir ();

	pvoie->recliste.offset = offset;
	pvoie->recliste.ptemp = bptr;

	return (retour);
}

int themes_lx (void)
{
	pvoie->temp1 = 1;
	if (pvoie->reverse)
	{
		pvoie->recliste.ptemp = tete_dir;
		pvoie->recliste.offset = 0;
	}
	else
	{
		pvoie->recliste.ptemp = last_dir ();
		pvoie->recliste.offset = T_BLOC_MESS;
	}
	return (1);
}

int themes_rx (int verbose)
{
	int error = 0;
	long no;
	int c, ok = TRUE;
	bullist *pbul;
	rd_list *ptemp = NULL;

	df ("themes_rx", 1);
/*
   print_fonction(stdout); print_history(stdout); sleep_(10);
   for (;;);
 */
	sup_ln (indd);
	c = toupper (*indd);
	++indd;

	if ((c != ' ') && (*indd != ' ') && (*indd != '\0'))
	{
		ff ();
		return (1);
	}

	pvoie->aut_nc = 1;

	libere_tread (voiecur);
	init_recliste (voiecur);
	pvoie->recliste.l = verbose;

	switch (c)
	{

		/*
		   case 'A' :
		   pvoie->recliste.status = 'A' ;
		   break ;
		   case 'L' :
		   if (teste_espace()) {
		   if (isdigit(*indd))
		   pvoie->recliste.last = lit_chiffre(0) ;
		   else {
		   texte(T_ERR + 3) ;
		   ok = 0 ;
		   }
		   } else {
		   --indd;
		   error = 1;
		   ok = 4 ;
		   }
		   break ;
		   case 'M' :
		   case 'N' :
		   if (read_mine(c))
		   ok = 2 ;
		   else
		   ok = 0 ;
		   break ;
		   case 'S' :
		   if (teste_espace())
		   strn_cpy(19, pvoie->recliste.find, indd) ;
		   else {
		   --indd;
		   error = 1;
		   ok = 4 ;
		   }
		   break ;
		   case '<' :
		   if (teste_espace()) {
		   strn_cpy(6, pvoie->recliste.exp, indd) ;
		   } else {
		   texte(T_ERR + 2) ;
		   ok = 0 ;
		   }
		   break ;
		   case '>' :
		   if (teste_espace()) {
		   strn_cpy(6, pvoie->recliste.dest, indd) ;
		   } else {
		   texte(T_ERR + 2) ;
		   ok = 0 ;
		   }
		   break ;
	 */ case ' ':
		trans_num ();
		/*if (strchr(indd, '-')) {
		   if (isdigit(*indd))
		   pvoie->recliste.debut = lit_chiffre(1) ;
		   else {
		   texte(T_ERR + 3) ;
		   ok = 0 ;
		   break ;
		   }
		   ++indd ;
		   if (isdigit(*indd))
		   pvoie->recliste.fin = lit_chiffre(1) ;
		   if (pvoie->recliste.fin <= pvoie->recliste.debut)
		   ok = 0 ;
		   } else {         */
		ok = 0;
		while ((no = lit_chiffre (1)) != 0L)
		{
			if ((pbul = ch_record (NULL, no, 'Y')) != NULL)
			{
				if (droit_ok (pbul, 1))
				{
					if (ptemp)
					{
						ptemp->suite = (rd_list *) m_alloue (sizeof (rd_list));
						ptemp = ptemp->suite;
					}
					else
					{
						pvoie->t_read = ptemp = (rd_list *) m_alloue (sizeof (rd_list));
					}
					ptemp->suite = NULL;
					ptemp->nmess = no;
					ptemp->verb = verbose;
					ok = 2;
				}
				else
					texte (T_ERR + 10);
			}
			else
				texte (T_ERR + 10);
		}
		/* }                  */
		break;
	default:
		if ((c == '\0') && (verbose))
		{
			texte (T_MBL + 8);
			ok = 0;
		}
		else
		{
			error = 1;
			--indd;
			ok = 4;
		}
		break;
	}
	switch (ok)
	{
	case 0:
		prompt_themes ();
		break;
	case 1:
		pvoie->recliste.ptemp = last_dir ();
		pvoie->recliste.offset = T_BLOC_MESS;
		pvoie->temp1 = 1;
		pvoie->sr_mem = 1;
		ch_niv3 (1);
		themes_read (verbose);
		break;
	case 2:
		pvoie->sr_mem = 1;
		ch_niv3 (2);
		themes_read (verbose);
		break;
	}
	ff ();
	return (error);
}

static int themes_read (int verbose)
{
	int error = 0;

	df ("themes_read", 1);

	switch (pvoie->niv3)
	{
	case 0:
		++indd;
		error = themes_rx (verbose);
		break;
	case 1:
		switch (mbl_bloc_list ())
		{
		case 0:				/* Pas de message */
			texte (T_MBL + 3);
			prompt_themes ();
		case 1:				/* Pas fini */
			break;
		case 2:				/* Termine */
			ch_niv3 (2);
			mbl_read (verbose);
			break;
		}
		break;
	case 2:
		if (mbl_mess_read () == 0)
		{
			prompt_themes ();
		}
		break;
	case 3:
		if (read_mess (1) == 0)
			ch_niv3 (2);
		break;
	default:
		fbb_error (ERR_NIVEAU, "MSG-READ", pvoie->niv3);
	}
	ff ();
	return (error);
}


static void trans_num (void)
{
	char s[256];
	char buf[80];
	char *ptr;
	int num;
	int i;

	n_cpy (255, s, indd);
	*indd = '\0';

	ptr = s;
	while (*ptr)
	{
		if (isdigit (*ptr))
		{
			i = 0;
			while (isdigit (*ptr))
			{
				buf[i++] = *ptr++;
			}
			buf[i] = '\0';

			num = atoi (buf) - 1;
			if ((num >= 0) && (num < (pvoie->psiz / sizeof (long))))
			{
				long lnum;

				lnum = ((long *) pvoie->ptemp)[num];
				strcat (indd, ltoa (lnum, buf, 10));
			}
			else
			{
				/* Erreur */
			}
		}
		else
		{
			buf[0] = *ptr++;
			buf[1] = '\0';
			strcat (indd, buf);
		}
	}
}

int themes_list (void)
{
	int mode_list = 1;
	int verbose = 0;
	int error = 0;

	switch (pvoie->niv3)
	{
	case 0:
		if (toupper (*indd) == 'C')
		{
			return (list_lc ());
		}

		switch (themes_lx ())
		{
		case 0:
			prompt_themes ();
		case 2:
			mode_list = 0;
			break;
		case 1:
			pvoie->temp2 = nbl_page (voiecur);
			alloue_list_numeros ();
			ch_niv3 (1);
			break;
		case 3:
			mode_list = 0;
			error = 1;
			--indd;
			break;
		}
		break;
	case 1:
		break;
	case 2:
		while_space ();
		switch (toupper (*indd))
		{
		case 'A':
			mode_list = 0;
			prompt_themes ();
			break;
		case 'V':
			verbose = 1;
		case 'R':
			mode_list = 0;
			incindd ();
			if (isdigit (*indd))
			{
				trans_num ();
				pvoie->aut_nc = 1;
				list_read (verbose);
				pvoie->sr_mem = 1;
				if (mbl_mess_read () == 0)
				{
					pvoie->sr_mem = 0;
					texte (T_QST + 6);
				}
			}
			else
			{
				texte (T_ERR + 3);
				texte (T_QST + 6);
			}
			break;
		default:
			pvoie->temp2 = nbl_page (voiecur);
			alloue_list_numeros ();
			ch_niv3 (1);
			break;
		}
		break;
	case 3:
		mode_list = 0;
		pvoie->aut_nc = 1;
		if (read_mess (1) == 0)
			ch_niv3 (4);
		break;
	case 4:
		mode_list = 0;
		pvoie->aut_nc = 1;
		pvoie->sr_mem = 1;
		if (mbl_mess_read () == 0)
		{
			pvoie->sr_mem = 0;
			texte (T_QST + 6);
			ch_niv3 (2);
		}
		break;
	default:
		fbb_error (ERR_NIVEAU, "MSG-LIST", pvoie->niv3);
	}

	if (mode_list)
	{
		pvoie->lignes = -1;
		switch (themes_bloc_liste ())
		{
		case 0:
			break;
		case 1:
			prompt_themes ();
			break;
		case 2:
			texte (T_QST + 6);
			ch_niv3 (2);
			break;
		}
	}
	return (error);
}

int nom_theme (char *nom)
{
	int i;

	strupr (sup_ln (nom));

	for (i = 0; i < tot_themes; i++)
	{
		if (strncmp (theme_liste[i].nom, nom, 3) == 0)
		{
			pvoie->finf.theme = i;
			list_topics ();
			prompt_themes ();
			return (1);
		}
	}
	return (0);
}

void theme_err (char *ptri)
{
	int i = 0;
	char *ptr = varx[0];

	while (ISGRAPH (*ptri))
	{
		if (++i == 40)
			break;
		else
			*ptr++ = *ptri++;
	}
	*ptr = '\0';
	texte (T_ERR + 1);
	*varx[0] = '\0';
	if ((FOR (pvoie->mode)) || (++pvoie->nb_err == MAX_ERR))
		pvoie->deconnect = 6;
	else
		prompt_themes ();
}


int menu_themes (void)
{
	int error = 0;
	int verbose = 0;
	char *com = indd;


	if (tot_themes == 0)
	{
		texte (T_DOS + 2);
		retour_mbl ();
		return (error);
	}

	if (nom_theme (indd))
		return (error);

	switch (toupper (*indd))
	{
	case 'H':
		display_themes ();
		break;
	case 'Q':
	case 'F':
		retour_mbl ();
		break;
	case 'L':
		ch_niv2 (1);
		error = themes_list ();
		break;
	case 'V':
		verbose = 1;
	case 'R':
		ch_niv2 (2);
		error = themes_read (verbose);
		break;
	case 'B':
		maj_niv (N_MENU, 0, 0);
		sortie ();
		break;
	default:
		if (isdigit (*indd))
		{
			int select = atoi (indd);

			if ((select >= 0) && (select < tot_themes) && (theme_liste[select].nb_bull))
			{
				pvoie->finf.theme = select;
				list_topics ();
			}
			else
			{
				texte (T_DOS + 2);
			}
			prompt_themes ();
		}
		else if (!ISGRAPH (*indd))
		{
			display_themes ();
		}
		else
		{
			error = 1;
		}
		break;
	}

	if (error)
		theme_err (com);

	return (error);
}

int themes (void)
{
	int ret;

	switch (pvoie->niv2)
	{
	case 0:
		ret = menu_themes ();
		break;
	case 1:
		ret = themes_list ();
		break;
	case 2:
		ret = themes_read (0);
		break;
	default :
		ret = 0;
		break;
	}

	return (ret);
}


static void error_file (void)
{
	char wtexte[200];

	deb_io ();
#ifdef ENGLISH
	if (operationnel)
	{
		sprintf (wtexte, "\r\nError in file THEMES.SYS line %d  \r\n\a", nolig);
		if (w_mask & W_FILE)
			mess_warning (admin, "*** FILE ERROR ***    ", wtexte);
	}
	sprintf (wtexte, "Error in file THEMES.SYS line %d  ", nolig);
#else
	if (operationnel)
	{
		sprintf (wtexte, "\r\nErreur fichier THEMES.SYS ligne %d\r\n\a", nolig);
		if (w_mask & W_FILE)
			mess_warning (admin, "*** ERREUR FICHIER ***", wtexte);
	}
	sprintf (wtexte, "Erreur fichier THEMES.SYS ligne %d", nolig);
#endif
	fin_io ();
	win_message (5, wtexte);
}
