#include "jsonBuilder.h"
#include <cstdlib>

#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/prettywriter.h>
#include "constdef.h"

namespace YA
{
	jsonBuilder::jsonBuilder()
	{

	}

	jsonBuilder::~jsonBuilder()
	{

	}

	std::string jsonBuilder::__FmtCardID( const _BASE_CARD_ & CardPos )
	{
		char szID[32] = { 0 };

		sprintf( szID, "%03d%.10d", CardPos.Type, CardPos.ID );

		return szID;
	}

	void jsonBuilder::__AddVersion( rapidjson::Value& root, rapidjson::Document::AllocatorType& Allocator )
	{
		rapidjson::Value value( rapidjson::kStringType );

		value.SetString( INTERFACE_VERSION_1_4, Allocator );
		root.AddMember( JSON_ROOT_KEY_VERSION, value, Allocator );
	}

	void jsonBuilder::__SetCmd( const char* szCmd, rapidjson::Value & root, rapidjson::Document::AllocatorType & Allocator )
	{
		rapidjson::Value value( rapidjson::kStringType );

		value.SetString( szCmd, Allocator );
		root.AddMember( JSON_ROOT_KEY_CMD, value, Allocator );
	}

	bool jsonBuilder::__BuildDetail( const _CARD_POS_ & CardPos, rapidjson::Document::AllocatorType& Allocator, rapidjson::Value & DetailItem )
	{
		rapidjson::Value Array( rapidjson::kArrayType );
		rapidjson::Value tmp_object( rapidjson::kObjectType );

		//0 ID
		tmp_object.SetString( __FmtCardID( CardPos ).c_str(), Allocator );
		Array.PushBack( tmp_object, Allocator );

		//1 x
		tmp_object.SetDouble( CardPos.x );
		Array.PushBack( tmp_object, Allocator );

		//2 y
		tmp_object.SetDouble( CardPos.y );
		Array.PushBack( tmp_object, Allocator );

		//3 入井时间戳
		tmp_object.SetDouble( CardPos.down_time );
		Array.PushBack( tmp_object, Allocator );

		//4 进入区域时间戳
		tmp_object.SetDouble( CardPos.enter_area_time );
		Array.PushBack( tmp_object, Allocator );

		//5 最后接收时间戳
		tmp_object.SetDouble( CardPos.rec_time );
		Array.PushBack( tmp_object, Allocator );

		//6 工作时长
		tmp_object.SetDouble( CardPos.work_time );
		Array.PushBack( tmp_object, Allocator );

		//7 地图编号
		tmp_object.SetInt( CardPos.map_id );
		Array.PushBack( tmp_object, Allocator );

		//8 区域编号
		tmp_object.SetInt( CardPos.area_id );
		Array.PushBack( tmp_object, Allocator );

		//9 部门编号
		tmp_object.SetInt( CardPos.dept_id );
		Array.PushBack( tmp_object, Allocator );

		//10 状态
		tmp_object.SetInt( CardPos.stat );
		Array.PushBack( tmp_object, Allocator );

		//11 运行状态
		tmp_object.SetInt( CardPos.running_stat );
		Array.PushBack( tmp_object, Allocator );

		//12 业务状态
		tmp_object.SetInt( CardPos.biz_stat );
		Array.PushBack( tmp_object, Allocator );

		//13 速度
		tmp_object.SetDouble( CardPos.speed );
		Array.PushBack( tmp_object, Allocator );

		//14 地标编号
		tmp_object.SetInt( CardPos.landmark_id );
		Array.PushBack( tmp_object, Allocator );

		//15 地标方向
		tmp_object.SetInt( CardPos.lm_direction );
		Array.PushBack( tmp_object, Allocator );

		//16 距离地标的距离
		tmp_object.SetDouble( CardPos.landmark_dis );
		Array.PushBack( tmp_object, Allocator );

		//17 级别编号
		tmp_object.SetInt( CardPos.level_id );
		Array.PushBack( tmp_object, Allocator );

		//18 车辆当天出勤的标识
		tmp_object.SetInt( CardPos.is_on_duty );
		Array.PushBack( tmp_object, Allocator );

		DetailItem = Array;
		return true;
	}

	bool jsonBuilder::__BuildDept( const std::map<int, _STAT_DEPT_ITEM_>& dept_map, rapidjson::Document::AllocatorType & Allocator, rapidjson::Value & Dept )
	{
		std::map<int, _STAT_DEPT_ITEM_>::const_iterator mit_dept;
		for ( mit_dept = dept_map.begin(); mit_dept != dept_map.end(); mit_dept++ )
		{
			rapidjson::Value DeptItem( rapidjson::kObjectType );

			__BuildDeptItem( mit_dept->second, Allocator, DeptItem );

			rapidjson::Value dept_id( rapidjson::kObjectType );
			char szNum[20] = { 0 };
			//itoa( mit_dept->second.DeptID, szNum, 10 );
			sprintf(szNum,"%d",mit_dept->second.DeptID);

			dept_id.SetString( szNum, strlen( szNum ), Allocator );
			Dept.AddMember( dept_id, DeptItem, Allocator );
		}

		return true;
	}

	void jsonBuilder::__BuildDeptItem( const _STAT_DEPT_ITEM_ & st_dept_item, rapidjson::Document::AllocatorType & Allocator, rapidjson::Value & DeptItem )
	{
		//Area
		__BuildIDSumMap( st_dept_item.Area, JSON_ROOT_KEY_STATISTIC_AREA, Allocator, DeptItem );

		//Dept
		__BuildIDSumMap( st_dept_item.Dept, JSON_ROOT_KEY_STATISTIC_DEPT, Allocator, DeptItem );

		//occupation_level
		__BuildIDSumMap( st_dept_item.OcptLvl, JSON_ROOT_KEY_STATISTIC_LEVEL, Allocator, DeptItem );

		//sum
		rapidjson::Value Sum( rapidjson::kObjectType );
		Sum.SetInt( st_dept_item.Sum );
		DeptItem.AddMember( JSON_ROOT_KEY_STATISTIC_SUM, Sum, Allocator );
	}

	void jsonBuilder::__BuildBaseCardItem( const _BASE_CARD_ & Card, rapidjson::Document::AllocatorType & Allocator, rapidjson::Value & CardItem )
	{
		rapidjson::Value TmpObj( rapidjson::kObjectType );
		rapidjson::Value CardObj( rapidjson::kArrayType );

		//0 卡号
		TmpObj.SetString( __FmtCardID( Card ).c_str(), Allocator );
		CardObj.PushBack( TmpObj, Allocator );
		
		//1 x坐标
		TmpObj.SetDouble( Card.x );
		CardObj.PushBack( TmpObj, Allocator );

		//2 y坐标
		TmpObj.SetDouble( Card.y );
		CardObj.PushBack( TmpObj, Allocator );

		//3 入井时间戳
		TmpObj.SetDouble( Card.down_time );
		CardObj.PushBack( TmpObj, Allocator );

		//4 进入区域时间戳
		TmpObj.SetDouble( Card.enter_area_time );
		CardObj.PushBack( TmpObj, Allocator );

		//5 接收时间戳
		TmpObj.SetDouble( Card.rec_time );
		CardObj.PushBack( TmpObj, Allocator );

		//6 工作时长
		TmpObj.SetDouble( Card.work_time );
		CardObj.PushBack( TmpObj, Allocator );

		//7 地图编号
		TmpObj.SetInt( Card.map_id );
		CardObj.PushBack( TmpObj, Allocator );

		//8 区域编号
		TmpObj.SetInt( Card.area_id );
		CardObj.PushBack( TmpObj, Allocator );

		//9 部门编号
		TmpObj.SetInt( Card.dept_id );
		CardObj.PushBack( TmpObj, Allocator );

		//10 状态
		TmpObj.SetInt( Card.stat );
		CardObj.PushBack( TmpObj, Allocator );

		//11 运行状态
		TmpObj.SetInt( Card.running_stat );
		CardObj.PushBack( TmpObj, Allocator );

		//12 业务状态
		TmpObj.SetInt( Card.biz_stat );
		CardObj.PushBack( TmpObj, Allocator );

		//13 速度
		TmpObj.SetDouble( Card.speed );
		CardObj.PushBack( TmpObj, Allocator );

		CardItem = CardObj;
	}

	void jsonBuilder::__CreateDeptMap( const _CARD_POS_ & CardPos, std::map<int, _STAT_DEPT_ITEM_>& DeptMap )
	{
		std::map<int, _STAT_DEPT_ITEM_>::iterator mit_dept_map;

		mit_dept_map = DeptMap.find( CardPos.dept_id );
		if ( mit_dept_map == DeptMap.end() )
		{
			_STAT_DEPT_ITEM_ sdItem;
			sdItem.DeptID = CardPos.dept_id;
			sdItem.Area.insert( std::make_pair( CardPos.area_id, 1 ) );
			sdItem.Dept.insert( std::make_pair( CardPos.dept_id, 1 ) );
			sdItem.OcptLvl.insert( std::make_pair( CardPos.level_id, 1 ) );
			sdItem.Sum = 1;
			DeptMap.insert( std::make_pair( sdItem.DeptID, sdItem ) );
		}
		else
		{
			__CreateDeptItem( CardPos, mit_dept_map->second );
			
		}
	}

	void jsonBuilder::__CreateDeptItem( const _CARD_POS_ & CardPos, _STAT_DEPT_ITEM_ & DeptItem )
	{
		std::map<int, int>::iterator mit_id_sum;

		//area
		mit_id_sum = DeptItem.Area.find( CardPos.area_id );
		if ( mit_id_sum == DeptItem.Area.end() )
		{
			DeptItem.Area.insert( std::make_pair( CardPos.area_id, 1 ) );
		}
		else
		{
			mit_id_sum->second++;
		}

		//Dept
		mit_id_sum = DeptItem.Dept.find( CardPos.dept_id );
		if ( mit_id_sum == DeptItem.Dept.end() )
		{
			DeptItem.Dept.insert( std::make_pair( CardPos.dept_id, 1 ) );
		}
		else
		{
			mit_id_sum->second++;
		}

		//occupation_level
		mit_id_sum = DeptItem.OcptLvl.find( CardPos.level_id );
		if ( mit_id_sum == DeptItem.OcptLvl.end() )
		{
			DeptItem.OcptLvl.insert( std::make_pair( CardPos.level_id, 1 ) );
		}
		else
		{
			mit_id_sum->second++;
		}

		//Sum
		DeptItem.Sum++;
	}

	void jsonBuilder::__BuildIDSumMap( const std::map<int, int>& id_sum_map, const char* szName, rapidjson::Document::AllocatorType & Allocator, rapidjson::Value & Parent )
	{
		rapidjson::Value Array( rapidjson::kArrayType );
		std::map<int, int>::const_iterator mit_id_sum;

		for ( mit_id_sum = id_sum_map.begin(); mit_id_sum != id_sum_map.end(); mit_id_sum++ )
		{
			rapidjson::Value Item( rapidjson::kArrayType );
			rapidjson::Value tmpobj( rapidjson::kObjectType );

			tmpobj.SetInt( mit_id_sum->first );
			Item.PushBack( tmpobj, Allocator );

			tmpobj.SetInt( mit_id_sum->second );
			Item.PushBack( tmpobj, Allocator );

			Array.PushBack( Item, Allocator );
		}

		Parent.AddMember( rapidjson::StringRef( szName ), Array, Allocator );
	}

	std::string jsonBuilder::BuildLogin( const _JS_LOGIN_& Login )
	{
		rapidjson::StringBuffer sb;
		rapidjson::Writer<rapidjson::StringBuffer> writer( sb );
		rapidjson::Document doc;
		rapidjson::Document::AllocatorType& Allocator = doc.GetAllocator();

		rapidjson::Value root( rapidjson::kObjectType );
		rapidjson::Value child( rapidjson::kObjectType );
		rapidjson::Value value( rapidjson::kStringType );

		__SetCmd( JSON_CMD_VALUE_LOGIN, root, Allocator );

		value.SetString( Login.user_name.c_str(), Allocator );
		child.AddMember( JSON_KEY_USERNAME, value, Allocator );

		value.SetString( Login.user_password.c_str(), Allocator );
		child.AddMember( JSON_KEY_PASSWORD, value, Allocator );

		root.AddMember( JSON_ROOT_KEY_DATA, child, Allocator );

		root.Accept( writer );

		return sb.GetString();
	}

	std::string jsonBuilder::BuildCardPos( const std::map<uint64_t, _CARD_POS_>& CardPosList )
	{
		rapidjson::StringBuffer sb;
		rapidjson::Writer<rapidjson::StringBuffer> writer( sb );
		rapidjson::Document doc;
		rapidjson::Document::AllocatorType& Allocator = doc.GetAllocator();

		rapidjson::Value root( rapidjson::kObjectType );

		__SetCmd( JSON_CMD_VALUE_POS_MAP, root, Allocator );

		rapidjson::Value s( rapidjson::kObjectType );
		rapidjson::Value v( rapidjson::kObjectType );
		rapidjson::Value s_Detail( rapidjson::kArrayType );
		rapidjson::Value v_Detail( rapidjson::kArrayType );
		rapidjson::Value s_dept( rapidjson::kObjectType );
		rapidjson::Value v_dept( rapidjson::kObjectType );
		std::map<int, _STAT_DEPT_ITEM_> s_dept_map;
		std::map<int, _STAT_DEPT_ITEM_> v_dept_map;
		_STAT_DEPT_ITEM_ s_glbl_item;
		_STAT_DEPT_ITEM_ v_glbl_item;
		std::map<uint64_t, _CARD_POS_>::const_iterator mit_card;
		for ( mit_card = CardPosList.begin(); mit_card != CardPosList.end(); mit_card++ )
		{
			//不显示的卡不往前端推送
			if ( !mit_card->second.display )
			{
				continue;
			}

			rapidjson::Value DetailItem;
			if ( !__BuildDetail( mit_card->second, Allocator, DetailItem ) )
			{
				continue;
			}
			
			if( mit_card->second.Type == 1)
			{
				s_Detail.PushBack( DetailItem, Allocator );
				__CreateDeptMap( mit_card->second, s_dept_map );
				__CreateDeptItem(  mit_card->second, s_glbl_item );
			}
			else //车卡、采煤机等等
			{
				v_Detail.PushBack( DetailItem, Allocator );
				__CreateDeptMap( mit_card->second, v_dept_map );
				__CreateDeptItem(  mit_card->second, v_glbl_item );
			}
		}

		s.AddMember( JSON_ROOT_KEY_STATISTIC_DETAIL, s_Detail, Allocator );
		v.AddMember( JSON_ROOT_KEY_STATISTIC_DETAIL, v_Detail, Allocator );

		//stat
		rapidjson::Value s_stat( rapidjson::kObjectType );
		rapidjson::Value v_stat( rapidjson::kObjectType );

		if ( __BuildDept( s_dept_map, Allocator, s_dept ) )
		{
			s_stat.AddMember( JSON_ROOT_KEY_STATISTIC_DEPT, s_dept, Allocator );
		}

		if ( __BuildDept( v_dept_map, Allocator, v_dept ) )
		{
			v_stat.AddMember( JSON_ROOT_KEY_STATISTIC_DEPT, v_dept, Allocator );
		}

		//glbl
		rapidjson::Value s_glbl( rapidjson::kObjectType );
		rapidjson::Value v_glbl( rapidjson::kObjectType );

		__BuildDeptItem( s_glbl_item, Allocator, s_glbl );
		__BuildDeptItem( v_glbl_item, Allocator, v_glbl );

		//s.AddMember( JSON_ROOT_KEY_STATISTIC_GLOBAL, s_glbl, Allocator );
		//v.AddMember( JSON_ROOT_KEY_STATISTIC_GLOBAL, v_glbl, Allocator );

		s_stat.AddMember( JSON_ROOT_KEY_STATISTIC_GLOBAL, s_glbl, Allocator );
		v_stat.AddMember( JSON_ROOT_KEY_STATISTIC_GLOBAL, v_glbl, Allocator );
			
		s.AddMember( JSON_ROOT_KEY_STATISTIC_STAT, s_stat, Allocator );
		v.AddMember( JSON_ROOT_KEY_STATISTIC_STAT, v_stat, Allocator );

		rapidjson::Value Data( rapidjson::kObjectType );
		Data.AddMember( JSON_ROOT_KEY_STATISTIC_STAFF_DATA, s, Allocator );
		Data.AddMember( JSON_ROOT_KEY_STATISTIC_VEHICLE_DATA, v, Allocator );

		root.AddMember( JSON_ROOT_KEY_DATA, Data, Allocator );

		__AddVersion( root, Allocator );
		root.Accept( writer );

		return sb.GetString();
	}

	std::string jsonBuilder::BuildSpecialAreaProcess( const _BASE_CARD_ & stCard )
	{
		rapidjson::StringBuffer sb;
		rapidjson::Writer<rapidjson::StringBuffer> writer( sb );
		rapidjson::Document doc;
		rapidjson::Document::AllocatorType& Allocator = doc.GetAllocator();

		rapidjson::Value root( rapidjson::kObjectType );
		__SetCmd( JSON_CMD_VALUE_SPECIAL_AREA_UP_MINE, root, Allocator );

		rapidjson::Value CardItem( rapidjson::kObjectType );
		rapidjson::Value CardList( rapidjson::kArrayType );

		__BuildBaseCardItem( stCard, Allocator, CardItem );
		CardList.PushBack( CardItem, Allocator );

		root.AddMember( JSON_ROOT_KEY_DATA, CardList, Allocator );

		root.Accept( writer );

		return sb.GetString();
	}

	bool jsonBuilder::ParseCall_Card_Req( const std::string& JasonText, _JS_CALL_CARD_REQ_& CallCardReq, std::string& Error )
	{
		rapidjson::Document doc;
		if ( doc.Parse( JasonText.c_str() ).HasParseError() )
		{
			Error = "Failed to parse jason text!";
			return false;
		}

		rapidjson::Value::MemberIterator itValue;
		itValue = doc.FindMember( "data" );
		if ( itValue == doc.MemberEnd() )
		{
			Error = "Failed to find member: data!";
			return false;
		}

		rapidjson::Value Data;
		rapidjson::Document::AllocatorType allocator;
		Data.CopyFrom( itValue->value, allocator );

		if ( !Data.HasMember( JSON_KEY_CALL_CARD_CALL_TYPE ) )
		{
			Error = "Failed to find value: ";
			Error += JSON_KEY_CALL_CARD_CALL_TYPE;
			return false;
		}
		CallCardReq.call_type_id = Data[JSON_KEY_CALL_CARD_CALL_TYPE].GetInt();

		if ( !Data.HasMember( JSON_KEY_CALL_CARD_CALL_TIME_OUT ) )
		{
			Error = "Failed to find value: ";
			Error += JSON_KEY_CALL_CARD_CALL_TIME_OUT;
			return false;
		}
		CallCardReq.call_time_out = Data[JSON_KEY_CALL_CARD_CALL_TIME_OUT].GetInt();

		if ( !Data.HasMember( JSON_KEY_CALL_CARD_CALL_LEVEL ) )
		{
			Error = "Failed to find value: ";
			Error += JSON_KEY_CALL_CARD_CALL_LEVEL;
			return false;
		}
		CallCardReq.call_time_interval = Data[JSON_KEY_CALL_CARD_CALL_LEVEL].GetInt();

		if ( !Data.HasMember( JSON_KEY_CALL_CARD_USER_NAME ) )
		{
			Error = "Failed to find value: ";
			Error += JSON_KEY_CALL_CARD_USER_NAME;
			return false;
		}
		CallCardReq.user_name = Data[JSON_KEY_CALL_CARD_USER_NAME].GetString();

		//data::stations
		if ( !Data.HasMember( JSON_KEY_CALL_CARD_STATIONS ) )
		{
			Error = "Failed to find value: ";
			Error += JSON_KEY_CALL_CARD_STATIONS;
			return false;
		}
		rapidjson::Value & stations = Data[JSON_KEY_CALL_CARD_STATIONS];
		if ( !stations.IsArray() )
		{
			Error = "data::stations is not a valid array!";
			return false;
		}
		for ( int i = 0; i < (int)stations.Size(); ++i )
		{
			rapidjson::Value & v = stations[i];
			if ( !v.IsObject() )
			{
				char szError[1024] = { 0 };
				sprintf( szError, "data::stations[%d] is not a object!", i );
				Error = szError;
				return false;
			}

			_JS_STATION_ Station;
			if ( !v.HasMember( JSON_KEY_CALL_CARD_STATION_ID ) && v[JSON_KEY_CALL_CARD_STATION_ID].IsInt() )
			{
				Error = "Error, failed to found value: ";
				Error += JSON_KEY_CALL_CARD_STATION_ID;
				return false;
			}
			Station.stationid = v[JSON_KEY_CALL_CARD_STATION_ID].GetInt();

			CallCardReq.stations.push_back( Station );
		}

		//data::cards
		if ( !Data.HasMember( JSON_KEY_CALL_CARD_CARDS ) )
		{
			Error = "Failed to find value: ";
			Error += JSON_KEY_CALL_CARD_CARDS;
			return false;
		}
		rapidjson::Value & cards = Data[JSON_KEY_CALL_CARD_CARDS];
		for ( int i = 0; i < (int)cards.Size(); ++i )
		{
			rapidjson::Value & v = cards[i];
			if ( !v.IsObject() )
			{
				char szError[1024] = { 0 };
				sprintf( szError, "data::cards[%d] is not a object!", i );
				Error = szError;
				return false;
			}

			_JS_CARD_ Card;
			if ( !v.HasMember( JSON_KEY_CALL_CARD_CARD_ID ) && v[JSON_KEY_CALL_CARD_CARD_ID].IsInt() )
			{
				Error = "Error, failed to found value: ";
				Error += JSON_KEY_CALL_CARD_CARD_ID;
				return false;
			}
			Card.cardid = v[JSON_KEY_CALL_CARD_CARD_ID].GetInt();

			if ( !v.HasMember( JSON_KEY_CALL_CARD_CARD_TYPE_ID ) && v[JSON_KEY_CALL_CARD_CARD_TYPE_ID].IsInt() )
			{
				Error = "Error, failed to found value: ";
				Error += JSON_KEY_CALL_CARD_CARD_TYPE_ID;
				return false;
			}
			Card.cardtype = v[JSON_KEY_CALL_CARD_CARD_TYPE_ID].GetInt();

			CallCardReq.cards.push_back( Card );
		}

		return true;
	}
}
