#define MODULE_LOG_PREFIX "dvbapi"

#include "globals.h"

#ifdef HAVE_DVBAPI

#include "oscam-config.h"
#include "oscam-ecm.h"
#include "oscam-string.h"
#include "module-dvbapi.h"
#include "module-dvbapi-chancache.h"

extern DEMUXTYPE demux[MAX_DEMUX];

static LLIST *channel_cache;

void dvbapi_save_channel_cache(void)
{
	if(boxtype_is("dbox2")) return; // dont save channelcache on these boxes, they lack resources and will crash!

	if (USE_OPENXCAS) // Why?
		return;

	char fname[256];
	int32_t result = 0;
	get_config_filename(fname, sizeof(fname), "oscam.ccache");
	FILE *file = fopen(fname, "w");

	if(!file)
	{
		cs_log("dvbapi channelcache can't write to file %s", fname);
		return;
	}

	LL_ITER it = ll_iter_create(channel_cache);
	struct s_channel_cache *c;
	while((c = ll_iter_next(&it)))
	{
		result = fprintf(file, "%04X,%06X,%04X,%04X,%06X\n", c->caid, c->prid, c->srvid, c->pid, c->chid);
		if(result < 0)
		{
			fclose(file);
			result = remove(fname);
			if(!result)
			{
				cs_log("error writing cache -> cache file removed!");
			}
			else
			{
				cs_log("error writing cache -> cache file could not be removed either!");
			}
			return;
		}
	}

	fclose(file);
	cs_log("dvbapi channelcache saved to %s", fname);
}

void dvbapi_load_channel_cache(void)
{
	if(boxtype_is("dbox2")) return; // dont load channelcache on these boxes, they lack resources and will crash!

	if (USE_OPENXCAS) // Why?
		return;

	char fname[256];
	char line[1024];
	FILE *file;
	struct s_channel_cache *c;

	get_config_filename(fname, sizeof(fname), "oscam.ccache");
	file = fopen(fname, "r");
	if(!file)
	{
		cs_log_dbg(D_TRACE, "dvbapi channelcache can't read from file %s", fname);
		return;
	}

	int32_t i = 1;
	int32_t valid = 0;
	char *ptr, *saveptr1 = NULL;
	char *split[6];

	memset(line, 0, sizeof(line));
	while(fgets(line, sizeof(line), file))
	{
		if(!line[0] || line[0] == '#' || line[0] == ';')
			{ continue; }

		for(i = 0, ptr = strtok_r(line, ",", &saveptr1); ptr && i < 6 ; ptr = strtok_r(NULL, ",", &saveptr1), i++)
		{
			split[i] = ptr;
		}

		valid = (i == 5);
		if(valid)
		{
			if(!cs_malloc(&c, sizeof(struct s_channel_cache)))
			{ continue; }
			c->caid = a2i(split[0], 4);
			c->prid = a2i(split[1], 6);
			c->srvid = a2i(split[2], 4);
			c->pid = a2i(split[3], 4);
			c->chid = a2i(split[4], 6);

			if(valid && c->caid != 0)
			{
				if(!channel_cache)
				{
					channel_cache = ll_create("channel cache");
				}

				ll_append(channel_cache, c);
			}
			else
			{
				NULLFREE(c);
			}
		}
	}
	fclose(file);
	cs_log("dvbapi channelcache loaded from %s", fname);
}

struct s_channel_cache *dvbapi_find_channel_cache(int32_t demux_id, int32_t pidindex, int8_t caid_and_prid_only)
{
	struct s_ecmpid *p = &demux[demux_id].ECMpids[pidindex];
	struct s_channel_cache *c;
	LL_ITER it;

	if(!channel_cache)
		{ channel_cache = ll_create("channel cache"); }

	it = ll_iter_create(channel_cache);
	while((c = ll_iter_next(&it)))
	{

		if(caid_and_prid_only)
		{
			if(p->CAID == c->caid && (p->PROVID == c->prid || p->PROVID == 0))  // PROVID ==0 some provider no provid in PMT table
				{ return c; }
		}
		else
		{
			if(demux[demux_id].program_number == c->srvid
					&& p->CAID == c->caid
					&& p->ECM_PID == c->pid
					&& (p->PROVID == c->prid || p->PROVID == 0)) // PROVID ==0 some provider no provid in PMT table
			{

#ifdef WITH_DEBUG
				char buf[ECM_FMT_LEN];
				ecmfmt(buf, ECM_FMT_LEN, c->caid, 0, c->prid, c->chid, c->pid, c->srvid, 0, 0, 0, 0, 0, 0, NULL, NULL);
				cs_log_dbg(D_DVBAPI, "Demuxer %d found in channel cache: %s", demux_id, buf);
#endif
				return c;
			}
		}
	}
	return NULL;
}

int32_t dvbapi_edit_channel_cache(int32_t demux_id, int32_t pidindex, uint8_t add)
{
	struct s_ecmpid *p = &demux[demux_id].ECMpids[pidindex];
	struct s_channel_cache *c;
	LL_ITER it;
	int32_t count = 0;

	if(!channel_cache)
		{ channel_cache = ll_create("channel cache"); }

	it = ll_iter_create(channel_cache);
	while((c = ll_iter_next(&it)))
	{
		if(demux[demux_id].program_number == c->srvid
				&& p->CAID == c->caid
				&& p->ECM_PID == c->pid
				&& (p->PROVID == c->prid || p->PROVID == 0))
		{
			if(add && p->CHID == c->chid)
			{
				return 0; //already added
			}
			ll_iter_remove_data(&it);
			count++;
		}
	}

	if(add)
	{
		if(!cs_malloc(&c, sizeof(struct s_channel_cache)))
			{ return count; }
		c->srvid = demux[demux_id].program_number;
		c->caid = p->CAID;
		c->pid = p->ECM_PID;
		c->prid = p->PROVID;
		c->chid = p->CHID;
		ll_append(channel_cache, c);
#ifdef WITH_DEBUG
		char buf[ECM_FMT_LEN];
		ecmfmt(buf, ECM_FMT_LEN, c->caid, 0, c->prid, c->chid, c->pid, c->srvid, 0, 0, 0, 0, 0, 0, NULL, NULL);
		cs_log_dbg(D_DVBAPI, "Demuxer %d added to channel cache: %s", demux_id, buf);
#endif
		count++;
	}

	return count;
}

#endif
