/*$Copyright:
 * Copyright (C) 1992.5.22. Recruit Co.,Ltd. 
 * Institute for Supercomputing Research
 * All rights reserved.
 * NewsBase  by ISR, Kazuto MIYAI, Gary ARAKAKI, Katsunori SUZUKI, Kok-meng Lue
 *
 * You may freely copy, distribute and reuse the code in this program under 
 * following conditions.
 * - to include this notice in the source code, if it is to be distributed 
 *   with source code.
 * - to add the file named "COPYING" within the code, which shall include 
 *   GNU GENERAL PUBLIC LICENSE(*).
 * - to display an acknowledgement in binary code as follows: "This product
 *   includes software developed by Recruit Co.,Ltd., ISR."
 * - to display a notice which shall state that the users may freely copy,
 *   distribute and reuse the code in this program under GNU GENERAL PUBLIC
 *   LICENSE(*)
 * - to indicate the way to access the copy of GNU GENERAL PUBLIC LICENSE(*)
 *
 *   (*)GNU GENERAL PUBLIC LICENSE is stored in the file named COPYING
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
$*/
/* INewsRc */

#import "INewsRc.h"
#import "InfoD.h"
#import "ITreeNodeD.h"
#import "data_types.h"
#import "errdebug.h"

#import <appkit/Application.h>
#import <appkit/Panel.h>
#import <objc/NXStringTable.h>
#import <streams/streams.h>
#import <stdio.h>
#import <string.h>
#import <libc.h>
#import <objc/zone.h>
#import <mach/mach.h>

#import "Localization.h"

#define LoStr(key)      doLocalString(NULL,key,NULL)

@implementation INewsRc

- initFile:(const char *)krcfile
{
    char	buf[MAXPATHLEN*2];

    [super init];
    
    if (!(strcmp(krcfile,""))) { 		/* default is $HOME/.newsrc */
	strcpy (iNewsRcFileName, NXHomeDirectory());
	strcat (iNewsRcFileName, "/.newsrc");
    } else {
	strcpy (iNewsRcFileName, krcfile);
    }

    DBG(10,fprintf(stderr,"-- iNewsRcFileName = %s is set\n",
    						iNewsRcFileName));

    /* check command line length for sprintf */
    if ((strlen(iNewsRcFileName)*2 + 6) > (MAXPATHLEN*2)) {
	fprintf (stderr, "ERROR:INewsRc: file name is over buf\n");
	return NULL;
    }
    sprintf (buf, "cp %s %s~", iNewsRcFileName, iNewsRcFileName);
    if (system (buf)) {
	/* 'cp' command failed */
	if(strlen(iNewsRcFileName)>MAXPATHLEN) {
	    fprintf (stderr, "ERROR:INewsRc: file name is over buf\n");
	    return NULL;
	}
	/* because user specifield not existing file */
	sprintf(buf,"%s is not found, NewsBase will make it",iNewsRcFileName);
	if (NXRunAlertPanel(LoStr("NewsBase"),LoStr(buf),
		LoStr("OK"),LoStr("Cancel"),NULL) == 0) {
	    /* Cancel is clicked */
	    return NULL;
	}
	return self;
    } else {
        return self;
    }
}

- readRcfile
{
    /* read .newsrc file and make string table */
    char	*groupname;
    char	*group_line;
    char	ch;
    char	line_buf[LINE_BUF_MAXLEN];
    char	*line_ptr;

    /* initialize string table */
    istringTableZone = NXCreateZone (vm_page_size, vm_page_size, YES);
    istringTable = [[NXStringTable allocFromZone:istringTableZone] init];
    
    if((iFileStream=NXMapFile(iNewsRcFileName, NX_READWRITE))!=NULL) {
    /* if newsrc file exist */
	NXSeek (iFileStream, 0, NX_FROMSTART);

	while (ch=NXGetc(iFileStream) != EOF) {
	    NXUngetc(iFileStream);
	    /* get one line */
	    NXScanf(iFileStream, "%4087[^\n]", line_buf); 
	    if (strlen(line_buf) >= (LINE_BUF_MAXLEN-1)) {
		NXRunAlertPanel(LoStr("NewsBase"),
		LoStr("newsrc file : line is too long"),LoStr("OK"),NULL,NULL);
	    }
	    NXGetc(iFileStream);				/* get \n */

	    group_line = NXCopyStringBufferFromZone(line_buf,istringTableZone);
	    /* replace ':' or '!' to '\0' */
	    line_ptr = line_buf;
	    if ((line_ptr=strchr(line_buf, ':')) != NULL) {
		;
	    } else if ((line_ptr=strchr(line_buf, '!')) != NULL) {
		;
	    } else {
		/* line is empty so go to next line */
		line_buf[0]='\0';
		continue;
	    }
	    *line_ptr = '\0';
	    /* copy newsgroup name into groupname */
	    groupname = NXCopyStringBufferFromZone(line_buf,istringTableZone);
	    [istringTable insertKey:(char *)groupname 
	    					value:(char *)group_line];
	    line_buf[0]='\0';
	}
	NXCloseMemory (iFileStream, NX_FREEBUFFER);
	return self;
    } else {
	fprintf(stderr, "INewsRc:warning: can't map .newsrc file\n");
	return NULL;
    }
}

- (void)saveToRcfileFrom:knewsGroupTreeRoot
{
    /* save groupInfo into .newsrc file with istringTable */
    NXTreeState		state;
    id		node;
    id		groupInfo;
    NXStream	*memoryStream;
    NXHashState	hashState;
    const void	*groupname;
    void	*group_line;
    char	buf[128];

    [knewsGroupTreeRoot initState:&state];
    while ((node=[knewsGroupTreeRoot nextState:&state]) != nil) {
	if ([node isMemberOf:[ITreeNodeD class]] == YES) {
	    if ((groupInfo=[node dataForKey:GROUPINFO]) != nil) {
	        [self _writeToTableGroupInfo:groupInfo];
	    }
	}
    }
       
    memoryStream = NXOpenMemory (NULL, 0, NX_WRITEONLY);
    hashState = [istringTable initState];
    while ([istringTable nextState:&hashState 
    					key:&groupname value:&group_line]) {
	NXPrintf(memoryStream, "%s\n", (char *)group_line);
    }
    if (NXSaveToFile (memoryStream, iNewsRcFileName) != 0 ) {
	sprintf(buf,"error occured writing data to file \"%.90s\"",
							iNewsRcFileName);
	NXRunAlertPanel(LoStr("NewsBase"),LoStr(buf),LoStr("OK"),NULL,NULL);
    }
    NXCloseMemory(memoryStream, NX_FREEBUFFER);
}

- (NewsStat)isSubscribe:(char *)groupname
{
    const char 	*group_line;
    
    if ((group_line=[istringTable valueForStringKey:groupname]) == NULL) {
	/* groupname is not in table, so this news group is new one */
	return NotExist;
    } else {
	if (strchr(group_line,':') != NULL) {
	    /* "comp.sys.next: ..." -> subscribe */ 
	    return Subscribe;
	} else {
	    /* "comp.sys.next! ..." -> unsubscribe */ 
	    return UnSubscribe;
	}
    }
}

- setGroupInfo:kgroupInfo
{
    [self _readRcfileAndSetGroupInfo:kgroupInfo];
    return self;
}

- (void)_writeToTableGroupInfo:kgroupInfo
{
    char	*groupname, *groupnameKey;
    char	*art_num_set;
    char	*group_line, *old_line;
    
    groupname = (char *)[kgroupInfo infoForKey:GROUPNAME];
    art_num_set = (char *)[kgroupInfo infoForKey:ART_NUM_SET];
    if ([istringTable valueForStringKey:groupname] == NULL) {
	/* key is not in string table, so allocate memory for key */
	groupnameKey = NXCopyStringBufferFromZone(groupname,istringTableZone);
    } else {
	groupnameKey = groupname;
    }
    
    group_line = (char *)NXZoneMalloc(istringTableZone, 
		    		(strlen(groupnameKey)+strlen(art_num_set)+3));
    if (!(strcmp([kgroupInfo infoForKey:SUBSCRIBE], "yes"))) {
        sprintf (group_line, "%s: %s", groupname, art_num_set);
    } else {
        sprintf (group_line, "%s! %s", groupname, art_num_set);
    }
    /* insert group_line to string table */
    /* if news group is not new one, and exist in table */
    /* free the old group_line which has "groupname:...." */
    if((old_line = [istringTable insertKey:groupnameKey value:group_line])
    								    !=NULL){
	NXZoneFree(istringTableZone, old_line);
    }

    return;
}

//- readGroupInfo:sender
//{
//    id		groupInfo;
    
//    if ((groupInfo=[sender dataForKey:GROUPINFO]) != nil) {
//	[self _readRcfileAndSetGroupInfo:groupInfo];
//    }
//    return self;
//}

- (void)_readRcfileAndSetGroupInfo:kgroupInfo
{
    char	*groupname, *iLineBuf_ptr, ch;
    char	buf[256];
    int		first;
    
    groupname = (char *)[kgroupInfo infoForKey:GROUPNAME];
    					/* if group is exist in .newsrc */
					/* and it has ':' or ';' */
    if (([self _getLineGroup:groupname]!='\0') && 
          (strchr(iLineBuf, ':') || strchr(iLineBuf, '!'))) {
	iLineBuf_ptr = iLineBuf;
						/* check subscription */
	if (strchr(iLineBuf, '!')) {
	    [kgroupInfo addInfoString:"no" key:SUBSCRIBE];
	} else {				
	    [kgroupInfo addInfoString:"yes" key:SUBSCRIBE];
	}
								
	while ( (ch = *(++iLineBuf_ptr)) != ':' && ch != '!')
	    ;				/* move ptr. after ':' or '!' */
	while ( (ch = *(++iLineBuf_ptr)) == ' ' )
	    ;
							/* skip space */
	if (ch=='\0') {			/* if iLineBuf is "groupname: " */
	    				/* art_num_set is "0-(LAST-1)" */
	    first = (int)[kgroupInfo infoForKey:FIRST] - 1;
	    if (first < 0) {
		first = 0;
	    }
	    sprintf (buf, "0-%d", first);
	    [kgroupInfo addInfoString:buf key:ART_NUM_SET];
	    return;
	} else {
	    [kgroupInfo addInfoString:iLineBuf_ptr key:ART_NUM_SET];
	}
				/* read xxx-xxx store xxx-xxx to groupInfo */
    } else {
    					/* if not group in .newsrc file */
					/* set initial value to groupInfo */
	    				/* art_num_set is "1- (FIRST-1)" */
	first = (int)[kgroupInfo infoForKey:FIRST] - 1;
	if (first < 0) {
	    first = 0;
	}
	sprintf (buf, "0-%d", first);
	[kgroupInfo addInfoString:"yes" key:SUBSCRIBE];
	[kgroupInfo addInfoString:buf key:ART_NUM_SET];

	/* sould be changed to display new added group to screen */
//	fprintf (stderr, "WARNING: new group \"%s\" is added\n", groupname);
    }
    return;
}

- (char *)_getLineGroup:(char *)kgroup
{
    const char	*group_line;

    iLineBuf[0] = '\0';
    if ((group_line=[istringTable valueForStringKey:kgroup]) != NULL) {
	/* len. of group_line < LINE_BUF_MAXLEN. if not, "-readRcfile:" */
	/* must make alert panel */
        strncpy (iLineBuf, group_line, sizeof(iLineBuf));
    }
    return iLineBuf;
}

- free
{
    NXDestroyZone (istringTableZone);
    return [super free];
}

@end
