/*
		                  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).

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

#include "lcrzo_incl.h"

/*-------------------------------------------------------------*/
int lcrzo_priv_process_print(lcrzo_conststring desc,
                             lcrzo_process *pprocess);
int lcrzo_priv_process_print(lcrzo_conststring desc,
                             lcrzo_process *pprocess)
{ 
#if defined LCRZODEF_SYSTEM_Unix
  printf("%s: \n", desc);
  lcrzo_uint32_print("", pprocess->processid, "%u", "\n");
#elif defined LCRZODEF_SYSTEM_Windows
  printf("%s: ", desc);
  lcrzo_uint32_print("proc", pprocess->processid, "%08X", ":");
  lcrzo_uint32_print("thr", pprocess->threadid, "%08X", ":");
  printf("thrh%p\n", pprocess->threadhandle);
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_priv_process_print2(lcrzo_conststring desc);
int lcrzo_priv_process_print2(lcrzo_conststring desc)
{ 
#if defined LCRZODEF_SYSTEM_Unix
  printf("%s: \n", desc);
  lcrzo_uint32_print("", getpid(), "%u", "\n");
#elif defined LCRZODEF_SYSTEM_Windows
  printf("%s: ", desc);
  lcrzo_uint32_print("proc", _getpid(), "%08X", ":");
  lcrzo_uint32_print("thr", GetCurrentThreadId(), "%08X", "\n");
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_priv_wait_process_wait.c"
#include "sysdep/lcrzo_priv_wait_process_read.c"


/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
#include "sysdep/lcrzo_process_current_init.c"
#include "sysdep/lcrzo_process_current_exit.c"
#include "sysdep/lcrzo_process_current_priority_set.c"
#include "sysdep/lcrzo_process_current_priority_get.c"

/*-------------------------------------------------------------*/
int lcrzo_process_other_init(int (*pfunc)(void *infos,
					  lcrzo_int32 infossize, 
					  lcrzo_process *pparentprocess),
			     void *infos,
			     lcrzo_int32 infossize,
			     lcrzo_process *pchildprocess)
{ return(lcrzo_process_other_init2(pfunc, infos, infossize, 
				   NULL, NULL, pchildprocess));
}

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

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

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

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


/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
typedef struct
{ lcrzo_int32 index;
  lcrzo_process *pprocess;
} lcrzo_priv_multiprocess;
int lcrzo_priv_multiprocess_erase(void *pelem);
int lcrzo_priv_multiprocess_erase(void *pelem)
{ lcrzo_priv_multiprocess *mp=(lcrzo_priv_multiprocess *)pelem;
  return(lcrzo_data_free((lcrzo_data)mp->pprocess));
}

/*-------------------------------------------------------------*/
int lcrzo_multiprocess_init(lcrzo_multiprocess *pmultiprocess)
{
  /* parameter verification */
  if (pmultiprocess==NULL) return(LCRZO_ERR_PANULLPTR);

  /* initialize the waitlist */
  lcrzo_er(lcrzo_wait_list_init(&pmultiprocess->waitlist));

  /* initialize the process list */
  lcrzo_er(lcrzo_list_init(&pmultiprocess->processlist, sizeof(lcrzo_priv_multiprocess), &lcrzo_priv_multiprocess_erase));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_multiprocess_close(lcrzo_multiprocess *pmultiprocess)
{ lcrzo_priv_multiprocess lpmp;
  lcrzo_int32 i, count;

  /* parameter verification */
  if (pmultiprocess==NULL) return(LCRZO_ERR_PANULLPTR);

  /* kill every stored process */
  lcrzo_er(lcrzo_list_count(&pmultiprocess->processlist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(&pmultiprocess->processlist, i, &lpmp));
    lcrzo_er(lcrzo_process_other_exit(lpmp.pprocess));
  }

  /* wait for the end of each process */
  lcrzo_er(lcrzo_list_count(&pmultiprocess->processlist, &count));
  while( count > 0)
  { lcrzo_er(lcrzo_multiprocess_process_wait_end(pmultiprocess, LCRZO_WAIT_INFINITE,
                                                 NULL, NULL, NULL));
    lcrzo_er(lcrzo_list_count(&pmultiprocess->processlist, &count));
  }

  /* close the waitlist */
  lcrzo_er(lcrzo_list_close(&pmultiprocess->waitlist));

  /* close the process list */
  lcrzo_er(lcrzo_list_close(&pmultiprocess->processlist));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_multiprocess_process_init(lcrzo_multiprocess *pmultiprocess,
                                    lcrzo_int32 processindex,
                                    int (*pfunc)(void *infos,
						 lcrzo_int32 infossize, 
					        lcrzo_process *pparentprocess),
			            void *infos,
                                    lcrzo_int32 infossize)
{ return(lcrzo_multiprocess_process_init2(pmultiprocess,
					  processindex,
					  pfunc, infos, infossize,
					  NULL, NULL));
}

/*-------------------------------------------------------------*/
int lcrzo_multiprocess_process_init2(lcrzo_multiprocess *pmultiprocess,
				     lcrzo_int32 processindex,
				     int (*pfunc)(void *infos, 
						  lcrzo_int32 infossize,
						lcrzo_process *pparentprocess),
				     void *infos,
				     lcrzo_int32 infossize,
			      lcrzo_uint8 (*punixreturn_int2uint8)(int ret),
			      int (*punixreturn_uint82int)(lcrzo_uint8 ret))
{ lcrzo_priv_multiprocess lpmp;
  lcrzo_wait waitend;

  /* parameter verification */
  if (pmultiprocess==NULL) return(LCRZO_ERR_PANULLPTR);

  /* set the structure */
  lpmp.index=processindex;
  lcrzo_er(lcrzo_data_alloc(sizeof(lcrzo_process), 
			    (lcrzo_data *)&lpmp.pprocess));

  /* create the child process */
  lcrzo_er(lcrzo_process_other_init2(pfunc, infos, infossize, 
				     punixreturn_int2uint8,
				     punixreturn_uint82int,
				     lpmp.pprocess));

  /* add it in the process list */
  lcrzo_er(lcrzo_list_add_last(&pmultiprocess->processlist, &lpmp));

  /* create a wait link on it */
  lcrzo_er(lcrzo_wait_init_process_end(lpmp.pprocess, &waitend));
  lcrzo_er(lcrzo_wait_list_add(&pmultiprocess->waitlist, processindex, 
			       &waitend));

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_multiprocess_process_count(lcrzo_multiprocess *pmultiprocess,
                                     lcrzo_int32 *pnumberofprocesses)
{ return(lcrzo_list_count(&pmultiprocess->processlist, pnumberofprocesses));
}

/*-------------------------------------------------------------*/
int lcrzo_multiprocess_process_exit(lcrzo_multiprocess *pmultiprocess,
                                    lcrzo_int32 processindex)
{ lcrzo_priv_multiprocess lpmp;
  lcrzo_int32 i, count;

  /* parameter verification */
  if (pmultiprocess==NULL) return(LCRZO_ERR_PANULLPTR);

  /* kill the process (ignore error if not found) */
  lcrzo_er(lcrzo_list_count(&pmultiprocess->processlist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(&pmultiprocess->processlist, i, &lpmp));
    if (lpmp.index==processindex)
    { lcrzo_er(lcrzo_process_other_exit(lpmp.pprocess));
      break;
    }
  }

  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
int lcrzo_multiprocess_process_wait_end(lcrzo_multiprocess *pmultiprocess,
                                        lcrzo_time *pmaxwaitingtime,
                                        lcrzo_bool *paprocesshasended,
                                        lcrzo_int32 *pindexoftheendedprocess,
                                        int *preturnedvalue)
{ lcrzo_priv_multiprocess lpmp;
  lcrzo_bool event;
  lcrzo_int32 indexoftheendedprocess;
  lcrzo_int32 i, count;

  /* parameter verification */
  if (pmultiprocess==NULL) return(LCRZO_ERR_PANULLPTR);

  /* wait for one process */  
  lcrzo_er(lcrzo_wait_list_wait(&pmultiprocess->waitlist,
                                pmaxwaitingtime, &event,
                                &indexoftheendedprocess, NULL));
  if (paprocesshasended!=NULL) *paprocesshasended=event;

  /* if no process has ended */
  if (!event)
  { return(LCRZO_ERR_OK);
  }
  else
  { if (pindexoftheendedprocess!=NULL) *pindexoftheendedprocess=indexoftheendedprocess;
  }

  /* remove the waited item */
  lcrzo_er(lcrzo_wait_list_del(&pmultiprocess->waitlist, indexoftheendedprocess));

  /* get the return code */
  lcrzo_er(lcrzo_list_count(&pmultiprocess->processlist, &count));
  for ( i=1 ; i<=count ; i++ )
  { lcrzo_er(lcrzo_list_value_pos(&pmultiprocess->processlist, i, &lpmp));
    if (lpmp.index==indexoftheendedprocess)
    { /* set the return code */
      lcrzo_er(lcrzo_process_other_wait_end(lpmp.pprocess, LCRZO_WAIT_NODELAY, 
                                            &event, preturnedvalue));
      if (!event) return(lcrzo_ie("lcrzo_multiprocess_process_wait_end", "event==LCRZO_FALSE", "event==LCRZO_FALSE"));
      /* remove the list item */
      lcrzo_er(lcrzo_list_remove_pos(&pmultiprocess->processlist, i));
      break;
    }
  }
  
  return(LCRZO_ERR_OK);
}

/*-------------------------------------------------------------*/
lcrzo_uint8 lcrzo_process_int2uint8_std(int ret)
{ lcrzo_uint8 ret8;

  ret8=255; /* means was not in a correct range */

  if ( ret>=LCRZO_ERR_00_BEGIN && ret<=LCRZO_ERR_00_END )
  { ret8=(lcrzo_uint8)ret;
  }
  else if ( ret>=LCRZO_ERRZONE_LCRZO1_BEGIN && ret<=LCRZO_ERRZONE_LCRZO1_END )
  { /* this is a free space for lcrzo returns  */
    ret8=(lcrzo_uint8)ret;
  }
  else if ( ret>=LCRZO_ERRZONE_USER1_BEGIN && ret<=LCRZO_ERRZONE_USER1_END )
  { /* this is a free space for user returns */
    ret8=(lcrzo_uint8)ret;
  }
  else if ( ret>=LCRZO_ERRZONE_LCRZO2_BEGIN && ret<=LCRZO_ERRZONE_LCRZO2_END )
  { lcrzo_err_print(ret);
    if ( ret>=LCRZO_ERR_03_BEGIN && ret<=LCRZO_ERR_03_END )
      ret8=LCRZO_ERRZONE_LCRZO1_END;
    else if ( ret>=LCRZO_ERR_04_BEGIN && ret<=LCRZO_ERR_04_END )
      ret8=LCRZO_ERRZONE_LCRZO1_END-1;
    else if ( ret>=LCRZO_ERR_05_BEGIN && ret<=LCRZO_ERR_05_END )
      ret8=LCRZO_ERRZONE_LCRZO1_END-2;
    else if ( ret>=LCRZO_ERR_06_BEGIN && ret<=LCRZO_ERR_06_END )
      ret8=LCRZO_ERRZONE_LCRZO1_END-3;
    else if ( ret>=LCRZO_ERR_07_BEGIN && ret<=LCRZO_ERR_07_END )
      ret8=LCRZO_ERRZONE_LCRZO1_END-4;
    else if ( ret>=LCRZO_ERR_08_BEGIN && ret<=LCRZO_ERR_08_END )
      ret8=LCRZO_ERRZONE_LCRZO1_END-5;
    else if ( ret>=LCRZO_ERR_09_BEGIN && ret<=LCRZO_ERR_09_END )
      ret8=LCRZO_ERRZONE_LCRZO1_END-6;
    else if ( ret>=LCRZO_ERR_10_BEGIN && ret<=LCRZO_ERR_10_END )
      ret8=LCRZO_ERRZONE_LCRZO1_END-7;
    else if ( ret>=LCRZO_ERR_11_BEGIN && ret<=LCRZO_ERR_11_END )
      ret8=LCRZO_ERRZONE_LCRZO1_END-8;
  }
  else if ( ret>=LCRZO_ERRZONE_USER2_BEGIN && ret<=LCRZO_ERRZONE_USER2_END )
  { lcrzo_err_print(ret);
    ret8=LCRZO_ERRZONE_USER1_END;
  }

  return(ret8);
}

/*-------------------------------------------------------------*/
int lcrzo_process_uint82int_std(lcrzo_uint8 ret)
{ int reti;

  reti=LCRZO_ERR_LOUNKNOWNERROR; /* default is not in a range */

  if ( ret<=LCRZO_ERR_00_END )
  { reti=ret;
  }
  else if ( ret>=LCRZO_ERRZONE_LCRZO1_BEGIN && ret<=LCRZO_ERRZONE_LCRZO1_END )
  { /* this is a free space for lcrzo returns */
	reti=ret;
	if (ret==LCRZO_ERRZONE_LCRZO1_END)
      reti=LCRZO_ERR_FM;
	else if (ret==LCRZO_ERRZONE_LCRZO1_END-1)
      reti=LCRZO_ERR_PO;
	else if (ret==LCRZO_ERRZONE_LCRZO1_END-2)
      reti=LCRZO_ERR_PA;
	else if (ret==LCRZO_ERRZONE_LCRZO1_END-3)
      reti=LCRZO_ERR_SP;
	else if (ret==LCRZO_ERRZONE_LCRZO1_END-4)
      reti=LCRZO_ERR_LO;
	else if (ret==LCRZO_ERRZONE_LCRZO1_END-5)
      reti=LCRZO_ERR_IE;
	else if (ret==LCRZO_ERRZONE_LCRZO1_END-6)
      reti=ret;
	else if (ret==LCRZO_ERRZONE_LCRZO1_END-7)
      reti=LCRZO_ERR_FU;
	else if (ret==LCRZO_ERRZONE_LCRZO1_END-8)
      reti=LCRZO_ERR_FU;
  }
  else if ( ret>=LCRZO_ERRZONE_USER1_BEGIN && ret<=LCRZO_ERRZONE_USER1_END )
  { /* this is a free space for user returns */
    reti=ret;
	if (ret==LCRZO_ERRZONE_USER1_END)
      reti=LCRZO_ERR_LOUNKNOWNERROR;
  }

  return(reti);
}

/*-------------------------------------------------------------*/
lcrzo_uint8 lcrzo_process_int2uint8_socktcp(int ret)
{
  if (ret==LCRZO_ERR_SPSOCKTCPNOSA)
    ret=LCRZO_ERRZONE_LCRZO1_BEGIN;
  else if (ret==LCRZO_ERR_SPSOCKTCPRST)
    ret=LCRZO_ERRZONE_LCRZO1_BEGIN+1;
  return(lcrzo_process_int2uint8_std(ret));
}

/*-------------------------------------------------------------*/
int lcrzo_process_uint82int_socktcp(lcrzo_uint8 ret)
{ int reti;

  reti=lcrzo_process_uint82int_std(ret);
  if (reti==LCRZO_ERRZONE_LCRZO1_BEGIN)
    reti=LCRZO_ERR_SPSOCKTCPNOSA;
  else if (reti==LCRZO_ERRZONE_LCRZO1_BEGIN+1)
    reti=LCRZO_ERR_SPSOCKTCPRST;

  return(reti);
}

