/*
 * This file is provided for unrestricted use
 * provided that this legend is included on all tape media
 * and as a part of the software program in whole or part.  Users
 * may copy or modify this file without charge, but are not authorized to
 * license or distribute it to anyone else except as part of a product
 * or program developed by the user.
 *
 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 *
 * This file is provided with no support and without any obligation on the
 * part of Sun Microsystems, Inc. to assist in its use, correction,
 * modification or enhancement.
 *
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE
 * OR ANY PART THEREOF.
 *
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even
 * if Sun has been advised of the possibility of such damages.
 *
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 */

#include <X11/Xos.h>
#include <stdio.h>
#include <xview/panel.h>
#include "xvnews.h"
#include "xvnews_ui.h"

extern struct globals	*Global;

add_articles(new, numstr1, numstr2)
	struct newsrc_node *new;
	char	*numstr1;
	char	*numstr2;
{
	int	first, last;
	struct article_node *newarticles, *art = NULL, *prev = NULL;

	if (!strlen(numstr1)) 
		return;
	sscanf(numstr1, "%d", &first);
	if (strlen(numstr2)) 
		sscanf(numstr2, "%d", &last);
	else
		last = 0;
	newarticles =(struct article_node *)malloc(sizeof(struct article_node));
	if (newarticles == NULL) {
		printf("Malloc failed!\n");
		return;
	}
	newarticles->first = first;
	newarticles->last = last;
	art = new->artlist;
	while (art != NULL) {
                prev = art;
                art = art->nextart;
        }
        newarticles->nextart = NULL;
        if (prev != NULL) 
                prev->nextart = newarticles;
        else
                new->artlist = newarticles;
}

	
#define RNUM 1
#define COMMA 2
#define DASH 3

struct newsrc_node *
parse_line(line, newsgroup)
	char	*line, *newsgroup;
{
	char	*c, *strchr();
	char	*num;
	char	numstr1[10], numstr2[10];
	int	i;
	int	state;
	struct newsrc_node	*new = NULL;
static  struct newsrc_node	*prev = NULL;

	if ((c = strchr(line, '\n')) != NULL)
		*c = '\0';
	for (i=0, c=line; i<BUFFERLEN; i++, c++) 
		if ((*c == ':') || (*c == '!')) 
			break;
	if (i == BUFFERLEN) {
		printf("Bogus newsgroup %s\n", line);
		return NULL;
	}

	new= (struct newsrc_node *)malloc(sizeof(struct newsrc_node));
	if (new == NULL) {
		printf("Malloc failed!\n");
		return NULL;
	}
	Global->head == NULL ? Global->head = new:NULL;
	prev != NULL ? prev->nextgroup = new:NULL;
	new->newsgroup = newsgroup;
	if (strchr(line, ':') != NULL)
                  new->subscribed = SUBSCRIBED;
        else
                  new->subscribed = UNSUBSCRIBED;
	new->artlist = NULL;
	new->nextgroup = NULL;
	new->description = NULL;
	new->articles = 0;
	new->kill = NULL;
	prev = new;

	c++;
	state = RNUM;
	memset(numstr1, '\0', 10);
	memset(numstr2, '\0', 10);
	num = numstr1;
	while (*c != '\0') {
		switch(*c) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			state = RNUM;
			*num++ = *c++;
			break;
		case '-':
			if (state != RNUM) {
				printf("Bogus dash in newsrc for group %s!\n",new->newsgroup);
				state = COMMA;
			} else {
				state = DASH;
				num = numstr2;
			}
			c++;
			break;
		case ',':
			if (state != RNUM) 
				printf("Bogus comma in newsrc for group %s!\n", new->newsgroup);
			else
				add_articles(new, numstr1, numstr2);
			state = COMMA;
			memset(numstr1, '\0', 10);
			memset(numstr2, '\0', 10);
			num = numstr1;
			c++;
			break;
		case ' ':
			c++;
			break;
		default : printf("Bad character in newsrc: %c\n", *c);
			c++;
		}
	}
	if (state = RNUM) 
		add_articles(new, numstr1, numstr2);

	/*
	if (new->artlist == NULL)
		add_articles(new, "0", "0");
	*/

	return new;
}

clear_artlist(curr)
struct newsrc_node *curr;
{
	struct article_node *art = NULL, *prev = NULL;

	if (curr->artlist == NULL)
		return;

	while(curr->artlist->nextart != NULL) {
		art = curr->artlist->nextart;
		while (art->nextart != NULL) {
			prev = art;
			art = art->nextart;
		}
		if (art->nextart == NULL && prev != NULL) {
			free(art);
			prev->nextart = NULL;
			art = curr->artlist->nextart;
		} else {
			free(curr->artlist->nextart);
			curr->artlist->nextart = NULL;
		}
		prev = NULL;	
	}
	free(curr->artlist);
	curr->artlist = NULL;
}

unread_articles(curr, first, last)
struct newsrc_node *curr;
int first, last;
{
	char	last_art[10];
	int unread = 0;
	struct article_node *art = curr->artlist, *prev = NULL, *new = NULL;

	if (art == NULL)
		return (last - first) + 1;

	if (art->nextart == NULL) {
		if (art->last < first)
			art->last = --first;
		if (art->last > (last + 2) && last != 0) {
			art->last = --first;
			printf("Article numbering problem in %s, marking all articles unread!\n", curr->newsgroup);
		}
	return last - art->last;
	}
	while (art != NULL) {
		if (art->last >= (first - 1) && art != curr->artlist)
			break;
		if ((art->first < first && last == 0) ||
		  (art->first < first && art->last < first)) {
			prev = art->nextart;
			free(art);
			art = prev;
			curr->artlist = art;
			continue;
		}
		if (curr->artlist == art && !art->last) {
			new = (struct article_node *)malloc(sizeof(struct article_node));
			if (new == NULL) {
				printf("Malloc failed\n");
				return -1;
			}
			new->first = art->first;
			new->last = 0;
			new->nextart = art->nextart;
			art->nextart = new;
                	art->last = first - 1;
                	art->first = 1;
			art = new;
		}
		if (curr->artlist == art && art->first != 1)  {
			if (art->first < first)
				art->first = 1;
			else {
				new = (struct article_node *)malloc(sizeof(struct article_node));
				if (new == NULL) {
					printf("Malloc failed\n");
					return -1;
				}
				new->first = 1;
				new->last = first - 1;
				new->nextart = art;
				curr->artlist = new;
			}
		}
		art = art->nextart;
	}
	if (curr->artlist == NULL) {
		sprintf(last_art, "%d", first - 1);
		add_articles(curr, "1", last_art);
		return  last - curr->artlist->last;
	}
	unread = last - curr->artlist->last;
	art = curr->artlist->nextart;
	while (art != NULL) {
		if (art->last == 0)
			unread--;
		else {
		   if (art->last > (last + 2) && last != 0) {
			clear_artlist(curr);
			sprintf(last_art, "%d", first - 1);
			add_articles(curr, "1", last_art);
			printf("Article numbering problem in %s, marking all articles unread!\n", curr->newsgroup);
			return last - curr->artlist->last;
		   } 
		   unread -= (art->last - art->first) + 1;
		}
		art = art->nextart;
	}
	return unread;
}

getReadArticles(ip, curr)
xvnews_xvnews_window_objects    *ip;
struct newsrc_node *curr;
{
	char	*old, first_art[10], last_art[10];
	int	first = 1, last = -1, range = 0, row, art, art_first, a=0;
	int rows = xv_get(ip->articles_list, PANEL_LIST_NROWS, NULL);

	for (row = 0; row < rows; row++) {
		old = (char *)xv_get(ip->articles_list,
                                 PANEL_LIST_STRING, row, NULL);
		sscanf(old, "%d", &art);
		if (strncmp(&old[strlen(old) - 6], "[read]", 6) == 0 ||
                      strncmp(&old[strlen(old) - 6], "[save]", 6) == 0) {
			if (first != -1)
				continue;
			if (range)
				last = art;
			else {
				if (a + 1 != art) 
					art_first = a + 1;
				else
					art_first = art;
				last = -1;
				range = 1;
			}
			a = art;
			continue;
		}
		if (first != -1) {
			first = art - 1;
			sprintf(last_art, "%d", first);
			add_articles(curr, "1", last_art);
			first = -1;
			a = art;
			continue;
		}
		if (range) {
			if (a + 1 != art) 
				last = art - 1;
			sprintf(first_art, "%d", art_first);
			sprintf(last_art, "%d", last);
			add_articles(curr, first_art, last == -1 ? "":last_art);
			range = 0;
			last = -1;
			a = art;
			continue;
		}
		if (a + 1 != art) {
			if (a + 2 != art) {
				sprintf(first_art, "%d", a + 1);
				sprintf(last_art, "%d", art - 1);
				add_articles(curr, first_art, last_art);
			} else {
				sprintf(first_art, "%d", a + 1);
				add_articles(curr, first_art, "");
			}
		}
		a = art;
	}
	if (first != -1) {
		sprintf(last_art, "%d",
			 art != curr->last_article ? curr->last_article:art);
		add_articles(curr, "1", last_art);
		return;
	}
	if (range) {
		last = curr->last_article;
		sprintf(last_art, "%d", curr->last_article);
		sprintf(first_art, "%d", art_first);
		add_articles(curr, first_art,
			 curr->last_article == art_first ? "":last_art);
		return;
	}
	if (art != curr->last_article) {
		sprintf(first_art, "%d", art + 1);
		sprintf(last_art, "%d", curr->last_article);
		add_articles(curr, first_art, art + 1 == curr->last_article ? "":last_art);
	}
}

delete_articles(ip, curr)
xvnews_xvnews_window_objects    *ip;
struct newsrc_node *curr;
{
	char	*old;
	int	rows = xv_get(ip->articles_list, PANEL_LIST_NROWS, NULL);
	int	row, num;
	struct	article_node	*art = curr->artlist->nextart;

	while (art != NULL) {
		for (row = 0; row < rows; row++) {
			old = (char *)xv_get(ip->articles_list,
			 	PANEL_LIST_STRING, row, NULL);
			sscanf(old, "%d", &num);
			if (art->last == 0) {
				if (art->first == num) {
					xv_set(ip->articles_list, PANEL_LIST_DELETE, row--, NULL);
					rows--;
					break;
				}
			} else
				if (num >= art->first && num <= art->last) {
					xv_set(ip->articles_list, PANEL_LIST_DELETE, row--, NULL);
					rows--;
				}
		}
		art = art->nextart;
	}
}
	
add_unread(curr, unread)
struct newsrc_node *curr;
int unread;
{
	struct article_node *art = curr->artlist, *new = NULL, *prev = NULL;

	if (art == NULL)
		return;

	if (unread == curr->artlist->last) {
		curr->artlist->last--;
		return;
	}
	while(art->nextart != NULL) {
		if (unread <= art->last || unread <= art->first)
			break;
		prev = art;
		art = art->nextart;
	}
	if (unread == art->first && unread != 1) {
		if (!art->last) {
			prev != NULL ? prev->nextart = art->nextart:NULL;
			free(art);
			return;
		}
		art->first++;
		if (art->first == art->last)
			art->last = 0;
		if (art->first > curr->last_article) {
			prev != NULL ? prev->nextart = NULL:NULL;
			free(art);
		}
		return;
	}
	if (unread == curr->last_article) {
		art->last--;
		if (art->last == art->first)
			art->last = 0;
		return;
	}
	new = (struct article_node *)malloc(sizeof(struct article_node));
	if (new == NULL) {
		printf("Malloc failed!\n");
		return;
	}
	new->first = unread + 1;
	new->nextart = art->nextart;
	art->nextart = new;
	new->last = new->first == art->last ? 0:art->last;
	if ((unread - 1) == 1)
		art->last = 1;
	else
		art->last = unread - 1 == art->first ? 0:unread - 1;
	if (unread == 1)
		art->first = 0;
}
