/*
 *			GPAC - MPEG-4 Systems C Development Kit
 *
 *			Copyright (c) Jean Le Feuvre 2000-2005
 *					All rights reserved
 *
 *  This file is part of GPAC / Stream Management sub-project
 *
 *  GPAC 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, or (at your option)
 *  any later version.
 *   
 *  GPAC 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 GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */


#include <gpac/intern/m4_esm_dev.h>

/*!! THIS IS TEST CODE, LIKELY BUGGY AND SUBJECT TO DRASTIC CHANGES !! */


Bool Term_CheckIPMPTool(M4Client *term, IPMP_Tool *ipmpt)
{
	/*ISMACryp decryption tool*/
	if ((ipmpt->IPMP_ToolID[14]==0x49) && (ipmpt->IPMP_ToolID[15]==0x53)) return 1;
	return 0;
}

typedef struct _ipmp_plugin
{
	/*query playback 'PLAY', 'STOP', etc. Returns 1 if granted*/
	Bool (*query)(struct _ipmp_plugin *, const char *);
	/*process stream data - assumes in-place protection*/
	Bool (*process_stream_data)(struct _ipmp_plugin *, char *in_data, u32 in_size, SLHeader *hdr);

	/*assigned at launch time by launcher*/
	struct _ipmp_instance *usr_tool;
} IPMPPlugin;

typedef struct _ipmp_instance
{
	InlineScene *is;
	IPMP_Descriptor *ipmp;

	/*all ODs governed by this instance*/
	Chain *ODMs;
	/*all channels governed by this instance*/
	Chain *channels;

	IPMPPlugin *tool;
} IPMPInstance;


Bool ismacryp_query(IPMPPlugin *p, const char *op)
{
	u32 i;
	if (!p->usr_tool || !p->usr_tool->ipmp) return 0;

	/*can always stop*/
	if (!stricmp(op, "STOP")) return 1;
	/*can never record*/
	if (!stricmp(op, "REC")) return 0;

	for (i=0; i<ChainGetCount(p->usr_tool->ipmp->ipmpx_data); i++) {
		IPMPX_Data *d = ChainGetEntry(p->usr_tool->ipmp->ipmpx_data, i);
		switch (d->tag) {
		}
	}
}

Bool ismacryp_process_stream_data(IPMPPlugin *p, char *in_data, u32 in_size, SLHeader *hdr)
{
}


IPMPPlugin *ISMAC_NewInstance()
{
	IPMPPlugin *ip;
	SAFEALLOC(ip, sizeof(IPMPPlugin));
	ip->query = ismacryp_query;
	ip->process_stream_data = ismacryp_process_stream_data;
	return ip;
}

IPMPInstance *IPMP_NewInstance(InlineScene *is, IPMP_Descriptor *ipmp)
{
	IPMPInstance *ipmpi;
	SAFEALLOC(ipmpi, sizeof(IPMPInstance));

	ipmpi->is = is;
	ipmpi->ODMs = NewChain();
	ipmpi->channels = NewChain();
	ipmpi->ipmp = ipmp;

	ipmpi->tool = ISMAC_NewInstance();
	ipmpi->tool->usr_tool = ipmpi;


	ChainAddEntry(is->ipmp_tools, ipmpi);
	return ipmpi;
}

void IPMPI_Shutdown(IPMPInstance *ipmpi)
{
	/*should we stop ODMs & ESs ?*/

	DeleteChain(ipmpi->ODMs);
	DeleteChain(ipmpi->channels);
	OD_DeleteDescriptor((Descriptor **)&ipmpi->ipmp);
	/*unregister*/
	ChainDeleteItem(ipmpi->is->ipmp_tools, ipmpi);
	free(ipmpi);
}

static M4INLINE Bool ipmp_is_good_pointer(IPMP_Descriptor *d, IPMP_DescrPointer *ptr)
{
	if (ptr->tag != IPMP_DescriptorPointer_Tag) return 0;
	if (d->IPMP_DescriptorID != ptr->IPMP_DescriptorID) return 0;
	if (d->IPMP_DescriptorID!=0xFF) return 1;
	if (d->IPMP_DescriptorIDEx!=ptr->IPMP_DescriptorIDEx) return 0;
	return 1;
}

void IPMP_SetupOD(IPMPInstance *ip, ODManager *odm)
{
	u32 i, j, count;
	Bool do_register;

	do_register = 0;
	/*browse all lists of channels and assign IPMP*/
	for (i=0; i<ChainGetCount(odm->channels); i++) {
		Channel *ch = ChainGetEntry(odm->channels, i);
		for (j=0; j<ChainGetCount(ch->esd->IPMPDescriptorPointers); j++) {
			IPMP_DescrPointer *p = ChainGetEntry(ch->esd->IPMPDescriptorPointers, j);
			if (!ipmp_is_good_pointer(ip->ipmp, p)) continue;
			/*register this channel with tool*/
			ChainAddEntry(ip->channels, ch);
			do_register = 1;
		}
	}
	/*browse all ODs*/
	for (i=0; i<ChainGetCount(odm->OD->IPMP_Descriptors); i++) {
		IPMP_DescrPointer *p = ChainGetEntry(odm->OD->IPMP_Descriptors, i);
		if (!ipmp_is_good_pointer(ip->ipmp, p)) continue;
		/*register this object with tool*/
		ChainAddEntry(ip->ODMs, odm);
		do_register = 1;
	}
	/*register this tool with OD, and respect seq code*/
	if (!do_register) return;
	count = ChainGetCount(odm->ipmp_tools);
	for (i=0; i<count; i++) {
		IPMPInstance *ip2 = ChainGetEntry(odm->ipmp_tools, i);
		if (ip2->ipmp->cp_sequence_code>ip->ipmp->cp_sequence_code) {
			ChainInsertEntry(odm->ipmp_tools, ip, i);
			return;
		}
	}
	ChainAddEntry(odm->ipmp_tools, ip);
}

void IS_UpdateIPMP(InlineScene *is, IPMP_Descriptor *ipmp)
{
	u32 i;
	IPMPInstance *ipmpi;

	Term_LockNet(is->root_od->term, 1);

	for (i=0; i<ChainGetCount(is->ipmp_tools); i++) {
		IPMPInstance *ipmpi = ChainGetEntry(is->ipmp_tools, i);
		if (ipmpi->ipmp->IPMP_DescriptorID!=ipmp->IPMP_DescriptorID) continue;
		if ((ipmp->IPMP_DescriptorID==0xFF) && (ipmp->IPMP_DescriptorIDEx!=ipmpi->ipmp->IPMP_DescriptorIDEx)) continue;
		IPMPI_Shutdown(ipmpi);
		i--;
	}

	ipmpi = IPMP_NewInstance(is, ipmp);

	/*browse all ODs and ESDs depending on this tool descriptor*/
	for (i=0; i<ChainGetCount(is->ODlist); i++) {
		ODManager *odm = ChainGetEntry(is->ODlist, i);
		IPMP_SetupOD(ipmpi, odm);
	}
	Term_LockNet(is->root_od->term, 0);
}


Bool IPMP_QueryPermission(ODManager *odm, const char *action)
{
	u32 i, count;
	count = ChainGetCount(odm->ipmp_tools);
	if (!count) return 1;

	for (i=0; i<count; i++) {
		IPMPInstance *ip = ChainGetEntry(odm->ipmp_tools, i);
		if (!ip->tool->query(ip->tool, action)) return 0;
	}
	return 1;
}
