/***************************************************************************
 *   copyright           : (C) 2002, 2003, 2004, 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 "scmxx.h"
#include "charsets.h"
#include "helper.h"
#include "pbmaskgsm.h"
#include "options.h"
#include "atcommand.h"
#include "pbookphone.h"
#include "pbookfile.h"
#include "gtincl.h"

#include <errno.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>

struct pbook_entry**
phoneentry_to_fileentry (struct pbook_phone_entry** pentries,
			 int uses_unicode)
{
  struct pbook_entry** fentries = NULL;
  unsigned int i = 0;

  while (pentries[i] != NULL) ++i;
  fentries = mem_alloc((i+1)*sizeof(*fentries),0);
  for (i = 0; pentries[i] != NULL; ++i) {
    fentries[i] = mem_alloc(sizeof(**fentries),0);
    fentries[i]->slot = pentries[i]->slot;
    fentries[i]->number = pentries[i]->number;
    if (uses_unicode) {
      fentries[i]->text = convert_from_ucs2_hexstring((char*)pentries[i]->text,letohs);
    } else {
      fentries[i]->text = convert_from_gsm(pentries[i]->text);
    }
    pentries[i]->number = NULL;
    pentries[i]->text = mem_realloc(pentries[i]->text,0);
    pentries[i] = mem_realloc(pentries[i],0);
  }
  fentries[i] = NULL;
  return fentries;
}

struct pbook_phone_entry**
fileentry_to_phoneentry (struct pbook_entry** fentries,
			 int use_unicode)
{
  struct pbook_phone_entry** pentries = NULL;
  unsigned int i = 0;

  while (fentries[i] != NULL) ++i;
  pentries = mem_alloc((i+1)*sizeof(*pentries),0);
  for (i = 0; fentries[i] != NULL; ++i) {
    pentries[i] = mem_alloc(sizeof(**pentries),0);
    struct_pbook_phone_entry_init(pentries[i]);
    pentries[i]->slot = fentries[i]->slot;
    pentries[i]->number = fentries[i]->number;
    pentries[i]->numtype = numtype(fentries[i]->number);
    if (use_unicode) {
      pentries[i]->text = (unsigned char*)convert_to_ucs2_hexstring(fentries[i]->text,htoles);
    } else {
      pentries[i]->text = convert_to_gsm(fentries[i]->text);
    }
    fentries[i]->number = NULL;
    fentries[i]->text = mem_realloc(fentries[i]->text,0);
    fentries[i] = mem_realloc(fentries[i],0);
  }
  pentries[i] = NULL;
  return pentries;
}

void pbook_send_entry (struct parameters* myparams) {
  int unicode;
  struct pbook_phone_entry** pentries = NULL;
  ucs4char_t* temp;

  unicode = set_charset("UCS2");
  pentries = mem_alloc(2*sizeof(*pentries),0);
  pentries[1] = NULL;
  pentries[0] = mem_alloc(sizeof(**pentries),0);
  struct_pbook_phone_entry_init(pentries[0]);
  pentries[0]->slot = myparams->slot;
  if (myparams->number != NULL) {
    pentries[0]->number = myparams->number;
    pentries[0]->numtype = numtype(myparams->number);
  }
  if (myparams->text != NULL) {
    temp = convert_from_system(myparams->text);
    if (unicode) {
      pentries[0]->text = (unsigned char*)convert_to_ucs2_hexstring(temp,htoles);
    } else {
      pentries[0]->text = convert_to_gsm(temp);
    }
    mem_realloc(temp,0);
  }
  if (pbook_phone_write(myparams->mem,pentries) == 0) {
    errexit("%s\n",_("something went wrong with sending the phonebook entries"));
  }
  set_charset("GSM");
}

void pbook_send (char* file, char* phonebook) {
  int unicode;
  struct pbook_phone_entry** pentries = NULL;
  struct pbook_entry** fentries;

  unicode = set_charset("UCS2");
  fentries = pbook_file_read(file);
  if (fentries == NULL) {
    errexit(_("invalid phonebook file %s.\n"),file);
  }
  if (fentries[0] == NULL) {
    errexit(_("empty phonebook file %s.\n"),file);
  }
  pentries = fileentry_to_phoneentry(fentries,unicode);
  if (pbook_phone_write(phonebook,pentries) == 0) {
    errexit("%s\n",_("something went wrong with sending the phonebook entries"));
  }
  set_charset("GSM");
}

void pbook_get (struct parameters* myparams, char* file) {
  int unicode;
  struct pbook_phone_entry** pentries = NULL;
  struct pbook_entry** fentries = NULL;

  unicode = set_charset("UCS2");
  if (myparams->slot >= SCMXX_SLOT_PBOOK_MIN) {
    pentries = pbook_phone_get_range(myparams->mem,
				     myparams->slot,
				     myparams->slot,
				     0);
  } else {
    pentries = pbook_phone_get(myparams->mem);
  }
  if (pentries == NULL || pentries[0] == NULL) {
    print_verbose(0,"%s\n",_("Nothing to get."));
  } else {
    fentries = phoneentry_to_fileentry(pentries,unicode);
    pbook_file_write(file,fentries);
  }
  set_charset("GSM");
}

void pbook_delete (char* phonebook) {
  char* ausgabe;
  char* temp;
  unsigned int i,min=0,max=0;
  enum return_code status;
  struct pbook_phone_entry** pentries = NULL;
  
  if ((!strcasecmp(phonebook,"DC"))
      || (!strcasecmp(phonebook,"MD"))
      || (!strcasecmp(phonebook,"LD"))) {
    at_command_send(AT_SIE_PB_DELETE,NULL);
    ausgabe = at_read_line();
    status = at_line_type(ausgabe,AT_SIE_PB_DELETE,&temp);
    if (status == AT_RET_OK) {
      print_verbose(0,_("%s deleted.\n"),phonebook);
    } else {
      errexit("%s\n%s\n",temp,_("Possible data corruption!"));
    }
    mem_realloc(ausgabe,0);
  } else {
    if (pbook_get_ranges(phonebook,1,&min,&max,NULL,NULL)) {
      pentries = mem_alloc((max-min+2)*sizeof(*pentries),0);
      for (i = 0; i <= max-min; ++i) {
	pentries[i] = mem_alloc(sizeof(**pentries),0);
	struct_pbook_phone_entry_init(pentries[i]);
	pentries[i]->slot = i+min;
      }
      pentries[max-min+1] = NULL;
      if (pbook_phone_write(phonebook,pentries) == 0) {
	errexit("%s\n",_("something went wrong with sending the phonebook entries"));
      }
    } else
      errexit("%s\n",_("the selected phonebook is not writable"));
  }
}

int pbook_get_ranges (char* mem, int write,
		      unsigned int* min, unsigned int* max,
		      int* nrlen, int* txtlen)
{
  char* command;
  char* ausgabe;
  char* temp;
  enum return_code status;
  
  if (mem == NULL) return 0;

  //reset those values to invalid
  if (nrlen != NULL) *nrlen = -1;
  if (txtlen != NULL) *txtlen = -1;

  if (write) {
    command = AT_GEN_PB_WRITE;
  } else {
    if (strcasecmp(mem,VCARD_PHONEBOOK_NAME) == 0) {
      command = AT_SIE_PB_VCF_READ;
      //answer does not contain nrlen or txtlen
      nrlen = NULL;
      txtlen = NULL;
    } else if (strcasecmp(mem,"RD") == 0 ||
	       strcasecmp(mem,"CS") == 0) {    
      command = AT_SIE_PB_READ_SORTED;
    } else {
      command = AT_GEN_PB_READ;
    }
  }

  at_command_send(command,AT_READ_SUFFIX);
  ausgabe = at_read_line();
  status = at_line_type(ausgabe,command,&temp);
  if (status != AT_RET_ANSWER && status != AT_RET_OTHER) {
    return 0;
  }
  mem_realloc(at_read_line(),0);
  /* examples:
   * +CPBW: (1-100),20,(128-255),17
   * +CPBR: (1-100),20,17
   * ^SPBG: (1-75),20,17
   * ^SDBR: (1-45)
   */
  //minimum of range
  if (min != NULL) {
    if (*temp != '(') return 0;
    *min = atoi(temp+1);
  }
  ++temp;
  //maximum of range
  if (max != NULL) {
    while (isdigit((int)*temp)) ++temp;
    switch(*temp) {
    case '-': *max = atoi(temp+1); break;
    case ')': *max = *min; break;
    default: return 0;
    }
  }
  //maximum number field length
  if (nrlen != NULL) {
    temp = strchr(temp,',');
    if (temp == NULL) return 0;
    *nrlen = atoi(temp+1);
  }
  //maximum text field length
  if (txtlen != NULL) {
    temp = strrchr(temp,',');
    if (temp == NULL) return 0;
    *txtlen = atoi(temp+1);
  }  
  return 1;
}

void pbook_manage (int action, char* outfile,
		   char** files, struct parameters* myparams)
{
  unsigned int i = 0;
  unsigned int max;

  if (myparams->mem == NULL) {
    //SIM myparams->mem seems to be a good default
    myparams->mem = "SM";
  }
  if (strcmp(myparams->mem,"?") == 0) {
    pbook_print_memlist(NULL,1);
    return;
  }

  if (action == 0) {
    errexit ("%s\n",_("You must specify a valid action."));
  }

  if (!pbook_select_mem(myparams->mem)) {
    errexit(_("Cannot select memory %s\n"),myparams->mem);
  }

  if (myparams->slot == SCMXX_SLOT_LAST) {
    if (pbook_get_ranges(myparams->mem,1,NULL,&max,NULL,NULL))
      myparams->slot = max;
    else
      errexit("%s\n",_("could not determine last slot."));	  
  }

  switch (action) {
  default:
    errexit("%s\n",_("You must specify exactly one operation."));
    break;
  case SCMXX_ACTION_REMOVE: //deleting
    if (myparams->slot >= SCMXX_SLOT_PBOOK_MIN) {
      pbook_send_entry(myparams);
    } else {
      pbook_delete(myparams->mem);
    }
    break;
  case SCMXX_ACTION_SEND: //sending
    if (myparams->number != NULL || myparams->text != NULL) {
      if (myparams->slot == SCMXX_SLOT_UNDEFINED) {
	myparams->slot = pbook_phone_find_empty(myparams->mem,0);
      } else if (myparams->slot < SCMXX_SLOT_PBOOK_MIN) {
	errexit("%s\n",_("invalid slot defined"));
      }
      pbook_send_entry(myparams);
    } else {
      while (files[i] != NULL) {
	pbook_send(files[i++],myparams->mem);
      }
    }
    break;
  case SCMXX_ACTION_GET: //getting
    pbook_get(myparams,outfile);
    break;
  }
}
