/*
 *  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.
 */
#include <fstream>
#include <iostream>
#include <iterator>
#include "adp.h"

#ifdef _WIN32

#include <crtdbg.h>
#endif

// 定数
#define APPLICATIN_GLOBAL	"application.awp"
#define ADP_WEB_PAGE_EXT	".awp"
#define ADP_WEB_PAGE_EXT_SIZE	4
#define ADP_CGI_PAGE_EXT	".cgi"
#define ADP_CGI_PAGE_EXT_SIZE	4
#ifdef ___X64____
#define VERSION_TEXT		"ADP Ver 0.77.0125 X64 (http://www.adp.la/)\nCopyright (C) 2011 Katsuhisa Ohfuji. This progman is distributed under GPL.\n"
#else
#if _WIN32
#define VERSION_TEXT		"ADP Ver 0.77.0125 x86 (http://www.adp.la/)\nCopyright (C) 2011 Katsuhisa Ohfuji. This progman is distributed under GPL.\n"
#else
#define VERSION_TEXT		"ADP Ver 0.77.0125 (http://www.adp.la/)\nCopyright (C) 2011 Katsuhisa Ohfuji. This progman is distributed under GPL.\n"
#endif
#endif

int main(int argc, char *argv[], char **envp)
{
	clock_t c = clock();
	time_t	t = time(0);
#ifdef _WIN32
	#ifndef _STLP_DEBUG 
		_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
	#endif
	//std::cout << std::flush;
	//int fd = _fileno(stdout);
	
	//_setmode(fd, _O_BINARY);

	{
	
	WSADATA				wsaData;
    WSAStartup( 0x0101, &wsaData);
	}
#endif

#ifdef _WIN32
	// Windows 7ではlocalを指定するとかえって文字化けを起こす
#else
	// MACでも動かないどうもロケールについてはきちんと調べる必要あり。
	// std::locale::global(std::locale(""));
#endif

	MyLogClear("pipe");
	
	argvector.clear();
	convertssmap( envp, envmap);
	getqueryvalue(query);
	getcookievalue(cookies);

	myrand();	// mt乱数シードの初期化
	pzero.value = 0;
	ptrue.value = -1;
	global = 0;
	session = 0;
	sessionid.clear();
	sessionpath.clear();
	sessionwriteflg = false;
	ssmap::iterator i = cookies.find(string(ADP_SESSION_ID_STRING));
	if ( i != cookies.end() ) {
		sessionid = i->second;
		session = getSession(sessionid, sessionpath);
	} else {
		i = envmap.find(string(ADP_SESSION_ID_STRING));
		if ( i != envmap.end() ) {
			sessionid = i->second;
			session = getSession(sessionid, sessionpath);
		} else {
			session = 0;
		}
	}
	default_quote_s = '`';
	default_quote_e = '`';

	first_print = true;
	compiletrace = false;
	thread_count = 0;
	init_ExecContext_Factory_Map();
	init_awpescapetags();
	bool	printTime = false;
	bool	printTimeClock = false;
	bool	printTimeTime = false;
	bool	printSessionID = false;
	bool	chdirflg = false;
	GlobalContext	adp;

	// ADP_APPLICATION_PATHの読み込み（ライブラリの読み込み）
	bool compile_application = false;
	if ( envmap.find( string("ADP_APPLICATION_PATH")) != envmap.end()  ) {
		string apppath = envmap[string("ADP_APPLICATION_PATH")];
		adp.compile(apppath, true);
	}

	if ( argc < 2 || envmap.find( string("PATH_TRANSLATED")) != envmap.end() ) {
		if ( envmap.find( string("PATH_TRANSLATED")) != envmap.end() ) {
			header_string = "Content-Type: text/html\r\n";
			string ppath = envmap[string("PATH_TRANSLATED")];
			string::reverse_iterator ri = find( ppath.rbegin(), ppath.rend(), pseparator);
			if ( ri != ppath.rend() ) {
				first_src_base_path = string( ppath.begin(), ri.base());
				string appath = first_src_base_path + APPLICATIN_GLOBAL;
				adp.compile(appath, false, false);
			}
			chdirflg = true;
			adp.compile(ppath, false, true);
		} else {
			fputs( VERSION_TEXT,stdout);
			fputs( "Usage: adp [Options] filename... [-A arguments...] \n",stdout);
			fputs( "     : adp [Options] -c \"adp code\" [-A arguments...] \n",stdout);
			fputs( "Options: -t Show execute time(ms). \n",stdout);
			fputs( "       : -d Show recompile code(for debug).\n",stdout);
			fputs( "       : -s Show session key(for debug).\n",stdout);
			fputs( "       : -cd Change current directory to first source directory.\n",stdout);
			return 1;
		} 
	} else {
		bool appdone = false;
		bool adpargs = false;
		for ( int i = 1; i < argc; i++ ) {	
			if ( argv[i][0] == '-' ) {
				// コマンドライン引数でコードを指定
				if ( strcmp( argv[i], "-c") == 0 && i + 1 < argc ) {
					i++;
					if ( !appdone ) {
						appdone = true;
						string appath = APPLICATIN_GLOBAL;
						adp.compile(appath, false, false);
					}
					adp.compile(argv[i], true);
				}
				if ( strcmp( argv[i], "-d") == 0 ) {
					compiletrace = true;
				}
				if ( strcmp( argv[i], "-t") == 0 ) {
					printTime = true;
				}
				if ( strcmp( argv[i], "-tc") == 0 ) {
					printTimeClock = true;
				}
				if ( strcmp( argv[i], "-tt") == 0 ) {
					printTimeTime = true;
				}
				if ( strcmp( argv[i], "-s") == 0 ) {
					printSessionID = true;
				}
				if ( strcmp( argv[i], "-cd") == 0 ) {
					chdirflg = true;
				}
				if ( strcmp( argv[i], "-A") == 0 ) {
					// 以降は、adpのArgumentとして扱う
					convertstringvector( argv + i + 1, argvector);
					break;	
				}
			} else {
				char *p = strstr( argv[i], ADP_WEB_PAGE_EXT);
				char *q = strstr( argv[i], ADP_CGI_PAGE_EXT);
				bool awp = false;
				if ( (p != 0 && p[ADP_WEB_PAGE_EXT_SIZE] == 0) || (q != 0 && q[ADP_CGI_PAGE_EXT_SIZE] == 0) ) {
					header_string = "Content-Type: text/html\r\n";
					chdirflg = true;
					awp = true;
				}
				if ( !appdone ) {
					appdone = true;
					string ppath = argv[i];
					string::reverse_iterator ri = find( ppath.rbegin(), ppath.rend(), pseparator);
					if ( ri != ppath.rend() ) {
						first_src_base_path = string( ppath.begin(), ri.base());
					}
					string appath = first_src_base_path + APPLICATIN_GLOBAL;
					adp.compile(appath, false, false);
				}
				adp.compile(argv[i], !awp, true);
			}
			
		}
	}
	
	if ( chdirflg ) {
		_chdir( first_src_base_path.c_str() );
	}
	adp.recompile();

	bool ret = adp.prolog();

	if ( sessionwriteflg && session ) {
		// write session to file
		string cvobj;
		string header;
		if ( toBinary( session, cvobj, header) ) {
			basic_ofstream<char> outputFile( sessionpath.c_str(), ios_base::out | ios::binary);
			outputFile << header;
			outputFile << cvobj;
		}
	}

	print_header();
	db_disconnect();

#ifdef _WIN32
    WSACleanup();
#endif

	if ( printTime || printTimeClock ) fprintf(stderr, "time is %5.0fms.(clock)\n", (clock()-c)*1000.0/CLOCKS_PER_SEC); 
	if ( printTime || printTimeTime ) fprintf(stderr, "time is %ds.(time)\n", time(0)-t); 
	if ( printSessionID && !sessionid.empty() ) fprintf(stderr, ADP_SESSION_ID_STRING"=%s\n", sessionid.c_str());
	return ret ? 0 : 1;
}

