/*
 * ipwstatus for IPWireless USB Modem
 *
 * Authors:
 *   Stephen Blackheath <stephen@blacksapphire.com>,
 *   Ben Martel (benm@symmetric.co.nz>
 *
 *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
 *
 * Released under the GNU General Public Licence
 */

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>

#include "tty_lock.h"
#include "modem_comm.h"

static int debug = 0;
static int defaultTimeoutSecs;

static int wait_for_write(int fd, int timeoutSecs)
{
  int ret;
  fd_set wrfs;
  struct timeval tv;
  FD_ZERO(&wrfs);
  FD_SET(fd, &wrfs);
  tv.tv_sec = timeoutSecs;
  tv.tv_usec = 0;
  return select(fd+1, NULL, &wrfs, NULL, &tv);
}

static int wait_for_read(int fd, int timeoutSecs)
{
  int ret;
  fd_set rdfs;
  struct timeval tv;
  FD_ZERO(&rdfs);
  FD_SET(fd, &rdfs);
  tv.tv_sec = timeoutSecs;
  tv.tv_usec = 0;
  return select(fd+1, &rdfs, NULL, NULL, &tv);
}

static int suck(int fd)
{
    char buf[20];
    int cleared = 0;
    while (1) {
      int n = read(fd, buf, sizeof(buf));
      if (n <= 0) {
        if (n == 0 || errno == EAGAIN)
          break;
        return n;
      }
      cleared += n;
      if (debug) {
        int i;
        for (i = 0; i < n; i++)
          printf("%02x ", (int) (unsigned char) buf[i]);
        printf("\n");
      }
    }
    if (debug)
      printf("cleared %d bytes\n", cleared);
    return 0;
}

int modem_init(char *device_name, int defaultTimeoutSecs_)
{
  int fd;

  if (tty_lock(device_name) < 0)
    return -1;

  defaultTimeoutSecs = defaultTimeoutSecs_;
  fd = open(device_name, O_RDWR|O_NONBLOCK);
  if (fd >= 0) {
      /* Clean any left over junk out of the buffer, though I don't
       * think there is any. */
    int ret;
    struct termios tios;

    ret = tcgetattr(fd, &tios);
    if (ret < 0) {
      modem_close(fd);
      return ret;
    }

      /* Things definitely don't work properly unless we set the terminal
       * settings to reasonable defaults. */
    tios.c_iflag = IGNBRK;
    tios.c_oflag = 0;
    tios.c_cflag = __MAX_BAUD/*B38400*/|CLOCAL|CREAD|CS8;
    tios.c_lflag = 0;
    ret = tcsetattr(fd, TCSANOW, &tios);
    if (ret < 0) {
      modem_close(fd);
      return ret;
    }
    ret = modem_write(fd, "\r", 1);
    if (ret < 0) {
      modem_close(fd);
      return ret;
    }
    usleep(200);
    ret = suck(fd);
    if (ret < 0) {
      modem_close(fd);
      return ret;
    }
  }
  else
    tty_unlock();
  return fd;
}

int modem_close(int fd)
{
  int ret = close(fd);
  tty_unlock();
  return ret;
}

int modem_write(int fd, char* command, int commandLen)
{
  int idx = 0;

  while (idx < commandLen) {
    int n;
    int ret = wait_for_write(fd, 5);
    if (ret < 0)
      return ret;
    n = write(fd, command+idx, commandLen-idx);
    if (n <= 0) return n;
    idx += n;
  }
  return commandLen;
}

int modem_issue_long(int fd, char* command, char* answer, int answerBufLen, int verbose, int timeoutSecs)
{
  int ret;
  int outIdx = 0;
  int newLines = 0;
  char buf[40];
  if (verbose)
    printf("%s\n", command);
  ret = modem_write(fd, command, strlen(command));
  if (ret < 0)
    return ret;
  ret = modem_write(fd, "\r", 1);
  if (ret < 0)
    return ret;
  while (1) {
    int i;
    int n;
    ret = wait_for_read(fd, timeoutSecs);
    if (ret < 0) {
      if (debug)
        printf("\n");
      return n;
    }
    n = read(fd, buf, 40);
    if (n < 0) {
      if (debug)
        printf("\n");
      return n;
    }
    for (i = 0; i < n; i++) {
      if (debug) {
        printf("%02x ", (int) (unsigned char) buf[i]);
        fflush(stdout);
      }
      if (buf[i] == '\n') {
        newLines++;
        if (newLines == 2) {
          answer[outIdx] = 0;
          if (debug)
            printf("\n");
          if (verbose)
            printf("%s\n", answer);
          return outIdx;
        }
      }
      else
      if (buf[i] != '\r' && newLines == 1 && outIdx < answerBufLen-1)
        answer[outIdx++] = buf[i];
    }
  }
}

int modem_issue(int fd, char* command, char* answer, int answerBufLen, int verbose)
{
  return modem_issue_long(fd, command, answer, answerBufLen, verbose, defaultTimeoutSecs);
}

char* get_ipwireless_driver_type()
{
}
