#include <memory>
#include <log.h>
#include <zloop.h>
#include "select_tool.h"
#include "loc_tool.h"

#include <area.h>
#include <site_area.h>

#include <card.h>
#include "config_file.h"
#include "db_api/CDBConnPool.h"
#include "websocket/wsTimerThread.h"

extern config_file config;
//一张卡一个ct的所有不同天线的信息
struct one_ct_message_handle
{
	static loc_tool_main m_loc_tool;
	ev::timer m_min_timer,m_max_timer;
    //loc_message.
	std::vector<loc_message> m_msg_list;
	card_location_base*m_card;
	const algo_config*m_ac=nullptr;
	int  m_ct;
	bool m_min_timeout=false;
    ev::dynamic_loop * m_loop = nullptr;
	one_ct_message_handle(card_location_base*card)
	{
		m_card=card;
		m_ct=-1;
	}

	void reset()
	{
		m_ct=-1;
		m_min_timeout=false;
		m_msg_list.clear();
	}

	void on_min_timer()
	{
		m_min_timer.stop();

		if((int)m_msg_list.size()>=m_ac->best_msg_cnt)
		{
			m_max_timer.stop();
			calc_location();
            return;
		}
		m_min_timeout=true;
	}

	void on_max_timer()
	{
		m_max_timer.stop();
		calc_location();
	}
    void set(ev::dynamic_loop * loop)
    {
        m_loop = loop;

        m_min_timer.set(*m_loop);
	    m_min_timer.set<one_ct_message_handle,&one_ct_message_handle::on_min_timer>(this);
	    m_max_timer.set(*m_loop);
	    m_max_timer.set<one_ct_message_handle,&one_ct_message_handle::on_max_timer>(this);
    }
	void on_message(ev::dynamic_loop *loop,const message_locinfo&loc)
	{
        if(m_loop == nullptr && loop!=nullptr)
            set(loop);
        else if(loop == nullptr)
          return;
   		if(!m_msg_list.empty()&& m_ct!=loc.m_card_ct)
		{
			m_msg_list.clear();
		}
		auto sitPtr = sit_list::instance()->get(loc.m_site_id);
		if(sitPtr==nullptr)
		  return;
		const site &s=*(sit_list::instance()->get(loc.m_site_id));
		if(m_msg_list.empty())
		{
			m_ct=loc.m_card_ct;
			m_ac=&s.config();
			m_min_timeout=false;
            //这里构造loc_message 保存数据
			m_msg_list.push_back(loc_message(s,loc.m_tof,loc.m_time_stamp,loc.m_card_id,
							loc.m_card_ct,loc.m_card_type,loc.m_ant_id,loc.m_rav,loc.m_acc,
							loc.m_sync_ct,loc.m_rssi));

			//启动本CT的最小、最大两个定时器
			m_min_timer.start(m_ac->min_wait_time);
			m_max_timer.start(m_ac->min_wait_time);
			return;
		}

		m_msg_list.push_back(loc_message(s,loc.m_tof,loc.m_time_stamp,loc.m_card_id,
						loc.m_card_ct,loc.m_card_type,loc.m_ant_id,loc.m_rav,loc.m_acc,
						loc.m_sync_ct,loc.m_rssi));

		if(m_min_timeout && (int)m_msg_list.size()>=m_ac->best_msg_cnt)
		{
			calc_location();
			m_max_timer.stop();
		}
	}

    void calc_location()
	{
        auto v = m_msg_list;

		std::vector<point> rc=std::move(m_loc_tool.calc_location(v));
        
		if(!rc.empty()) m_card->on_location(std::move(rc),v);

		reset();
	}
};
struct card_message_handle
{
	card_location_base*m_card;
	std::array<one_ct_message_handle*,16> m_ct_list;

	card_message_handle(card_location_base*card)
	{
		m_card=card;

		for(size_t i=0;i<m_ct_list.size();i++)
		{
			m_ct_list[i]=new one_ct_message_handle(card);
		}
	}

	~card_message_handle()
	{
		for(auto&it:m_ct_list)
		{
			delete it;
		}
	}

	void on_message(zloop<task*> * loop,const message_locinfo&loc,bool is_history)
	{
		if(is_history)
		{
			log_warn("%s","当前代码没有处理历史消息记录。");
			return;
		}

        if(loc.m_batty_status == 2) 
        {
            m_card->do_status(STA_TYPE::STATUS_LOW_POWER);
        }
        else if(loc.m_callinfo == 0x80)
        {
            m_card->do_status(STA_TYPE::STATUS_HELP);
        }

		m_ct_list[loc.m_card_ct&(m_ct_list.size()-1)]->on_message(loop,loc);
	}
};

struct card_area
{
	std::shared_ptr<site_area_hover> m_site_area;
	std::shared_ptr<area_tool> m_area_tool;
};

struct person:card_location_base,card_area
{
	person(std::string type,uint32_t cardid,uint16_t needdisplay,int16_t t)
        :card_location_base(type,cardid,needdisplay,t)
	{
        m_message_handle=new  card_message_handle(this);
	}
	~person(){}
};

struct car:card_location_base,card_area
{
	car(std::string type,uint32_t cardid,uint16_t needdisplay,int16_t t)
        :card_location_base(type,cardid,needdisplay,t)
    {
        m_message_handle=new  card_message_handle(this);
    }
	~car(){}
};

loc_tool_main one_ct_message_handle::m_loc_tool;

uint64_t card_list::getId(uint32_t cardid,uint64_t type)
{
	return type<<32|cardid;
}
void card_list::init_vehicle()
{
	std::unordered_map<uint64_t,std::shared_ptr<card_location_base>> map;
	std::string strategy = config.get("person.strategy","car1");
	const char *sql = "SELECT ve.vehicle_id, ve.card_id, c.card_type_id, \
						ve.dept_id, ve.group_id, v.vehicle_type_id, vt.vehicle_level_id, \
						vt.is_railroad AS vt_is_railroad,ve.need_display ,ve.power_alarm,\
						vt.vehicle_category_id,v.bigger_car_flag,vc.over_speed \
						FROM dat_vehicle_extend ve \
						LEFT JOIN dat_vehicle v ON ve.vehicle_id = v.vehicle_id \
						LEFT JOIN dat_card c ON ve.card_id = c.card_id \
						LEFT JOIN dat_dept d ON ve.dept_id = d.dept_id \
						LEFT JOIN dat_group g ON ve.group_id = g.group_id \
						LEFT JOIN dat_vehicle_type vt ON v.vehicle_type_id = vt.vehicle_type_id \
						LEFT JOIN dat_vehicle_category vc ON vc.vehicle_category_id = vt.vehicle_category_id \
						WHERE c.card_type_id = 2 AND c.state_id = 0;";
	std::string Error;
	YADB::CDBHelper DBHelper;
	YADB::CDBResultSet DBRes;
	sDBConnPool.Query(sql,DBRes,Error);
	int nCount = DBRes.GetRecordCount( Error );
	if (nCount > 0)
	{
		log_info( "init_staffer. The record count=%d\n", nCount );

		while ( DBRes.GetNextRecod(Error) )
		{
			unsigned int vehicle_id  = 0;
			DBRes.GetField( "vehicle_id",vehicle_id, Error );
			
			unsigned int card_type_id  = 0;
			DBRes.GetField( "card_type_id",card_type_id, Error );

			int dept_id = 0;
			DBRes.GetField( "dept_id",dept_id, Error );

			int group_id = 0;
			DBRes.GetField( "group_id",group_id, Error );

			int vehicle_type_id = 0;
			DBRes.GetField( "vehicle_type_id",vehicle_type_id, Error );

			int vehicle_level_id = 0;
			DBRes.GetField( "vehicle_level_id",vehicle_level_id, Error );

			int need_display = 0;
			DBRes.GetField( "need_display",need_display, Error );

			int power_alarm = 0;
			DBRes.GetField( "power_alarm",power_alarm, Error );

			int vehicle_category_id = 0;
			DBRes.GetField( "vehicle_category_id",vehicle_category_id, Error );

			int bigger_car_flag= 0;
			DBRes.GetField( "bigger_car_flag",bigger_car_flag, Error );

			double over_speed= 0;
			DBRes.GetField( "over_speed",over_speed, Error );


			std::shared_ptr<card_location_base> clb = std::make_shared<car>(strategy,vehicle_id,need_display,card_type_id);
			uint64_t cardid = getId(vehicle_id,2);
			log_info("cardId:%llu,vehicle_id:%d dept_id:%d,need_display:%d",cardid,vehicle_id,dept_id,need_display);
			map.insert({cardid,clb});
		}
	}
	
	card_list::instance()->add(map);
}

void card_list::init_staffer()
{
	std::unordered_map<uint64_t,std::shared_ptr<card_location_base>> map;
	std::string strategy = config.get("person.strategy","person1");
	const char *sql = "SELECT staff_id, s.card_id, c.card_type_id, s.dept_id, s.group_id, s.occupation_id, \
						ol.occupation_level_id,s.worktype_id,s.need_display \
						FROM dat_staff_extend s \
						LEFT JOIN dat_card c ON s.card_id = c.card_id \
						LEFT JOIN dat_occupation o ON s.occupation_id = o.occupation_id \
						LEFT JOIN dat_occupation_level ol ON ol.occupation_level_id = o.occupation_level_id \
						WHERE c.card_type_id = 1 AND s.duty_id = 0 AND c.state_id = 0;";
	std::string Error;
	YADB::CDBHelper DBHelper;
	YADB::CDBResultSet DBRes;
	sDBConnPool.Query(sql,DBRes,Error);
	int nCount = DBRes.GetRecordCount( Error );
	if (nCount > 0)
	{
		log_info( "init_staffer. The record count=%d\n", nCount );

		while ( DBRes.GetNextRecod(Error) )
		{
			unsigned int staff_id  = 0;
			DBRes.GetField( "staff_id",staff_id, Error );

			unsigned int card_type_id  = 0;
			DBRes.GetField( "card_type_id",card_type_id, Error );
			
			int dept_id = 0;
			DBRes.GetField( "dept_id",dept_id, Error );

			int group_id = 0;
			DBRes.GetField( "group_id",group_id, Error );

			int occupation_id = 0;
			DBRes.GetField( "occupation_id",occupation_id, Error );

			int occupation_level_id = 0;
			DBRes.GetField( "occupation_level_id",occupation_level_id, Error );

			int need_display = 0;
			DBRes.GetField( "need_display",need_display, Error );


			std::shared_ptr<card_location_base> clb = std::make_shared<person>(strategy,staff_id,need_display,card_type_id);
			uint64_t cardid = getId(staff_id,1);
			log_info("cardId:%llu,staff_id:%d dept_id:%d,need_display:%d",cardid,staff_id,dept_id,need_display);
			map.insert({cardid,clb});
		}
	}
	
	card_list::instance()->add(map);
}

void card_list::init_card_from_db()
{
	init_staffer();	
	init_vehicle();
}

void card_list::on_message(zloop<task*> *loop,const message_locinfo&loc,bool is_history)
{
	//std::shared_ptr<card_location_base>c=get(loc.m_card_id);
	uint64_t cardid = getId(loc.m_card_id,loc.m_card_type);
	const auto c=get(cardid);
	if(c==nullptr)
	{
		log_warn("数据库中未定义该卡的信息，card_id=%d", loc.m_card_id);
		return;
	}
	log_info("card message:site=%d,ant=%d,card=%d,tof=%lld,rav=%02X,acc=%02X,rssi=%d,stamp=%llu",
			loc.m_site_id,loc.m_ant_id,loc.m_card_id,loc.m_tof,loc.m_rav,loc.m_acc,loc.m_rssi,loc.m_time_stamp);

	c->on_message(loop,loc,is_history);
}
//-----------------card_location_base..
card_location_base::card_location_base(std::string type,uint32_t id,uint16_t dis,int16_t t)
	:card(id,dis,t)
{
    select_tool_manage::instance()->create_tool(type,m_sel_tool,m_smo_tool);
}
void card_location_base::on_location(const std::vector<point>&vp,const std::vector<loc_message> &lm )
{
    loc_point pt = m_sel_tool->select_solution(vp,lm);
	if(pt.m_useless)
		log_info("loc_point,x:%.2f,y:%.2f",pt.x,pt.y);

}

void card_location_base::on_message(zloop<task*> * loop,const message_locinfo&loc,bool is_history)
{
	if(m_loop == nullptr && loop != nullptr)
		set(loop);
	m_message_handle->on_message(loop,loc,is_history);
}

void card_location_base::set(ev::dynamic_loop * loop)
{
    m_loop = loop;

    m_timer.set(*m_loop);
    m_timer.set<card_location_base,&card_location_base::on_timer>(this);
	m_timer.start(1,1);
}

void card_location_base::on_timer()
{
	//push_point..
    loc_point lp = m_smo_tool->smooth_strategy();
	m_speed = lp.m_speed;
	m_stat  = lp.m_stat;

	YA::_CARD_POS_ cp;
	cp.x = x;
	cp.y = y;
	cp.z = z;
	cp.Type=m_type;
	cp.ID = m_id;
	cp.speed = m_speed;
	cp.stat = m_stat;

	swsTimerThrd.upt_card_pos(cp);
	//log_info("one seconds............later..............");
}


card_location_base::~card_location_base()
{
	if(m_message_handle == nullptr)
	  delete m_message_handle;
}
template<> std::shared_ptr<card_list> 
single_base<card_list, uint64_t, std::shared_ptr<card_location_base>>::m_instance=std::make_shared<card_list>();

