#include"common.h"

#include<iostream>
#include<fstream>

extern HWND hMainWindow;

extern int filever;
extern void GetFileVer(std::ifstream &f);

namespace Edit
{
	extern vector2D coordinates1;
	extern vector2D coordinates2;
}

namespace Interface
{
	extern vector2D AlignedMouseCoordinates;	//Grid::Interval間隔で
	extern vector2D FirstAlignedMouseCoordinates;	//始点
}


namespace Place
{
	extern unsigned int NewBusWidth;	//バス幅
	extern Direction NewDirection;	//新しい記号の方向
	extern Operation NewGateOperation;	//新しい論理ゲートの演算
	extern unsigned int NewGateIn; //新しい論理ゲートの入力数
	extern Module *pModule;
	extern char NewLabelName[SIZE_OF_LABEL_NAME];	//新しいラベルの名前
}

extern Data main_data;
extern Data copy_data;


void Data::CopyRange(bool Erase,bool Copy)
{
	vector2D top_left(		Edit::coordinates1.Getx()<Edit::coordinates2.Getx() ? Edit::coordinates1.Getx() : Edit::coordinates2.Getx(),
							Edit::coordinates1.Gety()<Edit::coordinates2.Gety() ? Edit::coordinates1.Gety() : Edit::coordinates2.Gety());

	vector2D bottom_right(	Edit::coordinates1.Getx()>Edit::coordinates2.Getx() ? Edit::coordinates1.Getx() : Edit::coordinates2.Getx(),
							Edit::coordinates1.Gety()>Edit::coordinates2.Gety() ? Edit::coordinates1.Gety() : Edit::coordinates2.Gety());

	int tmpNewBusWidth=Place::NewBusWidth;

	if(Copy)copy_data.Clear();

	for(unsigned int i=0;i<note.size();i++)
	{
		vector2D pos;
		pos=note[i].position();
		if(pos.Getx()>=top_left.Getx() && pos.Getx()<=bottom_right.Getx() && pos.Gety()>=top_left.Gety() && pos.Gety()<=bottom_right.Gety())
		{
			if(Copy)
			{
				Interface::AlignedMouseCoordinates=pos-Edit::coordinates2;
				strcpy_s(Place::NewLabelName,note[i].name());
				copy_data.WriteNote();
			}
			if(Erase) Delete(note,i--);
		}
	}

	for(unsigned int i=0;i<input.size();i++)
	{
		vector2D pos;
		pos=node_data[input[i].nodeindex()].position()-DirectionVector[input[i].direction()];
		if(pos.Getx()>=top_left.Getx() && pos.Getx()<=bottom_right.Getx() && pos.Gety()>=top_left.Gety() && pos.Gety()<=bottom_right.Gety())
		{
			if(Copy)
			{
				Interface::AlignedMouseCoordinates=pos-Edit::coordinates2;
				Place::NewDirection = input[i].direction();
				Place::NewBusWidth=input[i].nWire();
				strcpy_s(Place::NewLabelName,input[i].name());
				copy_data.PlaceInLabel();
			}
			if(Erase) EraseInputLabel(i--);
		}
	}

	for(unsigned int i=0;i<output.size();i++)
	{
		vector2D pos;
		pos=node_data[output[i].nodeindex()].position()-DirectionVector[output[i].direction()];
		if(pos.Getx()>=top_left.Getx() && pos.Getx()<=bottom_right.Getx() && pos.Gety()>=top_left.Gety() && pos.Gety()<=bottom_right.Gety())
		{
			if(Copy)
			{
				Interface::AlignedMouseCoordinates=pos-Edit::coordinates2;
				Place::NewDirection = ReverseDirection(output[i].direction());
				Place::NewBusWidth = node(output[i].nodeindex()).nWire();
				strcpy_s(Place::NewLabelName,output[i].name());
				copy_data.PlaceOutLabel();
			}
			if(Erase)EraseOutputLabel(i--);
		}
	}

	for(unsigned int i=0;i<busin.size();i++)
	{
		vector2D pos0,pos1;
		switch(busin[i].ReverseDirection())
		{
		case RIGHT:
			pos0=node_data[busin[i].NodeInIndex()].position()+DirectionVector[LEFT]*3+DirectionVector[UP]*busin[i].nOut();
			pos1=node_data[busin[i].NodeInIndex()].position()-DirectionVector[RIGHT]+DirectionVector[DOWN]*busin[i].nOut();
			break;
		case DOWN:
			pos0=node_data[busin[i].NodeInIndex()].position()+DirectionVector[LEFT]*busin[i].nOut()+DirectionVector[UP]*3;
			pos1=node_data[busin[i].NodeInIndex()].position()+DirectionVector[RIGHT]*busin[i].nOut()-DirectionVector[DOWN];
			break;
		case LEFT:
			pos0=node_data[busin[i].NodeInIndex()].position()-DirectionVector[LEFT]+DirectionVector[UP]*busin[i].nOut();
			pos1=node_data[busin[i].NodeInIndex()].position()+DirectionVector[RIGHT]*3+DirectionVector[DOWN]*busin[i].nOut();
			break;
		case UP:
			pos0=node_data[busin[i].NodeInIndex()].position()+DirectionVector[LEFT]*busin[i].nOut()-DirectionVector[UP];
			pos1=node_data[busin[i].NodeInIndex()].position()+DirectionVector[RIGHT]*busin[i].nOut()+DirectionVector[DOWN]*3;
			break;
		}
		if(pos0.Getx()>=top_left.Getx() && pos0.Getx()<=bottom_right.Getx() && pos0.Gety()>=top_left.Gety() && pos0.Gety()<=bottom_right.Gety()
			&&pos1.Getx()>=top_left.Getx() && pos1.Getx()<=bottom_right.Getx() && pos1.Gety()>=top_left.Gety() && pos1.Gety()<=bottom_right.Gety())
		{
			if(Copy)
			{
				Interface::AlignedMouseCoordinates=node_data[busin[i].NodeInIndex()].position()+DirectionVector[busin[i].direction()]-Edit::coordinates2;
				Place::NewDirection=busin[i].direction();
				Place::NewBusWidth=busin[i].nOut();
				copy_data.PlaceBusIn();
			}
			if(Erase)EraseBusIn(i--);
		}
	}

	for(unsigned int i=0;i<busout.size();i++)
	{
		vector2D pos0,pos1;
		switch(busout[i].direction())
		{
		case RIGHT:
			pos0=node_data[busout[i].NodeOutIndex()].position()+DirectionVector[LEFT]*3+DirectionVector[UP]*busout[i].nIn();
			pos1=node_data[busout[i].NodeOutIndex()].position()-DirectionVector[RIGHT]+DirectionVector[DOWN]*busout[i].nIn();
			break;
		case DOWN:
			pos0=node_data[busout[i].NodeOutIndex()].position()+DirectionVector[LEFT]*busout[i].nIn()+DirectionVector[UP]*3;
			pos1=node_data[busout[i].NodeOutIndex()].position()+DirectionVector[RIGHT]*busout[i].nIn()-DirectionVector[DOWN];
			break;
		case LEFT:
			pos0=node_data[busout[i].NodeOutIndex()].position()-DirectionVector[LEFT]+DirectionVector[UP]*busout[i].nIn();
			pos1=node_data[busout[i].NodeOutIndex()].position()+DirectionVector[RIGHT]*3+DirectionVector[DOWN]*busout[i].nIn();
			break;
		case UP:
			pos0=node_data[busout[i].NodeOutIndex()].position()+DirectionVector[LEFT]*busout[i].nIn()-DirectionVector[UP];
			pos1=node_data[busout[i].NodeOutIndex()].position()+DirectionVector[RIGHT]*busout[i].nIn()+DirectionVector[DOWN]*3;
			break;
		}
		if(pos0.Getx()>=top_left.Getx() && pos0.Getx()<=bottom_right.Getx() && pos0.Gety()>=top_left.Gety() && pos0.Gety()<=bottom_right.Gety()
			&&pos1.Getx()>=top_left.Getx() && pos1.Getx()<=bottom_right.Getx() && pos1.Gety()>=top_left.Gety() && pos1.Gety()<=bottom_right.Gety())
		{
			if(Copy)
			{
				Interface::AlignedMouseCoordinates=node_data[busout[i].NodeOutIndex()].position()+DirectionVector[busout[i].ReverseDirection()]-Edit::coordinates2;
				Place::NewDirection=busout[i].direction();
				Place::NewBusWidth=busout[i].nIn();
				copy_data.PlaceBusOut();
			}
			if(Erase)EraseBusOut(i--);
		}
	}

	unsigned int TurnOutOfNewGateIn = Place::NewGateIn;
	for(unsigned int i=0;i<gate.size();i++)
	{
		vector2D pos0,pos1;
		switch(gate[i].direction())
		{
		case RIGHT:
			pos0=node_data[gate[i].NodeOutIndex()].position()+DirectionVector[LEFT]*3+DirectionVector[UP]*gate[i].nIn();
			pos1=node_data[gate[i].NodeOutIndex()].position()-DirectionVector[RIGHT]+DirectionVector[DOWN]*gate[i].nIn();
			break;
		case DOWN:
			pos0=node_data[gate[i].NodeOutIndex()].position()+DirectionVector[LEFT]*gate[i].nIn()+DirectionVector[UP]*3;
			pos1=node_data[gate[i].NodeOutIndex()].position()+DirectionVector[RIGHT]*gate[i].nIn()-DirectionVector[DOWN];
			break;
		case LEFT:
			pos0=node_data[gate[i].NodeOutIndex()].position()-DirectionVector[LEFT]+DirectionVector[UP]*gate[i].nIn();
			pos1=node_data[gate[i].NodeOutIndex()].position()+DirectionVector[RIGHT]*3+DirectionVector[DOWN]*gate[i].nIn();
			break;
		case UP:
			pos0=node_data[gate[i].NodeOutIndex()].position()+DirectionVector[LEFT]*gate[i].nIn()-DirectionVector[UP];
			pos1=node_data[gate[i].NodeOutIndex()].position()+DirectionVector[RIGHT]*gate[i].nIn()+DirectionVector[DOWN]*3;
			break;
		}
		if(pos0.Getx()>=top_left.Getx() && pos0.Getx()<=bottom_right.Getx() && pos0.Gety()>=top_left.Gety() && pos0.Gety()<=bottom_right.Gety()
			&&pos1.Getx()>=top_left.Getx() && pos1.Getx()<=bottom_right.Getx() && pos1.Gety()>=top_left.Gety() && pos1.Gety()<=bottom_right.Gety())
		{
			if(Copy)
			{
				Interface::AlignedMouseCoordinates=node_data[gate[i].NodeOutIndex()].position()+DirectionVector[gate[i].ReverseDirection()]-Edit::coordinates2;
				Place::NewDirection=gate[i].direction();
				Place::NewGateOperation=gate[i].operation();
				if(gate[i].operation()!=NOT) Place::NewGateIn=gate[i].nIn();
				Place::NewBusWidth=node(gate[i].NodeOutIndex()).nWire();
				copy_data.PlaceGate();
			}
			if(Erase)EraseGate(i--);
		}
	}
	Place::NewGateIn = TurnOutOfNewGateIn;

	for(unsigned int i=0;i<conductor.size();i++)
	{
		vector2D pos0,pos1;
		pos0=node_data[conductor[i].nodeindex0()].position();
		pos1=node_data[conductor[i].nodeindex1()].position();
		if(pos0.Getx()>=top_left.Getx() && pos0.Getx()<=bottom_right.Getx() && pos0.Gety()>=top_left.Gety() && pos0.Gety()<=bottom_right.Gety()
			&&pos1.Getx()>=top_left.Getx() && pos1.Getx()<=bottom_right.Getx() && pos1.Gety()>=top_left.Gety() && pos1.Gety()<=bottom_right.Gety())
		{
			if(Copy)
			{
				Interface::FirstAlignedMouseCoordinates=pos0-Edit::coordinates2;
				Interface::AlignedMouseCoordinates=pos1-Edit::coordinates2;
				Place::NewBusWidth=conductor[i].nWire();
				copy_data.PlaceConductor();
			}
			if(Erase)EraseConductor(i--);
		}
	}

	for(unsigned int i=0;i<module.size();i++)
	{
		vector2D pos0,pos1;
		pos0=module[i].Center()+DirectionVector[UP]*(module[i].InternalHalfHeight()+module[i].Margin(3))+DirectionVector[LEFT]*(module[i].InternalHalfWidth()+module[i].Margin(2));
		pos1=module[i].Center()+DirectionVector[DOWN]*(module[i].InternalHalfHeight()+module[i].Margin(1))+DirectionVector[RIGHT]*(module[i].InternalHalfWidth()+module[i].Margin(0));

		if(pos0.Getx()>=top_left.Getx() && pos0.Getx()<=bottom_right.Getx() && pos0.Gety()>=top_left.Gety() && pos0.Gety()<=bottom_right.Gety()
			&&pos1.Getx()>=top_left.Getx() && pos1.Getx()<=bottom_right.Getx() && pos1.Gety()>=top_left.Gety() && pos1.Gety()<=bottom_right.Gety())
		{
			if(Copy)
			{
				Place::pModule=&module[i];//Place::NewModule=module[i];
				Interface::AlignedMouseCoordinates=module[i].Center()-Edit::coordinates2;
				copy_data.PlaceModule();
			}
			if(Erase)EraseModule(i--);
		}
	}

	Place::NewBusWidth=tmpNewBusWidth;

	if(Copy)
	{
		char ExePath[MAX_PATH+1];
		char FileEdit[MAX_PATH+1];
		char drive[MAX_PATH+1],dir[MAX_PATH+1];
		GetModuleFileName(NULL,ExePath,MAX_PATH);
		_splitpath_s(ExePath,drive,MAX_PATH+1,dir,MAX_PATH+1,NULL,0,NULL,0);
		_makepath_s(FileEdit,MAX_PATH+1,drive,dir,"FileUsedByEditingOfAst","log");
		std::ofstream f(FileEdit);
		f << "Ast0.84" << std::endl <<std::endl;
		f << copy_data;
		f.close();
	}
}

void LoadCopiedData()
{
	char ExePath[MAX_PATH+1];
	char FileEdit[MAX_PATH+1];
	char drive[MAX_PATH+1],dir[MAX_PATH+1];
	GetModuleFileName(NULL,ExePath,MAX_PATH);
	_splitpath_s(ExePath,drive,MAX_PATH+1,dir,MAX_PATH+1,NULL,0,NULL,0);
	_makepath_s(FileEdit,MAX_PATH+1,drive,dir,"FileUsedByEditingOfAst","log");
	std::ifstream f(FileEdit);

	if(f)
	{
		GetFileVer(f);
		if (filever == -1)
		{
			MessageBox(hMainWindow, "バージョンの異なるファイルです", "エラー", MB_OK);
		}
		else
		{
			copy_data.Clear();
			f >> copy_data;
			if (!f.good())
			{
				copy_data.Clear();
				MessageBox(hMainWindow, "ファイルが壊れています", "エラー", MB_OK);
			}
		}
		f.close();
	}
}

bool Data::AbleToPaste()
{
	unsigned int i;
	int tmpNewBusWidth=Place::NewBusWidth;
	vector2D MouseCoordinates=Interface::AlignedMouseCoordinates;
	for(i=0;i<input.size();i++)
	{
		vector2D pos;
		pos=node_data[input[i].nodeindex()].position()-DirectionVector[input[i].direction()];
		Interface::AlignedMouseCoordinates=pos+MouseCoordinates;
		Place::NewDirection = input[i].direction();
		Place::NewBusWidth = input[i].nWire();
		strcpy_s(Place::NewLabelName,input[i].name());
		if(!main_data.AbleToPlaceLabelIn())break;
	}
	Interface::AlignedMouseCoordinates=MouseCoordinates;
	if(i<input.size())return false;

	for(i=0;i<output.size();i++)
	{
		vector2D pos;
		pos=node_data[output[i].nodeindex()].position()-DirectionVector[output[i].direction()];
		Interface::AlignedMouseCoordinates=pos+MouseCoordinates;
		Place::NewDirection = ReverseDirection(output[i].direction());
		Place::NewBusWidth = node(output[i].nodeindex()).nWire();
		strcpy_s(Place::NewLabelName,output[i].name());
		if(!main_data.AbleToPlaceLabelOut())break;
	}
	Interface::AlignedMouseCoordinates=MouseCoordinates;
	if(i<output.size())return false;

	for(i=0;i<busin.size();i++)
	{
		Interface::AlignedMouseCoordinates=node_data[busin[i].NodeInIndex()].position()+DirectionVector[busin[i].direction()]+MouseCoordinates;
		Place::NewDirection=busin[i].direction();
		Place::NewBusWidth=busin[i].nOut();
		if(!main_data.AbleToPlaceBusIn())break;
	}
	Interface::AlignedMouseCoordinates=MouseCoordinates;
	if(i<busin.size())return false;

	for(i=0;i<busout.size();i++)
	{
		Interface::AlignedMouseCoordinates=node_data[busout[i].NodeOutIndex()].position()+DirectionVector[busout[i].ReverseDirection()]+MouseCoordinates;
		Place::NewDirection=busout[i].direction();
		Place::NewBusWidth=busout[i].nIn();
		if(!main_data.AbleToPlaceBusOut())break;
	}
	Interface::AlignedMouseCoordinates=MouseCoordinates;
	if(i<busout.size())return false;

	unsigned int TurnOutOfNewGateIn = Place::NewGateIn;
	for(i=0;i<gate.size();i++)
	{
		Interface::AlignedMouseCoordinates=node_data[gate[i].NodeOutIndex()].position()+DirectionVector[gate[i].ReverseDirection()]+MouseCoordinates;
		Place::NewDirection=gate[i].direction();
		Place::NewGateOperation=gate[i].operation();
		if(gate[i].operation()!=NOT)Place::NewGateIn=gate[i].nIn();
		Place::NewBusWidth=node(gate[i].NodeOutIndex()).nWire();
		if(!main_data.AbleToPlaceGate())break;
	}
	Place::NewGateIn = TurnOutOfNewGateIn;
	Interface::AlignedMouseCoordinates=MouseCoordinates;
	if(i<gate.size())return false;

	for(i=0;i<conductor.size();i++)
	{
		Interface::FirstAlignedMouseCoordinates=node_data[conductor[i].nodeindex0()].position()+MouseCoordinates;
		Interface::AlignedMouseCoordinates=node_data[conductor[i].nodeindex1()].position()+MouseCoordinates;
		Place::NewBusWidth = conductor[i].nWire();
		if(!main_data.AbleToPlaceConductor())break;
	}
	Interface::AlignedMouseCoordinates=MouseCoordinates;
	if(i<conductor.size())return false;

	for(i=0;i<module.size();i++)
	{
		Place::pModule=&module[i];//Place::NewModule=module[i];
		Interface::AlignedMouseCoordinates=module[i].Center()+MouseCoordinates;
		if(!main_data.AbleToPlaceModule())break;
	}
	Interface::AlignedMouseCoordinates=MouseCoordinates;
	if(i<module.size())return false;

	Place::NewBusWidth=tmpNewBusWidth;
	
	return true;
}

void Data::Paste()
{
	vector2D MouseCoordinates=Interface::AlignedMouseCoordinates;
	int tmpNewBusWidth=Place::NewBusWidth;
	for(unsigned int i=0;i<note.size();i++)
	{
		vector2D pos;
		pos=note[i].position();
		Interface::AlignedMouseCoordinates=pos+MouseCoordinates;
		strcpy_s(Place::NewLabelName,note[i].name());
		main_data.WriteNote();
	}
	for(unsigned int i=0;i<input.size();i++)
	{
		vector2D pos;
		pos=node_data[input[i].nodeindex()].position()-DirectionVector[input[i].direction()];
		Interface::AlignedMouseCoordinates=pos+MouseCoordinates;
		Place::NewDirection = input[i].direction();
		Place::NewBusWidth = input[i].nWire();
		strcpy_s(Place::NewLabelName,input[i].name());
		main_data.PlaceInLabel();
	}
	for(unsigned int i=0;i<output.size();i++)
	{
		vector2D pos;
		pos=node_data[output[i].nodeindex()].position()-DirectionVector[output[i].direction()];
		Interface::AlignedMouseCoordinates=pos+MouseCoordinates;
		Place::NewDirection = ReverseDirection(output[i].direction());
		Place::NewBusWidth = node(output[i].nodeindex()).nWire();
		strcpy_s(Place::NewLabelName,output[i].name());
		main_data.PlaceOutLabel();
	}
	for(unsigned int i=0;i<busin.size();i++)
	{
		Interface::AlignedMouseCoordinates=node_data[busin[i].NodeInIndex()].position()+DirectionVector[busin[i].direction()]+MouseCoordinates;
		Place::NewDirection=busin[i].direction();
		Place::NewBusWidth = busin[i].nOut();
		main_data.PlaceBusIn();
	}
	for(unsigned int i=0;i<busout.size();i++)
	{
		Interface::AlignedMouseCoordinates=node_data[busout[i].NodeOutIndex()].position()+DirectionVector[busout[i].ReverseDirection()]+MouseCoordinates;
		Place::NewDirection=busout[i].direction();
		Place::NewBusWidth = busout[i].nIn();
		main_data.PlaceBusOut();
	}
	unsigned int TurnOutOfNewGateIn = Place::NewGateIn;
	for(unsigned int i=0;i<gate.size();i++)
	{
		Interface::AlignedMouseCoordinates=node_data[gate[i].NodeOutIndex()].position()+DirectionVector[gate[i].ReverseDirection()]+MouseCoordinates;
		Place::NewDirection=gate[i].direction();
		Place::NewGateOperation=gate[i].operation();
		if(gate[i].operation()!=NOT)Place::NewGateIn=gate[i].nIn();
		Place::NewBusWidth = node(gate[i].NodeOutIndex()).nWire();
		main_data.PlaceGate();
	}
	Place::NewGateIn = TurnOutOfNewGateIn;
	for(unsigned int i=0;i<conductor.size();i++)
	{
		Interface::FirstAlignedMouseCoordinates=node_data[conductor[i].nodeindex0()].position()+MouseCoordinates;
		Interface::AlignedMouseCoordinates=node_data[conductor[i].nodeindex1()].position()+MouseCoordinates;
		Place::NewBusWidth = conductor[i].nWire();
		main_data.PlaceConductor();
	}
	for(unsigned int i=0;i<module.size();i++)
	{
		Place::pModule=&module[i];
		Interface::AlignedMouseCoordinates=module[i].Center()+MouseCoordinates;
		main_data.PlaceModule();
	}
	Place::NewBusWidth=tmpNewBusWidth;
	Interface::AlignedMouseCoordinates=MouseCoordinates;
}