/***************************************************************************
 *   copyright           : (C) 2005 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 "atcommand.h"
#include "scmxx.h"
#include "gtincl.h"
#include "smspdu.h"
#include "w32compat.h"

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

struct call_info {
  int id;
  int direction;
  int status;
  int mode;
  int conference;
  struct gsm_number num;
};
struct call_info* call_info_new () {
  struct call_info* retval = mem_alloc(sizeof(*retval),0);
  retval->id = 0;
  retval->direction = 0;
  retval->status = 0;
  retval->mode = 0;
  retval->conference = 0;
  gsm_number_init(&retval->num);
  return retval;
}

void call_info_delete (struct call_info* this) {
  gsm_number_delete(&this->num);
  mem_realloc(this,0);
}

struct call_info* parse_call_info_line (char* line) {
  struct call_info* retval = call_info_new();
  int type = 0;
  char number[3+20+1];
  int i;
  
  // <id1>,<dir>,<stat>,<mode>,<empty>,<number>,<type>
  memset(number,0,sizeof(number));
  i = sscanf(line,"%d,%d,%d,%d,%d,%23[\"+0-9],%d",
	      &retval->id,&retval->direction,&retval->status,
	      &retval->mode,&retval->conference,
	      number,&type);
  if (i == 7) {
    gsm_number_set_toa(&retval->num,(uint8_t)type&0xFF);
    gsm_number_set(&retval->num,number,str_len(number));
  } else {
    retval = mem_realloc(retval,0);
  }
  return retval;
}

struct call_info** get_call_info () {
  struct call_info** retval = NULL;
  unsigned int count = 0;
  unsigned int i = 0;
  char* answer;
  char* temp = NULL;
  enum return_code code;

  at_command_send(AT_GEN_CALLINFO,NULL);
  answer = at_read_line();
  code = at_line_type(answer,AT_GEN_CALLINFO,&temp);
  while (code == AT_RET_ANSWER) {
    if (i+1 >= count) {
      count += 5;
      retval = mem_realloc(retval,count*sizeof(*retval));
      retval[i+1] = NULL;
      retval[i+2] = NULL;
    }
    retval[i] = parse_call_info_line(temp);
    mem_realloc(answer,0);
    answer = at_read_line();
    code = at_line_type(answer,AT_GEN_CALLINFO,&temp);
  }
  return retval;
}

int dial_number (char* number) {
  char* temp;
  unsigned int length = str_len(number);

  if (length == 0) return 0;

  temp = mem_alloc(length+2,1);
  snprintf(temp,length+3,"D%s;",number);
  at_command_send(temp,NULL);
  mem_realloc(temp,0);
  temp = at_read_line();
  if (at_line_type(temp,NULL,NULL) == AT_RET_OK) return 1;
  else return 0;
}

void dial (char* number,int wait) {
  struct call_info** ci;
  struct gsm_number num;
  unsigned int i;
  int loop_break = 0;
  int timer = 0;

  print_verbose(0,_("Using dialing sequence %s.\n"),number);
  if (keypad_dial_number(number) == 0 &&
      dial_number(number) == 0)
    errexit("%s\n", _("dialing failed"));

  /* wait until it rings on the remote side */
  if (wait) {
    gsm_number_init(&num);
    gsm_number_set_toa(&num,numtype(number));
    gsm_number_set(&num,number,str_len(number));
    do {
      ci = get_call_info();
      if (ci == NULL || ci[0] == NULL) {
	usleep(100*1000);
	++timer;
      }
      if (ci != NULL) {
	for (i=0; ci[i] != NULL; ++i)
	  if (gsm_number_compare(&num,&ci[i]->num)) {
	    loop_break = 1;
	    if (ci[i]->status == 3) // 2 == dialing, 3 == alert (remote ring)
	      loop_break = 2;
	  }
	for (i=0; ci[i] != NULL; ++i)
	  call_info_delete(ci[i]);
	ci = mem_realloc(ci,0);
      } else {
	/* if user hangs up before it rings on the other side */
	if (loop_break == 1) ++loop_break;
      }
    } while (loop_break < 2 && timer < 100);
  }
}

void hangup () {
  at_command_send(AT_GEN_HANGUP,NULL);
  mem_realloc(at_read_line(),0);
}
