/***************************************************************************
 *   copyright           : (C) 2002 by Hendrik Sattler                     *
 *   mail                : post@hendrik-sattler.de                         *
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "ttyaccess.h"
#include "tty_serial.h"
#include "tty_bluetooth.h"

#include "scmxx.h"
#include "helper.h"
#include "atcommand.h"
#include "config.h"
#include "gtincl.h"
#include "w32compat.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>


struct tty_access* tty_open(struct port_args_t* args) {
  struct tty_access* t = NULL;

  print_verbose(0,_("Accessing device %s..."),args->device);
  switch (args->type) {
  case TTY_TYPE_BLUETOOTH:
    t = tty_bluetooth_open(args);
    break;
  case TTY_TYPE_SERIAL:
    t = tty_serial_open(args);
    break;
  default:
    break;
  }
  if (t == NULL) {
    print_error(_("Cannot open %s\n"),args->device);
    exit(EXIT_FAILURE);
  }
    
  print_verbose(0,"%s\n",_("done"));
  /* The following seems to be needed for C45
   * which seems to react too slow
   */
  if (args->startdelay) {
    print_verbose(0,_("Waiting for %d seconds as requested...\n"),args->startdelay);
    sleep(args->startdelay);
  }
  return t;
}

int tty_write (const char* data, size_t count,
	       long (*write_func) (const char* data, long len))
{
  long status = 0;
  long instatus;

  do {
    instatus = write_func(data+status,count-status);
    if (instatus != -1) {
      status += instatus;
    } else {
#if ! ( defined(DOS_API) || defined(WINDOWS_API) )
      if (errno == EAGAIN) usleep(1);
      else
#endif
	return 0;
    }
  } while (count-status > 0);
  return 1;
}


char* tty_read (int (*stop_condition)(const char*,const size_t),
		long (*read_func) (char* buf, long len))
{	
  char* retval = NULL;
  int retvalsize = 0;
  char buffer; //buffer the read character for checks
  int counter = 0; //count the read-and-used characters
  int repeat = 0; //tell the inner loop to loop

  long status;

  do {
    do {
      status = read_func(&buffer,1);
      switch (status) {
      case -1:
#if ! ( defined(DOS_API) || defined(WINDOWS_API) )
        if (errno == EAGAIN) {
          usleep(1);
          repeat = 1;
        } else
#endif
	{
          mem_realloc(retval,0);
          return NULL;
        }
      case 0:
        mem_realloc(retval,0);
        return str_dup("");
      default:
        repeat = 0;
      }
    } while (repeat);

    // allocate space on stack
    if (counter >= retvalsize) {
      retvalsize += BUFSIZ;
      retval = mem_realloc(retval,retvalsize+1);
      memset(retval+counter,0,retvalsize-counter+1);
    }

    /* fix the '@'=0x00 (GSM character set) problem here :-(
     * we simply set the MSB to 1, so when processing:
     * only look at the last 7 bits (char&0x7F)
     */
    retval[counter++] = (buffer == 0) ? 128 : buffer;
  } while (!stop_condition(retval,counter));
  /* There are two types of possible answers:
   * "> " (2 characters) for data input requests
   * "....<CR><LF>" for all other things (even empty)
   */
  return mem_realloc(retval,strlen(retval)+1);
}

