//File Lister Version 2.0
// By DreamVB

#include <iostream>
#include <Windows.h>
#include <time.h>
#include <sys/stat.h>

using namespace std;
using std::cout;
using std::endl;

bool DirExists(string Filename){
	//Check if a file was found.
	if (GetFileAttributesA(Filename.c_str()) == INVALID_FILE_ATTRIBUTES){
		return false;
	}
	if (!(GetFileAttributesA(Filename.c_str()) & FILE_ATTRIBUTE_DIRECTORY)){
		return false;
	}
	return true;
}

string AppPath(){
	char AppPath[MAX_PATH];
	//Get current folder app is running
	GetCurrentDirectoryA(MAX_PATH, AppPath);
	//Append backslash if needed.
	if (AppPath[strlen(AppPath) - 1] != '\\'){
		strcat(AppPath, "\\");
	}
	//Return path.
	return AppPath;
}

string LowerCase(string src){
	int i = 0;
	string buff = src;

	while (i < buff.length()){
		buff[i] = tolower(buff[i]);
		i++;
	}
	return buff;
}

char *IsSystem(int att){
	if (att & FILE_ATTRIBUTE_SYSTEM){
		return "YES";
	}
	return "NO ";
}

char *IsReadOnly(int att){
	if (att & FILE_ATTRIBUTE_READONLY){
		return "YES";
	}
	return "NO ";
}

char *IsHidden(int att){
	if (att & FILE_ATTRIBUTE_HIDDEN){
		return "YES";
	}
	return "NO ";
}

char *TextCase(char *src, int option){
	char *temp = NULL;
	int i = 0;
	temp = new char[strlen(src)];

	strcpy(temp, src);

	while (i < strlen(src)){
		if (option == 1){
			temp[i] = toupper(src[i]);
		}

		if (option == 2){
			temp[i] = tolower(src[i]);
		}
		i++;
	}
	return temp;
}

int main(int argc, char *argv[]){
	HANDLE f = 0;
	char c = '\0';
	WIN32_FIND_DATAA wfd;
	struct stat fattrib;

	string sTime = "";
	string lzPath = "";
	string fExtA = "";
	string fExtB = "";
	string sPath = "";
	string FullPathFile = "";

	int pos = 0;
	int fCount = 0;
	int fTotalSize = 0;
	int op_case = 0;
	bool allfiles = true;

	if (argc < 2){
		cout << "Usage: <Folder>[filetype] [/U] [/L]" << endl;
		exit(1);
	}

	//Convert char to wchar
	lzPath = argv[1];

	if (lzPath == "\\"){
		lzPath = AppPath();
		SetCurrentDirectoryA(lzPath.c_str());
	}

	//Append back slash if required.
	if (lzPath[lzPath.length() - 1] != '\\'){
		lzPath += "\\";
	}

	//Add the folder we be listing the files in.
	cout << "Directory of " << lzPath.c_str() << endl << endl;

	//Check if the source folder is found.
	if (!DirExists(lzPath)){
		cout << "Directory Not Found" << endl;
		exit(1);
	}

	//See if we need to add file ext to serach path.
	if (argc >= 3){
		if (argv[2][0] != '/'){
			fExtA = argv[2];
		}
		else{
			c = toupper(argv[2][1]);
			//Check arg op
			if (c == 'U'){
				//Uppercase file names
				op_case = 1;
			}
			if (c == 'L'){
				op_case = 2;
			}
		}
	}

	if (argc == 4){
		c = toupper(argv[3][1]);
		//Check arg op
		if (c == 'U'){
			//Uppercase file names
			op_case = 1;
		}
		if (c == 'L'){
			op_case = 2;
		}
	}

	//Serach path
	sPath = lzPath + "*.*";

	//Lowercase file type
	fExtA = LowerCase(fExtA);
	allfiles = fExtA == "*.*";

	if (allfiles){
		fExtB = "*.*";
	}
	else{
		//Remove * if present
		if (fExtA[0] == '*'){
			//Remove the * from input type *.ext to .ext
			fExtA.erase(0, 1);
		}
	}

	//Get first file.
	f = FindFirstFileA(sPath.c_str(), &wfd);

	//Check for inaild path.
	if (f == INVALID_HANDLE_VALUE){
		cout << "INVALID_HANDLE_VALUE" << endl << lzPath.c_str() << endl;
		exit(1);
	}

	//Output Headings
	cout << "-------------------------------------------------" << endl;
	cout << "DATE\t\t\t   RDO  HID  SYS    FILE" << endl;
	cout << "-------------------------------------------------" << endl;

	//Gets the list of files
	while (FindNextFileA(f, &wfd) != false){
		if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
			//Left for folders
		}
		else{
			//Output attrib and filename
			//Build path ans filename.
			FullPathFile = lzPath + wfd.cFileName;

			if (!allfiles){
				//Get last position of .
				pos = FullPathFile.find_last_of('.');

				if (pos != string::npos){
					//Extract file type from FullFilePath
					fExtB = LowerCase(FullPathFile.substr(pos));
				}
			}

			//Compare file types.
			if (fExtA.compare(fExtB.c_str()) == 0){

				//Get file date time
				stat(FullPathFile.c_str(), &fattrib);
				//Extract time
				sTime = ctime(&fattrib.st_ctime);

				//Date and time seems to include \n so we need to remove it.
				if (sTime[sTime.length() - 1] == '\n'){
					//Remove line break \n
					sTime.erase(sTime.length() - 1, 1);
				}

				//Outout file datetime, file attributes and filename.
				cout << sTime.c_str() << "   "
					<< IsReadOnly(wfd.dwFileAttributes) << "  " << IsHidden(wfd.dwFileAttributes) <<
					"  " << IsSystem(wfd.dwFileAttributes) << "    " << TextCase(wfd.cFileName, op_case) << endl;

				//INC number of files.
				fCount++;
				//Add up filesizes
				fTotalSize += wfd.nFileSizeLow;
			}
		}
	}

	//Write out number of files and total size of all files found.
	cout << endl;
	cout << fCount << " Files[s]  Size: " << fTotalSize << endl;

	//Close file
	FindClose(f);

	return 0;
}