#include "puma.h"
#include "libpuma.h"
#include <stdio.h>
#include <string.h>
#include "network/PrSocket.h"
#include "network/PrServerSocket.h"
#include "network/PrDataInput.h"
#include "network/PrDataOutput.h"
#include "driver/PrUtility.h"

#define PR_TYPE_ACTION         0
#define PR_TYPE_FLOAT          1

#define PR_ACTION_NONE         0
#define PR_ACTION_OPEN         1
#define PR_ACTION_CLOSE        2
#define PR_ACTION_EXIT         3
#define PR_ACTION_STOP         4
#define PR_ACTION_FLOAT        5
#define PR_ACTION_GOTO         6
#define PR_ACTION_RESET        7
#define PR_ACTION_SET_GOAL     8
#define PR_ACTION_SYNC         9

void main()
{
  PrSocket *clientServo = new PrSocket("localhost",
				       PUMA_USER_SERVO_TCP_PORT);
  if (clientServo->flag() != PR_SOCKET_OK)
    perror("client: can't create error");
  
  PrDataInput *inServo = new PrDataInput(clientServo);
  PrDataOutput *outServo = new PrDataOutput(clientServo);

  PrSocket *clientGather = new PrSocket("localhost",
					PUMA_USER_GATHER_TCP_PORT);
  if (clientGather->flag() != PR_SOCKET_OK)
    perror("client: can't create error");
  
  PrDataInput *inGather = new PrDataInput(clientGather);
  PrDataOutput *outGather = new PrDataOutput(clientGather);

  PrServerSocket *serverGUI = NULL;
  PrDataInput *inGUI = NULL;
  PrDataOutput *outGUI = NULL;
  PrSocket *guiSocket = NULL;
  if (guiOn == 1)
    {
      PrServerSocket *serverGUI = new PrServerSocket(PUMA_USER_GUI_TCP_PORT);
      if (serverGUI->flag() != PR_SERVERSOCKET_OK)
	::perror("server: can't create error");
    }

  int action,n;
  char buffer[PUMA_BUFFER_SIZE];
  int done=0;

  printf("start: User\n");
  fflush(stdout);
  int count = 1;
  int bufferlen;

  while(done != 1)
    {
      if (guiOn == 1 && guiSocket == NULL)
	{
	  printf("waiting for GUI connection ...\n");
	  guiSocket = serverGUI->accept();
	  printf("new client GUI connected!\n");
	  if (guiSocket == NULL)
	    ::perror("server: can't accept error");
	  else
	    {
	      inGUI = new PrDataInput(guiSocket);
	      outGUI = new PrDataOutput(guiSocket);
	    }
	}

      memset(buffer,PUMA_BUFFER_SIZE,NULL);

      printf("\npuma: %d> ",count);
      fflush(stdout);
      bufferlen=GetLine(stdin,buffer,PUMA_BUFFER_SIZE);
      if (bufferlen > 0) 
	{
	  if (strncmp(buffer,"exit",4)==0)
	    {
	      action = PUMA_ACTION_EXIT;
	      n = outGather->writeInt(&action,1);
	      if (outGather->flush(PUMA_TYPE_ACTION) != n)
		{
		  printf("write error\n");
		}
	      done = 1;
	    }
	  n = outServo->writeChar(buffer,bufferlen);
	  if (outServo->flush(PUMA_TYPE_CHAR)!=n)
	    {
	      printf("write error\n");
	    } 
	  count++;
	}
      else if (guiOn == 1 && guiSocket != NULL)
	{
	  action = PR_ACTION_NONE;

	  n=inGUI->ready();
	  if (n>=0)
	    {
	      int type = inGUI->type();
	      switch(type)
		{
		case PR_TYPE_ACTION:
		  inGUI->readInt(&action,1);
		  switch(action)
		    {
		    case PR_ACTION_EXIT:
		      action = PUMA_ACTION_EXIT;
		      n = outGather->writeInt(&action,1);
		      if (outGather->flush(PUMA_TYPE_ACTION) != n)
			{
			  printf("write error\n");
			}
		      action = PR_ACTION_EXIT;
		      done = 1;
		      break;
		    default:
		      printf("unknown action\n");
		      break;
		    }
		  break;
		default:
		  printf("unknown type\n");
		  break;
		}
	      if (action != PR_ACTION_NONE)
		outServo->writeInt(&action,1);
	      inGUI->readChar(buffer,n);
	      n = outServo->writeChar(buffer,n);
	      if (outServo->flush(type)!=n)
		{
		  printf("write error\n");
		} 
	      switch (action)
		{
		case PR_ACTION_SYNC:
		case PR_ACTION_FLOAT:
		case PR_ACTION_GOTO:
		  while(1)
		    {
		      n = inServo->ready();
		      if (n>=0)
			{
			  inServo->readChar(buffer,n);
			  outGUI->writeChar(buffer,n);
			  if(outGUI->flush(PR_TYPE_FLOAT)!=n)
			    ::perror("str_echo:float():write error");
			  break;
			}
		    }
		  break;
		case PR_ACTION_CLOSE:
		  delete inGUI;
		  delete outGUI;
		  guiSocket->close();
		  guiSocket = NULL;
		  break;
		}
	      count++;
	    }
	}
      util->microBlock(2000);
    }
  delete inServo;
  delete outServo;
  clientServo->close();
  delete clientServo;
  delete inGather;
  delete outGather;
  clientGather->close();
  delete clientGather;
  delete util;
  if (guiOn)
    {
      serverGUI->close();
      delete serverGUI;
      ::printf("exit serverGUI\n");
    }
  printf("done: User\n");
}

