// MVCREN
// Created by Kai Engert (c) 1998-2000
// donated to the public domain
// no guarantess given

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include <utime.h>
#include <string>
#include <map>
#include <fstream>
#include <strstream>

int myexit(int retcode)
{
        //cout << endl << "Press enter to continue..." << endl;

        //char buf[500];
        //gets( buf );

        return retcode;
}

class finfo
{
public:
	finfo() : daykey(0), year(0), month(0), day(0), timeofday(0) {}

	bool operator<( const finfo &other )
	{
		return 
			(daykey < other.daykey)
			||
			(daykey == other.daykey && timeofday < other.timeofday);
	}

	bool operator==( const finfo &other )
	{
		return daykey == other.daykey && timeofday == other.timeofday;
	}

	long daykey;
	int year;
	int month;
	int day;
	long timeofday;
	string filename;
};


int createindex( const char *path )
{
	typedef map< long, finfo > tag_daymap;
	typedef map< long, tag_daymap > tag_daysmap;
	
	tag_daysmap daysmap;
	
	cout << "creating index for " << path << endl;
	
	
		DIR *d = opendir( path );
		if( !d )
		{
			cout << "can't read destination directory" << endl;
			return myexit(0);
		}


        while(1)
        {
				struct dirent *de = readdir( d );
				if( !de )
				{
					break;
				}
				
				const char * const & fname = de->d_name;

				if( strlen( fname ) < 15 )
				{
					cout << "skipping " << fname << endl;
					continue;
				}

				for( int i = 0; i < 14; ++i )
				{
					if( !isdigit( fname[i] ) )
					{
						cout << "skipping " << fname << endl;
						continue;
					}
				}

				if( fname[14] != '.' )
				{
					cout << "skipping " << fname << endl;
					continue;
				}

				finfo fi;
				
				int got = sscanf( fname, "%8ld", &fi.daykey );
				got = sscanf( fname, "%4d%2d%2d%6ld", &fi.year, &fi.month, &fi.day, &fi.timeofday );
				
				fi.filename = fname;
				
				tag_daymap &day = daysmap[ fi.daykey ];
				
				day.insert( make_pair( fi.timeofday, fi ) );
        }

		closedir( d );
		

		{
			string indexfilename;
			indexfilename = string(path) + string("index.html");

			ofstream indexfile( indexfilename.c_str() );
			
			indexfile << "<HTML><BODY>";
		 
			 tag_daysmap::const_iterator walk_days = daysmap.begin();
			 for( ; walk_days != daysmap.end(); ++walk_days )
			 {
			 	const tag_daymap &dm = (*walk_days).second;
				if( !dm.size() )
					continue;
				
				const finfo &fi = (*dm.begin()).second;
			 
		 		indexfile << "<P><A HREF=\"" << fi.daykey << ".html\">" 
					<< fi.day << "." << fi.month << "." << fi.year << "</A>" << endl;
			 }
			 
			 indexfile << "</BODY></HTML>\n";
		}


		 tag_daysmap::const_iterator walk_days = daysmap.begin();
		 for( ; walk_days != daysmap.end(); ++walk_days )
		 {
			const tag_daymap &dm = (*walk_days).second;
			if( !dm.size() )
				continue;

			const finfo &fifirst = (*dm.begin()).second;
			 
			strstream filename;
			filename << path << fifirst.daykey << ".html" << ends;
			ofstream imgfile( filename.str() );

			imgfile << "<HTML><HEAD><TITLE>" 
				<< fifirst.day << "." << fifirst.month << "." << fifirst.year 
				<< "</TITLE></HEAD>\n<BODY>\n";

			tag_daymap::const_iterator walk_day = dm.begin();
			for( ; walk_day != dm.end(); ++walk_day )
			{
				const finfo &fi = (*walk_day).second;

				imgfile << "<P><IMG SRC=\"" << fi.filename << "\">";
			}
			
			imgfile << endl << "</BODY></HTML>" << endl;

		 }
	
	return 0;
}


int main( int argc, char *argv[] )
{
        cout << endl;
        cout << "Mavica Rename  v 0.1  |  (C) 1998-2000 Kai Engert" << endl << endl;
        cout << "                         Inspired by Leo Foretich, Jr." << endl;
        cout << "                         Donated to the public domain" << endl << endl << flush;
        

        if( argc != 3 && argc != 4 )
        {
                cout << "Files on multiple Sony Mavica disks cause naming conflicts with each other." << endl;
                cout << "This program copies files to harddisk and gives them a unique name." << endl;
                cout << "Please make sure that the clock in your Mavica is always set correctly." << endl;

                cout << endl << "Usage:    mvcren  <source path>  <destination path> [file extension]" << endl;
                cout << endl << "Example:  mvcren  /mnt/dosfloppy  /home/yourname/mavica/" << endl;
                cout << endl << "Example:  mvcren  /mnt/dosfloppy  /home/yourname/mavica/  jpg" << endl;
                cout << endl << "The destination path must exist!" << endl;

                return myexit(0);
        }

        char sourcepath[NAME_MAX];
        strcpy( sourcepath, argv[1] );

        {
                long len = strlen(sourcepath);
                if( sourcepath[len-1] != '/' )
                {
                        strcat( sourcepath, "/" );
                }
        }

        char destpath[NAME_MAX];
        strcpy( destpath, argv[2] );

        {
                long len = strlen(destpath);
                if( destpath[len-1] != '/' )
                {
                        strcat( destpath, "/" );
                }
        }

        char extension[NAME_MAX];
        extension[0] = 0;
        
		  strcpy( extension, "." );
		  
        if( argc == 4 )
        {
                strcat( extension, argv[3] );
        }
        else
        {
                strcat( extension, "jpg" );
        }

        char *filebuf = 0;
        long filebufsize = 0;
        int filecount = 0;


		DIR *d = opendir( sourcepath );
		if( !d )
		{
			cout << "can't read source directory" << endl;
			return myexit(0);
		}


        while(1)
        {
				struct dirent *de = readdir( d );
				if( !de )
				{
					//cout << "error in readdir..." << endl;
					//return myexit(0);
					break;
				}
				
				const char * const & fname = de->d_name;

				if( strlen(fname) < strlen(extension)+1 )
					continue;

				const char *startsearch = fname + strlen(fname) - strlen(extension);

				if( strstr( startsearch, extension ) != startsearch )
				{
					continue;
				}


                char infile[NAME_MAX];
                sprintf( infile, "%s%s", sourcepath, fname );




				struct stat stat_buf;

				if( stat( infile, &stat_buf ) != 0 )
				{
					cout << fname << " error calling stat..." << endl;
					return myexit(0);
				}
				
				if( !S_ISREG(stat_buf.st_mode) )
				{
					continue;
				}
				
				
                if( stat_buf.st_size > filebufsize )
                {
                        delete [] filebuf;
                        filebufsize = stat_buf.st_size;
                        filebuf = new char[ filebufsize ];
                        if( !filebuf )
                        {
                                cout << "not enough memory (RAM)..." << endl;
                                return myexit(1);
                        }
                }

                FILE *fpin = fopen( infile, "rb" );
                if( !fpin )
                {
                        cout << "unable to open file " << fname << endl;
                        continue;
                }
                
                char timestr[50];
                strftime( timestr, 50, "%Y%m%d%H%M%S", localtime( &stat_buf.st_mtime ) );

                char destfile[NAME_MAX];
                sprintf( destfile, "%s%s%s", destpath, timestr, extension );
                FILE *fpout = fopen( destfile, "rb" );

                if( fpout )
                {
                        cout << endl << "destination file already exists!!!   skipping file" << endl;
                        fclose( fpout );
                        fclose( fpin );
                        continue;
                }
                

                cout << "reading " << infile << endl;

                if( fread( filebuf, stat_buf.st_size, 1, fpin ) != 1 )
                {
                        cout << "unable to read file " << fname << endl;
                        fclose( fpin );
                        continue;
                }

                fclose( fpin );

                fpout = fopen( destfile, "wb" );
                if( !fpout )
                {
                        cout << "Unable to create destination file " << destfile << endl << endl;
                        cout << "Is the disk full??? Does the destination path exist???" << endl << endl;
                        return myexit(1);
                }

                cout << "writing " << destfile << endl;

                if( fwrite( filebuf, stat_buf.st_size, 1, fpout ) != 1 )
                {
                        cout << "Unable to create destination file " << destfile << endl << endl;
                        cout << "Is the disk full??? Does the destination path exist???" << endl << endl;
                        fclose( fpout );
                        return myexit(1);
                }
        
                if( fclose( fpout ) != 0 )
                {
                        cout << "Unable to create destination file " << destfile << endl << endl;
                        cout << "Is the disk full??? Does the destination path exist???" << endl << endl;
                        return myexit(1);
                }

		  			struct utimbuf utb;
		  
                utb.actime = utb.modtime = stat_buf.st_mtime;
					 if( utime( destfile, &utb ) != 0 )
					 {
					 	cout << "can't utime destination file" << endl;
						return myexit(0);
					 }

                filecount++;
        }
        //while( _findnext( handle, &fdata ) == 0 );

		closedir( d );

        delete [] filebuf;

        cout << endl << filecount << " files copied and renamed successfully." << endl;
		  
		  return createindex( destpath );
}

