#include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier
#include "BasicEdge.h"

BasicEdge basicEdge;

// 预处理分支点和卡箍之间的连线关系
void BasicEdge::buildEdgeBetweenClipAndBranchPoint()
{
	for (int i = 1; i <= 3000; i++)
	{
		for (int j = 0; j <= 1; j++)
		{
			assert(edge[i][j].size() == 0);
		}
	}
	for (int i = 1; i <= basicChannel.bundleNum; i++)
	{
		BundleNode *pbn = basicChannel.bundles[i].head;
		BundleNode *pre = NULL;
		while (pbn != NULL)
		{
			if (pre != NULL)
			{
				int cid1 = pre->pc->id;
				int cid2 = pbn->pc->id;
				int inOut1 = pre->inOut;
				int inOut2 = pbn->inOut;
				assert(cid1 != cid2);
				pair<int, int> pr = make_pair(cid2, inOut2);
				assert(pr.first == cid2);
				if (inOut1 != 0 && inOut1 != 1)
				{
					cout << "clip " << cid1 << "  inOut=" << inOut1 << endl;
				}
				if (inOut2 != 0 && inOut2 != 1)
				{
					cout << "clip " << cid2 << "  inOut=" << inOut2 << endl;
				}
				assert(inOut1 == 0 || inOut1 == 1);
				assert(inOut2 == 0 || inOut2 == 1);
				edge[cid1][inOut1].push_back(pr);
				pr = make_pair(cid1, inOut1 ^ 1);
				assert(pr.first == cid1);
				edge[cid2][inOut2 ^ 1].push_back(pr);
			}
			pre = pbn;
			pbn = pbn->next;
		}
		// cout<<i<<"  "<<edge[94][1].size()<<endl;
	}
	for (int i = 1; i <= 3000; i++)
	{
		for (int j = 0; j <= 1; j++)
		{
			for (int k = 0; k < edge[i][j].size(); k++)
			{
				if (edge[i][j][k].first == i)
					cout << i << "  " << j << "  " << k << endl;
				assert(edge[i][j][k].first != i);
			}
		}
	}
	for (int i = 1; i <= branchPointSet.branchPointNum; i++)
	{
		BranchPoint *pb = &branchPointSet.b[i];
		int cid1 = pb->pc1->id;
		int inOut1 = basicChannel.getClipInOut(cid1) ^ 1;
		int cid2 = pb->pc2->id;
		int inOut2 = basicChannel.getClipInOut(cid2);
		int inOut3 = basicChannel.isClipConnectedToClip(cid1, cid2);
		assert(inOut3 == inOut2);
		clip[i][0].push_back(make_pair(cid1, inOut1));
		clip[i][0].push_back(make_pair(cid2, inOut2));
		branchPoint[cid1][inOut1 ^ 1].push_back(make_pair(i, 1));
		branchPoint[cid2][inOut2 ^ 1].push_back(make_pair(i, 1));
		vector<int> vec = kdtree.search_by_dis(branchPointSet.b[i].coord, 600);
		for (int j = 0; j < vec.size(); j++)
		{
			int cid = vec[j];
			if (!bvh.iscollect(clipSet.c[cid].coord, branchPointSet.b[i].coord))
			{
				clip[i][1].push_back(make_pair(cid, 0)); // 这里相当于只存储卡箍,不存储进出信息,因为会变
				int clipType = basicChannel.clipType(cid);
				if (clipType == 0)
				{
					branchPoint[cid][0].push_back(make_pair(i, 0));
					branchPoint[cid][1].push_back(make_pair(i, 0));
				}
				else if (clipType == 1)
				{
					int inDir = basicChannel.getEXTClipInDir(cid);
					branchPoint[cid][inDir ^ 1].push_back(make_pair(i, 0));
				}
			}
		}
	}
}

// 返回卡箍能连接到的卡箍,如果没有能连接到的,返回只含有0的数组
vector<pair<int, int>> BasicEdge::getClipConnectedToClip(int cid, int inOut)
{
	if (edge[cid][inOut].size() != 0)
	{
		if (edge[cid][inOut][0].first == 0)
			return edge[cid][inOut];
		vector<pair<int, int>> res;
		for (int i = 0; i < edge[cid][inOut].size(); i++)
		{
			int v = edge[cid][inOut][i].first;
			assert(v != cid);
			int inOut2 = edge[cid][inOut][i].second;
			int clipType = basicChannel.clipType(v);
			if (clipType == 2)
			{
				int dir = basicChannel.isClipConnectedToClip(cid, v);
				if (dir != inOut2)
					continue;
				// 去除中间卡箍
			}
			res.push_back(make_pair(v, inOut2));
		}
		return res;
	}
	// 只有不在通道里的卡箍方向需要被处理,通道内卡箍应该提前处理好
	vector<int> vec1 = kdtree.search_by_dis(clipSet.c[cid].coord, 600);
	for (int i = 0; i < vec1.size(); i++)
	{
		int v = vec1[i];
		if (v == cid)
			continue;
		int clipType = basicChannel.clipType(v);
		if (clipType != 2 &&
			!bvh.iscollect(clipSet.c[cid].coord, clipSet.c[v].coord))
		{
			if (clipType == 0)
			{
				edge[cid][inOut].push_back(make_pair(v, 0));
				edge[cid][inOut].push_back(make_pair(v, 1));
			}
			else
			{
				int inDir = basicChannel.getEXTClipInDir(v);
				edge[cid][inOut].push_back(make_pair(v, inDir));
			}
		}
	}
	if (edge[cid][inOut].size() == 0)
		edge[cid][inOut].push_back(make_pair(0, 0));
	return edge[cid][inOut];
}

/*根据分支点返回卡箍
	mode=0为模式A,否则为模式B
	其中模式B需要过滤掉通道中的卡箍
*/
vector<pair<int, int>> BasicEdge::getClipConnectedToBranchPoint(int bid, int mode)
{
	if (mode == 0)
		return clip[bid][0];
	else
	{
		vector<pair<int, int>> v;
		for (int i = 0; i < clip[bid][1].size(); i++)
		{
			int cid = clip[bid][1][i].first;
			int clipType = basicChannel.clipType(cid);
			if (clipType == 0)
			{
				v.push_back(make_pair(cid, 0));
				v.push_back(make_pair(cid, 1));
			}
			else if (clipType == 1)
			{
				v.push_back(make_pair(cid, basicChannel.getEXTClipInDir(cid)));
			}
			else if (clipType == 2)
			{
				int dir = basicChannel.isBranchPointConnectedToClip(bid, cid);
				if (dir != -1)
					v.push_back(make_pair(cid, dir));
			}
		}
		return v;
	}
}

/*根据卡箍返回分支点,卡箍与分支点在同一个Bundle上
	卡箍分为3种,断头/通道中的点/孤立点
	其中通道中的点只能采用模式A
	孤立点只能采用模式B
	断头可以根据inOut来判断采用哪种模式
	offset代表偏移量,用来将分支点标号对应到Astar中点的标号
*/
vector<pair<int, int>> BasicEdge::getBranchPointConnectedToClip(int cid, int inOut, int offset)
{
	vector<pair<int, int>> v;
	for (int i = 0; i < branchPoint[cid][inOut].size(); i++)
	{
		int bid = branchPoint[cid][inOut][i].first;
		int mode = branchPoint[cid][inOut][i].second;
		v.push_back(make_pair(bid + offset, mode));
	}
	return v;
}

// 返回Astar中编号为id的点能建立边的下个点
vector<pair<int, int>> BasicEdge::getNextPoint(int id, int mode, int offset)
{
	int cid, bid;
	vector<pair<int, int>> v1, v2;
	if (id <= offset)
	{
		cid = id;
		v1 = this->getBranchPointConnectedToClip(cid, mode, offset);
		v2 = this->getClipConnectedToClip(cid, mode);
		if (v2.size() && v2[0].first != 0)
			v1.insert(v1.begin(), v2.begin(), v2.end());
		return v1;
	}
	else
	{
		bid = id - offset;
		v1 = this->getClipConnectedToBranchPoint(bid, mode);
		return v1;
	}
}

/*返回端点可以连接到的点
	p是端点坐标
	offSet是分支点坐标的偏移量
	isEnd=1表示这个端点是路径终点,否则是路径起点
*/
vector<pair<int, int>> BasicEdge::getEXTNextPoint(P p, int offSet, int isEnd)
{
	vector<pair<int, int>> res;
	vector<int> vec1 = kdtree.search_by_dis(p, 600);
	vec1 = basicChannel.getBranchPointAndClip(vec1, offSet);
	for (int i = 0; i < vec1.size(); i++)
	{
		int v = vec1[i];
		if (v <= offSet)
		{
			int clipType = basicChannel.clipType(v);
			if (clipType == 0)
			{
				res.push_back(make_pair(v, 0));
				res.push_back(make_pair(v, 1));
			}
			if (clipType == 1)
			{
				int inDir = basicChannel.getEXTClipInDir(v);
				res.push_back(make_pair(v, inDir ^ isEnd));
			}
		}
		else
		{
			if (isEnd)
				res.push_back(make_pair(v, 1));
			else
				res.push_back(make_pair(v, 0));
		}
	}
	return res;
}

// 根据新的路径更新边信息
void BasicEdge::addPath(Path path)
{
	for (int i = 0; i < path.size(); i++)
	{
		P &p = path.points[i];
		BundleNode *pbn; // 当前通道节点
		if (p.type == 0)
		{ // 卡箍
			int cid = p.ref;
			pbn = basicChannel.getClipBundleNodePointer(cid);
			int clipType = basicChannel.clipType(cid);
			assert(clipType == 2);
			int inOut = basicChannel.getClipInOut(cid);
			// 更新edge卡箍到卡箍的边
			edge[cid][inOut].clear();
			if (pbn->next->type == 0)
			{
				int cid2 = pbn->next->pc->id;
				int inOut2 = basicChannel.getClipInOut(cid2);
				edge[cid][inOut].push_back(make_pair(cid2, inOut2));
			}
			else
				edge[cid][inOut].push_back(make_pair(0, 0));
			edge[cid][inOut ^ 1].clear();
			if (pbn->pre->type == 0)
			{
				int cid2 = pbn->pre->pc->id;
				int inOut2 = basicChannel.getClipInOut(cid2);
				edge[cid][inOut ^ 1].push_back(make_pair(cid2, inOut2 ^ 1));
			}
			else
				edge[cid][inOut ^ 1].push_back(make_pair(0, 0));
			// 更新branch卡箍到分支点的边
			if (branchPoint[cid][0].size() != 0 && branchPoint[cid][0][0].second == 0)
			{ // 原本不在通道里
				int vv = 0;
				for (int i = 0; i < branchPoint[cid][0].size(); i++)
				{
					int v = branchPoint[cid][0][i].first;
					if (basicChannel.isBranchPointConnectedToClip(v, cid) == 1)
					{
						vv = v;
						break;
					}
				}
				branchPoint[cid][0].clear();
				if (vv != 0)
					branchPoint[cid][0].push_back(make_pair(vv, 0));
			}
			if (branchPoint[cid][1].size() != 0 && branchPoint[cid][1][0].second == 0)
			{
				int vv = 0;
				for (int i = 0; i < branchPoint[cid][1].size(); i++)
				{
					int v = branchPoint[cid][1][i].first;
					if (basicChannel.isBranchPointConnectedToClip(v, cid) == 0)
					{
						vv = v;
						break;
					}
				}
				branchPoint[cid][1].clear();
				if (vv != 0)
					branchPoint[cid][1].push_back(make_pair(vv, 0));
			}
			// 排除异分支模式
		}
		// 分支点不需要更新
	}
	return;
}