
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>  
#include <string.h>  
#include <pthread.h>
#include <fcntl.h>
#include <sys/prctl.h>

#include "src/core/nm-default-daemon.h"
#include "libnm-glib-aux/nm-dbus-aux.h"
#include "libnm-core-impl/nm-default-libnm-core.h"
#include "kylin_common.h"
#include "kylin_netctrol_interface.h"
#include "kylin_cfgInfo.h"




#define KYLIN_NETCTROL_CFG_PATH "/etc/NetworkManager/kylin_nm_ctrl.ini"

#define KYLIN_NETCTR_DBUS_SERVICE       "com.kylin.networkCtrol"
#define KYLIN_NETCTR_DBUS_PATH          "/com/kylin/networkCtrol"
#define KYLIN_NETCTR_DBUS_INTERFACE     "com.kylin.networkCtrol"

#define KYLIN_NC_DBUS_GET_METH	"getNetContrlRule"
#define KYLIN_NC_DBUS_SET_METH	"setNetContrlRule"
#define KYLIN_NC_DBUS_MAX_TIMEMS (3000) //超时时间3s


/*
#define KYLIN_COMMON_LOG(level, ...) \
    nm_log ((level), LOGD_SETTINGS, NULL, NULL, \
            "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
            __func__\
            _NM_UTILS_MACRO_REST (__VA_ARGS__))
            */


/*****************************************************************************/

/*
typedef enum E_KylinCfgDataType{
    KEYLIN_CFG_VARIANT= 0, //通用数据
    KEYLIN_CFG_USER,//用户自定义
}e_KylinCfgDataType;//networkmanager的枚举声明不能放到头文件中，全部通过html定义此处只能在c中再声明一次
*/



enum KYLIN_PARSE_TYPE{
	KYLIN_PARSE_D2R= 0,  //DBUS TO REAL
	KYLIN_PARSE_R2D= 1,//DBUS TO REAL

};

typedef struct ST_NtCtDbusParm
{
   char* modName;
   char* ruleName;
   void* data;
   int (*fromDbusCb) (void *dbusParm,void **realParm);//转换协议
   int (*toDbusCb) (void **dbusParm,void *realParm);//转换协议
   char* nmName;
   char* setingName;
   char* extendLabel;//拓展标识
}st_NtCtDbusParm;



int real2DbusCommonBool(void **dbusParm,void *realParm);
int realFromDbusCommonBool(void *dbusParm,void **realParm);


/*一个管控规则对应networkmanager几个配置项*/
st_NtCtDbusParm gNtCtDbusParm[]=
{
  {"IPV4","netIPV4ModifyCtrol",NULL,realFromDbusCommonBool,real2DbusCommonBool,"ipv4","addresses","ipaddr"},//IPV4模块的修改管控
  {"IPV6","netIPV6ModifyCtrol",NULL,realFromDbusCommonBool,real2DbusCommonBool,"ipv6","addresses","ipaddr"},//IPV6模块的修改管控
  {"DNS","netIPV4DNSModifyCtrol",NULL,realFromDbusCommonBool,real2DbusCommonBool,"ipv4","dns",""},//DNS模块的修改管控
  {"DNS","netIPV6DNSModifyCtrol",NULL,realFromDbusCommonBool,real2DbusCommonBool,"ipv6","dns",""},//DNS模块的修改管控
  {"Connect","netWireWirelessSyncConnectCtrol",NULL,realFromDbusCommonBool,real2DbusCommonBool,"Connect","netWireWirelessSyncConnectCtrol"},//连接模块的同时多连接管控（双跨管控）networkmanager没有对应配置
  {"IPV4","netMaskModifyCtrol",NULL,realFromDbusCommonBool,real2DbusCommonBool,"ipv4","addresses","ipmask"},//IPV4模块的掩码修改管控
  {"IPV4","netGwModifyCtrol",NULL,realFromDbusCommonBool,real2DbusCommonBool,"ipv4","gateway",""},//IPV4模块的网关修改管控
  {"IPV6","netMaskModifyCtrol",NULL,realFromDbusCommonBool,real2DbusCommonBool,"ipv6","addresses","ipmask"},//IPV4模块的掩码修改管控
  {"IPV6","netGwModifyCtrol",NULL,realFromDbusCommonBool,real2DbusCommonBool,"ipv6","gateway",""},//IPV4模块的网关修改管控
  {"LOG","netMonitorEnable",NULL,realFromDbusCommonBool,real2DbusCommonBool,"","",""},//网络ip gw等变化上报使能
};


st_ItemCfgInfo gItemCfgInfo[]=
{
  {"IPV4","netIPV4ModifyCtrol",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//IPV4模块的修改管控
  {"IPV6","netIPV6ModifyCtrol",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//IPV6模块的修改管控
  {"DNS","netIPV4DNSModifyCtrol",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//DNS模块的修改管控
  {"DNS","netIPV6DNSModifyCtrol",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//DNS模块的修改管控
  {"Connect","netWireWirelessSyncConnectCtrol",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//连接模块的同时多连接管控（双跨管控）networkmanager没有对应配置
  {"IPV4","netMaskModifyCtrol",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//IPV4模块的掩码修改管控
  {"IPV4","netGwModifyCtrol",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//IPV4模块的网关修改管控
  {"IPV6","netMaskModifyCtrol",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//IPV6模块的掩码修改管控
  {"IPV6","netGwModifyCtrol",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//IPV6模块的网关修改管控
  {"LOG","netMonitorEnable",NULL,KEYLIN_CFG_VARIANT,NULL,NULL,NULL,NULL},//网络ip gw等变化上报使能
};

typedef struct ST_KylinNtCtInfor 
{
	GDBusProxy *proxy;
	KYLIN_CFG_HANDLE cfgHandle;
	guint timeoutId;
	int isHedron;

}st_KylinNtCtInfor;

st_KylinNtCtInfor gKylinNtCtInfor;

static gboolean timeoutCheckIsHedron(void *data)
{
	char backStr[1024]={0};
	static int count=0;
	st_KylinNtCtInfor *pKylinNtCtInfor=(st_KylinNtCtInfor *)data;
	if(!pKylinNtCtInfor)
	{
		return G_SOURCE_REMOVE;
	}
	if(!kylinExeSystemCmd("ps -ef | grep '[u]sr/bin/hedron-client' | awk  '{print $2}' ",backStr))//域控是Python脚本需要grep搜关键字pgrep root权限值不一样
	{
		if(backStr[0])
		{
			pKylinNtCtInfor->isHedron=1;
			KYLIN_COMMON_LOG(_LOGK_DEBUG, "find %d %s",count,backStr);
			return G_SOURCE_REMOVE;//找到就终止
		}
	}
	count++;
	
	KYLIN_COMMON_LOG(_LOGK_DEBUG, "count is %d %s",count,backStr);
	if(count>20) 
    {
      KYLIN_COMMON_LOG(_LOGK_DEBUG, "stop count is %d",count);
      return G_SOURCE_REMOVE;
	}

	return G_SOURCE_CONTINUE;
}

int kylinNetCtrolCheckIsHedron(void)
{
	return gKylinNtCtInfor.isHedron;
}


int kylinNetCtrolSendLog(int errcode,int type,char * message)//同步调用
{

   GDBusProxy *proxy=NULL;
	GVariant *result;
	GError *error = NULL;

	int res = 0;

	KYLIN_COMMON_LOG(_LOGK_ERR, "send errcode%d,type%d, message:%s",errcode,type,message);

	proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,G_DBUS_PROXY_FLAGS_NONE,NULL,
										    KYLIN_NETCTR_DBUS_SERVICE,	  
							  				KYLIN_NETCTR_DBUS_PATH,							 
							  				KYLIN_NETCTR_DBUS_INTERFACE, 
										   NULL, &error);

	CHECK_POINTER_NULL(proxy);
	result = g_dbus_proxy_call_sync (proxy,
								  "sendNetCtrLog",
								  g_variant_new ("(iis)",errcode,type,message),
								  G_DBUS_CALL_FLAGS_NONE, KYLIN_NC_DBUS_MAX_TIMEMS,
								  NULL, &error);
	if (!result) {
		g_dbus_error_strip_remote_error (error);
		KYLIN_COMMON_LOG (_LOGK_ERR,"Error send log failed,%s", error->message);
		g_clear_error (&error);
		goto out;
	}

	if(g_variant_is_of_type(result, G_VARIANT_TYPE_INT32))
	{
		g_variant_get(result, "(&i)",&res );
		KYLIN_COMMON_LOG(_LOGK_DEBUG, "recv back %d!",res);
	}

out:
	if (result) g_variant_unref (result);
	g_object_unref (proxy);

	return COMMON_SUCCESS;
}




int real2DbusCommonBool(void **dbusParm,void *realParm)
{
	GVariant ** dbusValue=NULL;

	dbusValue=(GVariant **)dbusParm;
	*dbusValue=g_variant_new_boolean(*(gboolean *)realParm);

	return 0;
}

int realFromDbusCommonBool(void *dbusParm,void **realParm)
{
	gboolean *boolArray = g_new(gboolean, 1);
	if(!g_variant_is_of_type (dbusParm,G_VARIANT_TYPE_BOOLEAN))
	{
		KYLIN_COMMON_LOG(_LOGK_ERR, "not bool!");
		g_free(boolArray);
		*realParm=NULL;
		return -1;
	}
	*boolArray=g_variant_get_boolean(dbusParm);
	*realParm=boolArray;
	return 0;
}



// 信号处理函数
void kylinNetCtrolRuleChangeCb(GDBusProxy *proxy,char *modName,GVariant *parameters, gpointer user_data) 
{
	GVariantIter iter;
	const char *ruleName=NULL;
	GVariant *ruleValue=NULL;

	KYLIN_COMMON_LOG(_LOGK_INFO, "receive change single modName:%s!",modName);
	if(!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("a{sv}")))
	{
		KYLIN_COMMON_LOG(_LOGK_ERR, "not expect type,but %s!",g_variant_get_type_string(parameters));
		return;
	}

	g_variant_iter_init (&iter, parameters);

	while (g_variant_iter_next (&iter, "{sv}", &ruleName, &ruleValue)) 
	{
		kylinNetCtrolSetRuleValue(modName,(char *)ruleName,ruleValue);
		KYLIN_COMMON_LOG(_LOGK_INFO, " change single ruleName:%s!",ruleName);
	}
	//kylinNetCtrolSendLog(NETCT_SUCCESS,1,modName);//域控日志上报暂不需要上报配置动作
	return ;
}

static void dbusReadyCb (GObject *object,GAsyncResult *res,st_KylinNtCtInfor *pKylinNtCtInfor)
{
	GError *error = NULL;

	pKylinNtCtInfor->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
	if (!pKylinNtCtInfor->proxy ) 
	{
		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
			KYLIN_COMMON_LOG (_LOGK_ERR,"failed to acquire D-Bus proxy: %s",error->message);
		g_clear_error (&error);
		return;
	}


	_nm_dbus_proxy_signal_connect (pKylinNtCtInfor->proxy, "sigNetContrlRuleChanged", G_VARIANT_TYPE ("(sa{sv})"),
	                                          G_CALLBACK (kylinNetCtrolRuleChangeCb), pKylinNtCtInfor);
	KYLIN_COMMON_LOG(_LOGK_INFO, "kylin net ctrl dbus ready!");


}

int fristCreatCfgInfo()
{
    int cnt=sizeof(gItemCfgInfo)/sizeof(st_ItemCfgInfo);
    int i=0;
    st_ItemCfgInfo *pItemCfgInfo=NULL;
    for(i=0;i<cnt;i++)
    {
        pItemCfgInfo=&gItemCfgInfo[i];
       if(pItemCfgInfo->dataType==KEYLIN_CFG_VARIANT)
        {
            st_ItemCfgInfo * pItemNewCfgInfo=kylinCfgNewCommonItem(pItemCfgInfo->modName,pItemCfgInfo->itemName,(void *)g_variant_new_boolean(false));
            kylinCfgSetItem(gKylinNtCtInfor.cfgHandle,pItemNewCfgInfo);
        }
        else
        {
            // 其他类型TODO
             return -1;
        }
    }
    return 0;
}


int kylinNetCtrolInitCfg()
{
	gKylinNtCtInfor.cfgHandle=kylinCfgCreate();
	if(!gKylinNtCtInfor.cfgHandle)
	{
		return COMMON_DO_FAILED;
	}

	if(kylinCfgLoad(gKylinNtCtInfor.cfgHandle,KYLIN_NETCTROL_CFG_PATH)==COMMON_FILE_NOT_EXIST)
	{
		 fristCreatCfgInfo();
		 //kylinCfgFlush(gKylinNtCtInfor.cfgHandle);//配置文件在dbus服务端刷合理点
	}
	kylinCfgShow(gKylinNtCtInfor.cfgHandle);
	return COMMON_SUCCESS;
}


int kylinNetCtrolInit ()
{

	g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
	                          G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
	                          NULL,
	                          KYLIN_NETCTR_DBUS_SERVICE,
	                          KYLIN_NETCTR_DBUS_PATH,
	                          KYLIN_NETCTR_DBUS_INTERFACE,
	                          g_cancellable_new (),
	                          (GAsyncReadyCallback) dbusReadyCb,
	                          &gKylinNtCtInfor);


	
	if(kylinNetCtrolInitCfg())
	{
		KYLIN_COMMON_LOG(_LOGK_INFO, "kylin net ctrl init cfg failed!");
		return COMMON_DO_FAILED;
	}
	
	gKylinNtCtInfor.timeoutId = g_timeout_add_seconds (15, timeoutCheckIsHedron, &gKylinNtCtInfor);//域控临时方案检测域控程序是否运行。检测20次后退出

	
	KYLIN_COMMON_LOG(_LOGK_INFO, "kylin net ctrl success!");
	return 0;

}


void* kylinNetCtrolGetNmRuleValue(char * nmName,char * setingName,char * extendLabel)
{
	int cnt=0,i=0;	
	GHashTable * ruleHash=NULL;
	void * bakValue=NULL;
	st_NtCtDbusParm *pTempNtCtDbusParm=NULL;
	st_ItemCfgInfo * pItemCfgInfo=NULL;

	if(!nmName || !setingName)
	{
		KYLIN_COMMON_LOG(_LOGK_ERR, "modName or ruleName is null!");
		return NULL;
	}

	KYLIN_COMMON_LOG(_LOGK_INFO, "nmName:%s setingName:%s extendLabel:%s!",nmName,setingName,extendLabel? extendLabel:"none");
	cnt=sizeof(gNtCtDbusParm)/sizeof(st_NtCtDbusParm);
	for(i=0;i<cnt;i++)
	{
		pTempNtCtDbusParm=&gNtCtDbusParm[i];
		if(strcmp(pTempNtCtDbusParm->nmName,nmName)==0 && strcmp(pTempNtCtDbusParm->setingName,setingName)==0)
		{
			/*拓展标识存在意味着同一个配置对应几个不同的管控规则，此时需要根据拓展标识来定位管控规则*/
			if(extendLabel && strcmp(pTempNtCtDbusParm->extendLabel,extendLabel))
			{
				continue;
			}
			pItemCfgInfo=kylinCfgGetItem(gKylinNtCtInfor.cfgHandle,pTempNtCtDbusParm->modName,pTempNtCtDbusParm->ruleName);
			if(!pItemCfgInfo) 
			{
				return NULL;
			}
			pTempNtCtDbusParm->fromDbusCb(pItemCfgInfo->data,&bakValue);
			return (bakValue);
		}
	}	
	KYLIN_COMMON_LOG(_LOGK_ERR, "cant find nmName:%s setingName:%s!",nmName,setingName);
	return NULL;
}

void * kylinNetCtrolGetRuleValue(char * modName,char * ruleName)
{
	GHashTable * ruleHash=NULL;

	if(!modName || !ruleName)
	{
		KYLIN_COMMON_LOG(_LOGK_ERR, "modName or ruleName is null!");
		return NULL;
	}

	return (void *)kylinCfgGetItem(gKylinNtCtInfor.cfgHandle,modName,ruleName);
}


int kylinNetCtrolSetRuleValue(char * modName,char * ruleName,void * value)
{
	GHashTable * ruleHash=NULL;

	if(!modName || !ruleName)
	{
		KYLIN_COMMON_LOG(_LOGK_ERR, "modName or ruleName is null!");
		return -1;
	}
	
	st_ItemCfgInfo *pItemCfgInfo=kylinCfgNewCommonItem(modName,ruleName,(GVariant *)value);


	return kylinCfgSetItem(gKylinNtCtInfor.cfgHandle,pItemCfgInfo);
}


void* kylinNetCtrolCheckRuleValue(char * modName,void * ruleName)
{

	return NULL;
}




