/* nicks.c	- handle nickname groups

    Author: Tano Fotang, 1998

    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.
    see the file COPYING for more information.

Becasue of the way nickname groups are used, it is a better idea
to have just 1 nick in a group than to have very few nicks in the group.
Nicks are kept in a ring. If one nick is already in use, the next one
is sent to server.
Therefore, if u have only 2 nicks and both are already taken, client just
keeps alternating between the two..forever until server gets tired of it.
If there's only one nick, client appends a '_' to it and adds a random number.
Obviously, 1 or zero nick is better than having too few.
*/

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "nicks.h"
#include "util.h"

static Nicks *in_list(Nickcount i, const char *nick){
	Nicks *p =aNickList[i].start->left;
	while(p!=aNickList[i].start)
		if(!strcasecmp(p->nick, nick)) return p;
		else p=p->left;
	return NULL;
} 
extern Nicks *add_nick_to_list(Nickcount i, const char *nick){
	
	Nicks *p;
	if(i<0) {errno=0;return NULL;}
	p=in_list(i, nick);
	if(p) return p;
	p = (Nicks *) malloc(sizeof(Nicks));
	if (!p) return NULL;
	else{
	p->nick = strdup(nick);
	p->left=aNickList[i].current;
	p->right=aNickList[i].current->right;
	aNickList[i].current->right->left=p;
	aNickList[i].current->right=p;
	
	return p;
	}
}

#define NICKLIST_ALLOC 1	/* allocate space for so many lists each time*/
static int NickList_alloc(void){
	Nickcount i;
	if(aNickList==NULL)
		aNickList=malloc(sizeof(NickList)*NICKLIST_ALLOC);
	else
		aNickList=realloc(aNickList,
			(iNickListCount+NICKLIST_ALLOC)*sizeof(NickList));
	if(aNickList==NULL) return (-1);
	for (i=iNickListCount;i<iNickListCount+NICKLIST_ALLOC; i++)
		aNickList[i].label=NULL;
	iNickListCount+=NICKLIST_ALLOC;
	return (0);
}
Nickcount get_list_bylabel(const char *label){
	NickList *p=aNickList;
	while(p-aNickList<iNickListCount)
		if(p->label && !strcasecmp(p->label, label))
			return (p-aNickList);
		else p++;
	return -1;
}
Nickcount new_nicklist(const char *label){
/* find/return an unused  list */
	int i;
	if(aNickList==NULL && NickList_alloc()) 
		return (-1);
retry:
	for(i=0;i< iNickListCount; i++)
		if(!aNickList[i].label){
			aNickList[i].start = malloc(sizeof(Nicks));
			if (aNickList[i].start == NULL) return(-1);
			aNickList[i].start->left = aNickList[i].start->right = 
				aNickList[i].current = aNickList[i].start;
			aNickList[i].label=strdup(label);
			return i;
		}
	if(NickList_alloc()) return (-1);
	goto retry;
}
static char *
        get_line(FILE * fp)
{
/* 
 * read one line   */
	char    p[513];
	char   *buf;

	while (fgets(p, 513, fp)) {
		p[strlen(p) - 1] = '\0';
		if (!(buf = clean(p)) || *buf == COMMENT)
			continue;
		uncomment(buf, COMMENT);
		if(!buf || !(*buf)) continue;
		return buf;
	}
	return NULL;
}

static char * 
get_nick_entry (FILE * fp, int *count, char **d,  size_t size)
{
  char *buf, label[35],label2[36], *p;
  char got_tail=0, first_run=1;

*count=0;
label[0]=0;
*d='\0';
again:
  while((buf=get_line(fp)))
  	if(*buf=='<'){
		if(sscanf(buf,"<%[^>]", label)<1) goto again;
		/*if(first_run && *(buf+ strlen(label)) !='>') goto again;*/
		sprintf(label2,"</%s>", label);
	   work:
		p=strstr(buf,label2);
		if(p){ *p='\0';got_tail=1;}
		p=buf;
		if(first_run){first_run=0;while(*p++!='>');} /* <test>a b c,d,e */
		while(*p && *count<size){
			while(*p==' ' || *p==',' || *p=='\t' || *p=='\n'|| *p=='\r')
				*p++='\0';
			if(*p){ *d++=p; (*count)++;}
			while(*p && *p!=' ' && *p!=',' && *p!='\t' && *p!='\n' && *p!='\r')
				p++;
			/*if(*count>0) printf("%s- ",*(d-1));*/
		}
		if(!got_tail && *count<size && (buf=get_line(fp)))
		       goto work;
		*d='\0';
		return strdup(label);
	}
	
return NULL;
}


extern int load_nicks(const char *fname){
	FILE *fp=fopen(fname,"r");
	if(!fp) return errno;
	else{
		char **nicks/*[NICK_QUEUE_LEN+1]*/, *label;
		int count;

		nicks=malloc(sizeof(char *)*(NICK_QUEUE_LEN+1));
		while( (label=get_nick_entry(fp,&count,nicks,NICK_QUEUE_LEN))){
			Nickcount i=new_nicklist(label);
			char **p=nicks;
			if(i<0) {return errno;}
			p=nicks;
			while(*p && 
			(aNickList[i].current=add_nick_to_list(i, *p++)));
			if(errno) return errno;
			free(label);
		}
		free(nicks);
	}
	return 0;
}




