#include <iostream>
#include <string>
#include <fstream>
#include<direct.h>
#include<vector>
#include<map>
#include<stdio.h> 
#include<dos.h>
#include<conio.h>
#include <filesystem>
namespace fs = std::experimental::filesystem;
typedef long long ll;
using namespace std;

struct file
{
	char * data;
	string name;
	string exe;
	ll size;
};

struct  folder
{
	string name;
	//// next folders & counter of folders in this folder
	folder * next[200];
	int nxcount;
	//// prevous of folder
	folder * prev;
	//// files & counter of files in this folder
	file arrfile[200];
	int flcount;
	//// map for dont repeat name of foldres
	map<string, int> filemp;
	//// map for dont repeat name of files
	map<string, int> foldermp;
	int id;

};

map<string, int>::iterator it1;
ll memorysize;
folder * mycur;
folder * root = new folder;
ll actualsize;
long long fsize = 0;
int g = 0, h = -1;

void creatfoldermem(string s)
{
	folder *f = new folder;
	f->name = s;
	g++;
	if (g == 1)
	{

		root->name = "C:";
		root->nxcount = 0;
		root->prev = NULL;
		root->flcount = 0;
		root->id = 0;
		mycur = root;
	}
	else
	{
		it1 = mycur->foldermp.find(f->name);
		if (it1 == mycur->foldermp.end())
		{
			folder *neew = new folder;
			neew->name = f->name;
			neew->nxcount = 0;
			neew->prev = mycur;
			neew->flcount = 0;
			neew->id = mycur->id + 1;
			mycur->next[mycur->nxcount++] = neew;
			mycur->foldermp[f->name]++;
		}
		else cout << " This name of folder is used ." << endl;
	}
}

void cd(string s)
{

	for (int i = 0; i < mycur->nxcount; i++)
	{
		if (mycur->next[i]->name == s)
		{
			mycur = mycur->next[i];
		}
	}
}
 
void back()
{
	mycur = mycur->prev;
	cout << "current now in :" << mycur->name << endl;
}

void creatfile(string s, string exe)
{
	it1 = mycur->filemp.find(s);
	if (it1 == mycur->filemp.end())
	{
		mycur->arrfile[mycur->flcount].data = NULL;
		mycur->arrfile[mycur->flcount].name = s;
		mycur->arrfile[mycur->flcount].size = 0;
		mycur->arrfile[mycur->flcount].exe = exe;
		mycur->flcount++;
		mycur->filemp[s]++;
	}
	else cout << " This name of file is used ." << endl;
}

void showall(folder f)
{
	string s;
	h++;
	for (int i = 0; i < h; i++) cout << ".";
	cout << "Folder : " + f.name << endl;

	for (int i = 0; i < f.flcount; i++)
	{
		for (int i = 0; i < h; i++) cout << ".";
		cout << "File : " + f.arrfile[i].name + f.arrfile[i].exe << endl;

	}
	for (int i = 0; i < f.nxcount; i++)
	{
		showall(*f.next[i]);
	}

}

void showfolder(folder f) /// to show the current folder
{
	for (int i = 0; i < f.nxcount; i++)
	{
		cout << " - Sub Folder : " + f.next[i]->name << endl;
	}
	for (int i = 0; i < f.flcount; i++)
	{
		cout << " - File : " + f.arrfile[i].name << endl;
	}
}

string getname(string s) /// to get the last name of file/folder 
{
	string ss = "";
	for (int i = s.size() - 1; i >= 0; i--)
	{
		if (s[i] == '\\') break;
		ss += s[i];
	}
	reverse(ss.begin(), ss.end());
	return ss;
}

void copyfolder(string s1, string s2)
{
	folder *copy = new folder;
	folder *req = new folder;
	int d = 0;
	string sf = "";

	copy = root;
	req = root;
	////// get folder   C:\oo\b
	for (int i = 0; i < s1.size(); i++)
	{
		if (s1[i] == '\\')
		{
			d++;
			if (d == 1)
			{
				sf = "";
				continue;
			}
			for (int k = 0; k < copy->nxcount; k++)
			{
				if (copy->next[k]->name == sf)
				{
					copy = copy->next[k];
				}
			}
			sf = "";
		}
		else sf += s1[i];
	}

	for (int k = 0; k < copy->nxcount; k++)
	{
		if (copy->next[k]->name == sf)
		{
			copy = copy->next[k];
		}
	}
	/////// put folder
	for (int i = 0; i < s2.size(); i++)
	{
		if (s2[i] == '\\')
		{
			for (int k = 0; k < req->nxcount; k++)
			{
				if (req->next[k]->name == sf)
				{
					req = req->next[k];
				}
			}
			sf = "";
		}
		else sf += s2[i];
	}

	for (int k = 0; k < req->nxcount; k++)
	{
		if (req->next[k]->name == sf)
		{
			req = req->next[k];
		}
	}

	it1 = req->foldermp.find(copy->name);
	if (it1 == req->foldermp.end())
	{

		req->next[req->nxcount++] = copy;
		copy->prev = req;
		mycur = req;
	}
	else
	{
		cout << " There is folder with same name .";
	}
}

void copyfile(string s1, string s2)
{
	folder *copy = new folder;
	copy = root;
	folder *req = new folder;
	req = root;
	file fcopy;

	int d = 0;
	string sf = "";
	string fl = "";

	////// get file name
	fl = getname(s1);
	////// get folder
	int x = 0;
	for (int i = s1.size() - 1; i >= 0; i--)
	{
		if (s1[i] == '\\') break;
		x++;
	}
	s1.erase(s1.size() - (x + 1), x + 1);
	for (int i = 0; i < s1.size(); i++)
	{
		if (s1[i] == '\\')
		{
			d++;
			if (d == 1 || sf == fl)
			{
				sf = "";
				continue;
			}
			for (int k = 0; k < copy->nxcount; k++)
			{
				if (copy->next[k]->name == sf)
				{
					copy = copy->next[k];
				}
			}
			sf = "";
		}
		else sf += s1[i];
	}

	for (int k = 0; k < copy->nxcount; k++)
	{
		if (copy->next[k]->name == sf)
		{
			copy = copy->next[k];
		}
	}
	for (int i = 0; i < copy->flcount; i++)
	{
		string g = copy->arrfile[i].name;
		g += copy->arrfile[i].exe;

		if (g == fl)
		{
			fcopy = copy->arrfile[i];
			break;
		}
	}
	sf = "";
	/////// put folder
	for (int i = 0; i < s2.size(); i++)
	{
		if (s2[i] == '\\')
		{
			d++;
			if (d == 1)
			{
				sf = "";
				continue;
			}
			for (int k = 0; k < req->nxcount; k++)
			{
				if (req->next[k]->name == sf)
				{
					req = req->next[k];
				}
			}
			sf = "";
		}
		else sf += s2[i];
	}
	for (int k = 0; k < req->nxcount; k++)
	{
		if (req->next[k]->name == sf)
		{
			req = req->next[k];
		}
	}

	mycur = req;
	it1 = req->filemp.find(fcopy.name);
	if (it1 == req->filemp.end())
	{
		cout << req->flcount << endl;
		req->arrfile[req->flcount++] = fcopy;
	}
	else
	{
		cout << " There is file with same name .";
	}

}

void deletfolder(string s)
{
	folder *copy = root;
	folder *req = root;
	int d = 0;
	string sf = "";

	for (int i = 0; i < s.size(); i++)
	{
		if (s[i] == '\\')
		{
			d++;
			if (d == 1)
			{
				sf = "";
				continue;
			}
			for (int k = 0; k < copy->nxcount; k++)
			{
				if (copy->next[k]->name == sf)
				{
					copy = copy->next[k];
				}
			}
			sf = "";
		}
		else sf += s[i];
	}
	for (int k = 0; k < copy->nxcount; k++)
	{
		if (copy->next[k]->name == sf)
		{
			copy->next[k] = NULL;
			copy->nxcount--;
			break;
		}
	}
	sf = "";
}

void deletfile(string s)
{
	remove(s.c_str());
	folder *copy = new folder;
	copy = root;
	folder *req = new folder;
	req = root;
	file fcopy;

	int d = 0;
	string sf = "";
	string fl = "";

	////// get file name
	fl = getname(s);
	int x = 0;
	for (int i = s.size() - 1; i >= 0; i--)
	{
		if (s[i] == '\\') break;
		x++;
	}
	s.erase(s.size() - (x + 1), x + 1);
	////// get folder
	for (int i = 0; i < s.size(); i++)
	{
		if (s[i] == '\\')
		{
			d++;
			if (d == 1)
			{
				sf = "";
				continue;
			}
			for (int k = 0; k < copy->nxcount; k++)
			{
				if (copy->next[k]->name == sf)
				{
					copy = copy->next[k];
				}
			}
			sf = "";
		}
		else sf += s[i];
	}
	for (int k = 0; k < copy->nxcount; k++)
	{
		if (copy->next[k]->name == sf)
		{
			copy = copy->next[k];
		}
	}

	for (int i = 0; i < copy->flcount; i++)
	{
		string g = copy->arrfile[i].name;
		g += copy->arrfile[i].exe;

		if (g == fl)
		{
			remove(g.c_str());
			copy->arrfile[i].name = "";
			copy->arrfile[i].exe = "";
			copy->arrfile[i].data = NULL;
			copy->arrfile[i].size = NULL;
			copy->flcount--;
			break;
		}
	}
}

string path = "C:";

void delstr()  /// to delete last file/folder from path
{
	int x = 0;
	for (int i = path.size() - 1; i >= 0; i--)
	{
		if (path[i] == '\\') break;
		x++;
	}
	path.erase(path.size() - (x + 1), x + 1);
}

void ramtodisk(folder f)
{
	string s = f.name;
	path += "\\";
	path += s;

	_mkdir(path.c_str());
	for (int i = 0; i < f.flcount; i++)
	{
		ofstream outfile;

		path += "\\";
		path += f.arrfile[i].name;
		path += f.arrfile[i].exe;

		outfile.open(path, ios::binary | ios::out | ios::app);
		outfile.write(f.arrfile[i].data, f.arrfile[i].size);
		outfile.close();
		delstr();
	}

	for (int i = 0; i < f.nxcount; i++)
	{
		ramtodisk(*f.next[i]);
	}
	delstr();
}

folder *cur2 = new folder;

string deletfront(string path)
{
	int x = 0;
	for (int i = 0; i < path.size(); i++)
	{
		if (path[i] == '\\')
		{
			x++;
			break;
		}
		x++;
	}
	path.erase(0, x);
	return path;
}

//////// to save directory in ram "folderseqence" creat folders along path & "disktoram" creat the requset folder and which it consist on  
void folderseqence(string path,bool l)
{
	if(!l) cur2 = root;
	string s = "";
	//// C:\nada\dectop\fci
	for (int i = 0; i < path.size(); i++)
	{
		if (path[i] == '\\')
		{
			if (s == "C:")
			{
				s = "";
				continue;
			}
			it1 = cur2->foldermp.find(s);
			if (it1 == cur2->foldermp.end())
			{
				folder *newf = new folder;
				newf->name = s;   /// name = oooo
				newf->prev = cur2;
				cur2->next[cur2->nxcount++] = newf;
				cur2->foldermp[newf->name]++;
				newf->flcount = 0;
				newf->nxcount = 0;
				cur2 = newf;
			}
			else
			{
				for (int j = 0; j < cur2->nxcount; j++)
				{
					if (cur2->next[j]->name == s)
					{
						cur2 = cur2->next[j];
						string newpath = deletfront(path);
						folderseqence(newpath, 1);
					}
				}
			}
			s = "";
		}
		else s += path[i];
	}
}
void disktoram(string path)
{
	//// path of user     C:\oooo
	folder *newf = new folder;

	newf->name = getname(path);   /// name = oooo
	newf->prev = cur2;
	cur2->next[cur2->nxcount++] = newf;
	newf->flcount = 0;
	newf->nxcount = 0;

	for (const auto & entry : fs::directory_iterator(path))
	{
		string s = entry.path().string();
		string filename = "", fileexe = "";

		bool l = 0;
		for (int i = s.size() - 1; i >= 0; i--)
		{
			if (s[i] == '.' || s[i] == '\\')
			{
				if (s[i] == '.')l = 1;
				else break;
			}
			else if (!l)
			{
				fileexe += s[i];
			}
			else if (l)
			{
				filename += s[i];
			}
		}
		if (l)
		{
			/// if there is file ----- like -> C:\oooo\lala.txt
			fileexe += ".";
			reverse(fileexe.begin(), fileexe.end());
			reverse(filename.begin(), filename.end());

			ifstream infile;
			streampos begin, end;
			infile.open(s, ios::binary);

			if (!infile.is_open())
			{
				cout << "There is no file with this path" << endl;
				continue;
			}
			begin = infile.tellg();
			infile.seekg(0, ios::end);
			end = infile.tellg();
			fsize = end - begin;
			cout << "size is: " << fsize << " bytes.\n";
			infile.seekg(0, ios::beg);

			newf->arrfile[newf->flcount].data = new char[fsize];
			infile.read(newf->arrfile[newf->flcount].data, fsize);
			infile.close();
			newf->arrfile[newf->flcount].name = filename;
			newf->arrfile[newf->flcount].exe = fileexe;
			newf->arrfile[newf->flcount].size = fsize;
			newf->flcount++;
			actualsize += fsize;
		}
		else
		{
			/// if there is folder ------ like -> C:\oooo\a
			folder *subnew = new folder;
			cur2 = newf;
			disktoram(s);  ///// recursive call for subdirectory of this directory 
		}
	}
}

int main()
{
	creatfoldermem("$");    //// to creat root folder

	cout << "enter the size of memory by mega byte  : ";
	cin >> memorysize;
	memorysize *= 1024 * 1024;
	cout << endl << endl;
	cout << "                     " << "***  Welcome dear user  ***" << endl;
	do {
		int s;
		cout << endl;
		if (actualsize == memorysize)
		{
			cout << "memory is full if you need add you must delete any thing";
			break;
		}

		cout << " Press the number of choice you want : \n";
		cout << " 1) creat folder . \n";
		cout << " 2) creat file .\n";
		cout << " 3) copy folder .\n";
		cout << " 4) copy file .\n";
		cout << " 5) delete folder .\n";
		cout << " 6) delete file . \n";
		cout << " 7) show current folder . \n";
		cout << " 8) show all memory .\n";
		cout << " 9) show size of memory .\n";
		cout << " 10) move current to next . \n";
		cout << " 11) move current to previos . \n";
		cout << " 12) load current folder into disk . \n";
		cout << " 13) load folder from disk into memeory . \n";
		cout << " 14) to clear the screan . \n";
		cout << " 15) exit . \n";
		cout << " __________________________________________ \n";
		cin >> s;
		switch (s)
		{
		case 1:
		{
			string name;
			cout << "enter the folder name " << endl;
			cin >> name;
			creatfoldermem(name);

			break;
		}
		case 2:
		{
			string name, ex;
			cout << "enter name of file : ";
			cin >> name;
			creatfile(name, ".txt");

			break;
		}
		case 3:
		{
			cin.ignore();

			string path1, path2;
			cout << "enter path of folder which want copy it : ";
			getline(cin, path1);
			cout << "enter path of folder which want copy in it : ";
			getline(cin, path2);
			copyfolder(path1, path2);

			break;
		}
		case 4:
		{
			cin.ignore();

			string path1, path2;
			cout << "enter path of file which want copy it :";
			getline(cin, path1);
			cout << "enter path of folder which want copy in it :";
			getline(cin, path2);
			folderseqence(path1, 0);
			copyfile(path1, path2);

			break;
		}
		case 5:
		{
			cin.ignore();

			string name;
			cout << "enter the name of folder that you need delete : ";
			getline(cin, name);
			deletfolder(name);

			break;
		}
		case 6:
		{
			cin.ignore();

			string  name;
			cout << "enter name of file you need delete : ";
			getline(cin , name);
			deletfile(name);

			break;
		}
		case 7:
		{
			showfolder(*mycur);
			break;
		}
		case 8:
		{
			h = -1;
			showall(*root);
			break;
		}
		case 9:
		{
			cout << "Size of memory is : " << " " << actualsize << endl;
			break;
		}
		case 10:
		{
			cout << "enter name of folder : ";
			string s;
			cin >> s;
			cd(s);
			break;
		}
		case 11:
		{
			back();
			break;
		}
		case 12:
		{
			ramtodisk(*mycur);
			break;
		}
		case 13:
		{
			cin.ignore();
			cout << "enter path of folder : ";
			string path;
			getline(cin, path);
			folderseqence(path, 0);
			disktoram(path);
			break;
		}

		case 14:
		{
			system("CLS");
			break;
		}
		case 15:
		{
			return 0;
			break;
		}
		}
	} while (1);
}