#include"common.h"


namespace Interface
{
	extern vector2D AlignedMouseCoordinates;	//GridInterval間隔で
	extern vector2D FirstAlignedMouseCoordinates;	//始点
}


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

bool Data::AbleToPlaceLabel()
{
	for(unsigned int i=0;i<node_data.size();i++)
		if(node_data[i].position()==Interface::AlignedMouseCoordinates+DirectionVector[Place::NewDirection])
			if(node_data[i].isBranchExist(ReverseDirection(Place::NewDirection)))return false;
	return true;
}

void Data::PlaceInLabel()	//入力ラベル設置
{
	for(unsigned int i=0;i<node_data.size();i++)
	{
		LabelIn l(Place::NewDirection,i,Place::NewLabelName);
		if(node_data[i].position()==Interface::AlignedMouseCoordinates+DirectionVector[l.direction()])
		{
			node_data[i].write_branch(l.ReverseDirection(),label_input,input.size(),-1);
			input.push_back(l);
			DetectErrorAndConnect(i);
			return;
		}
	}

	LabelIn l(Place::NewDirection,node_data.size(),Place::NewLabelName);
	Node n;
	n.write_branch(l.ReverseDirection(),label_input,input.size(),-1);
	n.setposition(Interface::AlignedMouseCoordinates+DirectionVector[l.direction()]);
	node_data.push_back(n);
	input.push_back(l);
	DetectErrorAndConnect(node_data.size()-1);
}

void Data::PlaceOutLabel()
{
	for(unsigned int i=0;i<node_data.size();i++)
	{
		LabelOut l(ReverseDirection(Place::NewDirection),i,Place::NewLabelName);
		if(node_data[i].position()==Interface::AlignedMouseCoordinates+DirectionVector[l.direction()])
		{
			node_data[i].write_branch(l.ReverseDirection(),label_output,output.size(),-1);
			output.push_back(l);
			DetectErrorAndConnect(i);
			return;
		}
	}

	LabelOut l(ReverseDirection(Place::NewDirection),node_data.size(),Place::NewLabelName);
	Node n;
	n.write_branch(l.ReverseDirection(),label_output,output.size(),-1);
	n.setposition(Interface::AlignedMouseCoordinates+DirectionVector[l.direction()]);
	node_data.push_back(n);
	output.push_back(l);
	DetectErrorAndConnect(node_data.size()-1);
}

bool Data::AbleToPlaceGate()
{
	for(unsigned int i=0;i<node_data.size();i++)
	{
		if(node_data[i].position()==Interface::AlignedMouseCoordinates+DirectionVector[Place::NewDirection])
			if(node_data[i].isBranchExist(ReverseDirection(Place::NewDirection)))return false;

		vector2D v;
		Node n;
		switch(Place::NewDirection)
		{
		case RIGHT:
			n.setposition(Interface::AlignedMouseCoordinates+DirectionVector[LEFT]*2+DirectionVector[UP]*(Place::NewGateIn-1));
			v=DirectionVector[DOWN]*2;
			break;
		case DOWN:
			n.setposition(Interface::AlignedMouseCoordinates+DirectionVector[UP]*2+DirectionVector[RIGHT]*(Place::NewGateIn-1));
			v=DirectionVector[LEFT]*2;
			break;
		case LEFT:
			n.setposition(Interface::AlignedMouseCoordinates+DirectionVector[RIGHT]*2+DirectionVector[DOWN]*(Place::NewGateIn-1));
			v=DirectionVector[UP]*2;
			break;
		case UP:
			n.setposition(Interface::AlignedMouseCoordinates+DirectionVector[DOWN]*2+DirectionVector[LEFT]*(Place::NewGateIn-1));
			v=DirectionVector[RIGHT]*2;
			break;
		}
		if(node_data[i].isBranchExist(Place::NewDirection))
			for(unsigned int j=0;j<Place::NewGateIn;j++,n.setposition(n.position()+v))
				if(n.position()==node_data[i].position())return false;
	}
	return true;
}

void Data::PlaceGate()	//ゲート設置
{
	unsigned int i;
	int out;		//出力の節のインデックス
	vector<SourceData> in;	//入力の配列
//出力
	for(i=0;i<node_data.size();i++)	//全ノード探索
	{
		if(node_data[i].position()==Interface::AlignedMouseCoordinates+DirectionVector[Place::NewDirection]) //出力と一致する位置のノードが見つかれば
		{
			out=i;
			node_data[i].write_branch(ReverseDirection(Place::NewDirection),gate_out,gate.size(),-1);
			break;
		}
	}
	if(i==node_data.size()) //出力と一致する位置のノードが見つからなければ
	{
		Node n;
		out=node_data.size();
		n.write_branch(ReverseDirection(Place::NewDirection),gate_out,gate.size(),-1);
		n.setposition(Interface::AlignedMouseCoordinates+DirectionVector[Place::NewDirection]);
		node_data.push_back(n);
	}
//入力
	vector2D pos;
	vector2D v;
	switch(Place::NewDirection)
	{
	case RIGHT:
		pos=Interface::AlignedMouseCoordinates+DirectionVector[LEFT]*2+DirectionVector[UP]*(Place::NewGateIn-1);
		v=DirectionVector[DOWN]*2;
		break;
	case DOWN:
		pos=Interface::AlignedMouseCoordinates+DirectionVector[UP]*2+DirectionVector[RIGHT]*(Place::NewGateIn-1);
		v=DirectionVector[LEFT]*2;
		break;
	case LEFT:
		pos=Interface::AlignedMouseCoordinates+DirectionVector[RIGHT]*2+DirectionVector[DOWN]*(Place::NewGateIn-1);
		v=DirectionVector[UP]*2;
		break;
	case UP:
		pos=Interface::AlignedMouseCoordinates+DirectionVector[DOWN]*2+DirectionVector[LEFT]*(Place::NewGateIn-1);
		v=DirectionVector[RIGHT]*2;
		break;
	}
	for(i=0;i<Place::NewGateIn;i++,pos+=v)
	{
		SourceData gin;
		unsigned int j;
		for(j=0;j<node_data.size();j++)
		{
			if(node_data[j].position()==pos)
			{
				gin.SetNodeInIndex(j);
				in.push_back(gin);
				node_data[j].write_branch(Place::NewDirection,gate_in,gate.size(),i);
				break;
			}
		}
		if(j==node_data.size())
		{
			Node n;
			gin.SetNodeInIndex(node_data.size());
			in.push_back(gin);
			n.setposition(pos);
			n.write_branch(Place::NewDirection,gate_in,gate.size(),i);
			node_data.push_back(n);
		}
	}
	Gate g(Place::NewGateOperation,Place::NewDirection,Interface::AlignedMouseCoordinates,out,in);
	gate.push_back(g);
	for(i=0;i<in.size();i++)DetectErrorAndConnect(in[i].NodeInIndex());
	DetectErrorAndConnect(out);
}

bool Data::AbleToPlaceModule()
{
	for(unsigned int i=0;i<node_data.size();i++)
	{
		vector2D v;
		v=Interface::AlignedMouseCoordinates+DirectionVector[RIGHT]*(Place::NewModule.GetUpSize()-1)+DirectionVector[UP]*(Place::NewModule.InternalHalfHeight()+Place::NewModule.UpMargin()+1);
		for(int j=0;j<Place::NewModule.GetUpSize();j++,v+=DirectionVector[LEFT]*2)
				if(node_data[i].position()==v)if(node_data[i].isBranchExist(DOWN))return false;

		v=Interface::AlignedMouseCoordinates+DirectionVector[DOWN]*(Place::NewModule.GetRightSize()-1)+DirectionVector[RIGHT]*(Place::NewModule.InternalHalfWidth()+Place::NewModule.RightMargin()+1);
		for(int j=0;j<Place::NewModule.GetRightSize();j++,v+=DirectionVector[UP]*2)
				if(node_data[i].position()==v)if(node_data[i].isBranchExist(LEFT))return false;
	
		v=Interface::AlignedMouseCoordinates+DirectionVector[LEFT]*(Place::NewModule.GetDownSize()-1)+DirectionVector[DOWN]*(Place::NewModule.InternalHalfHeight()+Place::NewModule.DownMargin()+1);
		for(int j=0;j<Place::NewModule.GetDownSize();j++,v+=DirectionVector[RIGHT]*2)
				if(node_data[i].position()==v)if(node_data[i].isBranchExist(UP))return false;
	
		v=Interface::AlignedMouseCoordinates+DirectionVector[UP]*(Place::NewModule.GetLeftSize()-1)+DirectionVector[LEFT]*(Place::NewModule.InternalHalfWidth()+Place::NewModule.LeftMargin()+1);
		for(int j=0;j<Place::NewModule.GetLeftSize();j++,v+=DirectionVector[DOWN]*2)
				if(node_data[i].position()==v)if(node_data[i].isBranchExist(RIGHT))return false;
	}
	return true;
}

void Data::PlaceModule()
{
	int h;
	vector<int> out_nod(Place::NewModule.nOutput(),-1);//出力のノードのインデックスの配列
	SourceData tmp;
	tmp.SetNodeInIndex(-1),tmp.SourceDevice().SetDeviceClass(no_device),tmp.SourceDevice().SetIndexAndSubIndex(-1,-1);
	vector<SourceData> in_nod(Place::NewModule.nInput(),tmp);	//入力のノードのインデックスの配列
	vector2D v;

	Place::NewModule.SetCenter(Interface::AlignedMouseCoordinates);


	//上
	v=Place::NewModule.Center()+DirectionVector[RIGHT]*(Place::NewModule.GetUpSize()-1)+DirectionVector[UP]*(Place::NewModule.InternalHalfHeight()+Place::NewModule.UpMargin()+1);
	for(h=0;h<Place::NewModule.GetUpSize();h++,v+=DirectionVector[LEFT]*2)
	{
		switch(Place::NewModule.GetUp(h).GetDeviceClass())
		{
			unsigned int i;
		case module_out:
			for(i=0;i<node_data.size();i++)	//全ノード探索
			{
				if(node_data[i].position()==v) //出力と一致する位置のノードが見つかれば
				{
					out_nod[Place::NewModule.GetUp(h).GetDeviceIndex()]=i;
					node_data[i].write_branch(ReverseDirection(UP),module_out,module.size(),Place::NewModule.GetUp(h).GetDeviceIndex());
					break;
				}
			}
			if(i==node_data.size()) //出力と一致する位置のノードが見つからなければ
			{
				Node n;
				out_nod[Place::NewModule.GetUp(h).GetDeviceIndex()]=node_data.size();
				n.write_branch(ReverseDirection(UP),module_out,module.size(),Place::NewModule.GetUp(h).GetDeviceIndex());
				n.setposition(v);
				node_data.push_back(n);
			}
			break;
		case module_in:
			for(i=0;i<node_data.size();i++)
			{
				if(node_data[i].position()==v)
				{
					in_nod[Place::NewModule.GetUp(h).GetDeviceIndex()]=tmp;
					in_nod[Place::NewModule.GetUp(h).GetDeviceIndex()].SetNodeInIndex(i);
					node_data[i].write_branch(ReverseDirection(UP),module_in,module.size(),Place::NewModule.GetUp(h).GetDeviceIndex());
					break;
				}
			}
			if(i==node_data.size())
			{
				Node n;
				in_nod[Place::NewModule.GetUp(h).GetDeviceIndex()]=tmp;
				in_nod[Place::NewModule.GetUp(h).GetDeviceIndex()].SetNodeInIndex(node_data.size());
				n.setposition(v);
				n.write_branch(ReverseDirection(UP),module_in,module.size(),Place::NewModule.GetUp(h).GetDeviceIndex());
				node_data.push_back(n);
			}
			break;
		}
	}

	//右
	v=Place::NewModule.Center()+DirectionVector[DOWN]*(Place::NewModule.GetRightSize()-1)+DirectionVector[RIGHT]*(Place::NewModule.InternalHalfWidth()+Place::NewModule.RightMargin()+1);
	for(h=0;h<Place::NewModule.GetRightSize();h++,v+=DirectionVector[UP]*2)
	{
		switch(Place::NewModule.GetRight(h).GetDeviceClass())
		{
			unsigned int i;
		case module_out:
			for(i=0;i<node_data.size();i++)	//全ノード探索
			{
				if(node_data[i].position()==v) //出力と一致する位置のノードが見つかれば
				{
					out_nod[Place::NewModule.GetRight(h).GetDeviceIndex()]=i;
					node_data[i].write_branch(ReverseDirection(RIGHT),module_out,module.size(),Place::NewModule.GetRight(h).GetDeviceIndex());
					break;
				}
			}
			if(i==node_data.size()) //出力と一致する位置のノードが見つからなければ
			{
				Node n;
				out_nod[Place::NewModule.GetRight(h).GetDeviceIndex()]=node_data.size();
				n.write_branch(ReverseDirection(RIGHT),module_out,module.size(),Place::NewModule.GetRight(h).GetDeviceIndex());
				n.setposition(v);
				node_data.push_back(n);
			}
			break;
		case module_in:
			for(i=0;i<node_data.size();i++)
			{
				if(node_data[i].position()==v)
				{
					in_nod[Place::NewModule.GetRight(h).GetDeviceIndex()]=tmp;
					in_nod[Place::NewModule.GetRight(h).GetDeviceIndex()].SetNodeInIndex(i);
					node_data[i].write_branch(ReverseDirection(RIGHT),module_in,module.size(),Place::NewModule.GetRight(h).GetDeviceIndex());
					break;
				}
			}
			if(i==node_data.size())
			{
				Node n;
				in_nod[Place::NewModule.GetRight(h).GetDeviceIndex()]=tmp;
				in_nod[Place::NewModule.GetRight(h).GetDeviceIndex()].SetNodeInIndex(node_data.size());
				n.setposition(v);
				n.write_branch(ReverseDirection(RIGHT),module_in,module.size(),Place::NewModule.GetRight(h).GetDeviceIndex());
				node_data.push_back(n);
			}
			break;
		}
	}

	//下
	v=Place::NewModule.Center()+DirectionVector[LEFT]*(Place::NewModule.GetDownSize()-1)+DirectionVector[DOWN]*(Place::NewModule.InternalHalfHeight()+Place::NewModule.DownMargin()+1);
	for(h=0;h<Place::NewModule.GetDownSize();h++,v+=DirectionVector[RIGHT]*2)
	{
		switch(Place::NewModule.GetDown(h).GetDeviceClass())
		{
			unsigned int i;
		case module_out:
			for(i=0;i<node_data.size();i++)	//全ノード探索
			{
				if(node_data[i].position()==v) //出力と一致する位置のノードが見つかれば
				{
					out_nod[Place::NewModule.GetDown(h).GetDeviceIndex()]=i;
					node_data[i].write_branch(ReverseDirection(DOWN),module_out,module.size(),Place::NewModule.GetDown(h).GetDeviceIndex());
					break;
				}
			}
			if(i==node_data.size()) //出力と一致する位置のノードが見つからなければ
			{
				Node n;
				out_nod[Place::NewModule.GetDown(h).GetDeviceIndex()]=node_data.size();
				n.write_branch(ReverseDirection(DOWN),module_out,module.size(),Place::NewModule.GetDown(h).GetDeviceIndex());
				n.setposition(v);
				node_data.push_back(n);
			}
			break;
		case module_in:
			for(i=0;i<node_data.size();i++)
			{
				if(node_data[i].position()==v)
				{
					in_nod[Place::NewModule.GetDown(h).GetDeviceIndex()]=tmp;
					in_nod[Place::NewModule.GetDown(h).GetDeviceIndex()].SetNodeInIndex(i);
					node_data[i].write_branch(ReverseDirection(DOWN),module_in,module.size(),Place::NewModule.GetDown(h).GetDeviceIndex());
					break;
				}
			}
			if(i==node_data.size())
			{
				Node n;
				in_nod[Place::NewModule.GetDown(h).GetDeviceIndex()]=tmp;
				in_nod[Place::NewModule.GetDown(h).GetDeviceIndex()].SetNodeInIndex(node_data.size());
				n.setposition(v);
				n.write_branch(ReverseDirection(DOWN),module_in,module.size(),Place::NewModule.GetDown(h).GetDeviceIndex());
				node_data.push_back(n);
			}
			break;
		}
	}

	//左
	v=Place::NewModule.Center()+DirectionVector[UP]*(Place::NewModule.GetLeftSize()-1)+DirectionVector[LEFT]*(Place::NewModule.InternalHalfWidth()+Place::NewModule.LeftMargin()+1);
	for(h=0;h<Place::NewModule.GetLeftSize();h++,v+=DirectionVector[DOWN]*2)
	{
		switch(Place::NewModule.GetLeft(h).GetDeviceClass())
		{
			unsigned int i;
		case module_out:
			for(i=0;i<node_data.size();i++)	//全ノード探索
			{
				if(node_data[i].position()==v) //出力と一致する位置のノードが見つかれば
				{
					out_nod[Place::NewModule.GetLeft(h).GetDeviceIndex()]=i;
					node_data[i].write_branch(ReverseDirection(LEFT),module_out,module.size(),Place::NewModule.GetLeft(h).GetDeviceIndex());
					break;
				}
			}
			if(i==node_data.size()) //出力と一致する位置のノードが見つからなければ
			{
				Node n;
				out_nod[Place::NewModule.GetLeft(h).GetDeviceIndex()]=node_data.size();
				n.write_branch(ReverseDirection(LEFT),module_out,module.size(),Place::NewModule.GetLeft(h).GetDeviceIndex());
				n.setposition(v);
				node_data.push_back(n);
			}
			break;
		case module_in:
			for(i=0;i<node_data.size();i++)
			{
				if(node_data[i].position()==v)
				{
					in_nod[Place::NewModule.GetLeft(h).GetDeviceIndex()]=tmp;
					in_nod[Place::NewModule.GetLeft(h).GetDeviceIndex()].SetNodeInIndex(i);
					node_data[i].write_branch(ReverseDirection(LEFT),module_in,module.size(),Place::NewModule.GetLeft(h).GetDeviceIndex());
					break;
				}
			}
			if(i==node_data.size())
			{
				Node n;
				in_nod[Place::NewModule.GetLeft(h).GetDeviceIndex()]=tmp;
				in_nod[Place::NewModule.GetLeft(h).GetDeviceIndex()].SetNodeInIndex(node_data.size());
				n.setposition(v);
				n.write_branch(ReverseDirection(LEFT),module_in,module.size(),Place::NewModule.GetLeft(h).GetDeviceIndex());
				node_data.push_back(n);
			}
			break;
		}
	}
	Place::NewModule.LetNodeIn(in_nod);
	Place::NewModule.LetNodeOut(out_nod);
	module.push_back(Place::NewModule);

	for(unsigned int g=0;g<in_nod.size();g++)DetectErrorAndConnect(in_nod[g].NodeInIndex());
	for(unsigned int g=0;g<out_nod.size();g++)DetectErrorAndConnect(out_nod[g]);
}


bool Data::AbleToPlaceConductor()
{
	for(unsigned int i=0;i<node_data.size();i++)
	{
		if(node_data[i].position()==Interface::FirstAlignedMouseCoordinates)
			if(node_data[i].isBranchExist(AlignedDirection(Interface::FirstAlignedMouseCoordinates,Interface::AlignedMouseCoordinates)))return false;

		if(node_data[i].position()==AlignAngle(Interface::FirstAlignedMouseCoordinates,Interface::AlignedMouseCoordinates))
			if(node_data[i].isBranchExist(AlignedDirection(AlignAngle(Interface::FirstAlignedMouseCoordinates,Interface::AlignedMouseCoordinates),Interface::FirstAlignedMouseCoordinates)))return false;
	}
	return true;
}

void Data::PlaceConductor()
{
	Direction d;
	unsigned int i;
	int n0,n1;

	for(i=0;i<node_data.size();i++)
	{
		if(node_data[i].position()==Interface::FirstAlignedMouseCoordinates)
		{
			node_data[i].write_branch(AlignedDirection(Interface::FirstAlignedMouseCoordinates,Interface::AlignedMouseCoordinates),lead_wire,conductor.size(),0);
			break;
		}
	}
	if(i==node_data.size())
	{
		Node n;
		n.setposition(Interface::FirstAlignedMouseCoordinates);
		d=AlignedDirection(n.position(),Interface::AlignedMouseCoordinates);
		n.write_branch(d,lead_wire,conductor.size(),0);
		node_data.push_back(n);
	}
	n0=i;

	for(i=0;i<node_data.size();i++)
	{
		if(node_data[i].position()==AlignAngle(Interface::FirstAlignedMouseCoordinates,Interface::AlignedMouseCoordinates))
		{
			node_data[i].write_branch(AlignedDirection(AlignAngle(Interface::FirstAlignedMouseCoordinates,Interface::AlignedMouseCoordinates),Interface::FirstAlignedMouseCoordinates),lead_wire,conductor.size(),1);
			break;
		}
	}
	if(i==node_data.size())
	{
		Node n;
		n.setposition(AlignAngle(Interface::FirstAlignedMouseCoordinates,Interface::AlignedMouseCoordinates));
		d=AlignedDirection(n.position(),Interface::FirstAlignedMouseCoordinates);
		n.write_branch(d,lead_wire,conductor.size(),1);
		node_data.push_back(n);
	}
	n1=i;

	Conductor c(n0,n1,AlignedDirection(GetNodeCoordinate(n0),GetNodeCoordinate(n1)));
	conductor.push_back(c);

	DetectErrorAndConnect(c.nodeindex0());
}