#include"common.h"

namespace Interface
{
	extern POINT MouseCoordinates;	//マウス座標
	extern vector2D AlignedMouseCoordinates;	//GridInterval間隔で
	extern vector2D FirstAlignedMouseCoordinates;	//始点
}


template <class X> void Data::Delete(vector<X> &ar,unsigned int n)
{
	for(unsigned int i=n;i<ar.size()-1;i++) ar[i]=ar[i+1];
	ar.pop_back();
}

bool Data::EraseBranch(int index,Direction d)
{
	node_data[index].write_branch(d,no_device,-1,-1);
	if(node_data[index].nBranch()==0)
	{
		Delete(node_data,index);
		for(unsigned int i=0;i<input.size();i++)
			if(input[i].nodeindex()>index)input[i].dec_node_index();
		for(unsigned int i=0;i<output.size();i++)
			if(output[i].nodeindex()>index)output[i].dec_node_index();
		for(unsigned int i=0;i<gate.size();i++)
		{
			if(gate[i].NodeOutIndex()>index)gate[i].dec_out_index();
			for(int j=0;j<gate[i].nIn();j++)
				if(gate[i].NodeInIndex(j)>index)gate[i].dec_in_index(j);
		}
		for(unsigned int i=0;i<conductor.size();i++)
		{
			if(conductor[i].nodeindex0()>index)conductor[i].dec_node0();
			if(conductor[i].nodeindex1()>index)conductor[i].dec_node1();
		}
		for(unsigned int i=0;i<module.size();i++)
		{
			for(unsigned int j=0;j<module[i].nOutput();j++)
				if(module[i].NodeOut(j)>index)module[i].dec_NodeOut(j);
			for(unsigned int j=0;j<module[i].nInput();j++)
				if(module[i].NodeIn(j)>index)module[i].dec_NodeIn(j);
		}
		return true;
	}
	return false;
}

void Data::MoveOver(DeviceClassification dev,int n)
{
	for(unsigned int i=0;i<node_data.size();i++)
		for(unsigned int j=0;j<8;j++)
			if(node_data[i].dClass((Direction)j)==dev && node_data[i].index((Direction)j)>n)
				node_data[i].dec_index(j);


	for(unsigned int i=0;i<gate.size();i++)
		for(int j=0;j<gate[i].nIn();j++)
		{
			DeviceIndex di=gate[i].GetSourceDev(j);
			if(di.GetDeviceClass()==dev && di.GetDeviceIndex()>n)
				gate[i].SetSourceDevIndex(j,di.GetDeviceIndex()-1,di.GetDeviceSubIndex());
		}

	for(unsigned int i=0;i<output.size();i++)
		if(output[i].GetSourceDevClass()==dev && output[i].GetSourceDevIndex()>n)
		{
			DeviceIndex di=output[i].GetSourceDev();
			output[i].SetSourceDevIndex(di.GetDeviceIndex()-1,di.GetDeviceSubIndex());
		}

	for(unsigned int i=0;i<module.size();i++)
		for(unsigned int j=0;j<module[i].nInput();j++)
		{
			DeviceIndex di=module[i].InArray(j);
			if(di.GetDeviceClass()==dev && di.GetDeviceIndex()>n)
			{
				di.DecIndex();
				module[i].SetSourceDev(j,di);
			}
		}
}


void Data::EraseInputLabel(unsigned int n)
{
	int nodeindex=input[n].nodeindex();
	if(EraseBranch(input[n].nodeindex(),input[n].ReverseDirection()))nodeindex=-1;
	Delete(input,n);
	MoveOver(label_input,n);
	if(nodeindex>=0)DetectErrorAndConnect(nodeindex);
}

void Data::EraseOutputLabel(unsigned int n)
{
	int nodeindex=output[n].nodeindex();
	if(EraseBranch(output[n].nodeindex(),output[n].ReverseDirection()))nodeindex=-1;
	Delete(output,n);
	MoveOver(label_output,n);
	if(nodeindex>=0)DetectErrorAndConnect(nodeindex);
}

void Data::EraseGate(unsigned int n)
{
	int nodeindex=gate[n].NodeOutIndex();
	if(EraseBranch(gate[n].NodeOutIndex(),gate[n].ReverseDirection()))nodeindex=-1;
	if(nodeindex==-1)
	{
		for(int i=0;i<gate[n].nIn();i++)
			EraseBranch(gate[n].NodeInIndex(i),gate[n].direction());
	}
	else
	{
		for(int i=0;i<gate[n].nIn();i++)
		{
			int index=gate[n].NodeInIndex(i);
			if(EraseBranch(index,gate[n].direction()))if(nodeindex>index)nodeindex--;
		}
	}

	Delete(gate,n);
	MoveOver(gate_out,n);
	MoveOver(gate_in,n);
	if(nodeindex>=0)DetectErrorAndConnect(nodeindex);
}


void Data::EraseConductor(unsigned int n)
{
	int nodeindex0=conductor[n].nodeindex0();
	if(EraseBranch(nodeindex0,conductor[n].direction())) nodeindex0=-1;

	int nodeindex1=conductor[n].nodeindex1();
	if(EraseBranch(nodeindex1,conductor[n].ReverseDirection()))
	{
		if(nodeindex0>nodeindex1) nodeindex0--; //ここの不等式に等号をつけるかどうかの判断は棚上げ
		nodeindex1=-1;
	}

	Delete(conductor,n);
	MoveOver(lead_wire,n);

	if(nodeindex0>=0)DetectErrorAndConnect(nodeindex0);
	if(nodeindex1>=0)DetectErrorAndConnect(nodeindex1);
}

void Data::EraseModule(unsigned int n)
{
	vector<int> nodeindex;
	for(unsigned int i=0;i<module[n].nOutput();i++)nodeindex.push_back(module[n].NodeOut(i));

	for(int i=0;i<module[n].GetUpSize();i++)
	{
		switch(module[n].GetUp(i).GetDeviceClass())
		{
			int index;
		case module_out:
			index=module[n].NodeOut(module[n].GetUp(i).GetDeviceIndex());
			if(EraseBranch(index,DOWN))
			{
				nodeindex[module[n].GetUp(i).GetDeviceIndex()]=-1;
				for(unsigned int j=0;j<nodeindex.size();j++)
					if(nodeindex[j]>index)nodeindex[j]--;
			}
			break;
		case module_in:
			index=module[n].NodeIn(module[n].GetUp(i).GetDeviceIndex());
			if(EraseBranch(index,DOWN))
			{
				for(unsigned int j=0;j<nodeindex.size();j++)
					if(nodeindex[j]>index)nodeindex[j]--;
			}
			break;
		}
	}

	for(int i=0;i<module[n].GetRightSize();i++)
	{
		switch(module[n].GetRight(i).GetDeviceClass())
		{
			int index;
		case module_out:
			index=module[n].NodeOut(module[n].GetRight(i).GetDeviceIndex());
			if(EraseBranch(index,LEFT))
			{
				nodeindex[module[n].GetRight(i).GetDeviceIndex()]=-1;
				for(unsigned int j=0;j<nodeindex.size();j++)
					if(nodeindex[j]>index)nodeindex[j]--;
			}
			break;
		case module_in:
			index=module[n].NodeIn(module[n].GetRight(i).GetDeviceIndex());
			if(EraseBranch(index,LEFT))
			{
				for(unsigned int j=0;j<nodeindex.size();j++)
					if(nodeindex[j]>index)nodeindex[j]--;
			}
			break;
		}
	}

	for(int i=0;i<module[n].GetDownSize();i++)
	{
		switch(module[n].GetDown(i).GetDeviceClass())
		{
			int index;
		case module_out:
			index=module[n].NodeOut(module[n].GetDown(i).GetDeviceIndex());
			if(EraseBranch(index,UP))
			{
				nodeindex[module[n].GetDown(i).GetDeviceIndex()]=-1;
				for(unsigned int j=0;j<nodeindex.size();j++)
					if(nodeindex[j]>index)nodeindex[j]--;
			}
			break;
		case module_in:
			index=module[n].NodeIn(module[n].GetDown(i).GetDeviceIndex());
			if(EraseBranch(index,UP))
			{
				for(unsigned int j=0;j<nodeindex.size();j++)
					if(nodeindex[j]>index)nodeindex[j]--;
			}
			break;
		}
	}

	for(int i=0;i<module[n].GetLeftSize();i++)
	{
		switch(module[n].GetLeft(i).GetDeviceClass())
		{
			int index;
		case module_out:
			index=module[n].NodeOut(module[n].GetLeft(i).GetDeviceIndex());
			if(EraseBranch(index,RIGHT))
			{
				nodeindex[module[n].GetLeft(i).GetDeviceIndex()]=-1;
				for(unsigned int j=0;j<nodeindex.size();j++)
					if(nodeindex[j]>index)nodeindex[j]--;
			}
			break;
		case module_in:
			index=module[n].NodeIn(module[n].GetLeft(i).GetDeviceIndex());
			if(EraseBranch(index,RIGHT))
			{
				for(unsigned int j=0;j<nodeindex.size();j++)
					if(nodeindex[j]>index)nodeindex[j]--;
			}
			break;
		}
	}

	Delete(module,n);
	MoveOver(module_out,n);
	MoveOver(module_in,n);
	for(unsigned int i=0;i<nodeindex.size();i++)if(nodeindex[i]>=0)DetectErrorAndConnect(nodeindex[i]);
}

bool Data::EraseDevice()
{
	bool b=false;
	for(unsigned int i=0;i<input.size();i++)
		if(Interface::AlignedMouseCoordinates==GetNodeCoordinate(input[i].nodeindex())-DirectionVector[input[i].direction()])
			EraseInputLabel(i),b=true;
	for(unsigned int i=0;i<output.size();i++)
		if(Interface::AlignedMouseCoordinates==GetNodeCoordinate(output[i].nodeindex())-DirectionVector[output[i].direction()])
			EraseOutputLabel(i),b=true;
	for(unsigned int i=0;i<gate.size();i++)
	{
		switch(gate[i].direction())
		{
		case RIGHT:
			if(	(Interface::MouseCoordinates.x-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[LEFT]*2).toPOINT().x)>0 &&
				(Interface::MouseCoordinates.y-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[UP]*gate[i].nIn()).toPOINT().y)>0 &&
				(Interface::MouseCoordinates.x-(node_data[gate[i].NodeOutIndex()].position()-DirectionVector[RIGHT]).toPOINT().x)<0 &&
				(Interface::MouseCoordinates.y-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[DOWN]*gate[i].nIn()).toPOINT().y)<0)
				EraseGate(i),b=true;
			break;
		case DOWN:
			if(	(Interface::MouseCoordinates.x-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[LEFT]*gate[i].nIn()).toPOINT().x)>0 &&
				(Interface::MouseCoordinates.y-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[UP]*2).toPOINT().y)>0 &&
				(Interface::MouseCoordinates.x-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[RIGHT]*gate[i].nIn()).toPOINT().x)<0 &&
				(Interface::MouseCoordinates.y-(node_data[gate[i].NodeOutIndex()].position()-DirectionVector[DOWN]).toPOINT().y)<0)
				EraseGate(i),b=true;
			break;
		case LEFT:
			if(	(Interface::MouseCoordinates.x-(node_data[gate[i].NodeOutIndex()].position()-DirectionVector[LEFT]).toPOINT().x)>0 &&
				(Interface::MouseCoordinates.y-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[UP]*gate[i].nIn()).toPOINT().y)>0 &&
				(Interface::MouseCoordinates.x-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[RIGHT]*2).toPOINT().x)<0 &&
				(Interface::MouseCoordinates.y-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[DOWN]*gate[i].nIn()).toPOINT().y)<0)
				EraseGate(i),b=true;
			break;
		case UP:
			if(	(Interface::MouseCoordinates.x-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[LEFT]*gate[i].nIn()).toPOINT().x)>0 &&
				(Interface::MouseCoordinates.y-(node_data[gate[i].NodeOutIndex()].position()-DirectionVector[UP]).toPOINT().y)>0 &&
				(Interface::MouseCoordinates.x-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[RIGHT]*gate[i].nIn()).toPOINT().x)<0 &&
				(Interface::MouseCoordinates.y-(node_data[gate[i].NodeOutIndex()].position()+DirectionVector[DOWN]*2).toPOINT().y)<0)
				EraseGate(i),b=true;
			break;
		}
	}
	for(unsigned int i=0;i<conductor.size();i++)
		if (Interface::AlignedMouseCoordinates==GetNodeCoordinate(conductor[i].nodeindex0()) && Interface::FirstAlignedMouseCoordinates==GetNodeCoordinate(conductor[i].nodeindex1()) ||
			Interface::AlignedMouseCoordinates==GetNodeCoordinate(conductor[i].nodeindex1()) && Interface::FirstAlignedMouseCoordinates==GetNodeCoordinate(conductor[i].nodeindex0()) )
			EraseConductor(i),b=true;
	for(unsigned int i=0;i<module.size();i++)
		if(	(Interface::MouseCoordinates.x-(module[i].Center()+DirectionVector[LEFT]*(module[i].LeftMargin()+module[i].InternalHalfWidth())).toPOINT().x)>0 &&
			(Interface::MouseCoordinates.y-(module[i].Center()+DirectionVector[UP]*(module[i].UpMargin()+module[i].InternalHalfHeight())).toPOINT().y)>0 &&
			(Interface::MouseCoordinates.x-(module[i].Center()+DirectionVector[RIGHT]*(module[i].RightMargin()+module[i].InternalHalfWidth())).toPOINT().x)<0 &&
			(Interface::MouseCoordinates.y-(module[i].Center()+DirectionVector[DOWN]*(module[i].DownMargin()+module[i].InternalHalfHeight())).toPOINT().y)<0)
			EraseModule(i),b=true;
	return b;
}