
#ifndef _ANT_LIST_HPP_
#define _ANT_LIST_HPP_

#include <math.h>
#include <array>
#include <deque>
#include <tuple>
#include <memory>
#include <algorithm>
#include "line.h"
#include <iostream>
#include "point.h"

NAMESPACE_POINT_BEGIN(NAMESPACE_POINT)

struct ant:point
{
	std::array<std::array<point,6>,2> m_path;//映射的天线坐标、路径坐标、夹角

	std::array<point,6>&operator[](int i)
	{
		return m_path[i];
	}

	const std::array<point,6>&operator[](int i)const
	{
		return m_path[i];
	}
};

struct site:point
{
	site(int id=-1);

	mutable double m_height;
	int m_id;
	bool m_path_empty;
	std::array<ant,2> m_ant;
	std::array<line_v,2> m_line;

	mutable double m_ant_dist;
	mutable double m_ant_dist_sum_new;
	mutable int m_ant_dist_cnt_new;
	double m_scale;
	void count_ant_dist(double dist_tof1, double dist_tof2)const
	{
		if(dist_tof1<10 || dist_tof2<10)
			return;
		double dist = fabs(dist_tof1 - dist_tof2);
		if(dist>5)
			return;
		m_ant_dist_sum_new += dist;
		m_ant_dist_cnt_new++;
		
		if(m_ant_dist_cnt_new >= 2500)
		{
			m_ant_dist = m_ant_dist_sum_new / m_ant_dist_cnt_new;
			m_ant_dist_sum_new = 0;
			m_ant_dist_cnt_new = 0;
		}
	}
/*	mutable double m_test_dist=0;
	mutable int m_test_cnt=0;
	void test_dist(double d)const
	{
		if(fabs(m_ant_dist)<0.001)return;
		if(d>10)return;
		m_test_dist+=d;
		m_test_cnt++;
	}*/


/*
	const point&operator[](int ant_id)const
	{
		return m_ant[ant_id];
	}
	*/

	double ant_dist()const
	{
		return m_ant[0].dist(m_ant[1]);
	}

	void mapping(const point &p,point &tmp) const
	{
		point rp;
		double d,dmin=1e4;
		for(auto&line:m_line)
		{
			if(line.empty())
				continue;
			rp=line.line::projection(p);
			d=p.dist(rp);
			if(d<dmin)
			{
				dmin=d;
				tmp=rp;
			}
		}

		if(dmin>5) tmp.set(0,0);
	}
	
	void sort_path();
	bool is_path_empty()const
	{
		return m_path_empty;
	}

	bool have_valid_path()const
	{
		return m_id!=-1 && m_ant[0].dist(m_ant[1])>0.1 && (dist(path(0))>1 || dist(path(1))>1);
	}

	std::string to_string()const
	{
		char buf[128];

		int len=sprintf(buf,"id=%d, ant=[(%.2f,%.2f),(%.2f,%.2f)],path=[(%.2f,%.2f),(%.2f,%.2f)],%d"
			,m_id
			,m_ant[0].x,m_ant[0].y
			,m_ant[1].x,m_ant[1].y
			,m_ant[0].m_path[0][1].x,m_ant[0].m_path[0][1].y
			,m_ant[0].m_path[1][1].x,m_ant[0].m_path[1][1].y
			,check_k()
		);

		return std::move(std::string(buf,len));
	}

	const point&path(int i)const
	{
		return m_ant[0].m_path[i][1];
	}

	bool check_k()const
	{
		if(is_path_empty())
			return false;

		return eq(path(0).cos_k(*this),cos_k(path(1)),0.1);
	}

	//Cannot handle a non straight line.
	point  intersection(const site&o)const
	{
		//The cover area is not a straight line, giving up
		if(!check_k() || !o.check_k())
			return point();
		//The same slope, directly back to the empty
		if(eq(cos_k(path(0)),o.cos_k(o.path(0)),0.0001))
			return point();

		auto abc1=  get_abc(path(0));
		auto abc2=o.get_abc(o.path(0));

		point pt(
				  (std::get<2>(abc1)*std::get<1>(abc2)-std::get<2>(abc2)*std::get<1>(abc1))
				 /(std::get<0>(abc2)*std::get<1>(abc1)-std::get<0>(abc1)*std::get<1>(abc2)) ,

				  (std::get<2>(abc1)*std::get<0>(abc2)-std::get<2>(abc2)*std::get<0>(abc1))
				 /(std::get<1>(abc2)*std::get<0>(abc1)-std::get<1>(abc1)*std::get<0>(abc2)) 
				);

//		printf("cp=(%lf,%lf)\n",pt.x,pt.y);

		return pt;
	}

	double dist_to_site(const site&o)const
	{
		point pt=intersection(o);
		return dist(pt)+pt.dist(o);
	}
	double  getSolPoint(const ant&a,int path,double dist) const
	{
		double real_dist = 0;
		double last_d = 0;
		double next_d = dist;
		std::for_each(a[path].begin()+3,a[path].end(),[&next_d,&dist,&real_dist,&last_d](const point & p){
			if(!p.empty() && next_d)
			{
				double dis = p.x-last_d;
				last_d = p.x;
				if(dist > p.x)
				{
					real_dist += dis*dis/(dis+p.y);
					next_d = dist-p.x;
				}
				else
				{
					real_dist += next_d*dis/(dis+p.y);
					next_d = 0;
				}
			}
			else if(next_d != dist && next_d)
			{
				real_dist += next_d;
				next_d = 0;
			}
		});
		return !real_dist?dist:real_dist;
	}

	void solving(point**o, int ant_id, double dist)const
	{
		point*r=*o;
		const ant&a=m_ant[ant_id];
		if(dist<50 && dist>0)
		{
			if(dist<m_height)
			{
				m_height=dist;
				dist=0;				
			}
			else
			{
				dist=sqrt(dist*dist-m_height*m_height);
			}
		}

		double rd1 = getSolPoint(a,0,dist);
		point p1=point(a[0][0].x+rd1*a[0][2].x, a[0][0].y+rd1*a[0][2].y);
		double rd2 = getSolPoint(a,1,dist);
		point p2=point(a[1][0].x+rd2*a[1][2].x, a[1][0].y+rd2*a[1][2].y);
		if(fabs(m_ant_dist)>0.001)
		{
			double delta = (m_ant_dist - ant_dist())/2;
			
			if(p1.dist(*this)>p2.dist(*this))
			{
				rd1+=delta;
				rd2-=delta;
			}
			else
			{
				rd1-=delta;
				rd2+=delta;
			}
			point tmp1=point(a[0][0].x+rd1*a[0][2].x, a[0][0].y+rd1*a[0][2].y);
			point tmp2=point(a[1][0].x+rd2*a[1][2].x, a[1][0].y+rd2*a[1][2].y);
			point mapped1,mapped2;
			mapping(tmp1,mapped1);
			mapping(tmp2,mapped2);
			*r++=mapped1;
			*r++=mapped2;
		}
		else
		{
			point mapped1,mapped2;
			mapping(p1,mapped1);
			mapping(p2,mapped2);
			*r++=mapped1;
			*r++=mapped2;
		}

		*o=r;
	}
};

struct sit_list
{
	std::array<site,2000> m_list;
public:
	sit_list();

	void load(const char*ant_file,const char*path_file)
	{
		read_sit_list(ant_file);
		read_ant_path(path_file);
	}

	std::string to_string()const
	{
		std::string rt;
		rt.reserve(4096);
		for(auto s:m_list)
		{
			if(s.m_id==-1)
				continue;

			rt+=s.to_string();
			rt+="\n";
		}

		return std::move(rt);
	}

	void read_sit_list(const char*fname);
	void read_ant_path(const char*fname);
	void init_sit_list(int32_t readerid,int32_t antid, double ax, double ay,double scale);
	void init_sit_list();
	void init_ant_path(int32_t readerid,int32_t antid, double ax, double ay,std::vector<std::string>::iterator &b,std::vector<std::string>::iterator& e);
	void init_ant_path();
	const site& operator[](int id) const;
};

NAMESPACE_POINT_END(NAMESPACE_POINT)
#endif

