/*******************************************************************
 *                  Light Weight Chord Library 1.0                 *
 *  CopyRight(C) Yoshihide Matsumoto IDEON WorkingGroup 2003,2004  *
 *      matsumoto333@yahoo.co.jp (http://www.matchan.mydns.jp)     *
 *                                                                 *
 * Implementation of chord (Distributed Hash Table)                *
 * This program is distributed under GPL                           *
 * Light Weight Chord Library comes with ABSOLUTELY NO WARRANTY.   *
 * This is free software, and you are welcome to redistribute it   *
 * under certain conditions; read `COPYING' for details.           *
 *******************************************************************/

#include <stdio.h>
#include <stdlib.h>

#include "task_list.h"
#include "misc.h"

//-  Queue---Address1->Address2->Address3
//-             |         |
//-          Address1  Address2
//-             |
//-          Address1

//
void task_init(TASKLIST *pnew){
  //listの初期化デフォルト値の設定
  pnew->Type = T_EVENT;
  pnew->Fp = NULL;
  pnew->Data = NULL;
  pnew->Address.Ip = 0;
  pnew->Address.Port = 0;
  pnew->RetransmitCount = 0;
  pnew->SessId = 0;
  pnew->Size = 0;
  pnew->Next.Ip = 0;
  pnew->Next.Port = 0;
  pnew->Ans = 0;
  pnew->Ttl = 0;

  return;

}


//-昇順に並ぶようにインサート
TASKLIST *task_insert(TASKLIST **phead, ADDRESS address){

   TASKLIST *plist, *pnew, *plist_bak;
   plist = *phead;
   
   //エラー処理
   if(address.Ip == 0){
     log(WARNING, "task_insert\n");
      return NULL;
   }
   
   pnew = (TASKLIST *)malloc(sizeof(TASKLIST));
   task_init(pnew);
   
   pnew->Address = address;
   
   //１個目のリストを生成する場合   
   if(*phead == NULL){
     pnew->prev = NULL;
     pnew->next = NULL;
     *phead = pnew;
     return pnew;
   }
   
   //ipまで進める
   while(plist != NULL && plist->Address.Ip <= address.Ip){
     plist_bak = plist;
     plist = plist->next;
   }
   
   //portまで進める
   while(plist != NULL && plist->Address.Port <= address.Port){
     plist_bak = plist;
     plist = plist->next;
   }

   
   if(*phead == plist){
     //先頭に追加
     pnew->prev = NULL;
     pnew->next = plist;
     plist->prev = pnew;
     *phead = pnew;
     
   }else{
     
     //plist_bakの次、中間に追加する場合
     if(plist != NULL){
       plist_bak->next = pnew;
       pnew->prev = plist_bak;
       
       pnew->next = plist;
       plist->prev = pnew;
       
     }else{
       //最後の場合
       plist_bak->next = pnew;
       pnew->prev = plist_bak;
       
       pnew->next = NULL;
       
     }
   }
   
   return pnew;
}

//リストから指定されたポインタのリストを削除
TASKLIST *task_delete(TASKLIST **phead, TASKLIST *pdel){


  TASKLIST *plist;

  //リストが１つの場合
  if(pdel->prev == NULL && pdel->next == NULL){
    free(pdel);
    *phead = NULL;
//    fprintf(stderr,"最後のリストを削除しました\n");

    return NULL;
  }

  //リストが先頭の場合
  if(pdel->prev == NULL){
    pdel->next->prev = NULL;
    plist = pdel->next;
    free(pdel);
    *phead = plist;
    return plist;
  }

  //リストが最後尾の場合
  if(pdel->next == NULL){
    pdel->prev->next = NULL;
    free(pdel);
    return NULL;
  }

  //リストが間の場合
  plist = pdel->next;
  pdel->prev->next = pdel->next;
  pdel->next->prev = pdel->prev;
  free(pdel);

  //削除した次のリストを返す
  return plist;


}


//リストからKEYを元に削除
TASKLIST *task_delete_key(TASKLIST **phead, ADDRESS address){

   TASKLIST *plist, *pbak;
   plist = *phead;
   
   while( plist != NULL && plist->Address.Ip < address.Ip){
      plist = plist->next;
   }
   while( plist != NULL && plist->Address.Port < address.Port){
      plist = plist->next;
   }
   
   while( plist != NULL && plist->Address.Ip == address.Ip 
	  && plist->Address.Port == address.Port){
     //削除した次のリストを返す。ない場合はNULL
     plist = task_delete(phead, plist);
   }
   
   //削除した次のリストを返す
   return plist;
}


TASKLIST *task_search_sequenceno(TASKLIST *plist, int sequenceno){

  TASKLIST *list_local;
  list_local = plist;
   
   while(list_local != NULL && list_local->SeqNo <= sequenceno){

      if(list_local->SeqNo == sequenceno){
	 return list_local;
      }
      
      list_local = list_local->next;
   }
   
   return NULL;


}

//リストからキーの値がいくつ存在するか検索する
//ヒットしない場合は0を返す
TASKLIST *task_search(TASKLIST *plist, ADDRESS address){
  
  TASKLIST *list_local;
  list_local = plist;
  
  
  while(list_local != NULL && list_local->Address.Ip < address.Ip){
    list_local = list_local->next;
  }

  while(list_local != NULL && list_local->Address.Port < address.Port){
    list_local = list_local->next;
  }
  
  if(list_local != NULL && list_local->Address.Ip == address.Ip 
     && list_local->Address.Port == address.Port){
    return list_local;
  }
  
  
  return NULL;
   
}


//リストの数を調べる
int task_size(TASKLIST *plist){

   int count;
   TASKLIST *list_local;
   list_local = plist;

   count = 0;
   while(list_local != NULL){
      count ++;
      list_local = list_local->next;
   }
   
   return count;

}


//リストの一覧表示、デバッグ用
void task_print(TASKLIST **plist){

   int count;
   char buf[32];
   count = 0;
   TASKLIST *list_local;
   list_local = *plist;
   
   while(list_local != NULL){
     ip_to_str(list_local->Address.Ip, buf);
     
     log(NOTICE, "%d:IP=%s:%d,seq=[%d],SessId=%d,func=%d,mcid=%d\n", 
	     count, buf,list_local->Address.Port, list_local->SeqNo, 
	     list_local->SessId, list_local->Func, list_local->McId);
     count++;
     list_local = list_local->next;
   }

}
















