#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "hlist.h"
#include "user_hashtable.h"
#include "user_auth.h"


extern USER_AUTH_LIST g_user_auth_ret_table[] ;

/*链表全局变量 */
struct hlist_head *hash;
USER_INFO *pNode ;


/*计算hash值 */
struct hlist_head * call_hash(struct hlist_head *hash, uint32_t ip)
{
  unsigned int val = ip % 100;
  printf("val =%d\n", val);
  return &hash[val];
}


/*初始化函数 */
int Init_hash()
{
  int i = 0;

  /*创建hash头 */
  hash = (struct hlist_head*)malloc(sizeof(*hash)*100);
  if(NULL == hash)
  {
    printf("alloc error\n");
    return -1;
  }
  
  /*初始化hash表头 */
  for(i = 0; i < 100; i++)
  INIT_HLIST_HEAD(&hash[i]);


  /*hsah桶普通节点分配内存 */
  pNode = (struct user_info *)malloc(sizeof(struct user_info));
  if (NULL == pNode)
  {
    printf("alloc error\n");
    return -1;
  }
 
  /*初始化hash桶的普通结点 */
  memset(pNode,0,sizeof(struct user_info));
  INIT_HLIST_NODE(&pNode->hnode);
}


/*查找用户信息*/
USER_INFO * ufind_user(uint32_t user_ip)
{  

  struct hlist_node *p = NULL, *n = NULL ;

  /* 这个实际上就是一个for循环,从头到尾遍历链表。
  * pos:struct hlist_node类型的一个指针;
  * n:struct hlist_node类型的一个指针;
  * head:struct hlist_head类型的一个指针,表示hlist链表的头结点。
  */ 

  hlist_for_each_safe(p,n,call_hash(hash,user_ip))
  {

    /* p:表示struct hlist_node类型的一个地址。
    * struct user_info:结构体名
    * hnode:type结构体中的hlist_node成员变量的名称
    * 表示得到p所指地址的这个结构体的首地址
    */
    pNode = hlist_entry(p, struct user_info ,hnode);
    if(pNode != NULL)
    printf("[%ld %s %d %d %ld %ld %d]\n",pNode->auth_user.user_ip, pNode->auth_user.user_name, pNode->auth_user.user_id,
                  pNode->auth_user.group_id, pNode->auth_user.message_num,pNode->auth_user.byte_num, pNode->auth_user.online_time);
    return pNode;
  }
}


/*增加用户信息*/
int uadd_user(uint32_t user_ip, char *name, int user_id, int group_id, uint64_t message_num, uint64_t byte_num, time_t online_time)
{
  struct hlist_node *pos = NULL, *n = NULL ;

  pNode = NULL;
  struct hlist_head* pVal = call_hash(hash, user_ip);
  printf("pVal = %p, pVal->first = %p\n", pVal, pVal->first);

  //hlist_for_each_safe(p,n,call_hash(hash, user_ip))  /*查找ip是否存在hash表中 */
  for (pos = pVal->first; pos && ({ n = pos->next; 1; }); pos = n)
  { 
    pNode = hlist_entry(pos, struct user_info ,hnode);
    if(pNode != NULL)
      printf("IP ALEADY EXISTED\n");
  }

  if (pNode == NULL)
    { 
      pNode = (struct user_info *)malloc(sizeof(struct user_info));
      if (NULL == pNode)
      {
        return -1;
      }
      memset(pNode,0,sizeof(struct user_info));
      INIT_HLIST_NODE(&pNode->hnode);
      pNode->auth_user.user_ip = user_ip;
      hlist_add_head(&pNode->hnode, call_hash(hash, user_ip));
    }
   
  memcpy(pNode->auth_user.user_name, name, sizeof(char) * 32);
  pNode->auth_user.user_id = user_id;
  pNode->auth_user.group_id = group_id;
  pNode->auth_user.message_num = message_num;
  pNode->auth_user.byte_num = byte_num;
  pNode->auth_user.online_time = online_time;
 
}

/*删除用户信息 */
void udelete_user(int user_ip)
{
 
  struct hlist_node *p = NULL, *n = NULL ;
  int i = 0;
  unsigned short check_id;

  hlist_for_each_safe(p,n,call_hash(hash,user_ip))
  {  
    pNode = hlist_entry(p, struct user_info ,hnode);

    /*查找用户ID,确认ID是否存在 */
    check_id = g_user_auth_ret_table[pNode->auth_user.user_id].group_id;
    if(check_id != NULL)
    {
      hlist_del(&pNode->hnode);
    }
    
    #if 0
    if(pNode != NULL)
    {
      hlist_del(&pNode->hnode);
    }
    #endif

    free(pNode);
  }
}

/*删除所有的hash节点 */
void udelete_all()
{ 
  struct hlist_node *p = NULL, *n = NULL ;
  int i = 0;

  for(i = 0; i < 100; i++)
  {
    hlist_for_each_safe(p,n,&hash[i])
    {  
      pNode = hlist_entry(p, struct user_info ,hnode);
      hlist_del(&pNode->hnode);
      free(pNode);
    }
  }
}

/*打印所有信息信息 */
void uprintf_users()
{
  struct hlist_node *p = NULL, *n = NULL ;
  int i = 0;

  for(i = 0; i < 100; i++)
  {
    hlist_for_each_safe(p,n,&hash[i])
    {  
      char str[32];
      pNode = hlist_entry(p, struct user_info ,hnode);
      if(pNode != NULL)
        inet_ntop(AF_INET, (void *)&(pNode->auth_user.user_ip), str, 32);
        printf("[%s %s %d %d %ld %ld %d]\n", str, pNode->auth_user.user_name, pNode->auth_user.user_id,
                  pNode->auth_user.group_id, pNode->auth_user.message_num,pNode->auth_user.byte_num, pNode->auth_user.online_time);
    }
  }
}