#include "AxisAssertDataPrepare.h"
#include "AxisSectionConfigDataManage.h"
#include "PhysicalSectionDataManage.h"
#include "SystemParameterManage.h"

#include <stdarg.h>


/**
 * @brief 打印Debug信息
 * @param[in] UINT8 level 日志级别
 * @param[in] const char *fmt 打印信息
 * @return 无
 * @note 通过调用外部接口，实现本模块的打印
 */
void aam_PrintDebugInfo(UINT8 level,const char *fmt, ...)
{
	va_list para;
	CHAR tmpPrintBuf[AMM_PRINT_LEN] = {'\0'};

	if (AAM_LOG_LEVEL >= level)
	{
		va_start(para,fmt);
		(void)vsnprintf(tmpPrintBuf,AMM_PRINT_LEN,fmt,para);
		va_end(para);

		debug_infor_printf((const)"%s",(const)tmpPrintBuf);
	}
	else
	{
		/** 日志级别不够*/
	}	
}


/**
 * @brief 获取本OC范围有共管区内计轴区段的数组索引
 * @param[out] OUT UINT16** pACIdBuff 计轴区段ID数缓存
 * @return 0 查询错误
           1~AXIS_SECTION_SUM_MAX 查询正确
 * @note 由于OC支持计轴区段ID和索引的映射关系，故直接获取即可
 */
UINT16 aam_PrepareACBuffIndexs(OUT const UINT16** pACIdBuff)
{
	return elm_PrepareACBuffIndexs(pACIdBuff);
}

/**
 * @brief 通过计轴区段ID获取计轴区段的数组索引
 * @param[in] UINT16 ACId 计轴区段ID
 * @return 计轴区段缓存索引
 * @note 无
 */
UINT16 aam_PrepareACIndex(UINT16 ACId)
{
	return elm_PrepareACIndex(ACId);
}

/**
 * @brief 通过计轴ID获取计轴状态
 * @param[in] UINT16 ACID 计轴区段ID
 * @return ELM_AC_OCC 计轴占用
		   ELM_AC_FREE 计轴空闲
 * @note 
 */
UINT8 aam_PrepareACStatus(UINT16 ACID)
{
	return elm_PrepareACStatus(ACID);
}

/**
  * @brief 获取计轴区段是否属于本OC 
  * @param[in] UINT16 acID 计轴区段ID
  * @param[out] UINT8 *pOCId 所属OCid
  * @return ELM_BELONG_OTHER 属于相邻OC
            ELM_BELONG_OWNER 属于本OC
			其他，非法
  * @note 无
  */
 UINT8 aam_PrepareACIsSelf(UINT16 acID,UINT8 *pOCId)
 {
	 return elm_PrepareACIsSelf(acID,pOCId);
 }

  /**
 * @brief 查询计轴前/后方计轴
 * @param[in] UINT16 ACID 基准计轴ID
 * @param[in] UINT8 dir 查询方向
 * @param[out] UINT16 arACID[AC_MAXCNT_IN_SWITCH] 相邻计轴ID
 * @param[out] UINT8* DirectionPointFlag  是否有方向变化点 DIRECTIONPOINT_FLAG_VALID
 * @return UINT8_MAX 查询失败
           0~AC_MAXCNT_IN_SWITCH  查询成功
 * @note 无
 */
UINT8 aam_PrepareAdjacentAC(UINT16 ACID, UINT8 dir, INOUT UINT16 arACID[AC_MAXCNT_IN_SWITCH], UINT8* DirectionPointFlag)
{
	return elm_PrepareAdjacentAC(ACID, dir, arACID, DirectionPointFlag);
}

/**
 * @brief 通过计轴区段ID查找计轴区段位置
 * @param[in] UINT16 ACID 计轴区段ID
 * @param[in] UINT8 dir 查询方向
 * @param[out] ELM_AxisLocStruct* pACLoc 计轴区段位置
 * @return CI_SUCCESS 查询正确，返回成功
 *         CI_ERROR   查询错误，返回失败
 * @note 
 */
UINT8 aam_PrepareACLoc(UINT16 ACID, UINT8 dir, INOUT ELM_AxisLocStruct* pACLoc)
{
	return elm_PrepareACLoc(ACID,dir,pACLoc);
}


/**
 * @brief 通过计轴区段查找计轴区段相邻的物理区段
 * @param[in] UINT16 ACID
 * @param[out] UINT16 *PrePhyid 前方物理区段ID
 * @param[out] UINT16 *BackPhyid 后方物理区段ID 
 * @return CI_ERROR 返回错误
           CI_SUCCESS 返回正确
 * @note 
 *     1、新建，2022年4月22日，前方后方按照逻辑正方向进行确定
 */
UINT8 aam_PreparePreAndBackPhySecOFAC(UINT16 ACID,UINT16 *PrePhyid, UINT16 *BackPhyid)
{
	/*- 局部变量定义 */
	UINT8 ret = CI_ERROR;
	UINT8 tmpACCnt = 0u; 
	UINT16 tmpACId[AC_MAXCNT_IN_SWITCH] = {0u};
	UINT16 tmpPrePhyId = 0u;
	UINT16 tmpBackPhyid = 0u;
	UINT8 cDirectionPointFlag = 0U;			/*是否具有方向变化点标志*/

	/*- 入口参数判断 */
	ASSERT_RET_VALUE(NULL == PrePhyid,ret,0x80000000u);
	ASSERT_RET_VALUE(NULL == BackPhyid,ret,0x40000000u);

	/** 查询正方向相邻计轴区段 */
	tmpACCnt = elm_PrepareAdjacentAC(ACID, EMAP_SAME_DIR, tmpACId, &cDirectionPointFlag);

	if (UINT8_MAX == tmpACCnt)
	{
		/** 查询错误*/
	}
	else
	{
		if (0u == tmpACCnt)
		{
			/** 前方为尽头线 */
			tmpPrePhyId = UINT16_MAX;
		}
		else
		{
			tmpPrePhyId = GetAxisSecRelativePhySecId(tmpACId[0u]);
		}
		(*PrePhyid) = tmpPrePhyId;
	}

	/** 查询反方向相邻计轴区段 */
	tmpACCnt = elm_PrepareAdjacentAC(ACID, EMAP_CONVER_DIR, tmpACId, &cDirectionPointFlag);

	if (UINT8_MAX == tmpACCnt)
	{
		/** 查询错误*/
	}
	else
	{
		if (0u == tmpACCnt)
		{
			/** 前方为尽头线 */
			tmpBackPhyid = UINT16_MAX;
		}
		else
		{
			tmpBackPhyid = GetAxisSecRelativePhySecId(tmpACId[0u]);
		}
		(*BackPhyid) = tmpBackPhyid;
	}

	/** 设置函数返回值 */
	ASSERT_SETRET((0u == tmpPrePhyId) || (0u == tmpBackPhyid) || ((UINT16_MAX == tmpPrePhyId) && (tmpPrePhyId == tmpBackPhyid)),ret,CI_ERROR,CI_SUCCESS);
	return ret;
}


/**
 * @brief 获取物理区段状态
 * @param[in] UINT16 PhyId 物理区段id
 * @param[out] 无
 * @return SECTION_OCCUPY_YES 物理区段占用
           SECTION_OCCUPY_NO 物理区段空闲
 * @note 
 */
UINT8 aam_PreparePhyOccStatus(UINT16 PhyId)
{
	/*- 局部变量定义 */
	UINT8 ret = SECTION_OCCUPY_YES;
	
	/** 查询物理区段状态 */
	ret = GetPhySecCurOccupyState(PhyId);

	if (SECTION_OCCUPY_NO == ret)
	{
		/** 物理区段空闲，不处理*/
	}
	else
	{
		/** 其他情况都设置为占用 */
		ret = SECTION_OCCUPY_YES;
	}
	
	/** 函数返回 */
	return ret;
}


/**
 * @brief 获取计轴对应的物理区段
 * @param[in] UINT16 ACID 计轴区段ID
 * @param[out] 无
 * @return 
 * @note 
 */
UINT16 aam_PrepareACBelongPhyid(UINT16 ACID)
{
	return GetAxisSecRelativePhySecId(ACID);
}


/**
 * @brief 判断计轴区段是否为联锁线
 * @param[in] UINT16 ACID 计轴区段ID
 * @param[out]
 * @return CI_SUCCESS 为联锁线
           CI_ERROR 不为联锁线
 * @note 
 */
UINT8 aam_PrepareACIsLinkingAxle(UINT16 ACID)
{
	UINT8 chFunRet = AXIS_SEC_LINK_LINE_NO;
	UINT8 ret = CI_ERROR;
	chFunRet = GetAxisSecLinkLineFlag(ACID);
	if (AXIS_SEC_LINK_LINE_YES == chFunRet)
	{
		ret = CI_SUCCESS;
	}
	else
	{
		;
	}
	return ret;
}

/**
 * @brief 获取尽头线功能开关
 * @param[in] 无
 * @param[out] 无
 * @return CI_SUCCESS 功能打开
           CI_ERROR 功能关闭
 * @note 
 */
UINT8 aam_PrepareInitCTPassFlagSwitch(void)
{
	UINT8 chFunRet = 0u;
	UINT8 ret = CI_ERROR;

	chFunRet = GetCiFunctionSwitchConfig(FUNC_RESET_ARB_SWITCH);

	if (FUNC_SWITCH_ON == chFunRet)
	{/* 功能开关打开 */
		ret = CI_SUCCESS;
	}
	else
	{
		; /* 功能开关关闭 */
	}
	return ret;
}


/**
 * @brief 获取计轴诊断冗余周期数
 * @param[in]  无
 * @param[out] 无
 * @return 计轴诊断冗余周期数
 * @note 
 */
UINT8 aam_PrepareRedunTimes(void)
{
	/** 是否需要考虑对函数的返回值进行校验，比较纠结，先只是强制转换*/
	return (UINT8)GetSystemParaOccuToIdleCyc();
}


/**
 * @brief 获取物理区段包含的计轴区段
 * @param[in] UINT16 PhyId 物理区段
 * @param[out] UINT8* pACCnt 计轴区段数量
 * @return const UINT16* 计轴区段存储地址
 * @note 非NULL 查询正确
         NULL 查询错误
 */
const UINT16* aam_PreparePhyRelACIds(UINT16 PhyId,UINT8* pACCnt)
{
	const UINT16* ret = NULL;
	UINT8 tempCnt = 0u;

	/** 入口参数检查 */
	ASSERT_RET_VALUE(NULL == pACCnt,ret,0x80000000u);

	/** 获取物理区段包含的计轴区段 */
	tempCnt = GetPAxisSectionSum(PhyId);
	ret = GetPAxisSectionIdBuf(PhyId);

	if (0u == tempCnt) 
	{
		/** 查询错误 */
		*pACCnt = 0u;
		ret = NULL;
	}
	else
	{
		/** 查询正确 */
		*pACCnt = tempCnt;
	}

	return ret;
}

/**
* @brief 获取物理区段是否属于本TIOC
* @param[in] UINT16 phyID 物理区段ID
* @param[out] UINT8 *pOCId 所属TIOCid
* @return ELM_BELONG_OTHER 属于相邻TIOC
ELM_BELONG_OWNER 属于本TIOC
其他，非法
* @note 无
*/
UINT8 aam_PreparePhyIsSelf(UINT16 phyID, UINT8 *pOCId)
{
	/*- 局部变量定义 */
	UINT8 ret = ELM_BELONG_OWNER;
	UINT8 localOCid = 0u;
	UINT8 phyBelongOcid = 0u;

	/** 入口参数校验 */
	if (NULL == pOCId)
	{
		/** 入口参数错误 */
	}
	else
	{
		/** 获取本OCid */
		localOCid = GetSystemParaLocalCiId();

		/** 获取计轴所属OC id 不超过255*/
		phyBelongOcid = (UINT8)GetPhySecBelongCiId(phyID);

		if ((0u == localOCid) || (0u == phyBelongOcid))
		{
			/** 数据初始化错误 */
		}
		else if (localOCid == phyBelongOcid)
		{
			/** 在一个OC*/
			*pOCId = phyBelongOcid;
			ret = ELM_BELONG_OWNER;
		}
		else
		{
			/** 不在同一OC*/
			*pOCId = phyBelongOcid;
			ret = ELM_BELONG_OTHER;
		}
	}

	return ret;
}

/**
 * @brief 判断数值是否存在UINT16数值中 
 * @param[in] UINT16 targetValue 待查询的值
 * @param[in] const UINT16 arValue[] 冲突范围
 * @param[in] UINT16 buffsize 冲突范围大小
 * @return CI_SUCCESS 指定值在冲突范围内
 *         CI_ERROR   指定值不在冲突范围内
 * @note 无
 */
UINT8 aam_PrepareInUINT16Array(UINT16 targetValue,const UINT16 arValue[],UINT16 buffsize)
{
	/*- 局部变量定义 */
	UINT8 cRetVal = CI_ERROR;
	UINT16 cycle = 0u;

	/** 入口参数校验 */
	if (NULL == arValue)
	{
		/** 入口参数错误 */
	}
	else
	{
		/*- 目标值是否在指定范围内 */
		for (cycle = 0u; cycle < buffsize; cycle++)
		{
			if (targetValue == arValue[cycle])
			{
				cRetVal = CI_SUCCESS;
				break;
			}
		}
	}

	/** 函数返回*/
	return cRetVal;
}

/**
* @brief 获取ARB功能开关
* @param[in] 无
* @param[out] 无
* @return CI_SUCCESS 功能打开
CI_ERROR 功能关闭
* @note
*/
UINT8 aam_PrepareArbSwitch(void)
{
	UINT8 chFunRet = 0u;
	UINT8 ret = CI_ERROR;

	chFunRet = GetCiFunctionSwitchConfig(FUNC_ARB_SWITCH);

	if (FUNC_SWITCH_ON == chFunRet)
	{/* 功能开关打开 */
		ret = CI_SUCCESS;
	}
	else
	{
		; /* 功能开关关闭 */
	}
	return ret;
}

/**
* @brief 获取本RC通信的OCid
* @param[out] UINT8 *pOCIDbuff OCid缓存
* @return 本OC通信数量
*/
UINT8 aam_PrepareComOcId(IN const UINT8 **pOcIdBuff)
{
	/*- 局部变量定义 */
	UINT8 ret = 0u;

	/** 入口参数校验 */
	if (NULL == pOcIdBuff)
	{
		/** 入口参数错误，返回0,由外部处理*/
	}
	else
	{
		/** 获取本RC通信的OC数量 */
		ret = GetCiTransmitSpecifySysDevSum(CI_SYSTEM_TYPE_OC);

		/** 判断是否存在，不存在直接返回*/
		if (0u == ret)
		{
			/** 无OC */
		}
		else
		{
			/** 获取通信OD ID */
			(*pOcIdBuff) = GetCiTransmitSpecifySysDevBuf(CI_SYSTEM_TYPE_OC);
		}
	}

	return ret;
}


/**
* @brief 获取OC的通信状态
* @param[in] UINT8 OCID
* @return AAM_COM_STATUS_ERROR 通信状态错误
AAM_COM_STATUS_OK 通信状态正确
* @note
*/
UINT8 aam_PrepareOcCommStatus(UINT8 OcId)
{
	/*- 局部变量定义 */
	UINT8 ret = AAM_COM_STATUS_ERROR;
	UINT8 funRtn = TRANSMIT_STATE_BAD;
	UINT8 localId = GetSystemParaLocalCiId();
	UINT32 recvCyc = 0u;

	/** 获取OC通信状态 */
	funRtn = GetCiTransmitState(CI_SYSTEM_TYPE_OC, OcId);

	/** 获取收到消息周期号 */
	recvCyc = GetCiTransmitRecvDataCycNum(localId, CI_SYSTEM_TYPE_OC, OcId);

	/** 设置函数返回值 */
	ASSERT_SETRET(((TRANSMIT_STATE_GOOD == funRtn) && (0u != recvCyc)), ret, AAM_COM_STATUS_OK, AAM_COM_STATUS_ERROR);

	/** 函数返回*/
	return ret;
}

/**
* @brief 获取计轴系统功能开关
* @param[in] 无
* @param[out] 无
* @return CI_SUCCESS 功能打开
CI_ERROR 功能关闭
* @note
*/
UINT8 aam_PrepareAsSwitch(void)
{
	UINT8 ret = CI_ERROR;
	UINT8 acFty = 0u;
	acFty = GetCiFunctionSwitchConfig(FUNC_SWITCH_AC_FACTORY);
	/** 设置函数返回值 */
	ASSERT_SETRET(FUNC_SWITCH_OFF == acFty, ret, CI_ERROR, CI_SUCCESS);
	return ret;
}

/**
* @brief 获取本RC通信的计轴系统id
* @param[out] UINT8 *pAsIdBuff 计轴系统id缓存
* @return 本RC通信计轴系统数量
*/
UINT8 aam_PrepareComAsId(IN const UINT8 **pAsIdBuff)
{
	/*- 局部变量定义 */
	UINT8 ret = 0u;

	/** 入口参数校验 */
	if (NULL == pAsIdBuff)
	{
		/** 入口参数错误，返回0,由外部处理*/
	}
	else
	{
		/** 获取本RC通信的计轴系统数量 */
		ret = GetCiTransmitSpecifySysDevSum(CI_SYSTEM_TYPE_AXIS);

		/** 判断是否存在，不存在直接返回*/
		if (0u == ret)
		{
			/** 无计轴系统 */
		}
		else
		{
			/** 获取通信计轴系统 ID */
			(*pAsIdBuff) = GetCiTransmitSpecifySysDevBuf(CI_SYSTEM_TYPE_AXIS);
		}
	}

	return ret;
}


/**
* @brief 获取计轴系统的通信状态
* @param[in] UINT8 AsId
* @return AAM_COM_STATUS_ERROR 通信状态错误
AAM_COM_STATUS_OK 通信状态正确
* @note
*/
UINT8 aam_PrepareAsCommStatus(UINT8 AsId)
{
	/*- 局部变量定义 */
	UINT8 ret = AAM_COM_STATUS_ERROR;
	UINT8 funRtn = TRANSMIT_STATE_BAD;
	UINT8 localId = GetSystemParaLocalCiId();
	UINT32 recvCyc = 0u;

	/** 获取计轴系统通信状态 */
	funRtn = GetCiTransmitState(CI_SYSTEM_TYPE_AXIS, AsId);

	/** 获取计轴系统接收周期数 */
	recvCyc = GetCiTransmitRecvDataCycNum(localId, CI_SYSTEM_TYPE_AXIS, AsId);

	/** 设置函数返回值 */
	ASSERT_SETRET(((TRANSMIT_STATE_GOOD == funRtn) && (0u != recvCyc)), ret, AAM_COM_STATUS_OK, AAM_COM_STATUS_ERROR);

	/** 函数返回*/
	return ret;
}

/**
* @brief 判断两点是否同向
* @param[in] LOD_STRU strPointA
* @param[in] LOD_STRU strPointB
* @return CI_ERROR:比较失败；FLAG_SET:同向；FLAG_UNSET:不同向
* @note 无
*/
UINT8 aam_PrepareTwoPointsSameDir(const LOD_STRU strPointA, const LOD_STRU strPointB)
{
	return IsPointABSameDir(strPointA, strPointB);
}