/*
 *  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_BASE_H
#define ADP_BASE_H
#include <vector>
#include <map>
#include <string>
#include <cctype>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <functional>
#include <time.h>
#include <limits.h>
#include <float.h>
#include <stdlib.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <boost/regex.hpp>

#ifdef _WIN32
#include <windows.h>
#include <process.h>
#include <Wincrypt.h>
#include <io.h>
#include <direct.h>
#pragma comment (lib, "Crypt32")
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#if defined(__APPLE__)
#  define COMMON_DIGEST_FOR_OPENSSL
#  include <CommonCrypto/CommonDigest.h>
#  define SHA1 CC_SHA1
#else
#  include <openssl/sha.h>
#endif
#include <unistd.h>
#include <pthread.h>
#define SOCKET	int
#define closesocket	close
#endif
#include "kz_base.h"
#include "kz_array.h"
#include "kz_array_noexpand.h"
#include "kz_cformat.h"
#include "kz_net.h"
#include "kz_odbc.h"
#include "kz_readcsv.h"
#include "kz_scanregex.h"

using namespace std;

#ifdef ADP_COMMON_CPP
#define EXTERN 
#else
#define EXTERN	extern
#endif


// 言語要素
class PObject;
class PNil;
class PString;
class PDouble;
class PInteger;
class PList;
class PArray;
class PPredicate;
class PVeriable;
class PEVeriable;
class PWildCard;
class PGoal;
class PHorn;
class PHorns;
class PMemoryManager;

// 実行環境 
class CompileContext;
class ExecContext_Factory;
struct ExecContextRoot;
struct ExecContextBase;
struct ExecContext;
struct GlobalContext;

// 変項管理マップ 
typedef vector<string> VNames;

// グローバルに使う型（基本） 
typedef int PINTEGER32;
typedef long long PINTEGER;
#define PINTEGER_MAX (LLONG_MAX)
#define PINTEGER_MIN (LLONG_MIN)
typedef Array<const PObject*> PObjectArray;
typedef ArrayNoexpand<const PObject*> PObjectArrayNE;
typedef ArrayNoexpand<const PObject*> VLocal;
typedef map<string, size_t> PHashArrayMap;
typedef pair<string, size_t> PHashArrayPair;

typedef map<string,string>	ssmap;
typedef pair<string,string>	sspair;
typedef std::vector< std::string > string_array;

typedef ExecContextRoot *(*ExecContext_FactoryFunction)(ExecContext *, void *, const PPredicate *pred_, VLocal *l);
typedef Array<ExecContextRoot*>	ExecContextRootArray;
typedef ArrayNoexpand<ExecContextRoot*>	ExecContextRootArrayNE;

// グローバル変数（定数） 
extern PNil pnil;
extern PWildCard pwildcard;

// プラットホーム依存の定義 
#if _WIN32
	const char	pseparator = '\\';
	#define NOALIAS_FUNC	__declspec(noalias)
	#define RESTRICT_FUNC	__declspec(restrict)
	#define  __attribute__(X) 
	#define atoll _atoi64
	#define strtoll	_strtoi64
#else
	const char	pseparator = '/';
	#define NOALIAS_FUNC 
	#define RESTRICT_FUNC 
	#define __forceinline 
	#define _chdir chdir
	#define _unlink unlink
	#define _rmdir rmdir
#endif

// グローバル関数 事前定義が必要なもの（事後定義でよければ adp_global.hで定義する 
bool print_header();


template <class T> int sign(T v) {
    if ( v < 0 ) return -1;
    if ( v == 0 ) return 0;
    return 1;
};


// string のハッシュ値
inline int string_hash(const string &value) {
	size_t siz = value.size();
	int h = siz;
	for ( size_t i = 0; i < siz; i++ ) {
		h += value[i];
		h <<= 4;
		h += value[i];
	}
	return h;
}


// Thread 関係
extern int thread_count;
#ifdef _WIN32
	#define THREADHANDLE	HANDLE
	#define thread_return	unsigned
	#define waitamoment	Sleep(0)

	// create
	inline bool start_thread( THREADHANDLE *th, thread_return (__stdcall *func)(void*), void *arg) {
		*th = (THREADHANDLE)_beginthreadex( 0, 0, func, arg, 0, 0);
		return *th != 0;
	}

	// wait
	inline bool wait_thread( THREADHANDLE th) {
		 return WaitForSingleObject( th, 1) == WAIT_TIMEOUT;
	}

	#define destory_thread(th)	CloseHandle(th)

	// MyLockクラス
	#define MyLockObject	CRITICAL_SECTION
	#define MAX_SPIN_LOCK 10000

	#define InitMyLockObject(x)	InitializeCriticalSectionAndSpinCount(x, MAX_SPIN_LOCK)
	#define DeleteMyLockObject(x)	DeleteCriticalSection(x)

	class  MyLockSection {
		MyLockObject *lpcs;
	public:
		MyLockSection(MyLockObject &cs_) : lpcs(&cs_) {
			if ( thread_count > 0 ) {
				EnterCriticalSection(lpcs);
			}
		}
		
		~MyLockSection() {
			if ( thread_count > 0 ) {
				LeaveCriticalSection(lpcs);
			}
		}
	};

	extern  __declspec( thread ) void *tls_ptr;

	inline void	init_gc() { tls_ptr = 0;};
	inline void set_gc( GlobalContext *ptr ) { tls_ptr = ptr; };
	inline GlobalContext *get_gc() {return (GlobalContext *)tls_ptr;};
	inline void end_gc() { tls_ptr = 0; };
#else
	#define THREADHANDLE	pthread_t
	#define __stdcall 
	#define thread_return	void*
	#define waitamoment	sleep(0)

	// create
	inline bool start_thread( THREADHANDLE *th, thread_return (*func)(void*), void *arg) {
		return pthread_create( th, 0, func, arg) == 0;
	}

	// wait
	inline bool wait_thread( THREADHANDLE th) {
		pthread_join(th, 0);
		return false;
	}

	#define destory_thread(th)

	// MyLockクラス
	#define MyLockObject	pthread_mutex_t

	#define InitMyLockObject(x)	pthread_mutex_init(x, 0)
	#define DeleteMyLockObject(x)	 pthread_mutex_destroy(x)

	class  MyLockSection {
		MyLockObject *lpcs;
	public:
		MyLockSection(MyLockObject &cs_) : lpcs(&cs_) {
			if ( thread_count > 0 ) {
				pthread_mutex_lock(lpcs);
			}
		}
		
		~MyLockSection() {
			if ( thread_count > 0 ) {
				pthread_mutex_unlock(lpcs);
			}
		}
	};
	
	extern pthread_key_t	tsd_key;

	inline void	init_gc() { pthread_key_create(&tsd_key,0); };
	inline void set_gc( GlobalContext *ptr ) { pthread_setspecific(tsd_key,ptr); };
	inline GlobalContext *get_gc() { return (GlobalContext *)pthread_getspecific(tsd_key); };
	inline void end_gc() { pthread_key_delete(tsd_key); };
#endif

#define waitflg2(flg) while(!flg){ for(int i=0;i<1000000&&!flg;i++);if(flg)break;waitamoment;}
#define waitflg(flg) while(!flg){ waitamoment;}

// Threadのデバッグ時に使用
#if 0	
inline void MyLogClear( const char *logname)
{
	string fname = logname;
	fname += ".log";
	
	FILE *fp = fopen( fname.c_str(), "w");
	if ( fp ) {
		fclose(fp);
	}
}
inline void MyLog( const char *str, const char *logname)
{
	string fname = logname;
	fname += ".log";
	
	FILE *fp = fopen( fname.c_str(), "a");
	if ( fp ) {
		fwrite( str, strlen(str), 1, fp);
		fclose(fp);
	}
}
#else
#define MyLogClear(logname)
#define MyLog( str, logname)
#endif


// オブジェクトの破棄 
struct MyDeleteObject {
	template <typename T> void operator() (const T* ptr) const {
		delete ptr;
	}
};

// オブジェクト管理
class PObjectAllocList {
	MyLockObject		lock;
	PObjectArray		objs;
public:
	PObjectAllocList() {InitMyLockObject(&lock);};
	~PObjectAllocList() {DeleteMyLockObject(&lock);};
	void push_back(PObject* p) {
		
	}

};


#endif
