/*************************************************************
 *   mpgtx an mpeg toolbox                                   *
 *   by Laurent Alacoque <laureck@users.sourceforge.net>     *
 *   (c) 2001                                                *
 *   You may copy, modify and redistribute this              *
 *   source file under the terms of the GNU Public License   *
 ************************************************************/

#include "id3command.hh"

/** 
 * Parses commandline and decide what happens.
 *
 * @param argc       argc of calling parent programm
 * @param argv       argv of calling parent programm
 * @param arc_offset index begin of interesting args
 * @return 0 - ok, 1 - error or return code of called subroutine [0;1]
 */
int ParseID3Command(int argc, char** argv, int argc_offset){
	BTRACK;
	// starting from argc_offset format is :
	// -h or
	// set FORMAT file ... file ...
	// mov FORMAT2 file .... file ... 
	// del file ... file ...
	int argcount= argc -argc_offset;
	if (argcount==0){
		fprintf(stderr,"You must specify at least a mode\n");
		return 1;
	}


	if (!strcmp(argv[argc_offset],"-h")){
		// this is -h option
		printf("tagmp3 an ID3v1 tag editor\n");
		printf("Usage : tagmp3 [-n] [-v] [set|move|del|list|show] [FORMAT] [file...]\n\n");
		printf(" OPTIONS:\n");
		printf("   -v     prints version information\n");
		printf("   set    sets ID3v1 tag according to FORMAT\n");
		printf("   move   moves mp3 file according to the FORMAT\n");
		printf("   del    removes ID3v1 tag from file (if any)\n");
		printf("   list   lists known music genres along with their numeric values\n\n");
		printf(" FORMAT:\n");
		printf("   for set mode   : \"%%Y? %%X:VALUE  ...\" sets the X field of tag\n");
		printf("                    with VALUE and asks for the value of Y field\n");
		printf("   for move mode  : \"mymp3/%%X/%%Y/%%Z.mp3\" move file to\n");
		printf("                    ./mymp3/tag{X}/tag{Y}/tag{Z}.mp3\n\n"); 
		printf(" valid fields are :  %%A artist   %%t title    %%T track  %%y year\n");
		printf("                     %%a album    %%c comment  %%g genre\n");
		return 0;
	}

	if (!strcmp(argv[argc_offset],"-n")){
		//show only
		id3_Show_Only=true;
		argc_offset++;
	}


	if (!strcmp(argv[argc_offset],"list")){
		// list genres
		for (int i=0; i< MAX_ID3_GENRE; i+=4){
			if (i<MAX_ID3_GENRE) printf("%3d %-15.15s",i,genre[i]);
			if (i+1<MAX_ID3_GENRE) printf(" %3d %-15.15s",i+1,genre[i+1]);
			if (i+2<MAX_ID3_GENRE) printf(" %3d %-15.15s",i+2,genre[i+2]);
			if (i+3<MAX_ID3_GENRE) printf(" %3d %-15.15s",i+3,genre[i+3]);
			printf("\n");
		}
		return 0;
	}

	if (!strcmp(argv[argc_offset],"-v")){
		printf("tagmp3 version %s\n",MPGTX_VERSION);
		printf("Copyleft 2001 Laurent Alacoque <laureck@users.sourceforge.net>\n");
		printf("updates, bugs, patch, money :    http://mpgtx.sourceforge.net\n");
		return 0;

	}

	if (!strcmp(argv[argc_offset],"show")){
		if (argcount<2){
			fprintf(stderr,"show id3v1 tag of what file?\n");
			return 1;	
		}
		return ParseShow(argc,argv,argc_offset+1);
	}

	if (!strcmp(argv[argc_offset],"set")){
		if (argcount<3){
			fprintf(stderr,"Not enough arguments for set mode\n");
			return 1;	
		}
		return ParseSet(argc,argv,argc_offset+1);
	}	

	if (!strcmp(argv[argc_offset],"move")){
		if (argcount<3){
			fprintf(stderr,"Not enough argument for mov mode\n");
			return 1;	
		}
		return ParseMov(argc,argv,argc_offset+1);
	}

	if (!strcmp(argv[argc_offset],"del")){
		if (argcount<2){
			fprintf(stderr,"remove id3v1 tag from what?\n");
			return 1;	
		}
		return ParseDel(argc,argv,argc_offset+1);
	}

	// not a valid id3 mode 
	fprintf(stderr,"invalid mode : %s\n",argv[argc_offset]);
	return 1;
}


/** 
 * Shows ID3v1 TAG of files.
 *
 * @param argc       argc of calling parent programm
 * @param argv       argv of calling parent programm
 * @param arc_offset index begin of interesting args
 * @return allways 0, no error if there are no ID3v1 TAGs in file
 */
int ParseShow(int argc, char** argv, int argc_offset){
	BTRACK;
	OpenedFile* my;
	for (int i = argc_offset; i < argc; i++){
		my = OpenFile(argv[i]);
		if ((!my->thefile)){
			continue;
		}
		// okay we have a file here.
		if (!my->thetag){
			fprintf(stdout, "%s doesn't have any ID3v1 tag (Note: ID3v2 not supported)\n", argv[i]);

		}
		else{
			printf("%s\n", argv[i]);
			printf("    Artist : %s\n", my->thetag->artist);		
			printf("    Title  : %s\n", my->thetag->title);		
			printf("    Album  : %s\n", my->thetag->album);			
			if (my->thetag->track>0)
				printf("    Track  : %d\n", my->thetag->track);
			printf("    Year   : %s\n", my->thetag->year);
			if (my->thetag->genre < MAX_ID3_GENRE)
				printf("    Genre  : %s\n", genre[my->thetag->genre]);
			printf("    Comment: %s\n\n", my->thetag->comment);
		}


		// lets delete and close before next opened file
		if (my->thefile) fclose (my->thefile);
		if (my->thetag) delete my->thetag;
		delete my;
	}
	return 0;
}


/** 
 * Sets ID3v1 TAG of files.
 *
 * @param argc       argc of calling parent programm
 * @param argv       argv of calling parent programm
 * @param arc_offset index begin of interesting args
 * @return allways 0, no error if there are no ID3v1 TAGs in file
 */
int ParseSet(int argc, char** argv, int argc_offset){
	BTRACK;
	OpenedFile* my;
	int retval=1;
	for (int i = argc_offset + 1; i < argc; i++) {
		my = OpenFile(argv[i]);
		if ((!my->thefile) || (my->filetype != REAL_MP3)) {
			continue;
		}
		// okay we have a file here.
		// FIXME: This could not be reached, DEPRECATED?
                if (my->filetype != REAL_MP3) {
			fprintf(stderr, "Skipping file %s ", argv[i]);
			if (my->filetype== FAKE_MP3) fprintf(stderr,"(Wave file)\n");
			else fprintf(stderr,"(not an mp3)\n");
		}	
		printf("Setting %s tag \n",argv[i]);
		fflush(stdout);
		if (!SetID3(argv[argc_offset],my)){
			// something's wrong with the format
			fprintf(stderr,"ERROR while setting the format\n");
			retval=1;
                        break;
		}
		else{
			if(!id3_Show_Only) {
				// printf("Setting %s tag\n",argv[i]);
				WriteID3(my);
				retval=0;
			}
			else{
				// printf("\n");
		        }
		}

		// lets delete and close before next opened file
		if (my->thefile) fclose (my->thefile);
		if (my->thetag) delete my->thetag;
		delete my;
	}
	return retval;
}








/** 
 * Parses command line to prepare moving of MP3 files.
 *
 * @param argc       argc of calling parent programm
 * @param argv       argv of calling parent programm
 * @param arc_offset index begin of interesting args
 * @return allways 0, no error if there are no ID3v1 TAGs in file
 */
int ParseMov(int argc, char** argv, int argc_offset){
BTRACK
	OpenedFile* my;
	int i;
	int j;
	int last_slash;
	char* tempfilename=new char[300];
	char mybasename[300];
	char myfilename[300];

	// for each remaining arg
	for ( i=argc_offset+1; i<argc; i++){
		my=OpenFile(argv[i]);
		//if not opened, continue;
		if (!my->thefile){
			delete my;
			continue;
		}




		// opened, with a tag
		// compute basename and filename

		last_slash=-1;
		if (!strstr(argv[i],"/")){
			// no base directory in file name
			mybasename[0]=0;
		}
		else{
			for(j =0; j < int(strlen(argv[i])); j++){
				if (argv[i][j]=='/') last_slash=j;
			}

			for (j=0; j <= last_slash; j++){
				mybasename[j]=argv[i][j];
			}
			mybasename[j]=0;
		}
		// now we have the basename, last_slash is either
		// -1 (no basename) or the offset of the last slash
		last_slash++; 
		for (j=last_slash; j<=int(strlen(argv[i])); j++){
			myfilename[j-last_slash]=argv[i][j];
		}

		//basename and filename are okay

		// if this is a fake move it in fake-mp3
		// fake is a wav with mp3 extension

		if (my->filetype==FAKE_MP3){
			sprintf(tempfilename,"fake-mp3/");
			strcat(tempfilename,myfilename);
			Move2(argv[i],mybasename,tempfilename);
			if (my->thetag) delete my->thetag;
			delete my;
			continue;
		}

		// if this file doesn't have a tag
		// skip it
		if (! my->thetag){
			fprintf(stderr,"Skipping file %s (no tag)\n",argv[i]);
			fclose (my->thefile);
			delete my;
			continue;
		}


		// if this is not a mp3
		if (my->filetype==NOT_MP3){
			fprintf(stderr,"Skipping %s(not an mpeg file)\n",argv[i]);
		}
		else {

			// Now we have to handle the format string.
			tempfilename[0]	= 0;
			int name_offset=0;
			int fieldsize=-1;
			char *source=0;
			char* format= argv[argc_offset];
			bool error_found=false;
			char temptracknum[10];
			int track;
			int t,h,k,m;
			char* fieldname=0;
			unsigned char genre_num;
			const char* genre_as_string;
			int genre_length;
			j=0;
			// the format string is argv[argc_offset]
			while ((j < int(strlen(format)))&& !error_found ){
				if (format[j] == '%'){
					if (format[j+1] != '%'){
						// it starts like a field name
						fieldsize=-1;
						switch (format[j+1]){
							case 'a':
								fieldname="album";
								source= my->thetag->album;
								fieldsize=30;
								break;
							case 'A':
								fieldname="artist";
								source= my->thetag->artist;
								fieldsize=30;
								break;
							case 't':
								fieldname="title";
								source= my->thetag->title;
								fieldsize=30;
								break;
							case 'y':
								fieldname="year";
								source= my->thetag->year;
								fieldsize=4;
								break;
							case 'c':
								fieldname="comment";
								source= my->thetag->comment;
								fieldsize=30;
								break;
							case 'T':
								track= my->thetag->track;
								if (track <0){
									fprintf(stderr,"%s: empty track value needed by format\n",argv[i]);
									error_found=true;
								}
								else {
									sprintf(temptracknum,"%02d",track);
									for (h=0; h < int(strlen(temptracknum));h++){
										tempfilename[name_offset++]=temptracknum[h];
									}
								}
								break;
							case 'g':
								genre_num = my->thetag->genre;
								if (genre_num >= MAX_ID3_GENRE){
									genre_as_string = "Unknown";
									genre_length=7;
								}
								else {
									genre_as_string=genre[genre_num];
									genre_length=strlen(genre_as_string);
								}
								for (t=0; t <genre_length; t++){
									tempfilename[name_offset++]=genre_as_string[t];
								}

								break;

							default : 
								//invalid format
								fprintf(stderr,"Invalid format %s\n",&format[i]);
								return 1;
								break;
						}

						if (fieldsize >0){
							//eat leading white spaces
							for (k=0;(k <fieldsize)&& (source[k] == ' ');k++)
							{/*do nothing*/};

							if ((k>= fieldsize) || (source[k] == 0)){
								// this was a all white field... skip ?
								fprintf(stderr,"%s: empty field %s needed by format\n",argv[i],fieldname);
								error_found=true;
							}
							else {
								// k points to the first valid char
								int last_valid=k;
								for (int l =0; (l<fieldsize)&&(source[l]!=0); l++){
									if (source[l]!=' ') last_valid=l;
								}


								// here k is the first non ws char and last_valid the last one
								for (m=k;m<=last_valid;m++){
									//correct the dangerous chars
									switch (source[m]){
										case '/' : source[m]='\\'; break;
									}
									tempfilename[name_offset++]=source[m];
								}

							}
						}

						j+=2;					
					}
					else {
						// this is a %%
						tempfilename[name_offset++]=format[j];
						j+=2;
					}
				}
				else {
					// standard char
					tempfilename[name_offset++]=format[j++];
				}
			}
			tempfilename[name_offset]=0;
			if (error_found) continue;
			Move2(myfilename,mybasename,tempfilename);

		}



		// lets delete and close before next opened file
		if (my->thefile) fclose (my->thefile);
		if (my->thetag) delete my->thetag;
		delete my;

	}
	delete[] tempfilename;
	return 0;
}

/** 
 * Removes ID3v1 TAG from files.
 *
 * @param argc       argc of calling parent programm
 * @param argv       argv of calling parent programm
 * @param arc_offset index begin of interesting args
 * @return 1 - error: windows version dos not work yet, otherwise allways 0
 */
int ParseDel(int argc, char** argv, int argc_offset){
BTRACK

#ifdef _WIN32
// windows version
/*
 * from: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/setendoffile.asp
 * 
 * The SetEndOfFile function moves the end-of-file (EOF) position for the specified file 
 * to the current position of the file pointer.
 *
 * This function sets the physical end of a file (as indicated by allocated clusters). 
 * To set the logical end of a file, use the SetFileValidData function.
 *
 * BOOL SetEndOfFile(
 *      HANDLE hFile
 * );
 */
	printf("del\n");
	fprintf(stderr,"del mode is not implemented under windows : \nstill don't know how to truncate a file");
	return 1;

#else
	off_t FileSize;
	OpenedFile* my;
	for (int i=argc_offset; i < argc; i++){
		printf("Deleting tag in %s\n",argv[i]);
		my=OpenFile(argv[i]);
		if (!my->thefile){
			printf("Can not open file\n");
			if (my->thetag) delete my->thetag;
			delete my;
			continue;
		}
		// okay we have a file here.
		if (my->thetag) { 
			//		printf("tag is present\n");
			// this file has a tag
			FSEEK(my->thefile,0,SEEK_END);
			//		printf("Size before : %ld\n",ftello(my->thefile));
			FileSize=FTELL(my->thefile)-128;
			//		printf("Size after : %ld\n",FileSize);
			if (!id3_Show_Only)
				if(truncate(argv[i],FileSize)){
					fprintf(stderr,"Unable to truncate file \n");
					perror(argv[i]);
				}
		}
		//printf("File doesn't have any tag\n");
		// lets delete and close before next opened file
		if (my->thefile) fclose (my->thefile);
		if (my->thetag) delete my->thetag;
		delete my;
	}
	return 0;
        
#endif // _WIN32

}

/**
 * Fills a OpenedFile structure with TAG infos of a file according given FileName
 *
 * @param  FileName Name of file to open
 * @return Pointer to filled structure
 */
OpenedFile* OpenFile(char* FileName){
	BTRACK;
	unsigned char start[4];
	char TAG[128];
	OpenedFile* my = new OpenedFile;
	my->thetag=0;
	my->thefile=0;
	my->filetype=NOT_MP3;
	my->thefile=fopen(FileName,"r+b");
	if (!my->thefile){
		// error 
		perror(FileName);
		return my;
	}

	fread(start,4,1,my->thefile);
	if (!strncmp((char*)(start),"RIFF",4)){

		if (!strstr(FileName,".mp")||!strstr(FileName,".MP")){
			//				fprintf(stderr,"Skipping Fake mp3 file %s (Wave file)\n",FileName);
			my->filetype=FAKE_MP3;
			return my;
		}
		else {
			//			fprintf(stderr,"Skipping Wave file %s\n",FileName);
			my->filetype=NOT_MP3;
			return my;
		}
	}

	if ((start[0]==0xFF) && ((start[1]	& 0xE0) == 0xE0)){
		my->filetype=REAL_MP3;
	}
	else if (start[0]== 'I' && start[1]=='D' && start[2]=='3'){
		my->filetype=REAL_MP3;
	}
	else{
		//doesn't start like an mp3
		if (!strstr(FileName,".mp")||!strstr(FileName,".MP")){
			my->filetype=REAL_MP3;
		}
		else {
			fprintf(stderr,"Skipping unknown file %s\n",FileName);
			my->filetype=NOT_MP3;
			return my;
		}
	}


	FSEEK(my->thefile,-128,SEEK_END);
	fread(TAG,128,1,my->thefile);

	if ( strncmp (TAG,"TAG",3) ){
		// doesn't begin with TAG : no tag
		return my;
	}

	// begins with TAG : parse it.
	my->thetag=new myID3tag;
	strncpy(my->thetag->title,&TAG[3],30);
	strncpy(my->thetag->artist,&TAG[33],30);
	strncpy(my->thetag->album,&TAG[63],30);
	strncpy(my->thetag->year,&TAG[93],4);
	strncpy(my->thetag->comment,&TAG[97],30);
	if (TAG[125]==0){
		my->thetag->track=TAG[126];
	}
	else {
		my->thetag->track=-1;
	}
	my->thetag->genre=(unsigned char) TAG[127];

	return my;	
}

/**
 * Sets ID3v1 TAG of a MP3 file according given format string.
 *
 * @param format Format string with TAGs to set
 * @param tag    File to tag.
 * @return false on format errors, true otherwise 
 */
bool SetID3(char* format,OpenedFile* tag){
	BTRACK;
	// change tag->thetag to reflect format
	if (! tag->thetag) {
		tag->thetag=new myID3tag;
		tag->thetag->album[0]=0;
		tag->thetag->artist[0]=0;
		tag->thetag->year[0]=0;
		tag->thetag->comment[0]=0;
		tag->thetag->title[0]=0;
		tag->thetag->track=-1;
		tag->thetag->genre=255;
	}
	char *target=0;
	// parse the format
	int fieldsize;
	int tracknum=-1;
	int genre=-1;
	int length = strlen(format);
	for(int i=0; i <= length-3;){
		// first char must be %
		// second char must be tAaycgT
		// third char must be : or ?
		while(format[i]==' ') i++;
		if (format[i]!='%' || (format[i+2] != ':' && format [i+2] != '?')){
			fprintf(stderr,"Invalid format \"%s\"\n",format+i);
			return false;
		}
		fieldsize=-1;
		switch (format[i+1]){
			case 'a':
				if (format[i+2]=='?') fprintf(stdout,"Album  : ");
				target= tag->thetag->album;
				fieldsize=30;
				break;
			case 'A':
				if (format[i+2]=='?') fprintf(stdout,"Artist : ");
				target= tag->thetag->artist;
				fieldsize=30;
				break;
			case 't':
				if (format[i+2]=='?') fprintf(stdout,"Title  : ");
				target= tag->thetag->title;
				fieldsize=30;
				break;
			case 'c':
				if (format[i+2]=='?') fprintf(stdout,"Comment: ");
				target= tag->thetag->comment;
				fieldsize=30;
				break;
			case 'y':
				if (format[i+2]=='?') fprintf(stdout,"Year   : ");
				target= tag->thetag->year;
				fieldsize=4;
				break;
			case 'g':
				if (format[i+2]=='?') fprintf(stdout,"Genre  : ");
				break;
			case 'T':
				if (format[i+2]=='?') fprintf(stdout,"Track  : ");
				break;
		}

		// treat the '?'
		if (format[i+2]=='?'){
			// ask user
			if (fieldsize>0){
				//any char*
				fgets(target,fieldsize,stdin);
				// now remove the trailing \n if any
				if (strlen(target)!=0){
					if (target[strlen(target)-1]=='\n') target[strlen(target)-1]=0;
					else {
						// mmmmm no \n at the end : flush input
						while (getchar()!='\n');
					}
				}
			}
			else{
				// a number for genre or track
				if (format[i+1]=='T') scanf("%d",&tracknum);
				if (format[i+1]=='g') scanf("%d",&genre);
				//			printf("read T %d g %d\n",tracknum,genre);
			}
			i+=3;
			continue;
		}
		// treat the ':'
		// is this a 'standard' field?
		if (fieldsize==-1){
			if (length-i >3){
				if (format[i+1]=='T') sscanf(&format[i+3],"%d",&tracknum);
				if (format[i+1]=='g') sscanf(&format[i+3],"%d",&genre);
				//		printf("scanned T %d g %d\n",tracknum,genre);
				i+=3;
			}
			while ((format[i]>='0' && format[i]<='9')||(format[i]==' ')) i++;
			continue;
		}	
		// this is a char * field
		// move i to the start of field
		i+=3;
		// now copy everything until a % or fieldsize or format length
		bool finished=false;
		int n_processed=0;
		while (!finished){
			if ( // a % not followed by a %
					(format[i]=='%' && format[i+1]!='%')||
					// end of format
					(format[i]=='\0')
				) {
				finished=true;	
				//			while (n_processed <fieldsize) target[n_processed++]=' ';
			}
			else{
				if (n_processed<fieldsize){
					target[n_processed++]=format[i];
					target[n_processed]=0; // end the string
				}
				else {
					//				printf("skipping %c [offset : %d]\n",format[i],n_processed);
				}
				if (format[i]=='%') i++; // skip the second % sign
				i++;
			}
		}


	}

	//if (genre<0){
	//	tag->thetag->genre=255; // unspecified genre	
	//}
	if (genre>=0) tag->thetag->genre=genre;
	if (tracknum >=0 && tracknum <256 ){

		tag->thetag->track=(unsigned char) tracknum;
	}

	return true;
}

/**
 * Write ID3v1 TAG to given file.
 *
 * @param filename MP3 file to set ID3v1 TAG.
 */
void WriteID3(OpenedFile* filename){
BTRACK
	//write tag->thetag in tag->thefile
	/*
		printf ("artist %s\ntitle %s \nalbum %s\nyear %s\ncomment %s\ngenre %d\ntrack%d\n\n",
		filename->thetag->artist ,
		filename->thetag->title ,
		filename->thetag->album,
		filename->thetag->year ,
		filename->thetag->comment ,
		filename->thetag->genre ,
		filename->thetag->track);
	 */
	if (filename->thefile==0){
		fprintf(stderr,"ERROR : no valid FILE* in WriteID3\n");
		return;
	}
	if (filename->thetag==0){
		fprintf(stderr,"ERROR : no valid tag in WriteID3\n");
		return;
	}

	char TAG[128];
	TAG[0]='T';
	TAG[1]='A';
	TAG[2]='G';
	int length,i;
	length=strlen(filename->thetag->title);
	for (i=0; i < length; i++)
		TAG[3+i]=filename->thetag->title[i];
	for (;i<30; i++)
		TAG[3+i]=' ';

	length=strlen(filename->thetag->artist);
	for (i=0; i < length; i++)
		TAG[33+i]=filename->thetag->artist[i];
	for (;i<30; i++)
		TAG[33+i]=' ';

	length=strlen(filename->thetag->album);
	for (i=0; i < length; i++)
		TAG[63+i]=filename->thetag->album[i];
	for (;i<30; i++)
		TAG[63+i]=' ';

	length=strlen(filename->thetag->year);
	for (i=0; i < length; i++)
		TAG[93+i]=filename->thetag->year[i];
	for (;i<4; i++)
		TAG[93+i]=' ';

	length=strlen(filename->thetag->comment);
	for (i=0; i < length; i++)
		TAG[97+i]=filename->thetag->comment[i];
	for (;i<30; i++)
		TAG[97+i]=' ';

	if (filename->thetag->track >0){
		TAG[125]=0; TAG[126]=(unsigned char) filename->thetag->track;
	}


	//if(filename->thetag->genre !=255) TAG[127]=(unsigned char) filename->thetag->genre;
	TAG[127]= filename->thetag->genre;



	// okay we have our chunk.
	char checkTAG[3];
	FSEEK(filename->thefile, -128, SEEK_END);
	fread(checkTAG,3,1,filename->thefile);
	if (!strncmp(checkTAG,"TAG",3)){
		// a TAG is present
		FSEEK(filename->thefile, -128, SEEK_END);
		fwrite(TAG,128,1,filename->thefile);
	}else{
		// no tag in this file
		FSEEK(filename->thefile,0,SEEK_END);
		fwrite(TAG,128,1,filename->thefile);
	}

}

/**
 * Asks user for creation of a new directory.
 *
 *@param path Path of new directory
 *@return true if user allows creation, false if deny
 */ 
bool AskDirCreation(char* path){
BTRACK
	fprintf(stderr,"Create directory %s ?:[N/y]",path);
	char answer=getchar();
	while(getchar()!='\n');
RTRACK
	if (answer=='y' || answer=='Y') return true;
	
	return false;
}

/**
 * Moves file to destination, creates intermediate directories if necessary.
 *
 * @param name    Filename
 * @param basedir Source directory
 * @param dest    Destination directory
 */
void Move2(const char* name,const char* basedir,const char* dest){
BTRACK
	struct stat mystats;
	int ret;
	char *tempdest;
	char *fullname;
	int move2dirsize=0;
	fullname = new char [strlen(name)+strlen(basedir)+1];
	strcpy(fullname,basedir);
	strcat(fullname,name);

	// if the dest ends with a / , keep space for the name
	if (dest[strlen(dest)-1]=='/'){
		move2dirsize=strlen (name);
	}


	//handle the full path (begins with a /)
	if (dest[0]=='/'){
		tempdest=new char[strlen(dest)+1+move2dirsize];
		strcpy(tempdest,dest);
	}

	//handle the ~/ (home dir)
	else if(dest[0]=='~' && dest[1]=='/'){
		struct passwd* mypassentry;
		mypassentry=getpwuid(getuid());

		if (!mypassentry || !(mypassentry->pw_dir)){
			fprintf(stderr,"Could not resolve your home directory, use absolute path\n");
			return;
		}
		tempdest= new char [strlen(mypassentry->pw_dir)+strlen(dest)+1+move2dirsize];
		if (mypassentry->pw_dir[strlen(mypassentry->pw_dir)-1] == '/'){
			// pwdir ends with a slash
			strcpy(tempdest,mypassentry->pw_dir);
			strcat(tempdest,&dest[2]); // dest[2] after the /
		}
		else {
			//pw_dir doesn't end with a slash
			strcpy(tempdest,mypassentry->pw_dir);
			strcat(tempdest,&dest[1]);
		}

	}

	//handle the ./
	else if (dest[0]=='.' && dest[1]=='/'){
		//explicitely relative path
		tempdest= new char[strlen(dest)+strlen(basedir)+1+move2dirsize];
		strcpy(tempdest,basedir);
		strcat(tempdest,&dest[2]); //after the slash
	}

	// dest is relative, don't change it
	else
	{
		tempdest= new char[strlen(dest)+strlen(basedir)+1+move2dirsize];
		strcpy(tempdest,basedir);
		strcat(tempdest,dest);
	}

	if (move2dirsize){
		//the format ends with a /, append name
		strcat(tempdest,name);
	}
	//printf("%s\n  =>%s\n\n",name,tempdest);


	//this for is to create intermediate directories
	for (int i= 0; i < int(strlen(tempdest)); i++){
		if (tempdest[i]=='/' && i!=0){
			//check if dir exists

			//hide the trailing path
			tempdest[i]=0;
			ret=stat(tempdest,&mystats);
			if (!ret){
				//stat worked
				//check if this is a directory
				if ((mystats.st_mode & S_IFMT)==S_IFREG){
					fprintf(stderr,"Error : %s is not a directory\n",tempdest);
					delete [] tempdest;
					return;
				}


			}	
			else{
				//didn't work... check the error
				//		printf("%s  ",tempdest);
				switch(errno){
					case ENOENT:
						//				printf("ENOENT\n");
						if (id3_Show_Only) {
							printf("Would Create directory %s (if not created before)\n",tempdest);
						}
						else{
							if(AskDirCreation(tempdest)) mkdir(tempdest,0777);			
							else return;
						}
						break;
					case ENOTDIR:

						// a part of the path is a directory
						fprintf(stderr,"Error : %s is not a directory\n",tempdest);
						delete[]tempdest;
						return;
						break;
					case EACCES:
						perror(tempdest);
						delete[] tempdest;
						return;
						break;
					default :
						perror(tempdest);
						delete[] tempdest;
						return;
						break;
				}

			}	
			//show the trailing path again
			tempdest[i]='/';
		}
	}
	// okay we can rename
	// check if the destination already exist
	ret = stat(tempdest,&mystats);
	if (!ret){
		printf("Skipping %s (file exists)\n",tempdest);
		delete[] tempdest;
		return;
	}
	if(id3_Show_Only){
		printf("Would move %s\n",fullname);
		printf("to         %s\n\n",tempdest);
	}
	else{
		ret=rename(fullname,tempdest);
		if (ret){
			perror(fullname);
		}
		else{
			//printf("%s=>%s\n",name,tempdest);
		}
	}
}
