/* $Id: DD_client.c,v 1.3 2009/04/14 08:37:28 budnik Exp $ */
/*==============================================================
 *                  DD SYSTEM 
 *                 DD_client.c
 *                    V.4.8
 * List of changes:
 * November 1995, Version 1.0
 * August 1999 :Access security system was installed by Alexandr Grigoriev (v3.0)
 * October 22, 2002 - Communication ideology  is changed (V.4.0)
 * Oct 29, 2002 - Add DD_GetVersion() and some bags are corrected (V.4.1)
 * May 1, 2003 - Network error is developped. (The header receiving is changed): V.4.2
 * Nov 18, 2004 - Cach error is fixed.
 * Jun 17, 2007 - Fedorov, V.4.5 Create new VI and Update data requests
 * Sep 24, 2007 - Fedorov, V.4.6 Processing of return of Get_Data
 * Dec 03, 2007 - Budnik,  V.4.7 There may be several sessions with DD Server inside ONE
 *                               Client session. Keep UserHost & UserName
 * Oct 18, 2012  - Knizhnikova, V.4.8 new DD_SetTimeInfo() function
 *===============================================================*/

#include <unistd.h>
#include <stdio.h>
#include <string.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "DD.hh"

#ifdef LOG4CXX
log4cxx::LoggerPtr DD_Client::_logger = log4cxx::Logger::getLogger(
		"AMDA-Kernel.DD_Client");
#endif

/*------------------ GLOBAL STATIC VARIABLES --------------------------*/

//extern int errno;

/*================== FUNCTIONS =================================*/
/*----------------------- GET User Host-------------------------------*/

static size_t unixlen[] = {sizeof(char),sizeof(int),sizeof(float),sizeof(double),sizeof(short)};

static xdrproc_t ConvFunc[5]    = {(xdrproc_t )xdr_char, (xdrproc_t )xdr_int, (xdrproc_t )xdr_float, (xdrproc_t )xdr_double, (xdrproc_t )xdr_short};

DD_Client:: DD_Client() :
		idd (DD_CHAR, 0, NULL,1, (void**) malloc(sizeof(void*))),
		CurrentData(NULL),
		_varNumber(0),
	 	SocketID( -1),
	 	UserID(0),
		m1(0X000000FF),
		m2( 0X0000FF00),
		m3(0X00FF0000),
		m4( 0XFF000000),
		//Host(NULL),
	 	buffSetVarialbe(NULL),
	 	bufDD_SetTime (NULL),
	 	op(TIMESETREQ),
	    bufDD_GetData( NULL),
	    LastPacketFlag(OK),
	    bufDD_Close (NULL),
	    opDD_Close(CLOSEINSREQ),
	    bufDD_AddDataSet(NULL),
	    opDD_AddDataSet(ADDVIREQ),
	    Version(VERSION)

	{
	UserName[0] = '\0';
	UserHost[0] = '\0';
	RemSerName[0]='\0';
 	strcpy(TimeInt, "0000000000001000");
 	idd.Variables[0]=NULL;
}

int DD_Client::GetUserHost() {
	int userid;

	userid = getuid(); /* Get a client user  ID */

#ifdef LOG4CXX
	//LOG4CXX_DEBUG(_logger, "DD_Client::GetUserHost - UserId : " << userid);
#endif

	/* UserHost can be set by extern WEB function in case of WEB communicatio,
	 * or it should be defined as local host if DD_client is installed at USER
	 * computer
	 */
	if (UserHost[0] == '\0') {
		char HostName[HOSTNAMELENGTH];

		gethostname(HostName, HOSTNAMELENGTH); /* Get a client host name */

		struct sockaddr_in addr;

		if (getInfoFromHostName(HostName,addr) != 0)
			return NOHOST;

		unsigned int b1, b2, b3, b4;
		sscanf(inet_ntoa( addr.sin_addr), "%3u.%3u.%3u.%3u", &b1, &b2, &b3, &b4);
		snprintf(UserHost, MAXHOSTLENGTH, "%03u.%03u.%03u.%03u", b1, b2, b3, b4);

#ifdef LOG4CXX
		// LOG4CXX_DEBUG(_logger, "DD_Client::GetUserHost - UserHost : " << UserHost);
#endif
	}
	return userid;
}

void DD_Client::setUserHost(const char* host) {
	snprintf(UserHost, MAXHOSTLENGTH, "%s", host);
#ifdef LOG4CXX
	// LOG4CXX_DEBUG(_logger, "DD_Client::setUserHost - UserHost : " << UserHost);
#endif
}

void DD_Client::setUserName(const char* name) {
	snprintf(UserName, USRLENGTH, "%s", name);
#ifdef LOG4CXX
	// LOG4CXX_DEBUG(_logger, "DD_Client::setUserName - UserName : " << UserName);
#endif
}

int DD_Client::getInfoFromHostName(const char *hostName, struct sockaddr_in &addr)
{
	struct addrinfo hints;
	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_PASSIVE;
	hints.ai_protocol = 0;
	hints.ai_canonname = NULL;
	hints.ai_addr = NULL;
	hints.ai_next = NULL;

	struct addrinfo *result;
	int s;

	s = getaddrinfo(hostName, NULL, &hints, &result);

	if (s != 0)
	{
#ifdef LOG4CXX
		LOG4CXX_ERROR(_logger, "DD_Client::getIpFromHostName - Cannot get ip from host name " << hostName);
#endif
		return NOHOST;
	}

	struct sockaddr_in *h;
	h = (struct sockaddr_in *) result->ai_addr;

	memcpy(&addr,h,sizeof(struct sockaddr_in));

	freeaddrinfo(result);

	return 0;
}
/*-------------------------------------------------------------------*/

/*------------------ MAKE_CONNECTION ---------------------------*/
/*
 * The function returns opened socket, ready to read and write
 */
int DD_Client::GetSocket()
/*
 * Connect with remote server, and returns socket ID
 * In case of error return error number according DD_comm.h
 */
{
/*-------- Variables for resource file -----------------*/
   char rname[PATHLENGTH];      /* name of res file */
   char line[PATHLENGTH];
   char *path;
   FILE *resfile;       /* resource file */

/*---------- Variables for network ---------------------*/

   int normaddr;
/*
 *---------- Getting socket and its address ---------------------*/ 
/*---------------- HOST and PORT ------------------------------*/
   if((path = getenv("DDPATH")) == NULL)
   {
      strcpy(rname,"DD.res");
   }
   else
   {
      strcpy(rname,path);
      strcat(rname, "/DD.res");
   }
/*
   (void *)strcpy(rname,"./DD.res");
*/
   if((resfile = fopen(rname,"r")) == NULL)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::GetSocket - Cannot find resource file " << rname);
#endif

      fprintf(stderr,"No resource file, sorry\n");
      exit(1);
   }

   fgets(RemSerName, PATHLENGTH-1, resfile);
   fgets(line, PATHLENGTH-1, resfile);
   fclose(resfile);

   RemSerName[strlen(RemSerName)-1] = '\0';
   sscanf(line,"%5d",&(normaddr));
   

/*---------------- END of FILE READING --------------------------*/
/*
 *------- Trying to open socket with this address and name ---------
 */

   if((SocketID = socket(AF_INET,SOCK_STREAM,PROTOCOL)) < 0)
   {
#ifdef LOG4CXX
      LOG4CXX_ERROR(_logger, "DD_Client::GetSocket - Socket error ");
#endif
      perror("Socket:"); return(-1);
   }

/* Filling full internet address for socket "name"
 * this address will be used to get communication point */

   struct sockaddr_in IntAFAddr;

   if (getInfoFromHostName(RemSerName,IntAFAddr) != 0)
   		return NOHOST;

   IntAFAddr.sin_port = htons((uint16_t)normaddr); /* Conversion of the port number to
                                                         universal net form */
#ifdef LOG4CXX
   //LOG4CXX_DEBUG(_logger, "DD_Client::GetSocket - HostName : " << RemSerName << " - IP : " << inet_ntoa(IntAFAddr.sin_addr) << " - Port : " << IntAFAddr.sin_port);
#endif

   /* Connection to server socket on remote computer */
   int errnum = connect(SocketID,(struct sockaddr *)&IntAFAddr,sizeof(struct sockaddr_in));
   if(errnum < 0)
   {
#ifdef LOG4CXX
	   LOG4CXX_ERROR(_logger, "DD_Client::GetSocket - Connection to server socket error - " << strerror (errnum));
#endif
	   perror("connect");
	   return(-1);
   }
         
/*
 * Get Host name and Host ID for security application
 */
   if((UserID = GetUserHost()) < 0)
   {
#ifdef LOG4CXX
	   LOG4CXX_ERROR(_logger, "DD_Client::GetSocket - NOHOST error");
#endif
	   return(NOHOST);
   }

   return SocketID;
}
/*------------------- end of GetSocket ---------------------*/

/*==================== Receive From Net ======================*/
/*
 * Smart buffered receiver
 */
int DD_Client::ReceiveFromNet(char *buf, int PacketSize)
{
   int CurLength = 0;

   do
   {
      int i = 0;
      int cc = 0;
      while(( (cc = recv(SocketID,buf+ CurLength,PacketSize - CurLength,0)) < 0) && (i < TRY)) i++;
      if(cc <= 0) return -1;
      CurLength = CurLength + cc;
   } while(CurLength < PacketSize);
   return 1;
}

/*------------------ Open Virtual Instrument -----------------------*/
/*
 * If no connection, connect to server, then try to order data set and return
 * ID if OK or ErrorNumber if not
 */
int DD_Client::DD_SetVariable(char *InstrName)
{
   int InstrID; /* Instrumnet ID to return */
   int Request = OPENINSREQ;
   int hostlen,userlen;
   char *PUserHost = UserHost, *PUserName = UserName;
   char *pDDuser;
   
   /* We need this because XDR works with adresses of pointers */

/* If there is no connection, try to get it */
   if(SocketID < 0)
       if((SocketID = GetSocket()) < 0)
    	   {
#ifdef LOG4CXX
    	   	   LOG4CXX_ERROR(_logger, "DD_Client::DD_SetVariable - No connection");
#endif
    	   	   return(NOCONNECTION);
    	   }

/* Encoding request by XDR to buf */
/* Buffer and stream allocation */
   buffSetVarialbe = (caddr_t)calloc(REQUESTLENGTH, 1);

   xdrmem_create(&xdrs, buffSetVarialbe, REQUESTLENGTH, XDR_ENCODE);

   xdr_int(&xdrs,&Request);
   xdr_string(&xdrs, &InstrName, strlen(InstrName));

/* Send Open Virtual Instrument request */

   if( send(SocketID,buffSetVarialbe,REQUESTLENGTH,0) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_SetVariable - Cannot open virtual instrument");
#endif
      perror("DD_SetVariable:");
      free(buffSetVarialbe);
      xdr_destroy(&xdrs);
      return(REQSENDERR);
   }
   xdrmem_create(&xdrs, buffSetVarialbe, REQUESTLENGTH, XDR_FREE);

/*--------  preparation an authorization request ----------------*/
   if(UserName[0] == '\0') {
	   
	   pDDuser = getenv ("DDUSER");
	 
	   if (pDDuser != NULL) strcpy(UserName, pDDuser);
	   else {
		   strcpy(UserName,NONAME);
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_SetVariable - UserName is undefined");
#endif
	   }
   }
   hostlen = strlen(UserHost);
   userlen = strlen(UserName);
   
   xdrmem_create(&xdrs, buffSetVarialbe,REQUESTLENGTH, XDR_ENCODE);

   xdr_int(&xdrs,&UserID);
   xdr_string(&xdrs, &PUserHost, hostlen);
   xdr_string(&xdrs, &PUserName, userlen);
   //fprintf(stderr,"userid %d host %s DD_name %s\n",UserID,UserHost,UserName);  
  
/* Send request */
   if( send(SocketID,buffSetVarialbe,REQUESTLENGTH,0) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_SetVariable - Cannot send request");
#endif
      perror("DD_Set_Variable:");
      free(buffSetVarialbe);
      xdr_destroy(&xdrs);
      return(REQSENDERR);
   }

   free(buffSetVarialbe);
   xdr_destroy(&xdrs);

/* Get reply */
   buffSetVarialbe = (caddr_t)malloc(REPLYLENGTH);
/*
   i=0;
   while(((cc = recv(SocketID,buff,REPLYLENGTH,0)) < 0) && (i < TRY)) i++;
*/
   if( ReceiveFromNet(buffSetVarialbe, REPLYLENGTH) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_SetVariable - Cannot receive from net");
#endif
      perror("DD_SET_Variable:");
      free(buffSetVarialbe);
      return(REPLYRECERR);
   }

   xdrmem_create(&xdrs, buffSetVarialbe, REPLYLENGTH, XDR_DECODE);
   xdr_int(&xdrs,&InstrID);

/* Free all */
   free(buffSetVarialbe);
   xdr_destroy(&xdrs);

   return InstrID;
}

/*----------------------- DD_GetInform -----------------------------*/
/*
 * Returns "OK" if OK, fill DD_Data structure
 * Return negative value if error
 */

int DD_Client::DD_GetInform(int VarID,char *AttrName,DD_data_t **data)
{
   XDR xdrs;
   caddr_t bufDD_GetInform = NULL;
   int length;
   int op = DATAINFOREQ;
   int type;               /* type of information or error */
   int DimNumbers;
   int PacketSize;
   u_int count;
   u_int MaxNumber;

/*------------------- Empty static data ------------------------*/
   if(idd.Dimensions != NULL)
   {
      free(idd.Dimensions);
      idd.Dimensions = NULL;
   }
   if(idd.Variables[0] != NULL)
   {
      free(idd.Variables[0]);
      idd.Variables[0] = NULL;
   }

/*------------------ Check the Name length -----------------------*/
   if(strlen(AttrName) > MAXVARLENGTH) length = MAXVARLENGTH;
   else length = strlen(AttrName);

/*----------- Allocation of memory and stream --------------------*/
   bufDD_GetInform = (caddr_t)calloc(REQUESTLENGTH,1);
   xdrmem_create(&xdrs, bufDD_GetInform, REQUESTLENGTH, XDR_ENCODE);

/*------------------- Encoding the request ----------------------*/
   xdr_int(&xdrs,&op);
   xdr_int(&xdrs,&VarID);
   xdr_string(&xdrs, &AttrName, length);

/*------------------------ Send request ---------------------------*/
   if( send(SocketID,bufDD_GetInform,REQUESTLENGTH,0) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_GetInform - Cannot send request");
#endif
      perror("DD_GetInform:");
      free(bufDD_GetInform);
      xdr_destroy(&xdrs);
      return(REQSENDERR);
   }
   free(bufDD_GetInform);
   xdr_destroy(&xdrs);

/*------------------------ Get reply header ------------------------*/

   bufDD_GetInform = (caddr_t)malloc(REPLYLENGTH);
/*
   i=0;
   while(((cc = recv(SocketID,buf,REPLYLENGTH,0)) < 0) && (i < TRY)) i++;
   if(cc < 0)
*/
   if(( ReceiveFromNet(bufDD_GetInform, REPLYLENGTH)) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_GetInform - Cannot receive from net");
#endif
      perror("DD_GetInform:");
      free(bufDD_GetInform);
      return(REPLYRECERR);
   }

   xdrmem_create(&xdrs, bufDD_GetInform, REPLYLENGTH, XDR_DECODE);
   xdr_int(&xdrs,&type);
   if(type < 0)
   {
      free(bufDD_GetInform);
      xdr_destroy(&xdrs);
      return(type);
   }
   xdr_int(&xdrs,&DimNumbers);
   xdr_int(&xdrs,&PacketSize);
   free(bufDD_GetInform);
   xdr_destroy(&xdrs);

   idd.DimNumber = DimNumbers;
   idd.type = type;

/*---------------------------- Get Data Packet ----------------------*/
   if(PacketSize > 0) bufDD_GetInform = (caddr_t)malloc(PacketSize);
   else
   {
#ifdef LOG4CXX
	   LOG4CXX_ERROR(_logger, "DD_Client::DD_GetInform - Cannot Cannot get data packet");
#endif
	   return(REPLYRECERR);
   }

   if(( ReceiveFromNet(bufDD_GetInform, PacketSize)) < 0)
   {
#ifdef LOG4CXX
      LOG4CXX_ERROR(_logger, "DD_Client::DD_GetInform - Cannot receive from net");
#endif
      perror("DD_GetInform:");
      free(bufDD_GetInform);
      return(REPLYRECERR);
   }

/*--------------------- Decoding data packet ------------------------*/
   if(DimNumbers > 0)
   {
/*----------- Memory allocation and xdr creating -----------------*/
      xdrmem_create(&xdrs, bufDD_GetInform, (u_int)PacketSize, XDR_DECODE);

/*----------------- Dimensions decoding -------------------------*/
      if(idd.Dimensions !=NULL) free(idd.Dimensions);
      idd.Dimensions = (int *)malloc(DimNumbers*sizeof(int));

      xdr_array(&xdrs, (caddr_t *)&(idd.Dimensions),
                       &count,
                       (u_int )DimNumbers,
                       unixlen[DD_INT],
                       (xdrproc_t)xdr_int);

      count = 1;
      for(int i=0; i < DimNumbers;i++)
         count = count*idd.Dimensions[i];
      MaxNumber = count;
   }
   else
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_GetInform - Cannot decoding data packet");
#endif
      free(bufDD_GetInform);
      return(REPLYRECERR);
   }

/*---------------- Allocate memory for Variables and decoding ------------------*/
   if(idd.Variables[0] != NULL) free(idd.Variables[0]);
   idd.Variables[0] = (int *)malloc(unixlen[type] * MaxNumber);

   xdr_array(&xdrs,((caddr_t*)(&idd.Variables[0])),&count,
             MaxNumber, unixlen[type], ConvFunc[type]);

/*-------------------------- Free all ------------------------------*/
   free(bufDD_GetInform);
   xdr_destroy(&xdrs);

   *data = &idd;
   return OK;
}

/*------------------- DD_SETTIME ------------------------------------*/
/*
 * VarID - ID of Data Set
 * Time - string in DD type
 * Returns 1 if OK and negative in case of err
 */

int DD_Client:: DD_SetTime(int VarID,char *Time)
{
   int type;
   int DoneFlag = 0;

   while(DoneFlag == 0)
   {
/* Allocatein memory and stream */
   bufDD_SetTime = (caddr_t)calloc(REQUESTLENGTH, 1);
   xdrmem_create(&xdrsDD_SetTime, bufDD_SetTime, REQUESTLENGTH, XDR_ENCODE);

/* Encoding the request */
   xdr_int(&xdrsDD_SetTime,&op);
   xdr_int(&xdrsDD_SetTime,&VarID);
   xdr_string(&xdrsDD_SetTime, &Time, TIMELENGTH);

/* Send request */
   if(( send(SocketID,bufDD_SetTime,REQUESTLENGTH,0)) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_SetTime - Cannot send request");
#endif
      perror("DD_SetTime:");
      free(bufDD_SetTime);
      xdr_destroy(&xdrsDD_SetTime);
      return(REQSENDERR);
   }
   free(bufDD_SetTime);
   xdr_destroy(&xdrsDD_SetTime);

/* Get reply header */

   bufDD_SetTime = (caddr_t)malloc(REPLYLENGTH);

   if(( ReceiveFromNet(bufDD_SetTime, REPLYLENGTH)) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_SetTime - Cannot receive from net");
#endif
      perror("DD_SetTime:");
      free(bufDD_SetTime);
      return(REPLYRECERR);
   }

   xdrmem_create(&xdrsDD_SetTime, bufDD_SetTime, REPLYLENGTH, XDR_DECODE);
   xdr_int(&xdrsDD_SetTime,&type);

   free(bufDD_SetTime);
   xdr_destroy(&xdrsDD_SetTime);
       
   if(type < 0) 
   {
      if(type == CACHTOOREC) sleep((unsigned )(FILEACCMARG));
      else return type;
   }
   else DoneFlag = 1;
   } 
   return 1 ;
}

/*------------------- DD_SETTIMEINFO ------------------------------------*/
/*
 * VarID - ID of Data Set
 * Time - string in DD type
 * RealTime - double : time value pointer points to
 * Returns 1 if OK and negative in case of err
 */

int DD_Client:: DD_SetTimeInfo(int VarID, char *Time, double *RealTime)
{
    int err;

    DD_data_t *data; 
    
    if ((err = DD_SetTime(VarID, Time)) < 0)
    {
    	while ((err == WAITEXTCALL) || (err == TRYAGAIN))
    	{
    		sleep(2);
    		err = DD_SetTime(VarID, Time);
    	}
    }

    if (err < 1)
    {
#ifdef LOG4CXX
    	LOG4CXX_ERROR(_logger, "DD_Client::DD_SetTimeInfo - Cannot set time " << Time);
#endif
    	return err;
    }
    
    if ((err = DD_GetData(VarID, (char *)"Time", TimeInt, &data)) < 0)
    {
    	while ((err == WAITEXTCALL) || (err == TRYAGAIN))
        {
    		sleep(2);
        	err = DD_GetData(VarID, (char *)"Time", TimeInt, &data);
        }
    }

    if (err < 0)
    {
#ifdef LOG4CXX
    	LOG4CXX_ERROR(_logger, "DD_Client::DD_SetTimeInfo - Cannot get data " << Time);
#endif
    	return err;
    }
    if (data->VarNumber < 1)
    {
#ifdef LOG4CXX
    	LOG4CXX_ERROR(_logger, "DD_Client::DD_SetTimeInfo - OUTOFTIME error " << Time);
#endif
    	return OUTOFTIME;
    }

    *RealTime = DD_Time2Double((char *)data->Variables[0]);

    //BRE - When the corresponding time is the last one of a file, MOREDATA is returned by DDServer.
    // => force recall of DD_GetData to open the next file and finish correctly the request
    if (err == MOREDATA)
    {
    	if ((err = DD_GetData(VarID, (char *)"Time", TimeInt, &data)) < 0)
    	{
    		while ((err == WAITEXTCALL) || (err == TRYAGAIN))
    	    {
    			sleep(2);
    	        err = DD_GetData(VarID, (char *)"Time", TimeInt, &data);
    	    }
    	}
    }

   return 1 ;
}

/*------------------------- DD_GETDATA --------------------------------*/
/*
 * VarID - ID of open virtual instrument
 * VarName - Variable name associated with this virtual instrument
 * TimeInt - Time interval in DD_time style
 * data - returned data
 * Return values:
 *    positives:
 *    MOREDELAY - call this function again after delay
 *    MOREDATA - call this function again to complete request
 *    OK       - all data received
 *    negative value - error (see DD.h)
 */

int DD_Client::DD_GetData(int VarID,char *VarName,char *TimeInt,DD_data_t **data)
{
	   char *xxx=VarName;
	   int err = DD_GetMultiData(VarID, 1, &xxx, TimeInt, data, 1);
	   return err;
	}

/*------------------------- DD_GetMultiData() --------------------------------*/
/*---------------------------------------------------------
 * VarID - ID of open virtual instrument
 * VarSize - the size of the array names
 * VarNames - array of the variables names
 * TimeInt - Time interval in DD_time style
 * data - returned data
 * Return values:
 *    positives:
 *    MOREDELAY - call this function again after delay
 *    MOREDATA - call this function again to complete request
 *    OK       - all data received
 *    negative value - error (see DD.h)
 */
int DD_Client::DD_GetMultiData(int VarID,size_t VarSize, char **VarNames,char *TimeInt,DD_data_t **data, int BackFlag)
{
	size_t id;
	int *NameLength = NULL; /* Array of lengths */
	int XDRStrLen;          /* xdr length of a string */
	int XDRReqlength;  // Length in bytes the XDR stream
	int op = DATAGETREQ;
	int type;  /* type of information or error */
	int DimNumbers;
	int PacketSize;
	u_int count, MaxSize=0;
	int i;

	/*--------------------------------------
	 * Create a new Current Data empty array
	 *-------------------------------------*/
	for( int i = 0; i < _varNumber; ++i) {
		CurrentData[i].clear();
	}
	delete[] CurrentData;
	_varNumber = VarSize;
	CurrentData = new DD_data_t[_varNumber];

	/*--------------------------------------------------------------
	 * The follows request preparation and send is performed only
	 * if the priveous data packed is completely received
	 *--------------------------------------------------------------*/
	if((LastPacketFlag == OK) || (LastPacketFlag == MOREDELAY))
	{
		/*---------------------------------------
		 * Preparation of the array the name lengths
		 * Note that the names are cut down to the MAXVARLENGTH
		 * Calculation the packet size
		 *---------------------------------------*/
		NameLength = (int *)malloc(sizeof(int)*VarSize);
		XDRReqlength = 8; /* the length of the first+last arguments */
		for(id = 0; id < VarSize; id++)
		{
			if(strlen(VarNames[id]) > MAXVARLENGTH) NameLength[id] = MAXVARLENGTH;
			else NameLength[id] = strlen(VarNames[id]);
			XDRStrLen = (NameLength[id] / 4) * 4;
			if((NameLength[id] % 4) > 0) XDRStrLen += 4;
			XDRReqlength += XDRStrLen + 4; // String length + 4 bytes length coding
			//fprintf(stderr,"Variable %s, length %d, total %d\n",VarNames[id],XDRStrLen,XDRReqlength);
		}
		/*--------------------------------
		 * The first packet of the request of the standard size
		 * Allocation corresponding memory and stream
		 *------------------------------*/
		bufDD_GetData = (caddr_t)calloc(REQUESTLENGTH, 1);
		xdrmem_create(&xdrsDD_GetData, bufDD_GetData, REQUESTLENGTH, XDR_ENCODE);

		/* Encoding the request */
		xdr_int(&xdrsDD_GetData,&op);
		xdr_int(&xdrsDD_GetData,&VarID);
		xdr_string(&xdrsDD_GetData,&TimeInt,TIMELENGTH);
		xdr_int(&xdrsDD_GetData,&XDRReqlength);

		/* Send the first request */
		if(( send(SocketID,bufDD_GetData,REQUESTLENGTH,0)) < 0)
		{
#ifdef LOG4CXX
			LOG4CXX_ERROR(_logger, "DD_Client::DD_GetMultiData - Cannot send the first request");
#endif
			perror("DD_GetData: First Request");
			free(bufDD_GetData);
			free(NameLength);
			xdr_destroy(&xdrsDD_GetData);
			return(REQSENDERR);
		}
		free(bufDD_GetData);
		xdr_destroy(&xdrsDD_GetData);

		/*--------------------------------
		 * The Second packet of XDRReqlength size
		 * Allocation corresponding memory and stream
		 *------------------------------*/
		bufDD_GetData = (caddr_t)malloc(XDRReqlength);
		xdrmem_create(&xdrsDD_GetData, bufDD_GetData, XDRReqlength, XDR_ENCODE);
		xdr_int(&xdrsDD_GetData,(int *)(&VarSize));
		for(id = 0; id < VarSize; id++) xdr_string(&xdrsDD_GetData, &VarNames[id], NameLength[id]);

		free(NameLength);
		NameLength = NULL;
		xdr_int(&xdrsDD_GetData,&BackFlag);

		/* Send the second request */
		if(( send(SocketID,bufDD_GetData,XDRReqlength,0)) < 0)
		{
#ifdef LOG4CXX
			LOG4CXX_ERROR(_logger, "DD_Client::DD_GetMultiData - Cannot send the second request");
#endif
			perror("DD_GetData:Second Packet");
			free(bufDD_GetData);
			xdr_destroy(&xdrsDD_GetData);
			return(REQSENDERR);
		}
		free(bufDD_GetData);
		xdr_destroy(&xdrsDD_GetData);
	}

	/*-----------------------------------------------------------
	 * Get the VarSize reply headers and VarSize data
	 *----------------------------------------------------------*/
	for(id = 0; id < VarSize; id++)
	{
		/*-------------------
		 * The header
		 *-----------------*/
		bufDD_GetData = (caddr_t)malloc(REPLYLENGTH);
		if(( ReceiveFromNet(bufDD_GetData, REPLYLENGTH)) < 0)
		{
#ifdef LOG4CXX
			LOG4CXX_ERROR(_logger, "DD_Client::DD_GetMultiData - Cannot receive header");
#endif
			perror("DD_GetData:Error while header receive");
			free(bufDD_GetData);
			return(REPLYRECERR);
		}

		xdrmem_create(&xdrsDD_GetData, bufDD_GetData, REPLYLENGTH, XDR_DECODE);
		xdr_int(&xdrsDD_GetData,&type);
		xdr_int(&xdrsDD_GetData,&DimNumbers);
		xdr_int(&xdrsDD_GetData,&PacketSize);
		free(bufDD_GetData);
		xdr_destroy(&xdrsDD_GetData);

		if (type < 0) /* Server returns unrecoverable error */
		{
#ifdef LOG4CXX
			LOG4CXX_DEBUG(_logger, "DD_Client::DD_GetMultiData - Server returns " << type << ", no data\n");
#endif
			fprintf(stderr, "DD_GetData: Server returns %d, no data\n", type);
			return type;
		}

		/*----------- Header is received ----------------------*/
		CurrentData[id].DimNumber = DimNumbers - 1;
		CurrentData[id].type = type;

		/*--------------- Receive Data Packet ------------------------------*/
		if(PacketSize > 0) bufDD_GetData = (caddr_t)malloc(PacketSize);
		else
		{
#ifdef LOG4CXX
			LOG4CXX_ERROR(_logger, "DD_Client::DD_GetMultiData - Cannot receive data packet");
#endif
			return(REPLYRECERR);
		}
		if((ReceiveFromNet(bufDD_GetData, PacketSize)) < 0)
		{
#ifdef LOG4CXX
			LOG4CXX_ERROR(_logger, "DD_Client::DD_GetMultiData - Cannot receive data packet from web");
#endif
			perror("DD_GetData: Error while data packet receive");
			free(bufDD_GetData);
			return(REPLYRECERR);
		}
		/*----------------- Decoding data packet --------------------*/
		if(DimNumbers > 1)
		{
			xdrmem_create(&xdrsDD_GetData, bufDD_GetData, (u_int)PacketSize, XDR_DECODE);
			count = DimNumbers-1;
			/* allocation memory for dimensions */
			CurrentData[id].Dimensions = (int *)malloc((DimNumbers-1)*sizeof(int));

			xdr_int(&xdrsDD_GetData,&LastPacketFlag);        /* Last Paket Indicatort*/
			xdr_int(&xdrsDD_GetData,&CurrentData[id].VarNumber); /* Variables number */

			if(LastPacketFlag > 2)
			{
				LastPacketFlag = OK;
				CurrentData[id].VarNumber = 0;
				free(bufDD_GetData);
#ifdef LOG4CXX
				LOG4CXX_ERROR(_logger, "DD_Client::DD_GetMultiData - Reply received error");
#endif
				return(REPLYRECERR);
			}

			/*----- Decoding dimensions array -------------------*/
			xdr_array(&xdrsDD_GetData, (caddr_t *)&(CurrentData[id].Dimensions),
					&count,
					(u_int )DimNumbers-1,
					unixlen[DD_INT],
					(xdrproc_t)xdr_int);

			count = 1;
			for(i=0; i < DimNumbers-1;i++)
			{
				count = count*CurrentData[id].Dimensions[i];
			}
			MaxSize = count;
		}
		else {
			if (type != NOVAR) {
#ifdef LOG4CXX
				LOG4CXX_ERROR(_logger, "DD_Client::DD_GetMultiData - Reply received error");
#endif
				free (bufDD_GetData);
				return (REPLYRECERR);
			} else {
				CurrentData[id].VarNumber = 0;
			}
		}

		/*---------- Decoding variables -------------------------*/
		if (CurrentData[id].VarNumber != 0) {
			CurrentData[id].Variables = (void **) malloc(CurrentData[id].VarNumber * sizeof(void *));
		} else {
			CurrentData[id].Variables = NULL;
		}

		for(i = 0; i < CurrentData[id].VarNumber; i++)
		{
			CurrentData[id].Variables[i] = (void *)malloc(unixlen[type]*MaxSize);
			count = MaxSize;
			xdr_array(&xdrsDD_GetData,(caddr_t *)(&(CurrentData[id].Variables[i])),&count,MaxSize,unixlen[type], (xdrproc_t)ConvFunc[type]);
		}

		/* Free all */
		free(bufDD_GetData);
		xdr_destroy(&xdrsDD_GetData);
	}
	*data = CurrentData;
	return(LastPacketFlag);
}

/*===================================================================*/

/*-------------------------- DD_CLOSE --------------------------------*/
/*
 *
 * VarID - entry point of ID table
 * Returns 1 if OK or negative err
 * Close Socket if no VarID more ( this information supplyed by server )
 */

int DD_Client:: DD_Close(int VarID)
{
   int RemainedID;                 /* Server returns number of remained ID */
/* Allocatein memory and stream */
   bufDD_Close = (caddr_t)calloc(REQUESTLENGTH, 1);
   xdrmem_create(&xdrsDD_Close, bufDD_Close, REQUESTLENGTH, XDR_ENCODE);

/* Encoding the request */
   xdr_int(&xdrsDD_Close,&opDD_Close);
   xdr_int(&xdrsDD_Close,&VarID);

/* Send request */
   if(( send(SocketID,bufDD_Close,REQUESTLENGTH,0)) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_Close - Cannot send request " << VarID);
#endif
      perror("DD_Close:");
      free(bufDD_Close);
      xdr_destroy(&xdrsDD_Close);
      return(REQSENDERR);
   }
   free(bufDD_Close);
   xdr_destroy(&xdrsDD_Close);

/* Get reply header */

   bufDD_Close = (caddr_t)malloc(REPLYLENGTH);
/*
   i = 0;
   while(((cc = recv(SocketID,buf,REPLYLENGTH,0)) < 0) && (i < TRY)) i++;
   if(cc < 0)
*/
   if(( ReceiveFromNet(bufDD_Close, REPLYLENGTH)) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_Close - Cannot receive from net " << VarID);
#endif
      perror("DD_Close:");
      free(bufDD_Close);
      return(REPLYRECERR);
   }

   xdrmem_create(&xdrsDD_Close, bufDD_Close, REPLYLENGTH, XDR_DECODE);
   xdr_int(&xdrsDD_Close,&RemainedID);
   if(RemainedID< 0)
   {
      free(bufDD_Close);
      xdr_destroy(&xdrsDD_Close);
      return(RemainedID);
   }
   free(bufDD_Close);
   xdr_destroy(&xdrsDD_Close);

   if(RemainedID == 0) 
   {
     shutdown(SocketID,2);
     close(SocketID);
     SocketID = -1;
/*     
       UserHost[0] = '\0';
       UserName[0] = '\0';
*/
   }

   return(1);
}

DD_Client::~DD_Client() {

	   for( int i = 0; i < _varNumber; ++i) {
		   CurrentData[i].clear();
	   }
	   delete[] CurrentData;
}

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

/*=============== DATABASE UPDATE FUNCTIONS ====================================*/
/*------------------ DD_AddDataSet() -------------------------------------------*/
int DD_Client:: DD_AddDataSet(char *DataSetName, char *RemSetID, char *BaseName)
{

   int Err;                      /* Server returns OK or NOEXEC */
   int length;
   int CloseFlag = 0;
   
/* If there is no connection, try to get it */
   if(SocketID < 0)
   {
       if((SocketID = GetSocket()) < 0)
       {
#ifdef LOG4CXX
    	   LOG4CXX_ERROR(_logger, "DD_Client::DD_AddDataSet - No connection");
#endif
    	   return(NOCONNECTION);
       }
       CloseFlag = 1; // To close Connection at the end
   }

/* Allocatein memory and stream */
   bufDD_AddDataSet = (caddr_t)malloc(REQUESTLENGTH);
   xdrmem_create(&xdrsDD_AddDataSet, bufDD_AddDataSet, REQUESTLENGTH, XDR_ENCODE);

/* Encoding the request */
   xdr_int(&xdrsDD_AddDataSet,&opDD_AddDataSet);

/* Coding DataSetName */
      if((length = strlen(DataSetName)) > MAXSETLENGTH) length = MAXSETLENGTH;
      xdr_string(&xdrsDD_AddDataSet, &DataSetName, length);
/* Coding RemSetID */
      if((length = strlen(RemSetID)) > MAXVARLENGTH) length = MAXVARLENGTH;
      xdr_string(&xdrsDD_AddDataSet,   &RemSetID, length);
/* Coding BaseName */
      if((length = strlen(BaseName)) > MAXVARLENGTH) length = MAXVARLENGTH;
      xdr_string(&xdrsDD_AddDataSet, &BaseName, length);

/* Send request */
   if(( send(SocketID,bufDD_AddDataSet,REQUESTLENGTH,0)) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_AddDataSet - Cannot send request");
#endif
      perror("DD_AddDataSet:");
      free(bufDD_AddDataSet);
      xdr_destroy(&xdrsDD_AddDataSet);
      return(REQSENDERR);
   }
   free(bufDD_AddDataSet);
   xdr_destroy(&xdrsDD_AddDataSet);

/* Get reply header */
   bufDD_AddDataSet = (caddr_t)malloc(REPLYLENGTH);
   if(( ReceiveFromNet(bufDD_AddDataSet, REPLYLENGTH)) < 0)
   {
#ifdef LOG4CXX
	  LOG4CXX_ERROR(_logger, "DD_Client::DD_AddDataSet - Cannot receive from net");
#endif
      perror("DD_AddDataSet:");
      free(bufDD_AddDataSet);
      return(REPLYRECERR);
   }

   xdrmem_create(&xdrsDD_AddDataSet, bufDD_AddDataSet, REPLYLENGTH, XDR_DECODE);
   xdr_int(&xdrsDD_AddDataSet,&Err);
   
   if(CloseFlag)  // Close everything if function established connection
   {
     shutdown(SocketID,2);
     close(SocketID);
     SocketID = -1;
/*   Session with DD Server was closed, but User Session continues !!!!! */
  /*   UserHost[0] = '\0';
       UserName[0] = '\0';  */
   }
   return Err;
}
/*-----------------------------------------------------------------------------*/

/*---------------------- DD GET VERSION ---------------------------------------*/
const char *DD_Client:: DD_GetVersion()
/*
 * return static pointer to internal string with the DDLIB-SERVER package version
 */
{
    return Version;
}
/*------------------------- End Library -------------------------------*/