#include <string.h>
#include <time.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#include <malloc.h>
#else /*_WIN32*/
#include <malloc.h>
#endif /*_WIN32*/
#include "ul_htimer.h"

/*===========================================================*/
/* timing tests */

void timing_test_print(struct timeval *start, struct timeval *stop, char *s)
{
  long sec, usec;
  sec=stop->tv_sec-start->tv_sec;
  usec=stop->tv_usec-start->tv_usec;
  if(usec>=1000000) {
    usec-=1000000;
    sec++;
  }
  if(usec<0) {
    usec+=1000000;
    sec--;
  }
  printf("%s :\t%4ld.%06ld\n",s,sec,usec);
}

void timing_test(void)
{
  int i, r;
  int items_cnt=100000;
  ul_htimer_t *items;
  ul_htimer_t *p;
  ul_htim_time_t cmp_time;
  
  struct timeval time_start, time_stop;

  printf("\nRunning htimer timing test for %d items\n",items_cnt);
  
  items=malloc(items_cnt*sizeof(ul_htimer_t));
  if(!items){
    printf("malloc items failed\n");
    return;
  }
  
  for(i=0;i<items_cnt;i++){
    ul_htimer_init_detached(&items[i]);
    items[i].function=NULL;
    items[i].data=i;
    if(0){
      ul_htimer_set_expire(&items[i],(i&~1)*500);
    }else{
      do{
        r=rand();
      }while((r>0x7fffffff)||(r<0));
      ul_htimer_set_expire(&items[i],r);
    }
  }
  cmp_time=0x7fffffff;
      
  gettimeofday(&time_start,NULL);
  for(i=0;i<items_cnt;i++){
  //for(i=items_cnt;i-->0;){
    if(ul_htimer_add(&ul_root_htimer, items+i)<0)
      printf("ul_htimer_add is buggy\n");
  }
  gettimeofday(&time_stop,NULL);
  timing_test_print(&time_start,&time_stop,"htimer insert");
  
  r=0;
  gettimeofday(&time_start,NULL);
  for(i=0;i<items_cnt;i++){
    if(!(p=ul_htimer_cut_expired(&ul_root_htimer, &cmp_time)))
      printf("ul_htimer_cut_expired NULL\n");
    else{
      if(0){
	if(ul_htimer_get_expire(p)<r)
          printf("ul_htimer_cut_expired returns items in the bad order !!!!!\n");
	r=ul_htimer_get_expire(p);
	ul_htimer_set_expire(p,0);
      }
    }
  }
  gettimeofday(&time_stop,NULL);
  timing_test_print(&time_start,&time_stop,"cut expired");

  free(items);
}

/*===========================================================*/
/* mstimer test */

void test_htimer_fnc(unsigned long data)
{
  char s[30];
  ul_get_log_time_str(s);
  printf("%6ld : ms %8ld real %s\n",data,ul_mstime_last,s);
}

int mstime_test(void)
{
  int i;
  
  for(i=0;i<100;i++){
    ul_htimer_t *timer;
    /*allocate new timer*/
    timer=malloc(sizeof(ul_htimer_t));
    /*ensure, that timer is in detached state*/
    ul_htimer_init_detached(timer);
    timer->function=test_htimer_fnc;
    timer->data=i;
    ul_htimer_set_expire(timer,(i&~1)*500);
    if(ul_htimer_add(&ul_root_htimer, timer)<0)
      printf("ul_htimer_add is buggy\n");
  }
  
  while(1){
    ul_msdiff_t ms_sleep;
    ul_mstime_update();
    ul_htimer_run_expired(&ul_root_htimer,&ul_mstime_last);
    ul_mstime_update();
    ul_compute_mstime_next();
    ms_sleep=ul_mstime_next-ul_mstime_last;
    if(ms_sleep<0) ms_sleep=0;
    /* we do not want to overflow usec field of timeout.tv_usec */
    if(ms_sleep>(~(ul_mstime_t)0/2001)) ms_sleep=~(ul_mstime_t)0/2001;

   #ifdef there_is_something_else_do
    if(ul_inepoll(ul_net->ul_fd)>0){
      int loopcnt=100;
      do {
      ul_net_do_rec_msg(ul_net);
      } while((ul_inepoll(ul_net->ul_fd)>0)&&loopcnt--);
    }else 
   #endif /*there_is_something_else_do*/
    {
    #ifdef WITHOUT_SYS_SELECT
     #ifdef _WIN32
      if(ms_sleep>100) ms_sleep=100;
      Sleep(ms_sleep);
     #elif defined(UL_DRV_IN_LIB)
      if(ms_sleep>100) ms_sleep=100;
      usleep(ms_sleep*1000);
     #endif /* UL_DRV_IN_LIB */
    #else /* !WITHOUT_SYS_SELECT */
      {
	int ret;
	struct timeval timeout;
	fd_set set;

	FD_ZERO (&set);
	/*set ones for all other monitored file handles*/
	/*FD_SET (ul_net->ul_fd, &set);*/
	FD_SET (0, &set);
	timeout.tv_sec = 0;
	timeout.tv_usec = ms_sleep*1000;
	while ((ret=select(FD_SETSIZE,&set, NULL, NULL,&timeout))==-1
        	&&errno==-EINTR);
	/* printf("select %d ",ret); */
        if(FD_ISSET(0,&set))
        { char ch;
          read(0,&ch,1);
          switch(ch) {
            case 'q' : 
              printf("\nUser requested quit\n");
              return 0;
          }
        }
      }
    #endif /* !WITHOUT_SYS_SELECT */
    }
  }
}


int main(int argc, char *argv[])
{
  ul_mstime_init();
  ul_htimer_init_queue(&ul_root_htimer);

  timing_test();
  mstime_test();

  return 0;
}
