/***************************************************************************
 *   copyright           : (C) 2004 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 <smspdu.h>

#include <helper.h>

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

static
void sms_pdu_sort_type (struct sms** list, const char* sub_order) {
  //4 lists for type sorting
  struct sms** list_sub; //SMS-SUBMIT
  unsigned int lssub = 0;
  struct sms** list_del; //SMS-DELIVER
  unsigned int lsdel = 0;
  struct sms** list_sr; //SMS-STATUS-REPORT
  unsigned int lssr = 0;
  struct sms** list_uns; //unsupported types
  unsigned int lsuns = 0;
  unsigned int listsize = 0;

  if (list == NULL || list[0] == NULL) return;

  //count items in list;
  while (list[listsize] != NULL) ++listsize;

  //splitting into type lists
  list_sub = mem_alloc((listsize+1)*sizeof(struct sms*),0);
  list_del = mem_alloc((listsize+1)*sizeof(struct sms*),0);
  list_sr = mem_alloc((listsize+1)*sizeof(struct sms*),0);
  list_uns = mem_alloc((listsize+1)*sizeof(struct sms*),0);
  listsize = 0;
  //do type sorting
  while (list[listsize] != NULL) {
    switch (list[listsize]->decoded->pdu->options.type) {
    case SMS_TYPE_SUBMIT:
      list_sub[lssub++] = list[listsize];
      break;
    case SMS_TYPE_DELIVER:
      list_del[lsdel++] = list[listsize];
      break;
    case SMS_TYPE_STATUS_REPORT:
      list_sr[lssr++] = list[listsize];
      break;
    default:
      list_uns[lsuns++] = list[listsize];
      break;
    }
    ++listsize;
  }
  list_sub[lssub] = NULL;
  list_del[lsdel] = NULL;
  list_sr[lssr] = NULL;
  list_uns[lsuns] = NULL;

  //subsorting
  sms_pdu_sort(list_sub,sub_order);
  sms_pdu_sort(list_del,sub_order);
  sms_pdu_sort(list_sr,sub_order);

  //merging to list
  listsize = 0;
  for (lsuns = 0; list_uns[lsuns] != NULL; ++lsuns) list[listsize++] = list_uns[lsuns];
  for (lssub = 0; list_sub[lssub] != NULL; ++lssub) list[listsize++] = list_sub[lssub];
  for (lssr = 0; list_sr[lssr] != NULL; ++lssr) list[listsize++] = list_sr[lssr];
  for (lsdel = 0; list_del[lsdel] != NULL; ++lsdel) list[listsize++] = list_del[lsdel];
  list[listsize] = NULL;
  mem_realloc(list_uns,0);
  mem_realloc(list_sub,0);
  mem_realloc(list_sr,0);
  mem_realloc(list_del,0);
}

//as input for argument 4 of qsort
static
int sms_pdu_sort_slot (const void* s1, const void* s2) {
  const struct sms* sms1 = *((const struct sms**)s1);
  const struct sms* sms2 = *((const struct sms**)s2);
  int slot1 = sms1->encoded[sms1->decoded->pdu->partnum]->slot;
  int slot2 = sms2->encoded[sms1->decoded->pdu->partnum]->slot;
  return slot1-slot2;
}

//as input for argument 4 of qsort
static
int sms_pdu_sort_time (const void* s1, const void* s2) {
  const struct sms* sms1 = *((const struct sms**)s1);
  const struct sms* sms2 = *((const struct sms**)s2);
  struct sms_pdu_time* t1 = &sms1->decoded->pdu->timedata;
  struct sms_pdu_time* t2 = &sms2->decoded->pdu->timedata;
  if (t1->format != t2->format) return t1->format-t2->format;
  else return t1->value-t2->value;
}

void sms_pdu_sort (struct sms** list, const char* order) {
  char* new_order;
  char* orders[] = { "type", "slot", "time" };
  unsigned int listsize = 0;

  if (list == NULL || list[0] == NULL || str_len(order) == 0) return;

  //count items in list;
  while (list[listsize] != NULL) ++listsize;

  //find next sorting item
  new_order = strchr(order,',');
  if (new_order != NULL) {
    do {
      ++new_order;
    } while (isspace((int)*new_order) &&
	     *new_order != 0);
  }

  if (strncasecmp(order,orders[0],strlen(orders[0])) == 0) {
    /* type sorting */
    sms_pdu_sort_type(list,new_order);
  } else if (strncasecmp(order,orders[1],strlen(orders[1])) == 0) {
    /* slot sorting */
    qsort(list,listsize,sizeof(*list),sms_pdu_sort_slot);
  } else if (strncasecmp(order,orders[2],strlen(orders[2])) == 0) {
    /* time sorting */
    qsort(list,listsize,sizeof(*list),sms_pdu_sort_time);
  }
}
