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

/* ======================================================================== */
/* [stmt] */

INLINE
knh_bool_t knh_Stmt_hasMeta(Stmt *o)
{
	return (IS_NOTNULL(DP(o)->metaDictMap));
}

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

static
void knh_StmtMETA_addLabel(Ctx *ctx, Stmt *o, String *label)
{
	if(IS_NULL(DP(o)->metaDictMap)) {
		KNH_SETv(ctx, DP(o)->metaDictMap, new_DictMap(ctx, 2));
	}
	KNH_ASSERT(IS_String(label));
	knh_DictMap_set(ctx, DP(o)->metaDictMap, TS_ATlabel, UP(label));
}

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

static
void knh_StmtMETA_addMeta(Ctx *ctx, Stmt *o, String *p)
{
	if(IS_NULL(DP(o)->metaDictMap)) {
		KNH_SETv(ctx, DP(o)->metaDictMap, new_DictMap(ctx, 2));
	}
	KNH_ASSERT(IS_String(p));
	knh_DictMap_set(ctx, DP(o)->metaDictMap, p, UP(p));
}

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

static
void knh_StmtMETA_addMeta2(Ctx *ctx, Stmt *o, String *k, Token *p)
{
	if(IS_NULL(DP(o)->metaDictMap)) {
		KNH_SETv(ctx, DP(o)->metaDictMap, new_DictMap(ctx, 2));
	}
	KNH_ASSERT(IS_String(k));
	{
		knh_tokens_t tc;
		knh_Token_tc(p, &tc);
		if(tc.e == 0) {
			knh_DictMap_set(ctx, DP(o)->metaDictMap, k, UP(k));
		}
		else if(tc.e == 1) {
			if(IS_String(DP(tc.ts[0])->data)) {
				knh_DictMap_set(ctx, DP(o)->metaDictMap, k, DP(tc.ts[0])->data);
			}
			else {
				knh_DictMap_set(ctx, DP(o)->metaDictMap, k, UP(new_String(ctx, knh_Token_tobytes(tc.ts[0]), NULL)));
			}
		}
		else {
			TODO();
		}
	}
}

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

void knh_StmtMETA_add_prestmt(Ctx *ctx, Stmt *o, knh_tokens_t *tc, int start)
{
	if(SP(o)->stt == STT_DONE || SP(o)->stt == STT_ERR) {
		return ;
	}
	else {
		Token **ts = tc->ts;
		int i;
		for(i = tc->c + start; i >= 0; i--) {
			if(SP(ts[i])->tt == TT_LABEL) {
				DEBUG3("LABEL!! %s", knh_Token_tochar(ts[i]));
				knh_StmtMETA_addLabel(ctx, o, (String*)DP(ts[i])->data);
				continue;
			}
			if(SP(ts[i])->tt == TT_METAN) {
				DEBUG3("META!! %s", knh_Token_tochar(ts[i]));
				knh_StmtMETA_addMeta(ctx, o, (String*)DP(ts[i])->data);
				continue;
			}
			if(0 <= i - 1 && SP(ts[i])->tt == TT_PARENTHESIS && SP(ts[i-1])->tt == TT_METAN) {
				DEBUG3("META2!! %s", knh_Token_tochar(ts[i-1]));
				knh_StmtMETA_addMeta2(ctx, o, (String*)DP(ts[i-1])->data, ts[i]);
				i--;
				continue;
			}
			break;
		}
	}
}

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

void knh_StmtMETA_add(Ctx *ctx, Stmt *o, knh_tokens_t *tc)
{
	if(SP(o)->stt == STT_DONE || SP(o)->stt == STT_ERR) {
		return ;
	}
	else {
		Token **ts = tc->ts;
		int i;
		for(i = tc->c; i < tc->e; i++) {
			if(SP(ts[i])->tt == TT_LABEL) {
				DEBUG3("LABEL!! %s", knh_Token_tochar(ts[i]));
				knh_StmtMETA_addLabel(ctx, o, (String*)DP(ts[i])->data);
				continue;
			}
			if(SP(ts[i])->tt == TT_METAN && DP(ts[i])->tt_next == TT_PARENTHESIS) {
				DEBUG3("META2!! %s", knh_Token_tochar(ts[i]));
				knh_StmtMETA_addMeta2(ctx, o, (String*)DP(ts[i])->data, ts[i+1]);
				i++;
				continue;
			}
			if(SP(ts[i])->tt == TT_METAN) {
				DEBUG3("META!! %s", knh_Token_tochar(ts[i]));
				knh_StmtMETA_addMeta(ctx, o, (String*)DP(ts[i])->data);
				continue;
			}
			break;
		}
	}
}

/* ======================================================================== */
/* [flag] */

void knh_StmtMETA_dump(Ctx *ctx, Stmt *o, OutputStream *w, Any *m)
{
	if(IS_NULL(DP(o)->metaDictMap)) {
		return ;
	}
	else {
		int i = 0, size = DP((DP(o)->metaDictMap))->size;
		for(i = 0; i < size; i++) {
			String *k = (String*)knh_DictMap_keyAt(DP(o)->metaDictMap, i);
			String *v = (String*)knh_DictMap_valueAt(DP(o)->metaDictMap, i);
			if(k == v) {
				knh_printf(ctx, w, "@%s ", knh_String_tochar(k));
			}
			else {
				knh_printf(ctx, w, "@%s(%O) ", knh_String_tochar(k), v);
			}
		}
		if(size > 0) {
			knh_println(ctx, w, STEXT(""));
		}
	}
}



/* ======================================================================== */
/* [flag] */

knh_flag_t knh_Stmt_metaflag__class(Ctx *ctx, Stmt *o)
{
	knh_flag_t flag = 0;
	if(IS_NOTNULL(DP(o)->metaDictMap)) {
		Object *v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("Final"));
		if(IS_NULL(v)) {
			v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("final"));
		}
		if(IS_NOTNULL(v)) {
			flag |= KNH_FLAG_CF_FINAL;
		}
		v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("Private"));
		if(IS_NULL(v)) {
			v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("private"));
		}
		if(IS_NOTNULL(v)) {
			flag |= KNH_FLAG_CF_PRIVATE;
		}
		v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("Interface"));
		if(IS_NULL(v)) {
			v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("interface"));
		}
		if(IS_NOTNULL(v)) {
			flag |= KNH_FLAG_CF_INTERFACE;
		}
	}
	return flag;
}

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

knh_flag_t knh_Stmt_metaflag__method(Ctx *ctx, Stmt *o)
{
	knh_flag_t flag = 0;
	if(IS_NOTNULL(DP(o)->metaDictMap)) {
		Object *v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("Virtual"));
		if(IS_NULL(v)) {
			v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("virtual"));
		}
		if(IS_NOTNULL(v)) {
			flag |= KNH_FLAG_MF_VIRTUAL;
		}
		v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("Private"));
		if(IS_NULL(v)) {
			v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("private"));
		}
		if(IS_NOTNULL(v)) {
			flag |= KNH_FLAG_MF_PRIVATE;
		}
		v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("Static"));
		if(IS_NULL(v)) {
			v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("static"));
		}
		if(IS_NOTNULL(v)) {
			flag |= KNH_FLAG_MF_STATIC;
		}
		v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("ClassFunc"));
		if(IS_NOTNULL(v)) {
			flag |= KNH_FLAG_MF_CLASSFUNC;
		}
	}
	return flag;
}

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

knh_flag_t knh_Stmt_metaflag__field(Ctx *ctx, Stmt *b)
{
	return 0;
}

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

knh_flag_t knh_Stmt_metaflag__new(Ctx *ctx, Stmt *b)
{
	return 0;
}

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

knh_bool_t knh_StmtMETA_istime(Stmt *o)
{
	if(IS_NOTNULL(DP(o)->metaDictMap)) {
		Object *v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("time"));
		if(IS_NOTNULL(v)) {
			return 1;
		}
	}
	return 0;
}

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

knh_flag_t knh_StmtMETA_flagPRINT(Ctx *ctx, Stmt *o)
{
	knh_flag_t flag = 0;
	if(IS_NULL(DP(o)->metaDictMap)) {
		return flag;
	}
	else {
		Object *v = knh_DictMap_get__b(ctx, DP(o)->metaDictMap, STEXT("time"));
		if(IS_NOTNULL(v)) {
			flag |= KNH_FLAG_PF_TIME;
		}
	}
	return flag;
}

/* ======================================================================== */
/* [Annotation] */

knh_bool_t knh_StmtMETA_isHistoric(Stmt *o)
{
	if(IS_NOTNULL(DP(o)->metaDictMap)) {
		Object *v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("Historic"));
		if(IS_NOTNULL(v)) return 1;
		v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("historic"));
		if(IS_NOTNULL(v)) return 1;
	}
	return 0;  /* @Historic */
}

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

knh_bool_t knh_StmtMETA_isOverride(Stmt *o)
{
	if(IS_NOTNULL(DP(o)->metaDictMap)) {
		Object *v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("Override"));
		if(IS_NOTNULL(v)) return 1;
		v = knh_DictMap_get__b(NULL, DP(o)->metaDictMap, STEXT("override"));
		if(IS_NOTNULL(v)) return 1;
	}
	return 0;  /* @Historic */
}

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

#ifdef __cplusplus
}
#endif
