#include "RestoreInterface.h"

int restore_mount(string *args, struct shell_state *sh)
{
	mach_error_t retval;
	
	if( args[1] == "" || args[2] == "")
	{
		ifNotQuiet cout << "mount: please provide both arguments." << endl;
		set_rfr(1);
		return SHELL_CONTINUE;
	}
	
	D("allocating CFMutableDictionary");
	CFMutableDictionaryRef req = CFDictionaryCreateMutable(	kCFAllocatorDefault, 0,
								&kCFTypeDictionaryKeyCallBacks,
								&kCFTypeDictionaryValueCallBacks);
	
	D("setting values");
//	CFDictionarySetValue(req, CFSTR("Operation"), CFSTR("Mount"));
	CFDictionarySetValue(req, CFSTR("Request"), CFSTR("Mount"));
	CFDictionarySetValue(req, CFSTR("DeviceName"),
		CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII));
	CFDictionarySetValue(req, CFSTR("MountPoint"),
		CFStringCreateWithCString(NULL, args[2].c_str(), kCFStringEncodingASCII));
	
	D("sending dictionary");
	retval = performOperation(sh->restore_dev, req);
	
	ifVerbose cout	<< "mount: mounting '" << args[1] << "' at '" << args[2] << endl;
	
	// build a list of known error codes
	ifNotQuiet
	{
		switch (retval)
		{
			case 0:
				ifVerbose cout << "mount: Successful." << endl;
				break;
			case 6:
				cout << "mount: iPhone returned '6' - invalid argument." << endl;
				break;
			default:
				cout << "mount: iPhone returned '" << < retval << "' - unknown error code." << endl;
				break;
		}
	}
	
	// set return function retval so we can break a script if this doesn't work for some reason
	set_rfr(retval);
	
	return SHELL_CONTINUE;
}

int restore_partition(string *args, struct shell_state *sh)
{
	mach_error_t retval;
	
	D("allocating CFMutableDictionary");
	CFMutableDictionaryRef req = CFDictionaryCreateMutable(	kCFAllocatorDefault, 0,
								&kCFTypeDictionaryKeyCallBacks,
								&kCFTypeDictionaryValueCallBacks);
	
	D("setting values");
	CFDictionarySetValue(req, CFSTR("Request"), CFSTR("Partition"));
	
	D("sending dictionary");
	retval = performOperation(sh->restore_dev, req);
	
	ifVerbose cout	<< "partition: returned error code: "
			<< retval << endl;
	
	// set return function retval so we can break a script if this doesn't work for some reason
	set_rfr(retval);
	
	return SHELL_CONTINUE;
}

int restore_erase(string *args, struct shell_state *sh)
{
	mach_error_t retval;
	
	if( args[1] == "" || args[2] == "")
	{
		ifNotQuiet cout << "mount: please provide both arguments." << endl;
		set_rfr(1);
		return SHELL_CONTINUE;
	}
	
	D("allocating CFMutableDictionary");
	CFMutableDictionaryRef req = CFDictionaryCreateMutable(	kCFAllocatorDefault, 0,
								&kCFTypeDictionaryKeyCallBacks,
								&kCFTypeDictionaryValueCallBacks);
	
	D("setting values");
	CFDictionarySetValue(req, CFSTR("Request"), CFSTR("Erase"));
	CFDictionarySetValue(req, CFSTR("DeviceName"),
		CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
	CFDictionarySetValue(req, CFSTR("VolumeName"),
		CFStringCreateWithCString(NULL, args[2].c_str(), kCFStringEncodingASCII) );
	
	D("sending dictionary");
	retval = performOperation(sh->restore_dev, req);
	
	ifVerbose cout	<< "erase: erasing device '" << args[1] << "' at volume '" << args[2] << "': " << retval << endl;
	
	// set return function retval so we can break a script if this doesn't work for some reason
	set_rfr(retval);
		
	return SHELL_CONTINUE;
}

int restore_ditto(string *args, struct shell_state *sh)
{
	mach_error_t retval;
	
	if( args[1] == "" || args[2] == "")
	{
		ifNotQuiet cout << "ditto: please provide both arguments." << endl;
		set_rfr(1);
		return SHELL_CONTINUE;
	}
	
	D("allocating CFMutableDictionary");
	CFMutableDictionaryRef req = CFDictionaryCreateMutable(	kCFAllocatorDefault, 0,
								&kCFTypeDictionaryKeyCallBacks,
								&kCFTypeDictionaryValueCallBacks);
	
	D("setting values");
	CFDictionarySetValue(req, CFSTR("Request"), CFSTR("Ditto"));
	CFDictionarySetValue(req, CFSTR("SourcePath"),
		CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
	CFDictionarySetValue(req, CFSTR("DestinationPath"),
		CFStringCreateWithCString(NULL, args[2].c_str(), kCFStringEncodingASCII) );
	
	D("sending dictionary");
	retval = performOperation(sh->restore_dev, req);
	
	ifVerbose cout	<< "ditto: copying file '" << args[1] << "' to '" << args[2] << "': " << retval << endl;
	
	// set return function retval so we can break a script if this doesn't work for some reason
	set_rfr(retval);
	
	return SHELL_CONTINUE;
}

int erica_foo(string *args, struct shell_state *sh)
{
	mach_error_t retval;
	
	if( args[1] == "" )
	{
		ifNotQuiet cout << "foo: please provide a request." << endl;
		set_rfr(1);
		return SHELL_CONTINUE;
	}
	
	D("allocating CFMutableDictionary");
	CFMutableDictionaryRef req = CFDictionaryCreateMutable(
             kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
             &kCFTypeDictionaryValueCallBacks);
	
	D("setting values");

        // Attempt to set arguments Tests
	// CFDictionarySetValue(req, CFSTR("MsgType"), CFSTR("QueryType"));
        // CFDictionarySetValue(req, CFSTR("MsgType"), CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII));
	// CFDictionarySetValue(req, CFSTR("MountPoint"),
	// CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
	// CFDictionarySetValue(req, CFSTR("Operation"), CFSTR("Mount"));
	// CFDictionarySetValue(req, CFSTR("DeviceName"), CFSTR("/dev/disk0s1"));
	// CFDictionarySetValue(req, CFSTR("MountPoint"), CFSTR("/mnt1"));
        // CFDictionarySetValue(req, CFSTR("Request"), CFSTR("QueryType"));
	// CFDictionarySetValue(req, CFSTR("MsgType"), CFSTR("DataRequestMsg"));
         // CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII));

        // REQUEST IS ARG1
       // CFDictionarySetValue(req, CFSTR("Request"), CFSTR("QueryType"));
       // CFDictionarySetValue(req, CFSTR("Command"), CFSTR("Ditto"));
       CFDictionarySetValue(req, CFSTR("Request"), 
             CFStringCreateWithCString(NULL, args[1].c_str(),
             kCFStringEncodingASCII));
       CFDictionarySetValue(req, CFSTR("Type"), 
             CFStringCreateWithCString(NULL, args[2].c_str(),
             kCFStringEncodingASCII));


       // CFDictionarySetValue(req, CFSTR("MsgType"), CFSTR("StatusMsg"));

		 
	
	D("sending dictionary");
	retval = performOperation(sh->restore_dev, req);
	cout	<< "Testing: '" << args[1] << "': " << retval << endl;
	
	// set return function retval so we can break a script if this doesn't work for some reason
	set_rfr(retval);
	
	return SHELL_CONTINUE;
}

int restore_umount(string *args, struct shell_state *sh)
{
	mach_error_t retval;
	
	if( args[1] == "" )
	{
		ifNotQuiet cout << "umount: please provide an argument." << endl;
		set_rfr(1);
		return SHELL_CONTINUE;
	}
	
	D("allocating CFMutableDictionary");
	CFMutableDictionaryRef req = CFDictionaryCreateMutable(	kCFAllocatorDefault, 0,
								&kCFTypeDictionaryKeyCallBacks,
								&kCFTypeDictionaryValueCallBacks);
	
	D("setting values");
	CFDictionarySetValue(req, CFSTR("Request"), CFSTR("Unmount"));
	CFDictionarySetValue(req, CFSTR("MountPoint"),
	CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
	
	D("sending dictionary");
	retval = performOperation(sh->restore_dev, req);
	
	ifVerbose cout	<< "umount: Unmounting '" << args[1] << "': " << retval << endl;
	
	// set return function retval so we can break a script if this doesn't work for some reason
	set_rfr(retval);
	
	return SHELL_CONTINUE;
}

int restore_filesystemcheck(string *args, struct shell_state *sh)
{
	mach_error_t retval;
	
	if( args[1] == "" )
	{
		ifNotQuiet cout << "filesystemcheck: please provide a path to a disk to check." << endl;
		set_rfr(1);
		return SHELL_CONTINUE;
	}
	
	D("allocating CFMutableDictionary");
	CFMutableDictionaryRef req = CFDictionaryCreateMutable(	kCFAllocatorDefault, 0,
								&kCFTypeDictionaryKeyCallBacks,
								&kCFTypeDictionaryValueCallBacks);
	
	D("setting values");
	CFDictionarySetValue(req, CFSTR("Request"), CFSTR("FilesystemCheck"));
	CFDictionarySetValue(req, CFSTR("DeviceName"),
		CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
	
	D("sending dictionary");
	retval = performOperation(sh->restore_dev, req);
	
	ifVerbose cout	<< "FileSystemCheck: checking device '" << args[1] << "': " << retval << endl;
	
	//Here we should check for 'unknown device' error code to assume that anything else means
	//that fsck could not repair the disk, which we should alert the user to.
	
	// set return function retval so we can break a script if this doesn't work for some reason
	set_rfr(retval);
	
	return SHELL_CONTINUE;
}

int restore_mkdir(string *args, struct shell_state *sh)
{
	mach_error_t retval;
	
	if( args[1] == "" || args[2] == "")
	{
		ifNotQuiet cout << "mkdir: please provide both arguments." << endl;
		set_rfr(1);
		return SHELL_CONTINUE;
	}
	
	D("allocating CFMutableDictionary");
	CFMutableDictionaryRef req = CFDictionaryCreateMutable(	kCFAllocatorDefault, 0,
								&kCFTypeDictionaryKeyCallBacks,
								&kCFTypeDictionaryValueCallBacks);
	
	D("setting values");							
	CFDictionarySetValue(req, CFSTR("Request"), CFSTR("MakeDirectory"));
	CFDictionarySetValue(req, CFSTR("Mode"),
		CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
	CFDictionarySetValue(req, CFSTR("Path"),
		CFStringCreateWithCString(NULL, args[2].c_str(), kCFStringEncodingASCII) );
	
	D("sending dictionary");
	retval = performOperation(sh->restore_dev, req);
	
	ifVerbose cout	<< "mkdir: creating directory with modes '"
			<< args[1] << "' at location '" << args[2] <<  "': " << retval << endl;
	
	// set return function retval so we can break a script if this doesn't work for some reason
	set_rfr(retval);
			
	return SHELL_CONTINUE;
}

int restore_force(string *args, struct shell_state *sh)
{
	mach_error_t retval;
	
	if( args[1] == "" )
	{
		ifNotQuiet cout << "force: please provide a command." << endl;
		set_rfr(1);
		return SHELL_CONTINUE;
	}
	
	D("allocating CFMutableDictionary");
	CFMutableDictionaryRef req = CFDictionaryCreateMutable(	kCFAllocatorDefault, 0,
								&kCFTypeDictionaryKeyCallBacks,
								&kCFTypeDictionaryValueCallBacks);
							
	D("setting values");
	CFDictionarySetValue(req, CFSTR("Request"),
		CFStringCreateWithCString(NULL, args[1].c_str(), kCFStringEncodingASCII) );
	
	D("sending dictionary");
	retval = performOperation(sh->restore_dev, req);

	ifVerbose cout	<< "force: sending operation: '" << args[1] << "'" << endl;
	
	ifNotQuiet
	{
		switch(retval)
		{
			case 0:
				ifVerbose cout << "force: Successful." << endl;
				break;
			case 8:
				cout << "force: Unknown command." << endl;
				break;
			default:
				cout << "force: Unknown error code '" << retval << "'.  Please report." << endl;
				break;
		}
	}
	
	// set return function retval so we can break a script if this doesn't work for some reason
	set_rfr(retval);
	
	return SHELL_CONTINUE;
}

int restore_exit(string *args, struct shell_state *sh)
{
	ifNotQuiet cout << "shell: exiting restore mode." << endl;
	ifVerbose cout << "shell: If connected, the phone may restart itself. Otherwise use button combo." << endl;
	set_rfr(0);
	return SHELL_WAIT;
}