/****************************************************************************
 * 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

#define SELF STRUCT_InputStream

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

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

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

#define _knh_InputStream_struct_copy   NULL

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

#define _knh_InputStream_struct_compare  NULL

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

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

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

///* @ method InputStream InputStream.new(String! urn) */
//
//InputStream *knh_InputStream_new(Ctx *ctx, InputStream *b, FILE *urn)
//{
//	b->fp = urn;
//	KNH_INITv(b->codec, Null);
//	b->size = 0;
//	return b;
//}
//


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

INLINE
int_byte_t knh_InputStream_getc(Ctx *ctx, InputStream *b)
{
	return b->fgetc(ctx, b);
}

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

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

INLINE
void knh_InputStream_close(Ctx *ctx, InputStream *b)
{
	b->fclose(ctx, b);
}

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

InputStream *new_InputStream__FILE(Ctx *ctx, StreamStat *stat, FILE *fp)
{
	InputStream* b = (InputStream*)knh_Object_malloc(ctx, CLASS_InputStream);
	KNH_INITv(b->stat, stat);
	if(IS_NULL(stat)) {
		b->ftraverse = knh_InputStream_FILE_traverse;
		b->fgetc     = knh_InputStream_FILE_getc;
		b->fclose    = knh_InputStream_FILE_close;
	}
	else {
		b->ftraverse = knh_InputStream_FILE_traverse;
		b->fgetc     = knh_InputStream_FILE_getc__stat;
		b->fclose    = knh_InputStream_FILE_close;
	}
	b->in.fp = fp;
	return b;
}

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

void knh_InputStream_FILE_traverse(Ctx *ctx, InputStream *b, f_gc gc)
{
	
}

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

int_byte_t knh_InputStream_FILE_getc(Ctx *ctx, InputStream *b)
{
	return fgetc(b->in.fp);
}

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

int_byte_t knh_InputStream_FILE_getc__stat(Ctx *ctx, InputStream *b)
{
	int_byte_t ch = fgetc(b->in.fp);
	knh_StreamStat_read_ch(b->stat, ch);
	return ch;
}

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

int_byte_t knh_InputStream_NULL_getc(Ctx *ctx, InputStream *b)
{
	return EOF;
}

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

void knh_InputStream_FILE_close(Ctx *ctx, InputStream *b)
{
	if(b->in.fp != NULL) {
		if(b->in.fp == stdin) return ;
		fclose(b->in.fp);
		b->in.fp = NULL;
		b->fgetc = knh_InputStream_NULL_getc;
	}
}

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

InputStream *new_InputStream__Bytes(Ctx *ctx, StreamStat *stat, Bytes *ba, size_t s, size_t e)
{
	InputStream* b = (InputStream*)knh_Object_malloc(ctx, CLASS_InputStream);
	KNH_INITv(b->stat, stat);
	if(IS_NULL(stat)) {
		b->ftraverse = knh_InputStream_Bytes_traverse;
		b->fgetc     = knh_InputStream_Bytes_getc;
		b->fclose    = knh_InputStream_Bytes_close;
	}
	else {
		b->ftraverse = knh_InputStream_Bytes_traverse;
		b->fgetc     = knh_InputStream_Bytes_getc__stat;
		b->fclose    = knh_InputStream_Bytes_close;
	}
	KNH_INITv(b->in.buf.ba, ba);
	DEBUG_ASSERT(e <= knh_Bytes_size(ba));
	DEBUG_ASSERT(s <= e);
	b->in.buf.pos   = s;
	b->in.buf.end   = e;
	return b;
}

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

InputStream *new_InputStream__NULL(Ctx *ctx)
{
	knh_buffer_t cb = knh_Context_buffer(ctx);
	return new_InputStream__Bytes(ctx, Null, cb.ba, 0, 0);
}

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

void knh_InputStream_Bytes_traverse(Ctx *ctx, InputStream *b, f_gc gc)
{
	gc(ctx, b->in.buf.ba);
}

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

int_byte_t knh_InputStream_Bytes_getc(Ctx *ctx, knh_InputStream *b)
{
	if(IS_NULL(b->in.buf.ba)) return EOF;
	if(b->in.buf.pos < b->in.buf.end) {
		knh_uchar_t *p = (knh_uchar_t*)knh_Bytes_tochar(b->in.buf.ba);
		int_byte_t ch = p[b->in.buf.pos]; 
		b->in.buf.pos++;
		return ch;
	}
	return EOF;
}

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

int_byte_t knh_InputStream_Bytes_getc__stat(Ctx *ctx, knh_InputStream *b)
{
	if(IS_NULL(b->in.buf.ba)) return EOF;
	if(b->in.buf.pos < b->in.buf.end) {
		knh_uchar_t *p = (knh_uchar_t*)knh_Bytes_tochar(b->in.buf.ba);
		int_byte_t ch = p[b->in.buf.pos]; 
		b->in.buf.pos++;
		knh_StreamStat_read_ch(b->stat, ch);
		return ch;
	}
	return EOF;
}

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

void knh_InputStream_Bytes_close(Ctx *ctx, InputStream *b)
{
	KNH_SETv(ctx, b->in.buf.ba, Null);
	b->fgetc = knh_InputStream_NULL_getc;
}

/* ======================================================================== */
/* [mappings] */


/* ======================================================================== */
/* [iterators] */

//INLINE
//Object* knh_Int_byte_toObject(Ctx *ctx, int_byte_t ch)
//{
//	if(ch == EOF) {
//		return Null;
//	}else{
//		return new_Int__checked(ctx, CLASS_Int__byte, ch);
//	}
//}
//
///* ------------------------------------------------------------------------ */
//
//Object* knh_InputStream_byte_next(Ctx *ctx, Iterator *it)
//{
//	InputStream *b = (InputStream*)knh_Iterator_source(it);
//	int_byte_t ch = knh_InputStream_getc(ctx, b);
//	return knh_Int_byte_toObject(ctx, ch);
//}
//
///* ------------------------------------------------------------------------ */
//
///* @map InputStream Int:byte.. */
//
//
//Object* knh_InputStream_Int__byte__(Ctx *ctx, Object *self, MapMap *map)
//{
//	return new_Iterator(ctx, CLASS_Int__byte, self, knh_InputStream_byte_next);
//}
//

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

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


void knh_InputStream__dump(Ctx *ctx, InputStream *b, Writer *w, Any *m)
{
	
}


#ifdef __cplusplus
}
#endif
