void AddRead::Execute()
{
	this->ReadActionParameters();

	

	while (1)
	{
		Read *pRead = new Read(Position);

		Output *pOut = pManager->GetOutput();
		pOut->PrintMessage("Enter String: ");

		Input *pIn = pManager->GetInput();
		bool y = pRead->setData((pIn->GetString(pOut)));

		if (y)
		{
			pManager->AddStatement(pRead);
			pOut->ClearStatusBar();
			break;
		}
		else
		{
			pOut->MsgBox("Invalid text !! Click ok to Re-enter data", "Error", true);
		}
	}
}
void AddConnector::Execute()
{
	Output *pOut = pManager->GetOutput();

	if (pManager->getZoomMode())
	{
		pOut->MsgBox("You can't Add Connectors in zoom mode !!", "Error", true);
		return;
	}

	int SelectedCount = pManager->getSelectedCount();
	Statement** SelectedList = pManager->GetAllSelected();

	if (SelectedCount == 2)
	{
		if (SelectedList[0]->hasConn())
			pOut->MsgBox("Invalid! The selected source already has a connector to another one.", "Error", true);
		else if (dynamic_cast<End*>(SelectedList[0]))
			pOut->MsgBox("Invalid! The source can't be the End statement.", "Error", true);
		else if (dynamic_cast<Start*>(SelectedList[1]))
			pOut->MsgBox("Invalid! The destination can't be the Start statement.", "Error", true);
		else 
		{
			Connector *pConnector = new Connector(SelectedList[0], SelectedList[1]);
			pConnector->setStartPoint(SelectedList[0]->getOutlet());
			pConnector->setEndPoint(SelectedList[1]->getInlet());
			SelectedList[0]->setConn(pConnector);
			pManager->AddConn(pConnector);
			SelectedList[1]->SetSelected(false);
			pManager->RemoveSelected(SelectedList[1]);
			SelectedList[0]->SetSelected(false);
			pManager->RemoveSelected(SelectedList[0]);
			pOut->ClearStatusBar();
		}
	}
	else
		pOut->MsgBox("You should select exactly 2 items then click on this action", "Info", false);
}
void EditConnector::Execute()
{
	Output *pOut = pManager->GetOutput();

	if (pManager->ZM)
	{
		pOut->MsgBox("You can't Edit Connectors in zoom mode !!", "Error", true);
		return;
	}

	if (pManager->ConnSelectedCount > 0)
	{
		int toBeEdited = pManager->ConnSelectedCount;

		Action* DeleteConnAct = new Delete(pManager);
		DeleteConnAct->Execute();

		for (int i = 0; i < pManager->StatCount; i++)
		{
			pManager->StatList[i]->SetSelected(false);
		}
		pManager->EmptySelectedList();

		pManager->UpdateInterface();

		pOut->ClearStatusBar();

		for (int i = 0; i < toBeEdited; ++i)
		{
			pManager->UpdateInterface();
			Point SrcP, DstP;
			Statement *SrcS, *DstS;
			while (1)
			{
				pOut->PrintMessage("Select new source for Selected connector " + to_string(i + 1) + ": ");
				pManager->pIn->GetPointClicked(SrcP);
				SrcS = pManager->GetStatement(SrcP);
				if (SrcS)
				{
					SrcS->SetSelected(true);
					pManager->AddSelected(SrcS);
				}
				pManager->UpdateInterface();
				pOut->PrintMessage("Select new destination for Selected connector " + to_string(i + 1) + ": ");
				pManager->pIn->GetPointClicked(DstP);
				DstS = pManager->GetStatement(DstP);
				if (DstS)
				{
					DstS->SetSelected(true);
					pManager->AddSelected(DstS);
				}
				pManager->UpdateInterface();
				if (SrcS && DstS && SrcS != DstS && !SrcS->hasConn() && !dynamic_cast<End*>(SrcS) && !dynamic_cast<Start*>(DstS))
				{
					break;
				}
				else
				{
					if (SrcS)
					{
						SrcS->SetSelected(false);
						pManager->RemoveSelected(SrcS);
					}
					if (DstS)
					{
						DstS->SetSelected(false);
						pManager->RemoveSelected(DstS);
					}
					pManager->EmptySelectedList();
					pManager->UpdateInterface();
					pOut->MsgBox("Invalid source or destination !! Click ok to Re-select", "Error", true);
				}
			}

			Action* AddConnAct = new AddConnector(pManager);
			AddConnAct->Execute();
			delete AddConnAct;
		}

		DeleteConnAct = new Delete(pManager);
		DeleteConnAct->Execute();
		delete DeleteConnAct;

		pOut->PrintMessage("Edited Successfully !");
	}
	else
		pOut->MsgBox("You Should select the connector(s) first then click on the action", "Info", false);
}
void ZoomIN::Execute()
{
	Input *pIn = pManager->GetInput();
	Output *pOut = pManager->GetOutput();

	
	if (pManager->ZM)
	{
		pOut->MsgBox("You can't zoom in more than that...It's nonsense !!", "Error", true);
		return;
	}
	
	pManager->setZoomMode(true);


	if (pManager->SelectedCount == 1)
	{
		pManager->SelectedList[0]->setOldPos(pManager->SelectedList[0]->getPosition());   //saves old position before zooming in 
		pManager->SelectedList[0]->setOldHeight(pManager->SelectedList[0]->getHeight()); //saves old height before zooming in 
		pManager->SelectedList[0]->setOldWidth(pManager->SelectedList[0]->getWidth());  //saves old width before zooming in 

		if (pManager->SelectedList[0]->getConn())
		{
			pManager->SelectedList[0]->getConn()->setState("Appended");
		}

		pManager->SelectedList[0]->zoomIn(pOut,1); 
	}

	else if (pManager->SelectedCount == 2)
	{
		pManager->SelectedList[0]->setOldPos(pManager->SelectedList[0]->getPosition()); 
		pManager->SelectedList[1]->setOldPos(pManager->SelectedList[1]->getPosition()); 

		pManager->SelectedList[0]->setOldHeight(pManager->SelectedList[0]->getHeight());
		pManager->SelectedList[0]->setOldWidth(pManager->SelectedList[0]->getWidth());

		pManager->SelectedList[1]->setOldHeight(pManager->SelectedList[1]->getHeight());
		pManager->SelectedList[1]->setOldWidth(pManager->SelectedList[1]->getWidth());

		if (pManager->SelectedList[0]->getConn())
		{
			pManager->SelectedList[0]->getConn()->setState("Appended");
		}

		if (pManager->SelectedList[1]->getConn())
		{
			pManager->SelectedList[1]->getConn()->setState("Appended");
		}

		pManager->SelectedList[0]->zoomIn(pOut, 2, 1);
		pManager->SelectedList[1]->zoomIn(pOut, 2, 2);
	}

	else if (pManager->SelectedCount == 3)
	{
		pManager->SelectedList[0]->setOldPos(pManager->SelectedList[0]->getPosition());
		pManager->SelectedList[1]->setOldPos(pManager->SelectedList[1]->getPosition());
		pManager->SelectedList[2]->setOldPos(pManager->SelectedList[2]->getPosition());


		pManager->SelectedList[0]->setOldHeight(pManager->SelectedList[0]->getHeight());
		pManager->SelectedList[0]->setOldWidth(pManager->SelectedList[0]->getWidth());

		pManager->SelectedList[1]->setOldHeight(pManager->SelectedList[1]->getHeight());
		pManager->SelectedList[1]->setOldWidth(pManager->SelectedList[1]->getWidth());

		pManager->SelectedList[2]->setOldHeight(pManager->SelectedList[2]->getHeight());
		pManager->SelectedList[2]->setOldWidth(pManager->SelectedList[2]->getWidth());

		if (pManager->SelectedList[0]->getConn())
		{
			pManager->SelectedList[0]->getConn()->setState("Appended");
		}

		if (pManager->SelectedList[1]->getConn())
		{
			pManager->SelectedList[1]->getConn()->setState("Appended");
		}

		if (pManager->SelectedList[2]->getConn())
		{
			pManager->SelectedList[2]->getConn()->setState("Appended");
		}


		pManager->SelectedList[0]->zoomIn(pOut, 3, 1);
		pManager->SelectedList[1]->zoomIn(pOut, 3, 2);
		pManager->SelectedList[2]->zoomIn(pOut, 3, 3);


	}

	else if (pManager->SelectedCount > 3)
	{
		pOut->MsgBox("You can't zoom in to more than 3 Statements...It's nonsense !!", "Error", true);
		pManager->ZM = false;
	}


}
void GenerateCode::Execute()
{
	Output *pOut = pManager->GetOutput();
	Input *pIn = pManager->GetInput();
	Action* pVal = new Validate(pManager);
	string error;

	if (dynamic_cast<Validate*>(pVal)->isValid(error) || error.find("zero") != string::npos)
	{
		ofstream Code;
		Code.open("Code.cpp");

		// Search for Start ID & End ID & Variable Names
		int start_index, end_index;
		set<string> vars;
		set<string>::iterator it;
		for (int i = 0; i < pManager->getStatCount(); ++i)
		{
			string tmp, data;
			tmp = pManager->StatList[i]->CopyData();
			for (int i = 0; i < tmp.size(); i++)
			{
				if (tmp[i] == ' ')
					continue;
				data += tmp[i];
			}
			// Search for Start ID & End ID
			if (dynamic_cast<Start*>(pManager->StatList[i]))
				start_index = i;
			if (dynamic_cast<End*>(pManager->StatList[i]))
				end_index = i;
			// Search for Variable Names
			if (dynamic_cast<Read*>(pManager->StatList[i]))
			{
				char* cData = new char[data.size() + 1];
				strcpy(cData, data.c_str());
				char* var = strtok(cData, ",");
				while (var) {
					vars.insert(var);
					var = strtok(NULL, ",");
				}
				delete[] cData;
			}
			// Search for Variable Names
			if (dynamic_cast<Write*>(pManager->StatList[i]))
			{
				char* cData = new char[data.size() + 1];
				strcpy(cData, data.c_str());
				char* var = strtok(cData, ",");
				while (var) {
					vars.insert(var);
					var = strtok(NULL, ",");
				}
				delete[] cData;
			}
			// Search for Variable Names
			if (dynamic_cast<Assign*>(pManager->StatList[i]))
			{
				string Left = data.substr(0, data.find('='));
				vars.insert(Left);
				string Right = data.substr(data.find('=') + 1);
				string v;
				for (int i = 0; i < Right.size(); i++)
				{
					if ((Right[i] == '+' || Right[i] == '-' || Right[i] == '*' || Right[i] == '/' || Right[i] == '%') && v.size())
					{
						vars.insert(v);
						v.clear();
					}
					else if (isalpha(Right[i]))
						v += Right[i];
				}
				if (v.size())
					vars.insert(v);
			}
			// Search for Variable Names
			if (dynamic_cast<Cond*>(pManager->StatList[i]))
			{
				string cond = dynamic_cast<Cond*>(pManager->StatList[i])->getCond();
				string Left = data.substr(0, data.find(cond));
				string Right = data.substr(data.find(cond) + cond.size());
				string v;
				for (int i = 0; i < Left.size(); i++)
				{
					if ((Left[i] == '+' || Left[i] == '-' || Left[i] == '*' || Left[i] == '/' || Left[i] == '%') && v.size())
					{
						vars.insert(v);
						v.clear();
					}
					else if (isalpha(Left[i]))
						v += Left[i];
				}
				if (v.size())
					vars.insert(v);
				v.clear();
				for (int i = 0; i < Right.size(); i++)
				{
					if ((Right[i] == '+' || Right[i] == '-' || Right[i] == '*' || Right[i] == '/' || Right[i] == '%') && v.size())
					{
						vars.insert(v);
						v.clear();
					}
					else if (isalpha(Right[i]))
						v += Right[i];
				}
				if (v.size())
					vars.insert(v);
			}
		}

		string GeneratedCode;
		int curr_idx, next_idx;
		curr_idx = next_idx = start_index;

		// Generate Start code
		GeneratedCode += pManager->StatList[curr_idx]->GenerateCode(pManager->StatList, pManager->getStatCount(), end_index, curr_idx, next_idx, 0);

		// Generate variables declarations
		if (vars.size())
		{
			GeneratedCode += "\tdouble";
			for (it = vars.begin(); it != vars.end(); ++it)
			{
				GeneratedCode += " " + *it + " = 0";
				if (distance(it, vars.end()) > 1)
					GeneratedCode += ",";
			}
			GeneratedCode += ";\n";
		}

		// Generate code for each statement after Start till End
		while (1)
		{
			curr_idx = next_idx;

			GeneratedCode += pManager->StatList[curr_idx]->GenerateCode(pManager->StatList, pManager->getStatCount(), end_index, curr_idx, next_idx, 1);

			if (curr_idx == end_index)
				break;
		}

		Code << GeneratedCode;

		Code.close();

		pOut->MsgBox("Code generated successfully !", "Info", false);
		pOut->PrintMessage("Code generated successfully !");
	}
	else
		pOut->MsgBox("Sorry. You can only generate code of a valid flowchart. And this is NOT !", "Error", true);
}
void Load::Execute()
{
	Output *pOut = pManager->GetOutput();

	if (pManager->StatCount>0)
	{
		pOut->MsgBox("You Should delete any existing statements before loading a new flowchart !!", "Error", true);
		return;
	}

	ifstream In;

	In.open("Out.txt");

	if (!In.good())
	{
		pOut->MsgBox("File couldn't be Loaded !!", "Error", true);
		return;
	}

	int N1;
	In >> N1;

	string ST;
     
	for (int i = 0; i <N1; i++)
	{
		In >> ST;
		if (ST=="START")
		{
			Start* pT = new Start;
			pT->Load(In, pOut);
			pManager->AddStatement(pT,true);

		}

		else if (ST=="END")
		{
			End* pT = new End;
			pT->Load(In,pOut);
			pManager->AddStatement(pT, true);

		}

		else if (ST == "ASSIGN")
		{
			Assign* pT = new Assign;
			pT->Load(In, pOut);
			pManager->AddStatement(pT, true);

		}

		else if (ST == "COND")
		{
			Cond* pT = new Cond;
			pT->Load(In, pOut);
			pManager->AddStatement(pT, true);
		}

		else if (ST == "WRITE")
		{
			Write* pT = new Write;
			pT->Load(In, pOut);
			pManager->AddStatement(pT, true);
		}

		else if (ST == "READ")
		{
			Read* pT = new Read;
			pT->Load(In, pOut);
			pManager->AddStatement(pT, true);
		}
	}

	
	int N2;
	In >> N2;

	for (int i = 0; i < N2; i++)
	{
		int s, d,t;
		In >> s >> d>>t;
		Statement *S, *D; S = D = NULL;
		Point p1, p2;

		for (int j = 0; j < pManager->StatCount; j++)
		{
			if (s == pManager->StatList[j]->getID())
			{
				S = pManager->StatList[j];
				p1 = pManager->StatList[j]->getOutlet();
			}

			if (d == pManager->StatList[j]->getID())
			{
				D = pManager->StatList[j];
				p2 = pManager->StatList[j]->getInlet();
			}

			if (S && D)
				break;
		}

		/*Connector* pT = new Connector(S,D);
		pT->setStartPoint(p1);
		pT->setEndPoint(p2);
		pManager->AddConn(pT);
		pT->Draw(pManager->pOut);*/

		pManager->AddSelected(S);
		pManager->AddSelected(D);

		Action* pAct = NULL;
		pAct = new AddConnector(pManager);
		pAct->Execute();
	}


	In.close();

	pOut->MsgBox("File Loaded successfully !", "Info", false);
}