/*$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.
$*/
/* ITextD */

#import "ITextD.h"
#import <appkit/Application.h>
#import <appkit/Text.h>
#import <appkit/Panel.h>
#import <objc/hashtable.h>
#import <streams/streams.h>
#import <string.h>
#import <stdlib.h>
#import <libc.h>
#import <stdio.h>
#import <mach.h>
#import "errdebug.h"

#import "data_types.h"

#import "Localization.h"

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


#define		EOF	(-1)
#define		DEF_BLK_SIZE	512

@implementation ITextD

static NXAtom fileExtension;

+ initialize
{
    fileExtension = NXUniqueStringNoCopy("rtf");
    return(self);
}

+ (NXAtom)rtfControlWord
{
    return(NULL);
}

+ (NXAtom)fileExtension;
{
    return(fileExtension);
}

+ (NXAtom)pasteboardType
{
    return(NULL);
}

- init
{
    [super init];
    text = NULL;
    return(self);
}

- free
{
    vm_deallocate(task_self(), (vm_address_t)text, maxSize);
    return([super free]);
}

//- kanjiCodeConvert:(char *)conv_option
//{
//    NXStream *inStream, *outStream;
//    int status;
//    int kanjiconv (char *conv_option, NXStream *fin, NXStream *fout);
//
//    inStream = NXOpenMemory(text, size, NX_READONLY);
//    outStream = NXOpenMemory(NULL, 0, NX_READWRITE);
//    if ((status = kanjiconv(conv_option, inStream, outStream)) != 0) {
//        NXRunAlertPanel(LoStr("NewsBase"),
//	    LoStr("ERROR: ITextD: kanjiconv() abort %d\n"),
//	    NULL,NULL,NULL, status);
//        NXCloseMemory(inStream, NX_SAVEBUFFER);
//        NXCloseMemory(outStream, NX_FREEBUFFER);
//	return(NULL);
//    }
//    NXCloseMemory(inStream, NX_SAVEBUFFER);
//    vm_deallocate(task_self(), (vm_address_t)text, maxSize);
//    NXGetMemoryBuffer(outStream, &text, &size, &maxSize);
//    size = NXTell(outStream);
//    NXCloseMemory(outStream, NX_SAVEBUFFER);
//    return(self);
//}
//

- setTextData:(char *)data size:(int)length maxSize:(int)maxLength
{
    if (text != NULL) {
        vm_deallocate(task_self(), (vm_address_t)text, maxSize);
    }
    text = data;
    size = length;
    maxSize = maxLength;
    return(self);
}

- (BOOL)readFromFile:(const char *)pathName
{
    NXStream *tempStream;

    if (text != NULL) {
        vm_deallocate(task_self(), (vm_address_t)text, maxSize);
    }
    if ((tempStream = NXMapFile(pathName, NX_READONLY)) != NULL) {
        NXGetMemoryBuffer(tempStream, &text, &size, &maxSize);
        NXSeek(tempStream, 0, NX_FROMEND);
        size = NXTell(tempStream);
        NXCloseMemory(tempStream, NX_SAVEBUFFER);
        return(YES);
    } else {
        return(NO);
    }
}

- (BOOL)readFromStream:(NXStream *)stream
{
    long start;
    NXStream *tempStream;
    char buffer[vm_page_size];
    int	nread;

    if (text != NULL) {
        vm_deallocate(task_self(), (vm_address_t)text, maxSize);
    }
    if (stream->flags & NX_CANSEEK) {
        start = NXTell(stream);
        NXSeek(stream, 0, NX_FROMEND);
        size = NXTell(stream) - start;
        NXSeek(stream, start, NX_FROMSTART);
        if (vm_allocate(task_self(), (vm_address_t *)&text, size, TRUE)
            == KERN_SUCCESS) {
            NXRead(stream, text, size);
            return(YES);
        } else {
            return(NO);
        }
    } else {
        tempStream = NXOpenMemory(NULL, 0, NX_READWRITE);
        while((nread = NXRead(stream, buffer, sizeof(buffer))) > 0) {
            NXWrite(tempStream, buffer, nread);
        }
        NXGetMemoryBuffer(tempStream, &text, &size, &maxSize);
        size = NXTell(tempStream);
        NXCloseMemory(tempStream, NX_SAVEBUFFER);
        return(YES);
    }
}

- (void)writeToStream:(NXStream *)stream
{
    const char *ptr, *textEnd;

    textEnd = text + size;
    for (ptr = text; ptr < textEnd; ++ptr) {
//        if (*ptr != '\015') {
            NXPutc(stream, *ptr);
//        }
    }
}

- (char *)textData
{
    return text;
}

- writeRichTextStreamTo:textObj
{
    NXStream *tempStream;

    tempStream = NXOpenMemory(text, size, NX_READONLY);
    [textObj readRichText:tempStream];
    NXCloseMemory(tempStream, NX_SAVEBUFFER);
    return(self);
}

- writeTextStreamTo:textObj
{
    NXStream *tempStream;

    tempStream = NXOpenMemory(text, size, NX_READONLY);
    [textObj readText:tempStream];
    NXCloseMemory(tempStream, NX_SAVEBUFFER);
    return(self);
}

- (void)writeToTarStream:(NXStream *)stream
{
    NXStream *tempStream;
    int commandWithStreams(const char *, NXStream *, NXStream *);

    tempStream = NXOpenMemory(text, size, NX_READONLY);
    commandWithStreams("compress", tempStream, stream);
    NXCloseMemory(tempStream, NX_SAVEBUFFER);
}

- (BOOL)readFromTarStream:(NXStream *)stream
{
    NXStream *tempStream;
    int commandWithStreams(const char *, NXStream *, NXStream *);

    if (text != NULL) {
        vm_deallocate(task_self(), (vm_address_t)text, maxSize);
    }
    tempStream = NXOpenMemory(NULL, 0, NX_READWRITE);
    commandWithStreams("uncompress", stream, tempStream);
    NXGetMemoryBuffer(tempStream, &text, &size, &maxSize);
    size = NXTell(tempStream);
    NXCloseMemory(tempStream, NX_SAVEBUFFER);
    return(YES);
}

- (int)size
{
    return size;
}

- (int)countLine
{
    NXStream 	*textStream;
    int		count;
    int		ch;

    count = 0;
    textStream = NXOpenMemory(text, size, NX_READONLY);
    NXSeek(textStream, 0, NX_FROMSTART);
    while ((ch=NXGetc(textStream)) != EOF) {
	if (ch=='\n') {
	    count++;
	}
    }
    NXCloseMemory(textStream, NX_SAVEBUFFER);
    return count;
}
   
- (int)width
{
    int width;

    if (sscanf(text, "{\\info{\\width %d}}", &width) == 1) {
        return(width);
    } else {
        return(0);
    }
}

@end

#undef __OBJC__
#include "errdebug.h"

//
// commandWithStreams() runs a command with stdin and stdout from NXStreams
//
 
int
commandWithStreams(command, inStream, outStream)
	char *command;
	NXStream *inStream;
	NXStream *outStream;
{
	int pipeIn[2];
	int pipeOut[2];
        int saveFd0;
        int saveFd1;
	int pid;
	int noBytesReadInStream;
	int noBytesReadFromCommand;
#define BUFFER_SIZE vm_page_size
	unsigned char bufferOutToCommand[BUFFER_SIZE];
	unsigned char bufferInFromCommand[BUFFER_SIZE];
	 
    // create two pipes, pipeIn and pipeOut, and 3 processes, X, Y and Z and connect as follows
    // X > pipeIn[1] ==> 0 < Y > 1 ==> pipeOut[0] < Z
    pipe(pipeIn);
    pipe(pipeOut);
    saveFd0 = dup(0);
    saveFd1 = dup(1);
    dup2(pipeIn[0], 0);
    dup2(pipeOut[1], 1);
    close(pipeIn[0]);
    close(pipeOut[1]);
    if ((pid = fork()) == -1) {
	perror("tarSub: commandWithStreams: fork()");
	return(-1);
    } else if (pid > 0) {
        close(pipeIn[1]);
	 if ((pid = vfork()) == -1) {
		perror("tarSub: commandWithStreams: fork()");
		return(-1);
         } else if (pid > 0) {
	        // process Z: copies stdout of the command to outStream
	        close(0);
		close(1);
	        while ((noBytesReadFromCommand = read(pipeOut[0], bufferInFromCommand,
		     sizeof(bufferInFromCommand))) > 0) {
		    NXWrite(outStream, bufferInFromCommand, noBytesReadFromCommand);
	            DBG(10, fprintf(stderr, "%d bytes read from command\n", noBytesReadFromCommand););
               }
	       close(pipeOut[0]);
        } else {
	    // process Y: executes the command
	    close(pipeOut[0]);
//	    {char buffer[8192]; write(1, buffer, read(0, buffer, sizeof(buffer)));}
	    _exit(system(command));
        }
    } else {
	// process X: copies the inStream to stdin of command
	close(0);
	close(1);
	close(pipeOut[0]);
	while(NXAtEOS(inStream) == FALSE) {
            noBytesReadInStream = NXRead(inStream, bufferOutToCommand,
	        sizeof(bufferOutToCommand));
	    write(pipeIn[1], bufferOutToCommand, noBytesReadInStream);
	    DBG(10, fprintf(stderr, "%d bytes written to command\n", noBytesReadInStream););
        }
	close(pipeIn[1]);
	_exit(0);
    }
    dup2(saveFd0, 0);		
    dup2(saveFd1, 1);
    close(saveFd0);
    close(saveFd1);
    return 0;
}

