/***************************************************************************
* File:     hexnet.c
* Purpose:  Networkcommunications, hex I/O
* Author:   Axel Bergerhoff
*
*                                       Copyright (C) 2021 Axel Bergerhoff
****************************************************************************
* 
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
* 
* hexnet 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 General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
****************************************************************************
*
*/

#define _GNU_SOURCE
#include "hexnet.h"


/*******************************************************************************
  MAIN
*******************************************************************************/
int main(int argc, char * argv[])
{
  struct gengetopt_args_info    args_info;

  int       port;
  char      *host;
  int       maxnum = 256;
  unsigned char      *puffer, *ptr;
  int       dummy;
  int       numchars;
  int       i;
  int       displayformat = 1;
  char      is2nd;
  int       delay = 0;


  int                 sockfd;
  int                 numbytes = MAXINBUFSIZE;
  unsigned char buf[MAXINBUFSIZE];
  struct sockaddr_in  their_addr;


  // check params
  cmdline_parser_init(&args_info);
  if (cmdline_parser (argc, argv, &args_info) != 0)
  {
    cmdline_parser_free (&args_info);
    return -1;
  }

  if (args_info.maxnum_given)
    maxnum = args_info.maxnum_arg;

  if (args_info.delay_given)
    delay = args_info.delay_arg;
  delay *= 100000;   // 100 ms --> us

  if (args_info.verbose_given)    // debug is global
    debug = 1;
  else
    debug = 0;

  if (args_info.format_given)
    displayformat = args_info.format_arg;



  // "required" --> w/o check
  host = strdup(args_info.address_arg);
  port = args_info.port_arg;

  cmdline_parser_free (&args_info);

  // print settings
  if (debug)
    printf("Address:  %s:%d\nMaxBytes: %d\n", host, port, maxnum);


  // prepare buffer
  puffer = malloc(maxnum);

  // prepare and establish network connection
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  {
    perror("socket");
    free(puffer);
    free(host);
    return -1;
  }

  bzero(&their_addr, sizeof(their_addr));

  their_addr.sin_family = AF_INET;      // host byte order
  their_addr.sin_port = htons(port);    // short, network byte order

  inet_pton(AF_INET, host, &their_addr.sin_addr);

  if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
  {
    perror("connect");
    free(puffer);
    free(host);    
    return -1;
  }



  // endlessly -->
  while (1)
  {
    numbytes = MAXINBUFSIZE;
    printf("> ");
    numchars = inputwd(puffer, maxnum);
    if (debug)
      printf("Number of chars: %d\n", numchars);
    if (numchars > 0)   // if everything is alright
    {
      if (debug)
      {
        for (ptr = puffer; ptr < (puffer + numchars); ptr++)
        {
          printf("Char: ");
          dummy = *ptr;
          dummy = putchar(dummy);
          printf(", Code: %.2x\n", dummy);
        }
      }

      // put to net
      if ( send(sockfd, (void*)puffer, numchars, 0) == -1 )
        perror("send");

      // delay before expecting response
      usleep(delay);


      while (numbytes == MAXINBUFSIZE)
      {
        if ((numbytes=recv(sockfd, buf, MAXINBUFSIZE, 0)) == -1)
          perror("recv");
        else
        {
          switch (displayformat)
          {
            case 0:       // human readable
              for (i = 0; i < numbytes; i++)
                printf("%c", buf[i]);
              printf("\n");
              break;

            case 1:
              for (i = 0; i < numbytes; i++)
                printf("%.2x", buf[i]);
              printf("\n");
              break;

            case 2:
              for (i = 0; i < numbytes; i++)
              {
                printf("%.2x", buf[i]);
                if (i != (numbytes - 1))
                  printf(" ");
              }              
              printf("\n");
              break;

            case 3:
              for (i = 0; i < numbytes; i++)
              {
                printf("%.2x", buf[i]);
                if (i != (numbytes - 1))
                  printf(":");
              }
              printf("\n");
              break;

            case 4:
              is2nd = 0;
              for (i = 0; i < numbytes; i++)
              {
                if (is2nd)
                  printf("%.2x ", buf[i]);
                else
                  printf("%.2x", buf[i]);
                is2nd ^= 1;     // toggle
              }
              printf("\n");
              break;

            default:
              for (i = 0; i < numbytes; i++)
                printf("%.2x", buf[i]);
              printf("\n");
              break;
          }
        }
      }

    }
  }
  // endlessly <--





  close(sockfd);
  free(puffer);
  free(host);

  return 0;
}
