/*
 * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
 * 
 *     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.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program; if not, write to the Free Software
 *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */ 

#include "mutt.h"
#include "sort.h"

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

#define SORTCODE(x) (Sort & SORT_REVERSE) ? -(x) : x

int compare_size (const void *a, const void *b)
{
  HEADER **pa = (HEADER **) a;
  HEADER **pb = (HEADER **) b;

  return (SORTCODE ((*pa)->content->length - (*pb)->content->length));
}

int compare_date_sent (const void *a, const void *b)
{
  HEADER **pa = (HEADER **) a;
  HEADER **pb = (HEADER **) b;

  return (SORTCODE ((*pa)->date_sent - (*pb)->date_sent));
}

int compare_subject (const void *a, const void *b)
{
  HEADER **pa = (HEADER **) a;
  HEADER **pb = (HEADER **) b;
  int rc;

  if (!(*pa)->env->real_subj)
  {
    if (!(*pb)->env->real_subj)
      rc = compare_date_sent (pa, pb);
    else
      rc = -1;
  }
  else if (!(*pb)->env->real_subj)
    rc = 1;
  else
    rc = strcasecmp ((*pa)->env->real_subj, (*pb)->env->real_subj);
  return (SORTCODE (rc));
}

int compare_from (const void *a, const void *b)
{
  HEADER **ppa = (HEADER **) a;
  HEADER **ppb = (HEADER **) b;
  HEADER *pa = *ppa, *pb = *ppb;
  ADDRESS *adr;
  char bufa[SHORT_STRING], bufb[SHORT_STRING];
  char *fa, *fb;

  if (option (OPTREVALIAS) && (adr = alias_reverse_lookup (pa->env->from))
				&& adr->personal)
    fa = adr->personal;
  else if (pa->env->from && pa->env->from->personal)
    fa = pa->env->from->personal;
  else
  {
    bufa[0] = 0;
    rfc822_write_address (bufa, sizeof (bufa), pa->env->from);
    fa = bufa;
  }

  if (option (OPTREVALIAS) && (adr = alias_reverse_lookup (pb->env->from))
				&& adr->personal)
    fb = adr->personal;
  else if (pb->env->from && pb->env->from->personal)
    fb = pb->env->from->personal;
  else
  {
    bufb[0] = 0;
    rfc822_write_address (bufb, sizeof (bufb), pb->env->from);
    fb = bufb;
  }

  return (SORTCODE (strcasecmp (fa, fb)));
}

int compare_date_received (const void *a, const void *b)
{
  HEADER **pa = (HEADER **) a;
  HEADER **pb = (HEADER **) b;
  
  return (SORTCODE ((*pa)->received - (*pb)->received));
}

int compare_order (const void *a, const void *b)
{
  HEADER **ha = (HEADER **) a;
  HEADER **hb = (HEADER **) b;

  return (SORTCODE ((*ha)->index - (*hb)->index));
}

sort_t *mutt_get_sort_func (int method)
{
  switch (method & SORT_MASK)
  {
    case SORT_RECEIVED:
      return (compare_date_received);
    case SORT_ORDER:
      return (compare_order);
    case SORT_DATE:
      return (compare_date_sent);
    case SORT_SUBJECT:
      return (compare_subject);
    case SORT_FROM:
      return (compare_from);
    case SORT_SIZE:
      return (compare_size);
    default:
      return (NULL);
  }
  /* not reached */
}

void mutt_sort_headers (CONTEXT *ctx, int init)
{
  int i;
  sort_t *sortfunc;
  
  if (!ctx)
    return;

  if (!ctx->msgcount)
  {
    /* this function gets called by mutt_sync_mailbox(), which may have just
     * deleted all the messages.  the virtual message numbers are not updated
     * in that routine, so we must make sure to zero the vcount member.
     */
    ctx->vcount = 0;
    ctx->tree = 0;
    return; /* nothing to do! */
  }

  if (!ctx->quiet)
    mutt_message ("Sorting mailbox...");

  /* threads may be bogus, so clear the links */
  if (init)
    mutt_clear_threads (ctx);

  if ((Sort & SORT_MASK) == SORT_THREADS)
    mutt_sort_threads (ctx, init);
  else if ((sortfunc = mutt_get_sort_func (Sort)) == NULL)
  {
    mutt_error ("Could not find sorting function! [report this bug]");
    sleep (1);
    return;
  }
  else 
    qsort ((void *) ctx->hdrs, ctx->msgcount, sizeof (HEADER *), sortfunc);

  /* the threading function find_reference() needs to know how the mailbox
   * is currently sorted in memory in order to speed things up a bit
   */
  ctx->revsort = (Sort & SORT_REVERSE) ? 1 : 0;

  /* adjust the virtual message numbers */
  ctx->vcount = 0;
  for (i = 0; i < ctx->msgcount; i++)
  {
    if (ctx->hdrs[i]->virtual != -1)
    {
      ctx->hdrs[i]->virtual = ctx->vcount;
      ctx->v2r[ctx->vcount] = i;
      ctx->vcount++;
    }
    ctx->hdrs[i]->msgno = i;
  }

  if (!ctx->quiet)
    mutt_clear_error ();
}
