/*
		                  LCRZO
                             Network library
             Copyright(c) 1999,2000,2001,2002 Laurent Constantin
                                  -----

  Main server    : http://www.laurentconstantin.com/
  Backup servers : http://go.to/laurentconstantin/
                   http://laurentconstantin.est-la.com/
                   http://laurentconstantin.free.fr/
                   http://lauconstantin.multimania.com/
  [my current email address is on the web servers]

                                  -----
  This file is part of Lcrzo.

  Lcrzo is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  Lcrzo is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details (http://www.gnu.org).

------------------------------------------------------------------------
*/

/* -- Note about comments and variable names --
   In versions 1.00 up to 2.08, lcrzo was only written in French (my
   mother tongue). Since version 3.00, lcrzo is written in English, but
   most of comments and variable names are still in French.
   In future versions, I'll try to translate everything into English,
   but as you may guess, that's a quite big work...
   So, for the moment, here are some word translation, if you want to
   be able to understand what's going on in the functions :
     afficher - print     ;  ajouter - add         ;  copie - copy
     dernier - last       ;  donnee - data         ;  ecrire - write
     entete - header      ;  envoye - sent         ;  ferme - close
     fichier - file       ;  lire - read           ;  masque - mask 
     nboct - byte number  ;  ouvre, ouvrir - open  ;  paq, paquet - packet
     plage - range        ;  premier - first       ;  recu - received
     reseau - network     ;  retour - return       ;  taille - size
     tunnel - pipe

*/

#include "lcrzo_incl.h"


/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_time_sleep_sec.c"
#include "sysdep/lcrzo_time_sleep_msec.c"
#include "sysdep/lcrzo_time_sleep_usec.c"
#include "sysdep/lcrzo_time_pause_sec.c"
#include "sysdep/lcrzo_time_pause_msec.c"
#include "sysdep/lcrzo_time_pause_usec.c"

/*-------------------------------------------------------------*/
int lcrzo_time_fprint(LCRZOFILE *pf,
		      const char *startstring,
		      const lcrzo_time *ptime,
		      const char *endstring)
{ 
  /*parameters verification*/
  if (pf==NULL) return(LCRZO_ERR_PANULLPTR);
  if (ptime==NULL) return(LCRZO_ERR_PANULLPTR);

  lcrzo_er(lcrzo_uint32_fprint(pf, startstring, ptime->sec, "%u", "s"));
  lcrzo_er(lcrzo_uint32_fprint(pf, ":", ptime->usec, "%u", "us"));
  if (endstring!=NULL) fprintf(pf, "%s", endstring);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_time_init_currenttime.c"

/*-------------------------------------------------------------*/
int lcrzo_time_init_sec(lcrzo_uint32 sec,
			lcrzo_time *ptime)
{ return(lcrzo_time_init_secmsecusec(sec, 0, 0, ptime));
}

/*-------------------------------------------------------------*/
int lcrzo_time_init_msec(lcrzo_uint32 msec,
			 lcrzo_time *ptime)
{ return(lcrzo_time_init_secmsecusec(0, msec, 0, ptime));
}

/*-------------------------------------------------------------*/
int lcrzo_time_init_usec(lcrzo_uint32 usec,
			 lcrzo_time *ptime)
{ return(lcrzo_time_init_secmsecusec(0, 0, usec, ptime));
}

/*-------------------------------------------------------------*/
int lcrzo_time_init_secusec(lcrzo_uint32 sec,
			    lcrzo_uint32 usec,
			    lcrzo_time *ptime)
{ return(lcrzo_time_init_secmsecusec(sec, 0, usec, ptime));
}

/*-------------------------------------------------------------*/
int lcrzo_time_init_secmsec(lcrzo_uint32 sec,
			    lcrzo_uint32 msec,
			    lcrzo_time *ptime)
{ return(lcrzo_time_init_secmsecusec(sec, msec, 0, ptime));
}

/*-------------------------------------------------------------*/
int lcrzo_time_init_msecusec(lcrzo_uint32 msec,
			     lcrzo_uint32 usec,
			     lcrzo_time *ptime)
{ return(lcrzo_time_init_secmsecusec(0, msec, usec, ptime));
}

/*-------------------------------------------------------------*/
int lcrzo_time_init_secmsecusec(lcrzo_uint32 sec,
				lcrzo_uint32 msec,
				lcrzo_uint32 usec,
				lcrzo_time *ptime)
{ lcrzo_uint32 _sec, _usec;
  lcrzo_uint32 msec2usec, msec2sec, usec2usec, usec2sec, secsum;

  /* convert usec */
  if ( usec<=999999 )
  { usec2sec=0;
    usec2usec=usec;
  }
  else
  { usec2sec=usec/1000000;
    usec2usec=usec - 1000000*usec2sec;
  }
  /* usec2usec : [0..999999] */
  /* usec2sec :  [0..2^32/1000000]=[0..4294] */
  /*printf("usec2usec=%ld\t usec2sec=%ld\n", usec2usec, usec2sec);*/

  /* convert msec */
  if ( msec<=999 )
  { msec2sec=0;
    msec2usec=msec*1000;
  }
  else
  { msec2sec=msec/1000;
    msec2usec=1000*(msec - 1000*msec2sec);
  }
  /* msec2usec : [0..999999] */
  /* msec2sec :  [0..2^32/1000]=[0..4294967] */
  /*printf("msec2usec=%ld\t msec2sec=%ld\n", msec2usec, msec2sec);*/

  /* compute _usec=usec2usec+msec2usec */
  _usec=usec2usec+msec2usec;
  if ( _usec>999999 )
  { usec2sec++; /* overflow */
    _usec-=1000000;
  }
  
  /* usec2sec :  [0..4294+1]=[0..4295] */
  /*printf("_usec=%ld\t usec2sec=%ld\n", _usec, usec2sec);*/

  /* precompute sum for seconds */
  secsum=usec2sec+msec2sec;
  /* secsum : [0..4295+4294967]=[0..4299262] */
  /*printf("secsum=%ld\n", secsum);*/

  /* compute _sec=secsum+sec */
  if ( 0xFFFFFFFFu-sec<secsum )
  { /* overflow */
    return(LCRZO_ERR_SPTIMETIMEOVER);
  }
  _sec=secsum+sec;
  /*printf("_sec=%ld\n", _sec);*/

  /* store values */
  if (ptime!=NULL)
  { ptime->sec=_sec;
    ptime->usec=_usec;
  }
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_init_time(const lcrzo_time *ptimein,
			 lcrzo_time *ptimeout)
{ 
  /* parameters verification */
  if (ptimein==NULL) return(LCRZO_ERR_PANULLPTR);

  /* store values */
  if (ptimeout!=NULL)
  { ptimeout->sec=ptimein->sec;
    ptimeout->usec=ptimein->usec;
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_get_sec(const lcrzo_time *ptime,
		       lcrzo_uint32 *psec)
{ 
  /* parameters verification */
  if (ptime==NULL) return(LCRZO_ERR_PANULLPTR);

  /* store values */
  if (psec!=NULL) *psec=ptime->sec;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_get_msec(const lcrzo_time *ptime,
			lcrzo_uint32 *pmsec)
{ 
  /* parameters verification */
  if (ptime==NULL) return(LCRZO_ERR_PANULLPTR);

  if ( ptime->sec>4294967 ) return(LCRZO_ERR_SPTIMEMSECOVER);
  if ( ptime->sec==4294967 && ptime->usec>295999 )
    return(LCRZO_ERR_SPTIMEMSECOVER);

  /* store values */
  if (pmsec!=NULL) *pmsec= 1000*ptime->sec + ptime->usec/1000;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_get_usec(const lcrzo_time *ptime,
			lcrzo_uint32 *pusec)
{ 
  /* parameters verification */
  if (ptime==NULL) return(LCRZO_ERR_PANULLPTR);

  if ( ptime->sec>4294 ) return(LCRZO_ERR_SPTIMEUSECOVER);
  if ( ptime->sec==4294 && ptime->usec>967295 )
    return(LCRZO_ERR_SPTIMEUSECOVER);

  /* store values */
  if (pusec!=NULL) *pusec= 1000000*ptime->sec + ptime->usec;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_get_secusec(const lcrzo_time *ptime,
			   lcrzo_uint32 *psec,
			   lcrzo_uint32 *pusec)
{ 
  /* parameters verification */
  if (ptime==NULL) return(LCRZO_ERR_PANULLPTR);

  /* store values */
  if (psec!=NULL) *psec=ptime->sec;
  if (pusec!=NULL) *pusec=ptime->usec;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_get_secmsec(const lcrzo_time *ptime,
			   lcrzo_uint32 *psec,
			   lcrzo_uint32 *pmsec)
{ 
  /* parameters verification */
  if (ptime==NULL) return(LCRZO_ERR_PANULLPTR);

  /* store values */
  if (psec!=NULL) *psec=ptime->sec;
  if (pmsec!=NULL) *pmsec=ptime->usec/1000;
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_get_msecusec(const lcrzo_time *ptime,
			    lcrzo_uint32 *pmsec,
			    lcrzo_uint32 *pusec)
{ 
  /* parameters verification */
  if (ptime==NULL) return(LCRZO_ERR_PANULLPTR);

  if ( ptime->sec>4294967 ) return(LCRZO_ERR_SPTIMEMSECOVER);
  if ( ptime->sec==4294967 && ptime->usec>295999 )
    return(LCRZO_ERR_SPTIMEMSECOVER);

  /* store values */
  if (pmsec!=NULL) *pmsec= 1000*ptime->sec + ptime->usec/1000;
  if (pusec!=NULL) *pusec=ptime->usec-1000*(ptime->usec/1000);
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_get_secmsecusec(const lcrzo_time *ptime,
			       lcrzo_uint32 *psec,
			       lcrzo_uint32 *pmsec,
			       lcrzo_uint32 *pusec)
{ 
  /* parameters verification */
  if (ptime==NULL) return(LCRZO_ERR_PANULLPTR);

  /* store values */
  if (psec!=NULL)  *psec=  ptime->sec;
  if (pmsec!=NULL) *pmsec= ptime->usec/1000;
  if (pusec!=NULL) *pusec= ptime->usec-1000*(ptime->usec/1000);
  return(LCRZO_ERR_OK);
}


/*-------------------------------------------------------------*/
int lcrzo_time_plus_sec(const lcrzo_time *ptime,
			lcrzo_uint32 sec,
			lcrzo_time *presulttime)
{ lcrzo_time tmptime;

  lcrzo_er(lcrzo_time_init_sec(sec, &tmptime));
  lcrzo_er(lcrzo_time_plus_time(ptime, &tmptime, presulttime));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_plus_msec(const lcrzo_time *ptime,
			 lcrzo_uint32 msec,
			 lcrzo_time *presulttime)
{ lcrzo_time tmptime;

  lcrzo_er(lcrzo_time_init_msec(msec, &tmptime));
  lcrzo_er(lcrzo_time_plus_time(ptime, &tmptime, presulttime));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_plus_usec(const lcrzo_time *ptime,
			 lcrzo_uint32 usec,
			 lcrzo_time *presulttime)
{ lcrzo_time tmptime;

  lcrzo_er(lcrzo_time_init_usec(usec, &tmptime));
  lcrzo_er(lcrzo_time_plus_time(ptime, &tmptime, presulttime));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_plus_time(const lcrzo_time *ptime1,
			 const lcrzo_time *ptime2,
			 lcrzo_time *presulttime)
{ lcrzo_time resulttime;
  lcrzo_uint32 usecsum, secsum;

  if (ptime1==NULL) return(LCRZO_ERR_PANULLPTR);
  if (ptime2==NULL) return(LCRZO_ERR_PANULLPTR);

  /* compute microseconds */
  usecsum=ptime1->usec+ptime2->usec;
  if ( usecsum>999999 )
    resulttime.sec = usecsum/1000000;
  else
    resulttime.sec=0;
  resulttime.usec = usecsum - 1000000*resulttime.sec;

  /* compute seconds */
  secsum=ptime1->sec+resulttime.sec;
  if ( secsum<ptime1->sec || secsum<resulttime.sec )
    return(LCRZO_ERR_SPTIMETIMEOVER);
  resulttime.sec=secsum;
  secsum=ptime2->sec+resulttime.sec;
  if ( secsum<ptime2->sec || secsum<resulttime.sec )
    return(LCRZO_ERR_SPTIMETIMEOVER);
  resulttime.sec=secsum;

  /* set result */
  if (presulttime!=NULL)
  { presulttime->sec=resulttime.sec;
    presulttime->usec=resulttime.usec;
  }

  return(LCRZO_ERR_OK);
}


/*-------------------------------------------------------------*/
int lcrzo_time_minus_sec(const lcrzo_time *ptime,
			 lcrzo_uint32 sec,
			 lcrzo_time *presulttime)
{ lcrzo_time tmptime;

  lcrzo_er(lcrzo_time_init_sec(sec, &tmptime));
  lcrzo_er(lcrzo_time_minus_time(ptime, &tmptime, presulttime));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_minus_msec(const lcrzo_time *ptime,
			  lcrzo_uint32 msec,
			  lcrzo_time *presulttime)
{ lcrzo_time tmptime;

  lcrzo_er(lcrzo_time_init_msec(msec, &tmptime));
  lcrzo_er(lcrzo_time_minus_time(ptime, &tmptime, presulttime));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_minus_usec(const lcrzo_time *ptime,
			  lcrzo_uint32 usec,
			  lcrzo_time *presulttime)
{ lcrzo_time tmptime;

  lcrzo_er(lcrzo_time_init_usec(usec, &tmptime));
  lcrzo_er(lcrzo_time_minus_time(ptime, &tmptime, presulttime));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_minus_time(const lcrzo_time *ptime1,
			  const lcrzo_time *ptime2,
			  lcrzo_time *presulttime)
{ lcrzo_uint32 usec, sec;

  if (ptime1==NULL) return(LCRZO_ERR_PANULLPTR);
  if (ptime2==NULL) return(LCRZO_ERR_PANULLPTR);

  /* negative difference */
  if ( ptime1->sec < ptime2->sec ) return(LCRZO_ERR_SPTIMEDIFFNEG);
  if ( ptime1->sec == ptime2->sec && ptime1->usec < ptime2->usec )
    return(LCRZO_ERR_SPTIMEDIFFNEG);

  /* compute */
  if ( ptime1->usec >= ptime2->usec )
  { sec =  ptime1->sec  - ptime2->sec;
    usec = ptime1->usec - ptime2->usec;
  }
  else
  { sec =  ptime1->sec  - ptime2->sec  -1 ;
    usec = ptime1->usec - ptime2->usec +1000000;
  }

  /* set result */
  if (presulttime!=NULL)
  { presulttime->sec=sec;
    presulttime->usec=usec;
  }

  return(LCRZO_ERR_OK);
}


/*-------------------------------------------------------------*/
int lcrzo_time_diffcurrent_sec(const lcrzo_time *ptime,
			       lcrzo_uint32 *psec)
{ lcrzo_time currenttime, tmptime;

  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_minus_time(&currenttime, ptime, &tmptime));
  lcrzo_er(lcrzo_time_get_sec(&tmptime, psec));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_diffcurrent_msec(const lcrzo_time *ptime,
				lcrzo_uint32 *pmsec)
{ lcrzo_time currenttime, tmptime;

  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_minus_time(&currenttime, ptime, &tmptime));
  lcrzo_er(lcrzo_time_get_msec(&tmptime, pmsec));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_diffcurrent_usec(const lcrzo_time *ptime,
				lcrzo_uint32 *pusec)
{ lcrzo_time currenttime, tmptime;

  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_minus_time(&currenttime, ptime, &tmptime));
  lcrzo_er(lcrzo_time_get_usec(&tmptime, pusec));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_diffcurrent_secusec(const lcrzo_time *ptime,
				   lcrzo_uint32 *psec,
				   lcrzo_uint32 *pusec)
{ lcrzo_time currenttime, tmptime;

  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_minus_time(&currenttime, ptime, &tmptime));
  lcrzo_er(lcrzo_time_get_secusec(&tmptime, psec, pusec));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_diffcurrent_secmsec(const lcrzo_time *ptime,
				   lcrzo_uint32 *psec,
				   lcrzo_uint32 *pmsec)
{ lcrzo_time currenttime, tmptime;

  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_minus_time(&currenttime, ptime, &tmptime));
  lcrzo_er(lcrzo_time_get_secmsec(&tmptime, psec, pmsec));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_diffcurrent_msecusec(const lcrzo_time *ptime,
				    lcrzo_uint32 *pmsec,
				    lcrzo_uint32 *pusec)
{ lcrzo_time currenttime, tmptime;

  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_minus_time(&currenttime, ptime, &tmptime));
  lcrzo_er(lcrzo_time_get_msecusec(&tmptime, pmsec, pusec));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_diffcurrent_secmsecusec(const lcrzo_time *ptime,
				       lcrzo_uint32 *psec,
				       lcrzo_uint32 *pmsec,
				       lcrzo_uint32 *pusec)
{ lcrzo_time currenttime, tmptime;

  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_minus_time(&currenttime, ptime, &tmptime));
  lcrzo_er(lcrzo_time_get_secmsecusec(&tmptime, psec, pmsec, pusec));
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_time_diffcurrent_time(const lcrzo_time *ptime,
				lcrzo_time *pdifftime)
{ lcrzo_time currenttime;

  lcrzo_er(lcrzo_time_init_currenttime(&currenttime));
  lcrzo_er(lcrzo_time_minus_time(&currenttime, ptime, pdifftime));
  return(LCRZO_ERR_OK);
}
