
/* Generated by Interface Builder */

#import "Newsgroup.h"

@implementation Newsgroup

+ new
{
  
  self = [super new];
  bogus = TRUE;
  subscribed = TRUE;
  newMessages = 0;
  
  seenStorage = [Storage newCount:0 
	elementSize:(unsigned)sizeof(seenStruct) 
	description:"{II}"];
  
  cellStrings[NEWSGROUP_MESSAGES] = newMessagesString;
  cellStrings[NEWSGROUP_NAME] = name;
  cellStrings[NEWSGROUP_PURPOSE] = NULL;
  
  return self;
}

+ newName:(const char *)newName subscribed:(BOOL)newSubscribed
{
  self = [Newsgroup new];
  strcpy(name, newName);
  subscribed = newSubscribed;
  if (!subscribed)
    [self setSubscribed:subscribed];

  return self;
}

+ newFromNewsrc:(NXStream *)newsrcStream
{
  int		c;
  long		first, last;

  self = [Newsgroup new];
  
  if (NXScanf(newsrcStream, "%253[^:!]", &name) == 1) {
    subscribed = ((c = NXGetc(newsrcStream)) == ':');
    if (!subscribed)
      [self setSubscribed:subscribed];

    while (((c = NXGetc(newsrcStream)) == ' ') || (c == ',')) {
      if (NXScanf(newsrcStream, "%ld-%ld", &first, &last) == 2) {
	[self addSeenFirst:first last:last];
      } else {
	[self addSeenFirst:first last:first];
      }
    }
    while (c != '\n')
      c = NXGetc(newsrcStream);
  } else {
    [self free];
    self = nil;
  }
  
  return self;
}

- writeToNewsrc:(NXStream *)newsrcStream
{
  int		seenIndex;
  seenStruct	*seen;
  
  if (!bogus) {
    NXPrintf(newsrcStream, "%s%c", name, (subscribed ? ':' : '!'));

    for (seenIndex = 0; seenIndex < [seenStorage count]; seenIndex++) {
      if (seenIndex == 0)
	NXPutc(newsrcStream, ' ');
      else
	NXPutc(newsrcStream, ',');

      seen = [seenStorage elementAt:seenIndex];
      
      if (seen->first == seen->last)
	NXPrintf(newsrcStream, "%ld", seen->first);
      else
	NXPrintf(newsrcStream, "%ld-%ld", seen->first, seen->last);
    }
    NXPutc(newsrcStream, '\n');
  }
  
  return self;
}

- (BOOL)selectOnNNTP:(FILE *)nntpFile
{
  int	inCode;
  char	inCodeText[BUFFER_SIZE];
  long	first, last;

  fprintf(nntpFile, "group %s\r\n", name);
  fflush(nntpFile);
  fseek(nntpFile, (long)0, SEEK_END);

  fscanf(nntpFile, "%d ", &inCode);
  switch (inCode) {
    case OK_GROUP:
      fscanf(nntpFile, "%*ld %ld %ld %*[^\r]\r", &first, &last);
      [self setAvailableFirst:first last:last];
      break;
    case ERR_NOGROUP:
      bogus = TRUE;
    default:
      fscanf(nntpFile, "%[^\r]\r", &inCodeText);
      break;
  }

  fgetc(nntpFile);
  fseek(nntpFile, (long)0, SEEK_END);

  return (inCode == OK_GROUP);
}



- addSeenFirst:(long)first last:(long)last
{
  seenStruct	seen = {first, last};
  int		seenIndex = 0;
  BOOL		doLoop = TRUE;
  
  while (doLoop) {
    doLoop = FALSE;
    
    if (seenIndex == [seenStorage count])
      [seenStorage addElement:&seen];
      
    else {
      if (seen.last+1
      		< (((seenStruct *)(seenStorage->dataPtr))[seenIndex]).first) {
	[seenStorage insert:&seen at:seenIndex];
      } else if ((((seenStruct *)(seenStorage->dataPtr))[seenIndex]).last+1
 		< seen.first) {
	seenIndex++;
	doLoop = TRUE;
      } else {
	seen.first = MIN(seen.first,
		(((seenStruct *)(seenStorage->dataPtr))[seenIndex]).first);
	(((seenStruct *)(seenStorage->dataPtr))[seenIndex]).first = seen.first;

	if (seen.last
		> (((seenStruct *)(seenStorage->dataPtr))[seenIndex]).last) {
	  [seenStorage removeAt:seenIndex];
	  doLoop = TRUE;
	}
      }
    }
  }
  return [self calcNewMessages];
}

- removeSeenFirst:(long)first last:(long)last
{
  return [self calcNewMessages];
}

- setModerated:(BOOL)newModerated
{
  moderated = newModerated;

  if (moderated)
    cellBitmaps[NEWSGROUP_MODERATED] = [Bitmap findBitmapFor:"moderated"];
  else
    cellBitmaps[NEWSGROUP_MODERATED] = nil;
  return self;
}

- (BOOL)moderated
{
  return moderated;
}

- setAvailableFirst:(long)newFirst last:(long)newLast
{
  available.first = newFirst;
  available.last = newLast;
  
//  [self removeSeenFirst:newLast+1 last:MAXLONG];
  if (newFirst > 1)
    [self addSeenFirst:1 last:newFirst-1];
  
  return [self calcNewMessages];
}

- calcNewMessages
{
  int	i, numSeenStruct = [seenStorage count];
  long	first, last;
  
  if (available.last == 0)
    newMessages = 0;
  else {
    newMessages = (available.last - available.first) + 1;
    for (i=0; i<numSeenStruct; i++) {
      first = (((seenStruct *)(seenStorage->dataPtr))[i]).first;
      last = (((seenStruct *)(seenStorage->dataPtr))[i]).last;
      if ((first <= available.last) && (last >= available.first))
	newMessages -= (MIN(last, available.last)
			- MAX(first, available.first)) + 1;
    }
  }
  
  sprintf(newMessagesString, "%d", newMessages);		

  if (newMessages)
    cellBitmaps[NEWSGROUP_UNSEEN] = [Bitmap findBitmapFor:"unseen"];
  else
    cellBitmaps[NEWSGROUP_UNSEEN] = nil;
  return self;
}

- (long)newMessages
{
  return newMessages;
}
- setSubscribed:(BOOL)newSubscribed
{
  subscribed = newSubscribed;

  if (!subscribed)
    cellBitmaps[NEWSGROUP_UNSUBSCRIBED] =
    			[Bitmap findBitmapFor:"unsubscribed"];
  else
    cellBitmaps[NEWSGROUP_UNSUBSCRIBED] = nil;
  return self;
}
- (BOOL)subscribed
{
  return subscribed;
}

@end
