/***************************************************************************
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#ifndef _REENTRANT
# define _REENTRANT
#endif

#include <smspdu.h>
#include "smscoding.h"
#include "smsudh.h"

#include <charsets.h>
#include <helper.h>
#include <gtincl.h>
#include <intincl.h>

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

static
struct sms_pdu_raw* sms_pdu_create_submit_frame (char* number,
				   unsigned long options,
				   int header_present)
{
  uint8_t sca_len = 0;
  struct gsm_number sca; //short message service center address
  uint8_t pdutype; //PDU type
  uint8_t mr; //message reference
  uint8_t da_len = 0;
  struct gsm_number da; //destination address
  uint8_t pid = 0; //protocol identifier (normally 0)
  uint8_t dcs; //data coding scheme
  uint8_t vp_rel = 0xff; //validity period (0xff = max = 63 weeks)
  //char vp_abs[15]; //validity period (YYMMDDhhmmssTZ)

  struct sms_pdu_raw* frame = mem_alloc(sizeof(*frame),0);
  char* temp;
  uint8_t* ptr;

  sms_pdu_raw_init(frame);

  /* not yet supported
   * zero length means that the phone will use its default
   */
  gsm_number_init(&sca);
  sca_len = 0;
  
  /* set PDU type to standard values
   */
  pdutype = 1; //message type SMS-SUBMIT
  pdutype |= (1<<4); //validity period format: relative
  if (options&SMS_CREATE_OPT_REPORT) {
    pdutype |= (1<<5); //status report request;
  }
  if (header_present) {
    pdutype |= (1<<6); //user data header indication
  }

  /* message reference must be zero for Siemens phones!
   */
  mr = 0;

  /* destination number
   */
  if (is_telephone_number(number) == 0) {
    fprintf(stderr,"%s: %s\n",_("Error"),_("No valid number specified."));
    return NULL;
  }
  gsm_number_init(&da);
  gsm_number_set_toa(&da,numtype(number));
  gsm_number_set(&da,number,str_len(number));
  temp = gsm_number_get(&da);
  if (temp == NULL || strcmp(temp,number) != 0) {
    fprintf(stderr,_("%s: sms number cannot have more than %lu digits.\n"),_("Error"),(unsigned long)sizeof(da.digits)-1);
    return NULL;
  }
  mem_realloc(temp,0);
  da_len = strlen(da.digits);

  /* support "flash-SMS" and unicode here
   */
  dcs = 0;
  if (options&SMS_CREATE_OPT_FLASH) {
    dcs &= 0xec; //clear all affected bits
    dcs |= 0x10; //set class 0 message (immediate display)
  }
  if (options&SMS_CREATE_OPT_UNICODE) {
    dcs &= 0xf3; //clear all affected bits
    dcs |= 0x08; //set unicode charset
  }

  //leave pid and vp_rel as is

  //create PDU frame
  ptr = frame->data;
  ptr[0] = sca_len;
  ++ptr;
  if (sca_len) {
    ptr[0] = gsm_number_get_toa(&sca);
    ptr += gsm_number_get_semioctets(&sca,ptr)+1;
  }

  ptr[0] = pdutype;
  ptr[1] = mr;
  ptr += 2;
  
  ptr[0] = da_len;
  ptr[1] = gsm_number_get_toa(&da);
  ptr += 2;
  if (da_len) ptr += gsm_number_get_semioctets(&da,ptr);

  ptr[0] = pid;
  ptr[1] = dcs;
  ptr[2] = vp_rel;
  ptr += 3;
  frame->size = ptr-frame->data;

  gsm_number_delete(&sca);
  gsm_number_delete(&da);

  return frame;
}

struct sms_pdu_raw** sms_pdu_create_submit (char* text,
					    char* number,
					    unsigned long options)
{
  ucs4char_t* wide_str = convert_from_system(text);
  struct sms_pdu_raw** tpdu = NULL;
  unsigned int i = 0;
  struct sms_pdu_raw* frame;
  enum sms_encoding charset = SMS_CHARSET_GSM;
  gsmchar_t* g1 = NULL;
  ucs2char_t* g2 = NULL;

  if (options&SMS_CREATE_OPT_UNICODE) charset = SMS_CHARSET_UCS2;
  if (charset == SMS_CHARSET_GSM &&
      options&SMS_CREATE_OPT_AUTOCHAR)
  {
    g1 = convert_to_gsm(wide_str);
    if (gsmwidth(g1) < ucs4len(wide_str)) {
      g2 = convert_to_ucs2(wide_str);
      if (ucs2len(g2) == ucs4len(wide_str) ||
	  ucs2len(g2) > gsmwidth(g1))
      {
	/* more characters from the original string can be
	 * encoded if UCS-2 is used instead of the default GSM character set
	 */
	fprintf(stderr,"%s: %s\n",_("Notice"),_("Selecting UCS-2 character set."));
	charset = SMS_CHARSET_UCS2;
      } else {
	/* we do not want error messages from convert_to_gsm
	 * being printed twice
	 */
	mem_realloc(wide_str,0);
	wide_str = convert_from_gsm(g1);
      }
      mem_realloc(g2,0);
    }
    mem_realloc(g1,0);
  }
  tpdu = sms_data_encode(charset,NULL, wide_str);
  mem_realloc(wide_str,0);

  if (tpdu == NULL) return NULL;

  frame = sms_pdu_create_submit_frame(number,options,
				      (tpdu[1] == NULL)? 0 : 1);
  if (frame == NULL) return NULL;

  for (; tpdu[i] != NULL; ++i) {
    memmove(tpdu[i]->data+frame->size,tpdu[i]->data,tpdu[i]->size);
    memcpy(tpdu[i]->data,frame->data,frame->size);
    tpdu[i]->size += frame->size;
  }
  mem_realloc(frame,0);

  return tpdu;
}
