// CppFiles.cpp : main project file.

#include "stdafx.h"

using namespace System;
using namespace System::IO;

int main()
{
	// Get the command line arguments
	array<String^>^args = Environment::GetCommandLineArgs();

	// Check for required arguments
	if (args->Length < 2)
	{
		Console::WriteLine(L"Usage: CppFiles [options] [path]");
		return 0;
	}

	String^ options = nullptr;
	String^ path = nullptr;
	bool bGotOptions = false;

	// Split out the arguments
	if (args->Length == 3)
	{
		bGotOptions = true;
		options = gcnew String(args[1]);
		path = gcnew String(args[2]);
	}
	else if (args->Length == 2)
		path = gcnew String(args[1]);

	bool bSize = false;
	bool bDate = false;
	bool bAtts = false;

	// If we have options, check them. The default is to list
	// the name only
	// Possible options are:
	//   v      verbose listing, gives name, size & access time
	//   s      list size
	//   d      list last access date
	//   a      list attributes
	if (bGotOptions)
	{
		options = options->ToLower();

		if (options->IndexOf('v') != -1)
		{
			bSize = true;
			bDate = true;
			bAtts = true;
		}
		else
		{
			if (options->IndexOf('s') != -1) bSize = true;
			if (options->IndexOf('d') != -1) bDate = true;
			if (options->IndexOf('a') != -1) bAtts = true;
		}
	}

	// Check whether the user has entered a file or a directory
	bool bItsAFile = false;
	bool bItsADirectory = false;

	FileInfo^ fi = gcnew FileInfo(path);
	DirectoryInfo^ di = gcnew DirectoryInfo(path);

	if (fi->Exists)
		bItsAFile = true;
	else if (di->Exists)
		bItsADirectory = true;

	if (!bItsAFile && !bItsADirectory)
	{
		Console::WriteLine(L"No such file or directory");
		return(-1);
	}

	// Process files 
	if (bItsAFile)
	{
		Console::Write(fi->Name);

		if (bSize)
			Console::Write(L" {0}", (Object^)(fi->Length));
		if (bDate)
			Console::Write(L" {0}", File::GetLastAccessTime(fi->ToString()).ToString());
		if (bAtts)
		{
			FileAttributes fa = File::GetAttributes(fi->ToString());
			Console::Write(L" ");
			
			if ((fa & FileAttributes::Normal) == FileAttributes::Normal)
				Console::Write(L"<normal>");
			else
			{
				if ((fa & FileAttributes::Archive) == FileAttributes::Archive)
					Console::Write(L"a");
				if ((fa & FileAttributes::Hidden) == FileAttributes::Hidden)
					Console::Write(L"h");
				if ((fa & FileAttributes::System) == FileAttributes::System)
					Console::Write(L"s");
				if ((fa & FileAttributes::ReadOnly) == FileAttributes::ReadOnly)
					Console::Write(L"r");
				if ((fa & FileAttributes::Compressed) == FileAttributes::Compressed)
					Console::Write(L"z");
				if ((fa & FileAttributes::Encrypted) == FileAttributes::Encrypted)
					Console::Write(L"e");
			}
		}
		Console::WriteLine();
	}
	// Listing directory if it is directory
	else if (bItsADirectory)
	{
		// List the directory contents - subdirs first, then files
		array<String^>^ dirs = Directory::GetDirectories(di->ToString());
		for(int i=0; i<dirs->Length; i++)
		{
			DirectoryInfo^ sdi = gcnew DirectoryInfo(dirs->GetValue(i)->ToString());

			// Directories list in upper case
			String^ dirName = sdi->Name->ToUpper();
			Console::Write(L"{0,30}",dirName);
			// no size, so put a few blanks
			String^ ss = L"—";
			Console::Write(L"{0,12}",ss);

			// last mod date is OK
			if (bDate)
				Console::Write(L" {0}", 
					Directory::GetLastAccessTime(sdi->ToString()).ToString());
			// no attributes, either
			// finish the line
			Console::WriteLine();
			}
		}

	// Now do the files
	array<String^>^ files = Directory::GetFiles(di->ToString());
	for(int i=0; i<files->Length; i++)
	{
		FileInfo^ fci = gcnew FileInfo(files->GetValue(i)->ToString());
		// Files list in lower case
		String^ fileName = fci->Name->ToLower();
		Console::Write(L"{0, 30}", fileName);
		if (bSize)
			Console::Write(L"{0, 12}", (Object^)(fci->Length));
		if (bDate)
			Console::Write(L"  {0}", File::GetLastAccessTime(fci->ToString()).ToString());

		// Attributes
		FileAttributes fa = File::GetAttributes(fi->ToString());
			Console::Write(L"      ");
			
			if ((fa & FileAttributes::Normal) == FileAttributes::Normal)
				Console::Write(L"<normal>");
			else
			{
				if ((fa & FileAttributes::Archive) == FileAttributes::Archive)
					Console::Write(L"a");
				if ((fa & FileAttributes::Hidden) == FileAttributes::Hidden)
					Console::Write(L"h");
				if ((fa & FileAttributes::System) == FileAttributes::System)
					Console::Write(L"s");
				if ((fa & FileAttributes::ReadOnly) == FileAttributes::ReadOnly)
					Console::Write(L"r");
				if ((fa & FileAttributes::Compressed) == FileAttributes::Compressed)
					Console::Write(L"z");
				if ((fa & FileAttributes::Encrypted) == FileAttributes::Encrypted)
					Console::Write(L"e");
			}
		// finish the line
		Console::WriteLine();
		}
		return 0;
}

