/*
 *			GPAC - MPEG-4 Systems C Development Kit
 *
 *			Copyright (c) Cyril Concolato 2005
 *					All rights reserved
 *
 *  This file is part of GPAC / command-line mp21 toolbox
 *
 *  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_isomedia_dev.h>
#include <stdio.h>

void DumpItemInfo(M4File *file, u32 itemID, Bool full_dump);
void DumpFileInfo(M4File *file);


void PrintVersion()
{
	fprintf(stdout, "MP21Box - GPAC version %s\n", M4_VERSION);
}

void PrintUsage()
{
	fprintf (stdout, "MP21Box [option] input [option]\n"
			"Written by Cyril Concolato - ENST (c) 2005\n"
			" -m21:                 rewrites the input DID file as an MPEG-21 compliant file\n"
			" -res file:            imports the resource file (needs -m21)\n"
			" -did:                 extracts the DID from the input MPEG-21 compliant file\n"
			" -out filename:        specifies output file name. Default output is out_$INPUT\n"
			" -extract itemID file: extract the item into the specified file\n"
			" -add file:            adds a resource to an existing MPEG-21 file\n"
			" -extractAll:          extracts all the items\n");
}


/*return value:
	0: not supported 
	1: ISO media 
	2: input XML file (.xml)
*/
u32 get_file_type_by_ext(char *inName)
{
	char *lowername;
	u32 type;
	lowername = strdup(inName);
	if (!lowername) return 0;
	strlwr(lowername);
	if (strstr(lowername, ".m21") || strstr(lowername, ".mp4") || strstr(lowername, ".3gp") || strstr(lowername, ".mov") || strstr(lowername, ".3g2")) type = 1;
	else if (strstr(lowername, ".xml")) type = 2;
	else type = 0;	
	free(lowername);
	return type;
}

#ifdef ARM
#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, 
				   HINSTANCE hPrevInstance, 
				   LPWSTR lpCmdLine, 
				   int nShowCmd 
) {
	int argc;
	char **argv;
#else
int main(int argc, char **argv)
{
#endif
	char outfile[5000];
	M4Err e;
	char *arg, *inName, *outName, *mediaSource, *out_resource;
	u32 i;
	M4File *mp4;
	u8 m21mux, print_info, extract_item;
	u32 info_item_id, extract_item_id;
	Bool needSave;

	mp4 = NULL;
	inName = NULL;
	outName = NULL;
	mediaSource = NULL;

	m21mux = 0; 
	print_info = 0;
	info_item_id = 0;
	extract_item = 0;
	extract_item_id = 0;
	needSave = 0;

#ifdef ARM
	{ // Parse the command line and creates sets argc argv 
		u32 nb_spaces_in_cmd = 1;
		Bool in_a_path = 0;
		Bool path_to_end = 0;
		char *tmp, *old_tmp;
		char *cmdline= "-did \\Storage\\Program Files\\MP21Box\\TIRAMISU_DID.m21  -out \\Storage\\Program Files\\MP21Box\\test.xml";
		Chain *args = NewChain();
		//char cmdline[100];
		//wcstombs(cmdline, lpCmdLine, 100);
		
		//CCommandLineInfo cmdInfo;
		//ParseCommandLine(cmdInfo);

		tmp = cmdline;
		old_tmp = tmp;
		while (*tmp) {
			if (*tmp == M4_PATH_SEPARATOR) {
				if (!in_a_path) in_a_path = 1;
			} else if (*tmp == ' ') {
				if (!in_a_path) {
					char *arg = malloc(sizeof(char *)*(tmp-old_tmp+1));
					strncpy(arg, old_tmp, tmp-old_tmp);
					arg[tmp-old_tmp] = 0;
					ChainAddEntry(args, arg);
					old_tmp = tmp + 1;
				} else {
					if (path_to_end) {
						char *arg = malloc(sizeof(char *)*(tmp-old_tmp+1));
						strncpy(arg, old_tmp, tmp-old_tmp);
						arg[tmp-old_tmp] = 0;
						ChainAddEntry(args, arg);
						path_to_end = in_a_path = 0;
						old_tmp = tmp + 1;
					} else {
						// nothing
					}
				}
			} else if (*tmp == '.') {
				if (in_a_path) path_to_end = 1;
			}
			tmp++;
		}
		ChainAddEntry(args, strdup(old_tmp));

		argc = ChainGetCount(args) + 1; // +1 because executable name is not in the cmdline
		argv = malloc(argc*sizeof(char *));
		for (i = 0; i <argc-1; i++) {
			argv[i+1] = ChainGetEntry(args, i);
		}
		DeleteChain(args);
}
#endif

	/*parse our args*/
	for (i = 1; i < (u32) argc ; i++) {
		arg = argv[i];
		if (arg[0] != '-') {
			inName = arg;
		}
		else if (!stricmp(arg, "-?")) { PrintUsage(); return 0; }
		else if (!stricmp(arg, "-version")) { PrintVersion(); return 0; }
		else if (!stricmp(arg, "-m21")) { m21mux = 1; }
		else if (!stricmp(arg, "-did")) { m21mux = 2; }
		else if (!stricmp(arg, "-add")) { m21mux = 3; mediaSource = argv[i+1]; i++; }
		else if (!stricmp(arg, "-res")) { mediaSource = argv[i+1]; i++;  }
		else if (!stricmp(arg, "-out")) { outName = argv[i+1]; i++; }
		else if (!stricmp(arg, "-extract")) { 
			extract_item = 1;
			extract_item_id = atoi(argv[i+1]);
			out_resource = strdup(argv[i+2]);
			i+=2;
		}
		else if (!stricmp(arg, "-extractAll")) { 
			extract_item = 1;
		}
		else if (!stricmp(arg, "-info")) {
			print_info = 1;
			if ((i+1<(u32) argc) && (sscanf(argv[i+1], "%d", &info_item_id)==1)) {
				char szTk[20];
				sprintf(szTk, "%d", info_item_id);
				if (!strcmp(szTk, argv[i+1])) i++;
				else info_item_id=0;
			} else {
				info_item_id=0;
			}
		}

	}
	if (!inName) {
		PrintUsage();
		return 1;
	}
	e = M4OK;

	if (m21mux == 0) {
		switch (get_file_type_by_ext(inName)) {
		case 1:
			m21mux = 0;
			break;
		case 2:
			m21mux = 1;
			break;
		default:
			return M4NotSupported;
		}
	} 

	if (outName) {
		strcpy(outfile, outName);
	} else {
		strcpy(outfile, inName);
		while (outfile[strlen(outfile)-1] != '.') outfile[strlen(outfile)-1] = 0;
		outfile[strlen(outfile)-1] = 0;
		if (m21mux == 1 || m21mux == 3)
			strcat(outfile, ".m21");
		else if (m21mux == 2)
			strcat(outfile, ".xml");
	}

	// Opening the file
	switch (m21mux) {
	case 1:
		mp4 = M4_MovieOpen(outfile, M4_WRITE_EDIT);
		break;
	case 0:
	case 2:
		mp4 = M4_MovieOpen(inName, M4_OPEN_READ);
		break;
	case 3:
		mp4 = M4_MovieOpen(inName, M4_OPEN_EDIT);
		break;	
	}

	if (extract_item) {
		if (extract_item_id) {
			u32 extract_item_num = M4_GetMetaItemByID(mp4, 1, 0, extract_item_id);
			e = M4_ExtractMetaItem(mp4, 1, 0, extract_item_num/*, out_resource*/);
		} else {
			u32 j, itemID;
			u32 nb_item = M4_GetMetaItemCount(mp4, 1, 0);
			for (j=0; j<nb_item; j++) {
				char szPath[1024];
				M4_GetMetaItemInfo(mp4, 1, 0, j+1, &itemID, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
				sprintf(szPath, "item_d", itemID);
				e = M4_ExtractMetaItem(mp4, 1, 0, j+1/*, szPath*/);
				if (e) goto err_exit;
			}
		}
		if (e) goto err_exit;
	}

	if (print_info) {
		if (info_item_id) DumpItemInfo(mp4, info_item_id, 1);
		else DumpFileInfo(mp4);
	}

	// Processing the file
	switch (m21mux) {
	case 1:
		e = M4_SetMetaType(mp4, 1, 0, M4_MPEG21MediaType);
		if (e) goto err_exit;
		e = M4_SetMetaXML(mp4, 1, 0, inName, 0);
		if (e) goto err_exit;

		if (mediaSource) {
			e = M4_AddMetaItem(mp4, 1, 0, 0, mediaSource, NULL, "video/mp4", NULL, NULL, NULL);
			if (e) goto err_exit;
		}
		needSave = 1;
		break;
	case 2:
		e = M4_ExtractMetaXML(mp4, 1, 0, outfile, NULL);
		if (e) goto err_exit;
		break;
	case 3:
		e = M4_AddMetaItem(mp4, 1, 0, 0, mediaSource, NULL, "video/mp4", NULL, NULL, NULL);
		if (e) goto err_exit;
		needSave = 1;
		break;	
	}
	
	if (needSave) {
		fprintf(stdout, "Saving file into %s: ", outfile);
		M4_SetStorageMode(mp4, M4_STREAMABLE);
		e = M4_MovieClose(mp4);
		if (e) goto err_exit;
		fprintf(stdout, " done\n");
	} else {
		M4_MovieDelete(mp4);
	}

#ifdef ARM
	for (i = 1; i < argc; i++) {
		free(argv[i]);
	}
	free(argv);
#endif
	if (e) fprintf(stdout, "Error: %s\n", M4ErrToString(e));
	return (e!=M4OK) ? 1 : 0;

err_exit:
	M4_MovieDelete(mp4);
	fprintf(stdout, "\n\tError: %s\n", M4ErrToString(e));

#ifdef ARM
	for (i = 1; i < argc; i++) {
		free(argv[i]);
	}
	free(argv);
#endif

	return 1;
}