/**
* Petit utilitaire de transfert, mode texte, ligne de commande uniquement
* @author Thierry JOUIN
* @version 1.1
* @date 31/10/2001
*/

#include "CCPCDisc.h"
#include "CCPCBinaryFile.h"
#include "CCPCAsciiFile.h"

enum TCommand
{
    Catalogue,
		Format,
		PutFile,
		GetFile,
		GetAllFile,
		RenameFile,
		DeleteFile,
		PrintDisc,
		PrintFile,
		Unknown
};

int main(int argc, char* argv[])
{
	std::cout << "cpcFS (c) Ramlaid 2004" << std::endl << std::endl;

	std::vector<std::string> fileNames;
	
	if (argc < 3)
    {
		std::cerr << argv[0] << " <disc> <command> [option] [file *] [-s]" << std::endl;
		std::cerr << "Commands : " << std::endl;
		std::cerr << "\tc  : catalogue" << std::endl;
		std::cerr << "\tf  : disc format" << std::endl;
		std::cerr << "\tp  : put file" << std::endl;
		std::cerr << "\t     -ch : header creation when putting" << std::endl;
		std::cerr << "\t     -b : binary mode" << std::endl;
		std::cerr << "\tg  : get file" << std::endl;
		std::cerr << "\t     -nh : no header when getting" << std::endl;
		std::cerr << "\tga : get all file" << std::endl;
		std::cerr << "\t     -nh : no header when getting" << std::endl;
		std::cerr << "\tr  : rename file" << std::endl;
		std::cerr << "\td  : delete file" << std::endl;
		std::cerr << "\ti  : print disc info" << std::endl;
		std::cerr << "\th  : print file header" << std::endl;
		std::cerr << "Options : " << std::endl;
		std::cerr << "\t-s : select side B" << std::endl;
		std::cerr << "When putting or getting file, you can use [<user>:]name.ext[,S][,P][,start][,exec]" << std::endl;
		return -1;
    }
	
	std::string discFilename(argv[1]);
	std::string c(argv[2]);
	TCommand command = Unknown;
	
	if (c==std::string("c"))
	{
		command=Catalogue;
	}
	else
	{
		if (c==std::string("f"))
		{
			command=Format;
		}
		else
		{
			if (c==std::string("p"))
			{
				command=PutFile;
			}
			else
			{
				if (c==std::string("g"))
				{
					command=GetFile;
				}
				else
				{
					if (c==std::string("ga"))
					{
						command=GetAllFile;
					}
					else
					{
						if (c==std::string("r"))
						{
							command=RenameFile;
						}
						else
						{
							if (c==std::string("d"))
							{
								command=DeleteFile;
							}
							else
							{
								if (c==std::string("i"))
								{
									command=PrintDisc;
								}
								else
								{
									if (c==std::string("h"))
									{
										command=PrintFile;
									}
								}									
							}
						}
					}
				}
			}
		}
	}
	int i=3;
	
	int side=0;
	bool headerCreation = false;
	bool headerSaving = true;
	bool binary = false;
	TDisc typeDisc = Data;
	
	for (i=3;i<argc;i++)
	{
		if (std::string(argv[i])==std::string("-s"))
		{
			MSG("Side B");
			side = 1;
		}
		else
			if (std::string(argv[i])==std::string("-ch"))
			{
				MSG("Create header when putting");
				headerCreation = true;
			}
			else
				if (std::string(argv[i])==std::string("-nh"))
				{
					MSG("No header when getting");
					headerSaving = false;
				}
				else
					if (std::string(argv[i])==std::string("-b"))
					{
						MSG("Binary mode");
						binary = true;
					}
					else
						fileNames.push_back(std::string(argv[i]));
	}
	
	try
	{
		switch (command)
		{
		case Catalogue :
			{
				CCPCDisc *disc = CCPCDisc::openDisc(discFilename,side);
				
				disc->catalogue(std::cout);
				
				disc->close();
				delete disc;
				break;
			}
		case Format :
			{
				CCPCDisc *disc = CCPCDisc::createDisc(discFilename,typeDisc,side);
				
				disc->format();
				
				disc->close();
				delete disc;
				break;
			}
		case PutFile :
			{
				CCPCDisc *disc = CCPCDisc::openDisc(discFilename,side);
				
				for (unsigned int i=0;i<fileNames.size();i++)
				{
					std::string filename = fileNames[i];
					
					unsigned int start = (unsigned int)(0-1);
					unsigned int exec = (unsigned int)(0-1);
					
					unsigned int posVirg = filename.find(',');
					while (posVirg != std::string::npos)
					{
						posVirg++;
						if (filename[posVirg] != 'P' && filename[posVirg] != 'S')
						{
							unsigned int end = filename.size();
							if (filename.find(',',posVirg) != std::string::npos)
							{
								end = filename.find(',',posVirg);
								std::string subFilename = filename.substr(posVirg,end-posVirg);
								std::string newFilename = filename.substr(0,posVirg-1)+filename.substr(end,filename.size()-end);
								filename = newFilename;
								if (start == ((unsigned int)(0-1)))
								{
									start = strtol(subFilename.c_str(),NULL,0);
								}
								else
								{
									if (exec == ((unsigned int)(0-1)))
									{
										exec = strtol(subFilename.c_str(),NULL,0);
									}
									else
									{
										ERRORMSG("Too much argument for filename :" << fileNames[i]);
									}
								}
							}
							else
							{
								std::string subFilename = filename.substr(posVirg,end-posVirg);
								std::string newFilename = filename.substr(0,posVirg-1)+filename.substr(end,filename.size()-end);
								filename = newFilename;
								if (start == ((unsigned int)(0-1)))
								{
									start = strtol(subFilename.c_str(),NULL,0);
								}
								else
								{
									if (exec == ((unsigned int)(0-1)))
									{
										exec = strtol(subFilename.c_str(),NULL,0);
									}
									else
									{
										ERRORMSG("Too much argument for filename :" << fileNames[i]);
									}
								}
							}
							posVirg--;
						}
						posVirg = filename.find(',',posVirg);
					}
					if (binary)
					{
						CCPCBinaryFile fileIn;
						try
						{
							fileIn.openFile(filename,headerCreation);
						}
						catch (CException &e)
						{
							std::cerr << e << std::endl;
							ERRORMSG("Error opening binary file " << filename)
						}
						std::cout << "Putting binary file <" << filename << "> " << fileIn.getSize() << " bytes";
						if (start != ((unsigned int)(0-1)))
						{
							fileIn.setAdress(start);
							std::cout << " [start address &" << std::hex << start << "]" << std::dec;
						}
						if (exec != ((unsigned int)(0-1)))
						{
							fileIn.setExecute(exec);
							std::cout << " [execute address &" << std::hex << start << "]" << std::dec;
						}
						std::cout << std::endl;
						disc->putFile(fileIn,filename);
					}
					else
					{
						CCPCAsciiFile fileIn;
						try
						{
							fileIn.openFile(filename,headerCreation);
						}
						catch (CException &e)
						{
							std::cerr << e << std::endl;
							ERRORMSG("Error opening ascii file " << filename)
						}
						std::cout << "Putting ascii file <" << filename << "> " << fileIn.getSize() << " bytes" << std::endl;
						disc->putFile(fileIn,filename);
					}
		  }
		  
		  disc->close();
		  delete disc;
		  break;
	  }
	case GetFile :
		{
			CCPCDisc *disc = CCPCDisc::openDisc(discFilename,side);
			
			ASSERTMSG( (fileNames.size() != 0) , "No file to get !");
			
			for (unsigned int i=0;i<fileNames.size();i++)
			{
				CCPCFile *file = disc->getFile(fileNames[i]);
				std::cout << "Getting ";
				if (file->getType() == Binary)
				{
					std::cout << "Bin :";
				}
				else
				{
					std::cout << "Asc :";
				}
				std::cout << "<" << fileNames[i] << "> \t";
				std::cout << file->getSize() << " bytes \t" << (float)file->getSize()/1024.0f << "Kb " << std::endl;
				file->saveFile(fileNames[i],headerSaving);
				delete file;
			}
			
			disc->close();
			delete disc;
			break;
		}
	case GetAllFile :
		{
			CCPCDisc *disc = CCPCDisc::openDisc(discFilename,side);
			
			for (unsigned int i=0;i<disc->getNbFiles();i++)
			{
				std::string filename = disc->getFilename(i);
				CCPCFile *file = disc->getFile(filename);
				std::cout << "Getting ";
				if (file->getType() == Binary)
				{
					std::cout << "Bin :";
				}
				else
				{
					std::cout << "Asc :";
				}
				std::cout << "<" << filename << "> \t";
				std::cout << file->getSize() << " bytes \t" << (float)file->getSize()/1024.0f << "Kb " << std::endl;
				file->saveFile(filename,headerSaving);
				delete file;
			}
			
			disc->close();
			delete disc;
			break;
		}
	case RenameFile :
		{
			ASSERTMSG( (fileNames.size() == 2) , "2 fileNames for rename");
			CCPCDisc *disc = CCPCDisc::openDisc(discFilename,side);
			
			std::cout << "Rename file <" << fileNames[0] << "> to <" << fileNames[1] << ">" << std::endl;
			disc->renameFile(fileNames[0],fileNames[1]);
			
			disc->close();
			delete disc;
			break;
		}
	case DeleteFile :
		{
			CCPCDisc *disc = CCPCDisc::openDisc(discFilename,side);
			
			for (unsigned int i=0;i<fileNames.size();i++)
			{
				std::cout << "Delete file <" << fileNames[i] << ">" << std::endl;
				disc->eraseFile(fileNames[i]);
			}
			
			disc->close();
			
			delete disc;
			break;
		}
	case PrintDisc :
		{
			CCPCDisc *disc = CCPCDisc::openDisc(discFilename,side);
			
			disc->printInfo(std::cout);
			
			disc->close();
			delete disc;
			break;
		}
	case PrintFile :
		{
			CCPCDisc *disc = CCPCDisc::openDisc(discFilename,side);
			
			ASSERTMSG( (fileNames.size() != 0) , "No file to print !");
			
			for (unsigned int i=0;i<fileNames.size();i++)
			{
				CCPCFile *file = disc->getFile(fileNames[i]);
				std::cout << "File header <" <<  fileNames[i] << ">" << std::endl;
				
				std::cout << *file << std::endl;
				file->printHeader(std::cout);
				
				delete file;
			}
			
			disc->close();
			delete disc;
			break;
		}
	default :
		{
			ERRORMSG( "Unknown command : " << c);
		}
	}
    }
	catch (CException &e)
    {
		std::cerr << e << std::endl;
		return -1;
    }
	
	return 0;
}
