/****************************************************************************
 * KONOHA COPYRIGHT, LICENSE NOTICE, AND DISCRIMER  
 * 
 * Copyright (c) 2005-2008, Kimio Kuramitsu <kimio at ynu.ac.jp>
 *           (c) 2008-      Konoha Software Foundation  
 * All rights reserved.
 * 
 * You may choose one of the following two licenses when you use konoha. 
 * See www.konohaware.org/license.html for further information.
 * 
 * (1) GNU General Public License 2.0      (with    KONOHA_UNDER_GPL2)
 * (2) Konoha Software Foundation License 1.0
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  
 ****************************************************************************/

/* ************************************************************************ */

#include"commons.h"

/* ************************************************************************ */

#ifdef __cplusplus 
extern "C" {
#endif

/* ======================================================================== */
/* [structs] */

void
knh_OutputStream_struct_init(Ctx *ctx, Struct *s, int init, Object *cs)
{
	//OutputStream *b = (OutputStream*)s;
	TODO();
}

#define _knh_OutputStream_struct_copy      NULL
/* ------------------------------------------------------------------------ */

#define _knh_OutputStream_struct_compare   NULL

/* ------------------------------------------------------------------------ */

void
knh_OutputStream_struct_traverse(Ctx *ctx, Struct *s, f_gc gc)
{
	OutputStream *b = (OutputStream*)s;
	gc(ctx, b->stat);
	if(IS_SWEEP(gc)) {
		b->fclose(ctx, b);
	}
	b->ftraverse(ctx, b, gc);
}

/* ======================================================================== */
/* [constructors] */

///* @ method OutputStream OutputStream.new(String! urn) */
//
//
//OutputStream *knh_OutputStream_new(Ctx *ctx, OutputStream *b, FILE *urn)
//{
//	b->fp = urn;
//	KNH_INITv(b->codec, Null);
//	KNH_INITv(b->linefeed, new_String(ctx, STEXT(KONOHA_OS_LINEFEED)));
//	b->size = 0;
//	return b;
//}
//
///* ------------------------------------------------------------------------ */
//
//
//OutputStream *new_FileOutputStream(Ctx *ctx, knh_bytes_t file, char *op)
//{
//	OutputStream* b = (OutputStream*)knh_Object_malloc(ctx, CLASS_OutputStream);
//	FILE *fp = fopen((char*)file.buf, op);
//	if(fp == NULL) {
//		return_Null(ctx, "IO!!: Cannot open: %s", file.buf);
//	}
//	return knh_OutputStream_new(ctx, b, fp);
//}

/* ------------------------------------------------------------------------ */

/* ======================================================================== */
/* [methods] */

INLINE
void knh_OutputStream_putc(Ctx *ctx, OutputStream *b, int_byte_t ch)
{
	b->fputc(ctx, b, ch);
}

/* ------------------------------------------------------------------------ */

/* @method void OutputStream.write(Object buf) */

INLINE
void knh_OutputStream_write(Ctx *ctx, OutputStream *b, knh_bytes_t buf)
{
	b->fwrite(ctx, b, buf);
}

/* ------------------------------------------------------------------------ */

/* @method void OutputStream.flush() */

INLINE
void knh_OutputStream_flush(Ctx *ctx, OutputStream *b)
{
	b->fflush(ctx, b);
}


/* ------------------------------------------------------------------------ */

/* @method void OutputStream.close() */

INLINE
void knh_OutputStream_close(Ctx *ctx, OutputStream *b)
{
	b->fclose(ctx, b);
}

/* ======================================================================== */
/* [FILE] */


OutputStream *new_OutputStream__FILE(Ctx *ctx, StreamStat *stat, FILE *fp)
{
	OutputStream* b = (OutputStream*)knh_Object_malloc(ctx, CLASS_OutputStream);
	KNH_INITv(b->stat, stat);
	if(IS_NULL(stat)) {
		b->ftraverse = knh_OutputStream_FILE_traverse;
		b->fputc     = knh_OutputStream_FILE_putc;
		b->fwrite    = knh_OutputStream_FILE_write;
		b->fflush    = knh_OutputStream_FILE_flush;
		b->fclose    = knh_OutputStream_FILE_close;
	}
	else {
		b->ftraverse = knh_OutputStream_FILE_traverse;
		b->fputc     = knh_OutputStream_FILE_putc__stat;
		b->fwrite    = knh_OutputStream_FILE_write__stat;
		b->fflush    = knh_OutputStream_FILE_flush;
		b->fclose    = knh_OutputStream_FILE_close;
	}
	b->out.fp = fp;
	if(fp == NULL) {
		knh_OutputStream_FILE_close(ctx, b);
	}
	return b;
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_FILE_traverse(Ctx *ctx, OutputStream *b, f_gc gc)
{
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_FILE_putc(Ctx *ctx, OutputStream *b, int_byte_t ch)
{
	fputc((int)ch, b->out.fp);
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_FILE_putc__stat(Ctx *ctx, OutputStream *b, int_byte_t ch)
{
	fputc((int)ch, b->out.fp);
	knh_StreamStat_write_size(b->stat, 1);
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_FILE_write(Ctx *ctx, OutputStream *b, knh_bytes_t byte)
{
	fwrite((char*)byte.buf, 1, byte.len, b->out.fp);
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_FILE_write__stat(Ctx *ctx, OutputStream *b, knh_bytes_t byte)
{
	knh_StreamStat_write_size(b->stat, fwrite((char*)byte.buf, 1, byte.len, b->out.fp));
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_FILE_flush(Ctx *ctx, OutputStream *b)
{
	fflush(b->out.fp);
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_NULL_putc(Ctx *ctx, OutputStream *b, int_byte_t ch)
{
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_NULL_write(Ctx *ctx, OutputStream *b, knh_bytes_t byte)
{
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_NULL_flush(Ctx *ctx, OutputStream *b)
{
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_FILE_close(Ctx *ctx, OutputStream *b)
{
	if(b->out.fp != NULL) {
		if(b->out.fp == stdout || b->out.fp == stderr) return ;
		fclose(b->out.fp);
		b->out.fp = NULL;
	}
	if(b->out.fp == NULL) {
		b->fputc     = knh_OutputStream_NULL_putc;
		b->fwrite    = knh_OutputStream_NULL_write;
		b->fflush    = knh_OutputStream_NULL_flush;
	}
}

/* ======================================================================== */
/* [Bytes] */


OutputStream *new_OutputStream__Bytes(Ctx *ctx, StreamStat *stat, Bytes *ba)
{
	OutputStream* b = (OutputStream*)knh_Object_malloc(ctx, CLASS_OutputStream);
	KNH_INITv(b->stat, stat);
	if(IS_NULL(stat)) {
		b->ftraverse = knh_OutputStream_Bytes_traverse;
		b->fputc     = knh_OutputStream_Bytes_putc;
		b->fwrite    = knh_OutputStream_Bytes_write;
		b->fflush    = knh_OutputStream_Bytes_flush;
		b->fclose    = knh_OutputStream_Bytes_close;
	}
	else {
		b->ftraverse = knh_OutputStream_Bytes_traverse;
		b->fputc     = knh_OutputStream_Bytes_putc__stat;
		b->fwrite    = knh_OutputStream_Bytes_write__stat;
		b->fflush    = knh_OutputStream_Bytes_flush;
		b->fclose    = knh_OutputStream_Bytes_close;
	}		
	KNH_INITv(b->out.ba, ba);
	if(IS_NULL(ba)) {
		knh_OutputStream_Bytes_close(ctx, b);
	}
	return b;
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_Bytes_traverse(Ctx *ctx, OutputStream *b, f_gc gc)
{
	gc(ctx, b->out.ba);
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_Bytes_putc(Ctx *ctx, OutputStream *b, int_byte_t ch)
{
	knh_Bytes_putc(ctx, b->out.ba, ch);
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_Bytes_putc__stat(Ctx *ctx, OutputStream *b, int_byte_t ch)
{
	knh_Bytes_putc(ctx, b->out.ba, ch);
	knh_StreamStat_write_size(b->stat, 1);
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_Bytes_write(Ctx *ctx, OutputStream *b, knh_bytes_t buf)
{
	knh_Bytes_write(ctx, b->out.ba, buf);
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_Bytes_write__stat(Ctx *ctx, OutputStream *b, knh_bytes_t buf)
{
	knh_Bytes_write(ctx, b->out.ba, buf);
	knh_StreamStat_write_size(b->stat, buf.len);
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_Bytes_flush(Ctx *ctx, OutputStream *b)
{
}

/* ------------------------------------------------------------------------ */

void knh_OutputStream_Bytes_close(Ctx *ctx, OutputStream *b)
{
	KNH_SETv(ctx, b->out.ba, Null);
	if(IS_NULL(b->out.ba)) {
		b->fputc     = knh_OutputStream_NULL_putc;
		b->fwrite    = knh_OutputStream_NULL_write;
	}
}

/* ======================================================================== */
/* [Null] */


OutputStream *new_OutputStream_Null(Ctx *ctx)
{
	return new_OutputStream__Bytes(ctx, Null, Null);
}

/* ======================================================================== */
/* [movabletext] */


/* @method void OutputStream.%dump(Writer w, Any m) */


void knh_OutputStream__dump(Ctx *ctx, OutputStream *b, Writer *w, Any *m)
{
}

#ifdef __cplusplus
}
#endif
