/*
 *  ADP (Another Data Processor) www.adp.la
 *  Copyright (C) 2010 Katsuhisa Ohfuji <katsuhisa@ohfuji.name>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA 02110-1301, USA.
 */

#ifndef ADP_BUILTIN_STRING_H
#define ADP_BUILTIN_STRING_H

struct ExecContext_Regex_Search : public ExecContextBase {
	// regex
	boost::regex			reg;
	const string			*text;
	string::const_iterator	start;

	ExecContext_Regex_Search(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextBase(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() < 2 ) 
			return RERR_argment_number(excp, 2);
		PString *str = const_cast<PString*>(get<PString>(0));
		const PString *regex = get<PString>(1);
		if ( !str ) return RERR_argment_type( excp, 0);
		if ( !regex ) return RERR_argment_type( excp, 1);

		string regexnocrlf;
		replace_all( regex->c_str(), "\n", "", regexnocrlf);
		replace_all( regexnocrlf.c_str(), "\r", "", regexnocrlf);

		try {
			reg = boost::regex( regexnocrlf.c_str() );
		} catch(...) {
			return RERR_regex_format_error(excp);
		}
		text = &str->value;
		start = text->begin();
		return backtrack(excp);
	}
	virtual bool backtrack(PException &excp) {
		boost::smatch what;
		try {
			bool ret = boost::regex_search( start, static_cast<string::const_iterator>(text->end()), what, reg );
			if ( ret ) {
				PArray *alloc_ary = 0;
				if ( !size_check_and_alloc_array( what.size() - 1 + 2, excp, &alloc_ary) ) return false;
				start = what[0].second;
				size_t	vidx = 2;
				for ( size_t i = 1; i < what.size(); i++ ) {
					//if ( vidx >= pred->size() ) break;
					PString *po = pmm.newPString(pobjs, string(what[i].first, what[i].second));
					if ( !unify<PString>( vidx, po, excp) ) return false;
					vidx++;
				}
			} else if ( start == text->begin() ) {
				return false;
			}
			return ret;
		} catch(...) {
			return RERR_regex_format_error(excp);
		}
	}
};


struct ExecContext_Cat : public ExecContextRoot {
	ExecContext_Cat(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() < 2 ) return RERR_argment_number(excp, 2);
		size_t last = pred->size() - 1;
		string result_;
		for ( size_t i = 0; i < last; i++ ) {
			const PObject *item = get<PObject>(i);
			string str;
			if ( !item->cnv_string(str) ) return false;
			result_ += str;
		}
		const PString  *result = pmm.newPString(pobjs,result_);
		return unify<PString>( last, result, excp);
	}
};

struct ExecContext_Left : public ExecContextRoot {
	ExecContext_Left(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject *str = get<PObject>(0);
		const PObject *num = get<PObject>(1);
		PINTEGER s;

		if ( !str->c_str() ) return false;
		if ( !num->cnv_integer(s) ) return false;
		
		string item;
		if ( s < 0 ) return false;
		item.assign( str->c_str(), static_cast<size_t>(s));
		const PString  *result = pmm.newPString(pobjs,item);
		return unify<PString>( 2, result, excp);
	}
};


struct ExecContext_Right : public ExecContextRoot {
	ExecContext_Right(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject *str = get<PObject>(0);
		const PObject *num = get<PObject>(1);
		PINTEGER s;

		if ( !str->c_str() ) return false;
		if ( !num->cnv_integer(s) ) return false;
		
		string item;
		if ( s < 0 ) return false;
		const char *p = str->c_str();
		size_t	len = strlen(p);
		item.assign( p + len - s, static_cast<size_t>(s));
		const PString  *result = pmm.newPString(pobjs,item);
		return unify<PString>( 2, result, excp);
	}
};

struct ExecContext_Mid : public ExecContextRoot {
	ExecContext_Mid(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 4 ) return RERR_argment_number(excp, 4);
		const PObject *str = get<PObject>(0);
		const PObject *start = get<PObject>(1);
		const PObject *num = get<PObject>(2);
		PINTEGER s, n;

		if ( !str->c_str() ) return false;
		if ( !start->cnv_integer(s) ) return false;
		if ( !num->cnv_integer(n) ) return false;
		
		string item;
		const char *p = str->c_str();
		if ( s < 0 || s > (int)strlen(p)) return false;
		if ( n < 0 ) return false;
		item.assign( p + static_cast<size_t>(s), static_cast<size_t>(n));
		const PString  *result = pmm.newPString(pobjs,item);
		return unify<PString>( 3, result, excp);
	}
};

struct ExecContext_Chr : public ExecContextRoot {
	ExecContext_Chr(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject *code = get<PObject>(0);

		PINTEGER	n;
		if ( !code->cnv_integer(n) ) return false;
		
		string item;
		item.push_back( static_cast<char>(n) );
		const PString  *result = pmm.newPString(pobjs,item);
		
		return unify<PString>( 1, result, excp);
	}
};

struct ExecContext_Ascii : public ExecContextRoot {
	ExecContext_Ascii(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject *str = get<PObject>(0);
		if ( !str->c_str() ) return false;

		const PInteger  *result = pmm.newPInteger(pobjs, *(str->c_str()));
		
		return unify<PInteger>( 1, result, excp);
	}
};

struct ExecContext_Instr : public ExecContextBase {
	const PString *src;
	const PString *findstr;
	size_t pos;

	ExecContext_Instr(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextBase(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 && pred->size() != 4) return RERR_argment_number(excp, 3);
		src = get<PString>(0);
		findstr = get<PString>(1);
		if ( !src ) return RERR_argment_type(excp, 0);
		if ( !findstr) return RERR_argment_type(excp, 1);

		if ( pred->size() == 3 ) {
			pos = -1;
		} else {
			const PInteger *ofs = get<PInteger>(2);
			if ( !ofs ) return  RERR_argment_type(excp, 2);
			pos = static_cast<size_t>(ofs->value - 1);
		}
		return backtrack(excp);
	}

	virtual bool backtrack(PException &excp) {
		pos = src->value.find( findstr->value, pos + 1);
		if ( pos == string::npos ) return false;
		const PInteger  *result = pmm.newPInteger(pobjs, pos);
		return unify<PInteger>( pred->size() - 1, result, excp);
	}
};


struct ExecContext_InstrRev : public ExecContextBase {
	const PString *src;
	const PString *findstr;
	size_t rpos;

	ExecContext_InstrRev(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextBase(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 && pred->size() != 4) return RERR_argment_number(excp, 3);
		src = get<PString>(0);
		findstr = get<PString>(1);
		if ( !src ) return RERR_argment_type(excp, 0);
		if ( !findstr) return RERR_argment_type(excp, 1);

		if (  pred->size() == 3 ) {
			rpos = src->value.size();
		} else {
			const PInteger *ofs = get<PInteger>(2);
			if ( !ofs ) return  RERR_argment_type(excp, 2);
			rpos = static_cast<size_t>(ofs->value + 1);
		}
		return backtrack(excp);
	}

	virtual bool backtrack(PException &excp) {
		while ( true ) {
			rpos = src->value.find_last_of( *findstr->value.c_str(), static_cast<size_t>(rpos - 1));
			if ( rpos == string::npos ) return false;
			if ( memcmp( src->value.c_str() + rpos, findstr->value.c_str(), findstr->value.size()) == 0 ) {
				break;
			}
			if ( rpos == 0 ) return false;
		}
		const PInteger  *result = pmm.newPInteger(pobjs, rpos);
		return unify<PInteger>( pred->size() - 1, result, excp);
	}
};


struct ExecContext_Replace : public ExecContextRoot {
	ExecContext_Replace(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() < 4 || 5 < pred->size() ) return RERR_argment_number(excp, 4);
		const PString *src = get<PString>(0);
		const PObject *find = get<PObject>(1);
		const PObject *replace = get<PObject>(2);
		size_t off = 0;
		if ( pred->size() == 5 ) {
			const PInteger *poff = get<PInteger>(3);
			if ( !poff ) return RERR_argment_type(excp, 3);
			off = static_cast<size_t>(poff->value);
		}

		if ( !src ) return false;
		if ( !find->c_str() ) return false;
		if ( !replace->c_str() ) return false;
		
		string  result;
		replace_all( src->c_str(), find->c_str(), replace->c_str(), result, off);
		const PString *p = pmm.newPString( pobjs, result);
		return unify<PString>( pred->size() - 1, p, excp);
	}
};

struct ExecContext_ReplaceFirst : public ExecContextRoot {
	ExecContext_ReplaceFirst(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() < 4 || 5 < pred->size() ) return RERR_argment_number(excp, 4);
		const PString *src = get<PString>(0);
		const PObject *find = get<PObject>(1);
		const PObject *replace = get<PObject>(2);
		size_t off = 0;
		if ( pred->size() == 5 ) {
			const PInteger *poff = get<PInteger>(3);
			if ( !poff ) return RERR_argment_type(excp, 3);
			off = static_cast<size_t>(poff->value);
		}

		if ( !src ) return false;
		if ( !find->c_str() ) return false;
		if ( !replace->c_str() ) return false;
		
		string  result;
		replace_first( src->c_str(), find->c_str(), replace->c_str(), result, off);
		const PString *p = pmm.newPString( pobjs, result);
		return unify<PString>( pred->size() - 1, p, excp);
	}
};

struct ExecContext_RegexReplace : public ExecContextRoot {
	ExecContext_RegexReplace(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() < 4 || 5 < pred->size() ) return RERR_argment_number(excp, 4);
		const PString *src = get<PString>(0);
		const PObject *find = get<PObject>(1);
		const PObject *replace = get<PObject>(2);
		size_t off = 0;
		if ( pred->size() == 5 ) {
			const PInteger *poff = get<PInteger>(3);
			if ( !poff ) return RERR_argment_type(excp, 3);
			off = static_cast<size_t>(poff->value);
		}

		if ( !src ) return false;
		if ( !find->c_str() ) return false;
		if ( !replace->c_str() ) return false;
		
		string  result;
		replace_regex_all( src->value, find->c_str(), replace->c_str(), result, off);
		const PString *p = pmm.newPString( pobjs, result);
		return unify<PString>( pred->size() - 1, p, excp);
	}
};

struct ExecContext_RegexReplaceFirst : public ExecContextRoot {
	ExecContext_RegexReplaceFirst(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() < 4 || 5 < pred->size() ) return RERR_argment_number(excp, 4);
		const PString *src = get<PString>(0);
		const PObject *find = get<PObject>(1);
		const PObject *replace = get<PObject>(2);
		size_t off = 0;
		if ( pred->size() == 5 ) {
			const PInteger *poff = get<PInteger>(3);
			if ( !poff ) return RERR_argment_type(excp, 3);
			off = static_cast<size_t>(poff->value);
		}

		if ( !src ) return false;
		if ( !find->c_str() ) return false;
		if ( !replace->c_str() ) return false;
		
		string  result;
		replace_regex_first( src->value, find->c_str(), replace->c_str(), result, off);
		const PString *p = pmm.newPString( pobjs, result);
		return unify<PString>( pred->size() - 1, p, excp);
	}
};


struct ExecContext_Trim : public ExecContextRoot {
	ExecContext_Trim(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() < 2 ) return RERR_argment_number(excp, 2);
		const PString *src = get<PString>(0);
		if ( !src ) return false;
		const string &v = src->value;
		string::const_iterator l = v.begin();
		string::const_iterator r = v.end() - 1;

		/* LTrim */
		while ( *l == ' ' || *l == '\t' || *l == '\r' || *l == '\n' ) {
			if ( l < v.end() ) 
				l++;
			else
				break;
			
		}
		/* RTrim */
		while ( *r == ' ' || *r == '\t' || *r == '\r' || *r == '\n' ) {
			if ( r > v.begin() ) 
				r--;
			else
				break;
		}

		string result(l,r+1);
		const PString *p = pmm.newPString( pobjs,result);		
		return unify<PString>( 1, p, excp);
	}
};

struct ExecContext_Sprintf : public ExecContextRoot {
	ExecContext_Sprintf(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() < 2 ) return RERR_argment_number(excp, 2);
		const char	*f = get_charp(0);
		if ( !f ) return false;
		size_t	len = strlen(f);
		size_t	idx = 1;
		string out;
		size_t	i = 0;	
		while ( i < len ) {
			if ( f[i] == '%' ) {
				i++;
				string	flags;	// -+0 #
				size_t	width = (size_t)-1;
				size_t	precision = (size_t)-1;
				char	type = 0;	// s,d
				// get flgs
				while ( strchr("-+0 #", f[i]) != 0 ) {
					flags.push_back(f[i]);
					i++;
				}
				// get width;
				string buf;
				while ( isdigit(f[i]) ) {
					buf.push_back(f[i]);
					i++;
				}
				if ( !buf.empty() ) width = atoi(buf.c_str());
				buf.clear();
				// get precision
				if ( f[i] == '.' ) {
					i++;
					while ( isdigit(f[i]) ) {
						buf.push_back(f[i]);
						i++;
					}
					if ( !buf.empty() ) precision = atoi(buf.c_str());
				}
				// type
				switch ( f[i] ) {
					case 's':
						{
							const char *sp = get_charp(idx++);
							if ( !sp ) return false;
							size_t	slen = strlen(sp);
							if ( width == (size_t)-1 ) width = slen;
							if ( precision == (size_t)-1) precision = slen;
							bool leftflg = (strchr( flags.c_str(), '-') != 0);
							if ( width > slen && !leftflg ) {
								out += string( width - slen, ' ');
							}
							if ( precision < slen ) {
								out += string( sp, sp + precision);
							} else {
								out += sp;
							}
							if ( width > slen && leftflg ) {
								out += string( width - slen, ' ');
							}
							i++;
						}
						break;
					case 'd':
						{
							const PObject *pobj = get<PObject>(idx++);
							if ( !pobj ) return false;
							PINTEGER d;
							if ( !pobj->cnv_integer(d) ) return false;
							char	fmt[64];
							char	buf[64];
							if ( ( width == (size_t) - 1 ) && ( precision == (size_t) - 1 ) ) {
								sprintf( fmt, "%%%slld", flags.c_str());
							} else if ( width == (size_t) - 1 ) {
								sprintf( fmt, "%%%s.%dlld", flags.c_str(), precision);
							} else if ( precision == (size_t) - 1 ) {
								sprintf( fmt, "%%%s%dlld", flags.c_str(), width);
							} else {
								sprintf( fmt, "%%%s%d.%dlld", flags.c_str(), width, precision);
							}
							sprintf( buf, fmt, d);
							out += buf;
							i++;
						}
						break;
					case 'x':
						{
							const PObject *pobj = get<PObject>(idx++);
							if ( !pobj ) return false;
							PINTEGER	d;
							if ( !pobj->cnv_integer(d) ) return false;
							char	fmt[64];
							char	buf[64];
							if ( ( width == (size_t) - 1 ) && ( precision == (size_t) - 1 ) ) {
								sprintf( fmt, "%%%sllx", flags.c_str());
							} else if ( width == (size_t) - 1 ) {
								sprintf( fmt, "%%%s.%dllx", flags.c_str(), precision);
							} else if ( precision == (size_t) - 1 ) {
								sprintf( fmt, "%%%s%dllx", flags.c_str(), width);
							} else {
								sprintf( fmt, "%%%s%d.%dllx", flags.c_str(), width, precision);
							}
							sprintf( buf, fmt, d);
							out += buf;
							i++;
						}
						break;
					case 'o':
						{
							const PObject *pobj = get<PObject>(idx++);
							if ( !pobj ) return false;
							PINTEGER	d;
							if ( !pobj->cnv_integer(d) ) return false;
							char	fmt[64];
							char	buf[64];
							if ( ( width == (size_t) - 1 ) && ( precision == (size_t) - 1 ) ) {
								sprintf( fmt, "%%%sllo", flags.c_str());
							} else if ( width == (size_t) - 1 ) {
								sprintf( fmt, "%%%s.%dllo", flags.c_str(), precision);
							} else if ( precision == (size_t) - 1 ) {
								sprintf( fmt, "%%%s%dllo", flags.c_str(), width);
							} else {
								sprintf( fmt, "%%%s%d.%dllo", flags.c_str(), width, precision);
							}
							sprintf( buf, fmt, d);
							out += buf;
							i++;
						}
						break;
					case 'f':
						{
							const PObject *pobj = get<PObject>(idx++);
							if ( !pobj ) return false;
							double	d;
							if ( !pobj->cnv_double(d) ) return false;
							char	fmt[64];
							char	buf[64];
							if ( ( width == (size_t) - 1 ) && ( precision == (size_t) - 1 ) ) {
								sprintf( fmt, "%%%sf", flags.c_str());
							} else if ( width == (size_t) - 1 ) {
								sprintf( fmt, "%%%s.%df", flags.c_str(), precision);
							} else if ( precision == (size_t) - 1 ) {
								sprintf( fmt, "%%%s%df", flags.c_str(), width);
							} else {
								sprintf( fmt, "%%%s%d.%df", flags.c_str(), width, precision);
							}
							sprintf( buf, fmt, d);
							out += buf;
							i++;
						}
						break;
					case ',':
						{
							const PObject *pobj = get<PObject>(idx++);
							if ( !pobj ) return false;
							PINTEGER	d;
							if ( !pobj->cnv_integer(d) ) return false;
							buf.clear();
							formatNumber(d, buf);
							out += buf;
							i++;
						}
						break;
					case '%':
						out.push_back(f[i]);
						i++;
				}
			} else {
				out.push_back(f[i]);
				i++;
			}
		}
		const PString *p = pmm.newPString( pobjs, out);
		return unify<PString>( idx, p, excp);
	}
};

struct ExecContext_Split : public ExecContextRoot {
	ExecContext_Split(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PString *src = dynamic_cast<const PString*>(get<PObject>(0));
		const PString *find = dynamic_cast<const PString*>(get<PObject>(1));

		if ( !src || !find /*|| !v*/ ) return false;

		const string	&s = src->value;
		const string	&f = find->value;
		size_t			off = 0;
		size_t			flen = f.size();
		size_t			fnd;
		vector<size_t>	spos;
		spos.push_back(0);
		while ( (fnd = s.find( f, off)) != string::npos ) {
			spos.push_back(fnd);
 			off = fnd + flen;
			spos.push_back(off);
		}
		spos.push_back(s.size());

		PObject	*list = &pnil;
		for ( vector<size_t>::reverse_iterator i = spos.rbegin(); i < spos.rend(); i++ ) {
			size_t	end  = *i++;
			size_t	begin = *i;
			PString	*po = pmm.newPString(pobjs, s.begin() + begin, s.begin() + end);
			PList *nlist = pmm.newPList(pobjs, po, list, true);
			list = nlist;
		}
		return unify<PObject>(2, list, excp);
	}
};

struct ExecContext_Euc2sjis : public ExecContextRoot {
	ExecContext_Euc2sjis(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PString *src = get<PString>(0);

		if ( !src ) return false;
		
		string	dst;
		dst.reserve(src->value.capacity());
		char sj[3];

		for ( const unsigned char *p = (const unsigned char*)src->c_str(); *p != 0; p++ ) {
			if ( *p < 0x80 ) {	// チェックがあまい
				dst += *p;
			} else {
				ej2sj( (const unsigned char*)p, (unsigned char *)sj);
				if ( p[1] ) p++;
				dst += (char*)sj;
			}
		}
		const PString *p = pmm.newPString( pobjs,dst);
		return unify<PString>( 1, p, excp);
	}
};

struct ExecContext_FromUTF8 : public ExecContextRoot {
	ExecContext_FromUTF8(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PString *src = get<PString>(0);

		if ( !src ) return false;
		
		string	dst;
		utf8to( src->value, dst);
		const PString *p = pmm.newPString( pobjs,dst);
		return unify<PString>( 1, p, excp);
	}
};


struct ExecContext_CSV : public ExecContextRoot {
	ExecContext_CSV(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() < 2 ) return RERR_argment_number(excp, 2);

		size_t last = pred->size() - 1;
		string result;
		string str;
		result.reserve(8192);
		for ( size_t i = 0; i < last; i++ ) {
			if ( i != 0 ) { result += ','; }
			const PObject *item = get<PObject>(i);
			item->cnv_csv(result, ',', '"');
		}
		const PString *p = pmm.newPString( pobjs,result);
		return unify<PString>( last, p, excp);
	}
};

struct ExecContext_JSON : public ExecContextRoot {
	ExecContext_JSON(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		string result;
		result.reserve(8192);
		get<PObject>(0)->cnv_json(result);
		const PString *p = pmm.newPString( pobjs,result);
		return unify<PString>( 1, p, excp);
	}
};

struct ExecContext_ParseJSON : public ExecContextRoot {
	ExecContext_ParseJSON(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);

		const PString *str = get<PString>(0);
		size_t pos = 0;

		if ( str == 0 ) return RERR_argment_type(excp, 0);
		
		PObject *po = poFactory.createPObjectJSON( str->value, pos, pobjs);
		if ( po != 0 ) { po = po->parseJson( str->value, pos, pobjs); }
		if ( po == 0 ) return RERR_Convert( excp, pos);

		return unify<PObject>( 1, po, excp);
	}
};

struct ExecContext_SHA1 : public ExecContextRoot {
	ExecContext_SHA1(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PString *src = get<PString>(0);
		string hash;
		if ( !createHash( src->value, hash) ) return RERR_System_Call(excp);
	
		const PString *p = pmm.newPString( pobjs,hash);
		return unify<PString>( 1, p, excp);
	}
};

struct ExecContext_MakeSessionID : public ExecContextRoot {
	ExecContext_MakeSessionID(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		string sessionid;
		string temppath;
		if ( !createSessionID( sessionid, temppath, envmap) ) return RERR_File_Operation(excp);

		const PString *t = pmm.newPString( pobjs,temppath);
		const PString *p = pmm.newPString( pobjs,sessionid);
		return unify<PString>( 0, t, excp) && unify<PString>( 1, p, excp);
	}
};

struct ExecContext_CTimeStr : public ExecContextRoot {
	ExecContext_CTimeStr(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
static const char *wtbl[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const char *mtbl[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
		if ( pred->size() != 4 ) return RERR_argment_number(excp, 4);
		const PString *psrc = get<PString>(0);
		const PString *pfmt = get<PString>(1);
		const PString *pomt = get<PString>(2);
		if ( !psrc ) return RERR_argment_type( excp, 0);
		if ( !pfmt ) return RERR_argment_type( excp, 1);
		if ( !pomt ) return RERR_argment_type( excp, 2);
		const string &src = psrc->value;
		const string &fmt = pfmt->value;
		const string &omt = pomt->value;

		int year = 0;
		int month = 0;
		int day = 0;
		int hour = 0;
		int minute = 0;
		int secound = 0;
		int week = 0;
		//int timezone = 0;

		// DateTimeの取得
		size_t spos = 0;
		size_t fpos = 0;
		while ( spos < src.size() && fpos < fmt.size() ) {
			if ( fmt[fpos] == '%' ) {
				int i;
				fpos++;
				if ( fpos >= fmt.size() ) return false;
				switch( fmt[fpos] ) {
					case 'a' : 
						for ( i = 0; i < sizeof(wtbl)/sizeof(wtbl[0]); i++ ) {
							if ( memcmp( src.c_str() + spos, wtbl[i], 3) == 0 ) break;
						}
						if ( i >= sizeof(wtbl)/sizeof(wtbl[0]) ) return false;
						week = i;
						spos += 3;
						fpos++;
						break;
					case 'b' : 
						for ( i = 0; i < sizeof(mtbl)/sizeof(mtbl[0]); i++ ) {
							if ( memcmp( src.c_str() + spos, mtbl[i], 3) == 0 ) break;
						}
						if ( i >= sizeof(mtbl)/sizeof(mtbl[0]) ) return false;
						month = i + 1; // 1月始まり
						spos += 3;
						fpos++;
						break;
					case 'd' :
						if ( sscanf( src.c_str() + spos, "%2d", &day) != 1 ) return false;
						if ( day < 1) {
							return false;
						} else if ( day <= 31 ) {
							spos +=2;
						} else {
							return false;
						}
						fpos++;
						break;
					case 'H' :
						if ( sscanf( src.c_str() + spos, "%2d", &hour) != 1 ) return false;
						if ( hour < 0) {
							return false;
						} else if ( hour <= 23 ) {
							spos +=2;
						} else {
							return false;
						}
						fpos++;
						break;
					case 'm' :
						if ( sscanf( src.c_str() + spos, "%2d", &month) != 1 ) return false;
						if ( month < 1 ) {
							return false;
						} else if ( month <= 12 ) {
							spos +=2;
						} else {
							return false;
						}
						fpos++;
						break;
					case 'M' :
						if ( sscanf( src.c_str() + spos, "%2d", &minute) != 1 ) return false;
						if ( minute < 0 ) {
							return false;
						} else if ( minute <= 59 ) {
							spos +=2;
						} else {
							return false;
						}
						fpos++;
						break;
					case 'S' :
						if ( sscanf( src.c_str() + spos, "%2d", &secound) != 1 ) return false;
						if ( secound < 0) {
							return false;
						} else if ( secound <= 60 ) {
							spos +=2;
						} else {
							return false;
						}
						fpos++;
						break;
					case 'w' :
						if ( sscanf( src.c_str() + spos, "%1d", &secound) != 1 ) return false;
						if ( secound < 0) {
							return false;
						} else if ( secound <= 6 ) {
							spos +=1;
						} else {
							return false;
						}
						fpos++;
						break;
					case 'Y' :
						if ( sscanf( src.c_str() + spos, "%4d", &year) != 1 ) return false;
						if ( year < 0 ) {
							return false;
						} else if ( year < 10000 ) {
							spos +=4;
						} else {
							return false;
						}
						fpos++;
						break;
					case '%' :
						break; // % を記号として比較する
					default :
						return RERR_argment_type( excp, 1); // フォーマットエラー
				}
			} else {
				if ( src[spos] != fmt[fpos] ) return false;
				spos++;
				fpos++;
			}
		}
		if ( fpos < fmt.size() ) return false;
		
		
		// DateTimeの出力
		string buf;
		size_t opos = 0;
		while ( opos < omt.size() ) {
			if ( omt[opos] == '%' ) {
				opos++;
				if ( opos >= omt.size() ) break;
				switch( omt[opos] ) {
				case 'a' :
					buf += wtbl[week];
					opos++;
					break;
				case 'b' :
					buf += mtbl[month-1];
					opos++;
					break;
				case 'd' :
					buf += cformat("%02d", day);
					opos++;
					break;
				case 'H' :
					buf += cformat("%02d", hour);
					opos++;
					break;
				case 'm' :
					buf += cformat("%02d", month);
					opos++;
					break;
				case 'M' :
					buf += cformat("%02d", minute);
					opos++;
					break;
				case 'S' :
					buf += cformat("%02d", secound);
					opos++;
					break;
				case 'w' :
					buf += cformat("%01d", week);
					opos++;
					break;
				case 'Y' :
					buf += cformat("%04d", year);
					opos++;
					break;
				default :
					return RERR_argment_type( excp, 2);
				}
			} else {
				buf.push_back(omt[opos]);
				opos++;
			}
		}
		const PString *p = pmm.newPString( pobjs, buf);
		return unify<PString>( 3, p, excp);
	}
};

#endif
