/*****************************************************************************
 * AreaFix for HPT (FTN NetMail/EchoMail Tosser)
 *****************************************************************************
 * Copyright (C) 2000
 *
 * Lev Serebryakov
 *
 * Fido:     2:5030/661
 * Internet: lev@serebryakov.spb.ru
 * St.Petersburg, Russia
 *
 * This file is part of HPT.
 *
 * HPT 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, or (at your option) any
 * later version.
 *
 * HPT 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 HPT; see the file COPYING.  If not, write to the Free
 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *****************************************************************************
 * $Id: arealist.c,v 1.8 2003/01/16 12:50:16 stas_degteff Rel $
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>


#include <smapi/compiler.h>

#ifdef HAS_UNISTD_H
#   include <unistd.h>
#endif


#include "arealist.h"
#include "common.h"

#define LIST_PAGE_SIZE  256

ps_arealist newAreaList(void)
{
    ps_arealist al;
    
    if(NULL == (al = malloc(sizeof(s_arealist)))) 
        return NULL;
    al->areas = NULL;
    al->count = 0;
    al->maxcount = LIST_PAGE_SIZE;
    if(NULL == (al->areas = malloc(al->maxcount*sizeof(s_arealistitem))) )
    { 
        nfree(al);
        return NULL;
    }
    return al;
}

void freeAreaList(ps_arealist al)
{
    int i;

    if(al) {
        if(al->areas && al->maxcount) {
            for(i = 0; i < al->count; i++) {
                nfree(al->areas[i].tag);
                nfree(al->areas[i].desc);
            }
            nfree(al->areas);
        }
        nfree(al);
    }
    return;
}

int addAreaListItem(ps_arealist al, int active, int rescanable, char *tag, char *desc)
{
	ps_arealistitem areas;
	int l;

	if(al->count == al->maxcount) {
		if(NULL == (areas = realloc(al->areas,(al->maxcount+LIST_PAGE_SIZE)*sizeof(s_arealistitem)))) return 1;
		al->areas = areas;
		al->maxcount += LIST_PAGE_SIZE;
    }
    al->areas[al->count].active     = active;
    al->areas[al->count].rescanable = rescanable ? 2 : 0;
    al->areas[al->count].tag        = sstrdup(tag);
    if(desc) {
    	l = strlen(desc);
    	al->areas[al->count].desc = smalloc(l+3);
    	if('"' == desc[0] && '"' == desc[l-1]) {
    		strcpy(al->areas[al->count].desc,desc);
    	} else {
    		al->areas[al->count].desc[0] = '"';
    		strcpy(&al->areas[al->count].desc[1],desc);
			al->areas[al->count].desc[l+1] = '"';
			al->areas[al->count].desc[l+2] = '\x00';
    	}
	}
    else al->areas[al->count].desc = NULL;
	al->count++;

	return 0;
}

static int compare_arealistitems(const void *a, const void *b)
{ return sstricmp(((ps_arealistitem)a)->tag,((ps_arealistitem)b)->tag); }

void sortAreaList(ps_arealist al)
{
	if(al && al->count && al->areas)
		qsort(al->areas,al->count,sizeof(s_arealistitem),compare_arealistitems);
}

static int compare_arealistitems_and_desc(const void *a, const void *b) 
{
  register int r;

  /* compare areatags */
  r = sstricmp(((ps_arealistitem)a)->tag,((ps_arealistitem)b)->tag);
  if (r!=0)
  	return r;
  /* comapre descriptions: if both presents it's eq; if both absence then eq also;
     else NULL'ed is little */
  r = (((ps_arealistitem)b)->desc != NULL) - (((ps_arealistitem)a)->desc != NULL);
  return r;

/* Don't compare descriptions text
  if ((r!=0)||(((ps_arealistitem)a)->desc == NULL))
  	return r;

  return strcmp(((ps_arealistitem)a)->desc, ((ps_arealistitem)b)->desc);
*/
}

void sortAreaListNoDupes(unsigned int halcnt, ps_arealist *hal, int nodupes)
{
  int i,j;
  unsigned int k;
  char *prev;
  ps_arealist al;
  ps_arealistitem ali;

  if (!hal)
    return;

  al = hal[halcnt-1];

  if(!(al && al->count && al->areas))
    return;

  if (!nodupes)
  {
    sortAreaList(al);
    return;
  }

  qsort(al->areas,al->count,sizeof(s_arealistitem),compare_arealistitems_and_desc);

  j=0;
  prev = NULL;

  for(i=0; i<al->count; i++)
  {
    if (prev&&(sstricmp(prev, al->areas[i].tag)==0))
    {
      nfree(al->areas[i].tag);
      nfree(al->areas[i].desc);
      continue;
    }
    prev = al->areas[i].tag;

    ali = NULL;
    for(k=1; k<halcnt; k++)
    {
      ali = bsearch(&(al->areas[i]), hal[k-1]->areas, hal[k-1]->count, sizeof(s_arealistitem), compare_arealistitems);
      if (ali)
        break;
    }
    if (ali)
    {
      prev = NULL;
      nfree(al->areas[i].tag);
      nfree(al->areas[i].desc);
      continue;
    }

    if (i!=j) memcpy(&(al->areas[j]), &(al->areas[i]), sizeof(s_arealistitem));
    j++;
  }

  if (j!=(al->maxcount))
  {
    al->areas = realloc(al->areas, j*sizeof(s_arealistitem));
    al->maxcount = j;
  }
  al->count = j;
}


static char *addline(char *text, char *line, int *pos, int *tlen)
{
	int ll;

	if(!text) return NULL;
	if(!line) return text;

	ll = strlen(line);

	if(*pos+ll+1 > *tlen) {
		*tlen += 1024;
		if(NULL == (text = realloc(text,*tlen))) return NULL;
	}
	strcpy(&text[*pos],line);
	*pos += ll;
	return text;
}

static char *addchars(char *text, char c, int count, int *pos, int *tlen)
{
	int i;
	if(!text) return NULL;
	if(*pos+count+1 > *tlen) {
		*tlen += count+1024;
		if(NULL == (text = realloc(text,*tlen))) return NULL;
	}
	for(i = *pos; i < *pos+count; i++) text[i] = c;
    text[i] = '\x00';
    *pos += count;
	return text;
}

char *formatAreaList(ps_arealist al, int maxlen, char *activechars)
{
	char *text;
	char *p;
	int i;
	int clen,wlen;
	int tlen;
	int tpos = 0;

	if(!al || !al->count || !al->areas) return NULL;

	tlen = al->count * (maxlen+3);

	if(NULL == (text = malloc(tlen))) return NULL;
	text[tpos] = '\x00';
	
	for(i = 0; i < al->count; i++) {
		clen = 0;
		if(tpos >= tlen) {
			tlen += (maxlen+3) * 32;
			if(NULL == (text = realloc(text,tlen))) return NULL;
		}
		if(activechars) {
			text[tpos++] = activechars[al->areas[i].active];
            text[tpos++] = activechars[al->areas[i].rescanable];
			clen++;
		}
		text[tpos++] = ' ';
		clen++;
		text[tpos] = '\x00';

        if(NULL == (text = addline(text,al->areas[i].tag,&tpos,&tlen))) return NULL;

        /* Not add description */
        if(!al->areas[i].desc) {
			text[tpos++] = '\r';
			text[tpos] = '\x00';
        	continue;
		}

        clen += strlen(al->areas[i].tag);
        wlen = strlen(al->areas[i].desc);
        if(clen + 3 + wlen <= maxlen) {
			text[tpos++] = ' ';
			text[tpos] = '\x00';
	        if(NULL == (text = addchars(text,'.',maxlen-(clen+2+wlen),&tpos,&tlen))) return NULL;
			text[tpos++] = ' ';
			text[tpos] = '\x00';
	        if(NULL == (text = addline(text,al->areas[i].desc,&tpos,&tlen))) return NULL;
        } else {
        	p = strchr(al->areas[i].desc,' ');
        	if(p && (p - al->areas[i].desc) + clen + 3 <= maxlen) {
        		wlen = p - al->areas[i].desc;
				*p = '\x00';				

				text[tpos++] = ' ';
				text[tpos] = '\x00';
	    	    if(NULL == (text = addchars(text,'.',maxlen-(clen+2+wlen),&tpos,&tlen))) {
	        		*p = ' ';
	        		return NULL;
				}
				text[tpos++] = ' ';
				text[tpos] = '\x00';
	        	if(NULL == (text = addline(text,al->areas[i].desc,&tpos,&tlen))) {
	        		*p = ' ';
	        		return NULL;
				}
				wlen = strlen(p+1);
				text[tpos++] = '\r';
				text[tpos] = '\x00';
		        if(NULL == (text = addline(addchars(text,' ',maxlen-wlen,&tpos,&tlen),p+1,&tpos,&tlen))) {
					*p = ' ';
		        	return NULL;
				}
				*p = ' ';
        	} else {
				text[tpos++] = '\r';
				text[tpos] = '\x00';
		        if(NULL == (text = addline(addchars(text,' ',maxlen-wlen,&tpos,&tlen),al->areas[i].desc,&tpos,&tlen))) return NULL;
        	}
        }
		text[tpos++] = '\r';
		text[tpos] = '\x00';
	}
	return text;
}


syntax highlighted by Code2HTML, v. 0.9.1