/*------------------------------------------------------------------------------
* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team
* 
* Distributable under the terms of either the Apache License (Version 2.0) or 
* the GNU Lesser General Public License, as specified in the COPYING file.
------------------------------------------------------------------------------*/
#ifndef _lucene_util_Misc_H
#define _lucene_util_Misc_H

#include "dirent.h"

#if defined(_LUCENE_PRAGMA_ONCE)
# pragma once
#endif

CL_NS_DEF(util)


  /** A class containing various functions. 
  */
  class Misc{
  public:
    static uint64_t currentTimeMillis();
    static const TCHAR* replace_all( const TCHAR* val, const TCHAR* srch, const TCHAR* repl );
    static bool dir_Exists(const char* path);
	static int64_t file_Size(const char* path);

    static size_t ahashCode(const char* str);
	  static size_t ahashCode(const char* str, size_t len);

    static TCHAR* join ( const TCHAR* a, const TCHAR* b, const TCHAR* c=NULL, const TCHAR* d=NULL,const TCHAR* e=NULL,const TCHAR* f=NULL );
    static char* ajoin ( const char* a, const char* b, const char* c=NULL, const char* d=NULL,const char* e=NULL,const char* f=NULL );

    static bool priv_isDotDir( const TCHAR* name );
	//Creates a filename by concatenating Segment with ext and x
	static char* segmentname(const char* segment, const char* ext, const int32_t x=-1 );
	//Creates a filename in buffer by concatenating Segment with ext and x
	static void segmentname(char* buffer,int32_t bufferLen, const char* Segment, const char* ext, const int32_t x=-1);

   /**
   * Compares two strings, character by character, and returns the
   * first position where the two strings differ from one another.
   *
   * @param s1 The first string to compare
   * @param s1Len The length of the first string to compare
   * @param s2 The second string to compare
   * @param s2Len The length of the second string to compare
   * @return The first position where the two strings differ.
   */
	static int32_t stringDifference(const TCHAR* s1, const int32_t s1Len, const TCHAR* s2, const int32_t s2Len);
	
	

#ifdef _UCS2
    static size_t whashCode(const wchar_t* str);
		static size_t whashCode(const wchar_t* str, size_t len);
		#define thashCode whashCode
	  
    static char* _wideToChar(const wchar_t* s CL_FILELINEPARAM);
    static wchar_t* _charToWide(const char* s CL_FILELINEPARAM);

    static void _cpycharToWide(const char* s, wchar_t* d, size_t len);
    static void _cpywideToChar(const wchar_t* s, char* d, size_t len);
#else
	#define thashCode ahashCode
#endif
  };

CL_NS_END


#if defined (__SYMBIAN32__) && defined (RVCT22_STATICS_WORKAROUND)
// This magic is needed for RCVT 2.2 compiler - global and static member C++ 
// variables are not constructed, so we need to work around. The idea is that 
// instead of
// true global or static member variables, we will be using pointers
// to instances, and these pointers will point to dynamically allocated
// instances. Such instances will be created on demand, and macro will take
// care of providing seamless syntax (syntax of clients of the static variable 
// in existing code should not be modified).
// The dynamically allocated instances will also be destroyed when
// _lucene_shutdown() is called.
//
// Usage:
// Let's say you want to have a global variable foo of type Foo:
//   static Foo foo(true, false);
// but you can't, because it does not get constructed.
// You type instead:
//   DECL_STATVAR(Foo,foo,true,false)
//   #define foo GetInstanceFoofoo()
// Note that:
//   o  constructor arguments, if any, go to the declaration
//   o  the token 'foo' will be, in fact, resolved to
//      a function call, of which the name is GetInstance<TYPE><VAR>.
//  Alternatively, you can define foo as
//   #define foo GetInstance<T,foo_ID,true,false>(&pfoo_)
//  which is much more error prone, but slightly more efficent, as
//  it implies one function call less. Note that the there are two
//  identifiers (foo_ID, pfoo_) generated from the variable name
//  'foo'.
//
// Now, static member variables are to be handled thus: let's
// assume you wanted to have
//
//   class C
//   {
//     static Foo foo_;
//   };
// Instead of that, you write this in the header file
//
//   class C
//   {
//     DECL_STATMVAR1(Foo,foo_,true,false)
//   #define foo_ GetInstanceFoofoo_()
//   };
// Note, that in this case you can't define foo_ to resolve to the
// more convoluted and more efficient version, since the following
// client syntaxes need to work 'C::foo_', and that is only possible
// if foo_ resolves into something that is a static member of C -
// and GetInstanceFoofoo_ static member function is generated by
// the DECL_STATMVAR1 macro.
// Also, in the .cpp source file, you need a second declaration for
// initialization:
//   DECL_STATMVAR2(Foo,C,foo_)
//
// Static member variables that are pointers: instead of
//   class C
//   {
//     static Foo * foo_;
//   };
// you would write 
//   class C
//   {
//     struct foo_CREATOR
//     {
//        static Foo * create(bool,bool);
//     };
//     DECL_STATMPTR1(Foo,foo_CREATOR,foo_,true,false)
//   #define foo_ GetInstancePtrFoofoo_()
//   };
// Note the use of PTR and Ptr. 
// The DECL_STATMVAR2 usage in the .cpp source file
// is the same as above (DECL_STATMVAR2), but also
// static Foo * foo_CREATOR::create(bool,bool) needs to be defined.
// The need for CREATOR: in case of pointers, derived classes
// may also be instantiated, so there has to be an entity that
// knows what and how to create ... The reason we are not
// using simply (static member) functions is that they
// confuse the WinsCW compilation mightily. So we have
// to use structs with static 'create' member function.
//
// If you want to construct an instance with arguments that are
// not handled yet, just add a new overloaded flavour of the template
// function GetInstance below.
//
// Existing client operating on foo, like
//   foo.getFirstBoolean()
// will behave as before. On the first usage of 'foo' at runtime
// the instance will be created - that is, not at program startup.
//
// Note, template instanciation types cannot be used, e.g. you
// can't do DECL_STATVAR(Foo<int>,foo,true,false). You have to
// create a typedef for Foo<int> (Like FooInt) and use that instead.
//


/**
 * Base class for (templated) classes destroying C++ instances. 
 * */
class InstanceDestroyerBase
{
public:
	virtual ~InstanceDestroyerBase() = 0;
	virtual bool instanceEquals(void* p) = 0; 
};


/**
 * Template lass for destroying C++ instances.
 * */
template <typename T>
class InstanceDestroyer : public InstanceDestroyerBase
{
private:
		/**
		 * Address of a static (global or member) variable pointing
		 * to a dynamically allocated instance of type T.
		 * */
        T  * * ppInstance_;

public:
		/**
		 * Takes an address of a static (global or member) variable 
		 * that is a (dynamically allocated) pointer to T.
		 * When this is destructed, it destructs the dynamic instance too.
		 * */
        InstanceDestroyer(T * * pp) 
        	: ppInstance_(pp) 
        	{
        		; // assert( pp != NULL);
        		/* 
        		printf("### TODO REMOVE Pseudo-static instance %x is registered at %x\n",
        				*pp,
        				pp);
        				*/
        	}

        
        /**
         * Destroys the dynamic instance and sets the static variable to
         * NULL.
         * */
        virtual ~InstanceDestroyer() 
        	{
        		/*
	    		printf("### TODO REMOVE Pseudo-static instance %x is destroyed at %x\n",
	    				*ppInstance_,
	    				ppInstance_);
	    				*/
        		::delete *ppInstance_; // nomemtrace
        		ppInstance_ = NULL;
        	}
        
        // Is this safe???? 
        virtual bool instanceEquals(void *pInstance) {
        	return ((void*)(*ppInstance_)) == pInstance; 
        }
};



/**
 * A singleton class that will be responsible for destroying all
 * the pseudo-static instances registered into it.
 * */
class StaticInstances
{
private:
	std::list<InstanceDestroyerBase*> instances_;

	static StaticInstances * pInstance_;
	StaticInstances(); 
	virtual ~StaticInstances();

	static StaticInstances & instance();
        
public:
	/**
	 * Registers an InstanceDestroyerBase object that already
	 * takes care of one pseudo-static variable.
	 * */
    static void registerInstance(InstanceDestroyerBase * pIDB);
    
    /**
     * Destroys all pseudo-static instances entrusted to its
     * care.
     * */
    static void shutdown();
    
    /**
     * Destroys the given pseudo-static instance entrusted to its
     * care.
     * */
    static void shutdown(void* pInstance);
};


/**
 * Template method that
 * (a) creates a pseudo-static instance on demand (dynamically)
 * (b) registers newly created instances to StaticInstances (singleton)
 * (c) sets the static pointer to point to the newly created instance
 * (d) returns with the reference to the instance, creating thus the
 *     illusion of behaving like a static instance.
 * 
 * This flavour is for classes with default constructors.
 */
template<typename T,
         int ID>
T & GetInstance(T * * pp)
{
	if (*pp == NULL)
		{
			*pp = _CLNEW_NOMEMTRACE T;
			InstanceDestroyer<T>
				* pid = new InstanceDestroyer<T>(pp);
			StaticInstances::registerInstance(pid);
		}
	
	return **pp;
}


/**
 * Same as the overloaded GetInstance function above, except
 * this can construct objects taking one bool argument in their
 * constructor.
 * */
template<typename T,
         int ID,
         bool B>
T & GetInstance(T * * pp)
{
	if (*pp == NULL)
		{
			*pp = _CLNEW_NOMEMTRACE T(B);
			InstanceDestroyer<T>
				* pid = new InstanceDestroyer<T>(pp);
			StaticInstances::registerInstance(pid);
		}
	
	return **pp;
}



/**
 * Same as the overloaded GetInstance function above, except
 * this can construct objects taking two bool arguments in their
 * constructor.
 * */
template<typename T,
         int ID,
         bool B1,
         bool B2>
T & GetInstance(T * * pp)
{
	if (*pp == NULL)
		{
			*pp = _CLNEW_NOMEMTRACE T(B1, B2);
			InstanceDestroyer<T>
				* pid = new InstanceDestroyer<T>(pp);
			StaticInstances::registerInstance(pid);
		}
	
	return **pp;
}



// Very similar to the GetInstance family of functions, but this
// on operates on pointers, and because of that, a derived class
// may be created for a (abstract) base class pointer. Hence
// the extra template parameter, TNEW
template<typename T,
         typename CREATOR,
         int ID>
T * GetInstancePtr(T * * pp)
{
	if (*pp == NULL)
		{
			*pp = CREATOR::create();
			InstanceDestroyer<T>
				* pid = new InstanceDestroyer<T>(pp);
			StaticInstances::registerInstance(pid);
		}
	
	return *pp;
}

template<typename T,
		 typename CREATOR,
	     int ID,
	     int32_t I> 
T * GetInstancePtr(T * * pp)
	{
		if (*pp == NULL)
			{
				*pp = CREATOR::create(I);
				InstanceDestroyer<T>
					* pid = new InstanceDestroyer<T>(pp);
				StaticInstances::registerInstance(pid);
			}
		
		return *pp;
	}

#define DECL_STATVAR(TYPE,NAME,CTORARGS...) enum { NAME ## _ID = __LINE__ }; \
static TYPE * p ## NAME ## _ = 0; \
TYPE & GetInstance ## TYPE ## NAME() { return GetInstance<TYPE,NAME ## _ID, ##CTORARGS>(&p ## NAME ## _); }

#define FRWDECL_STATVAR(TYPE,NAME,CTORARGS...) enum { NAME ## _ID = __LINE__ }; \
extern TYPE & GetInstance ## TYPE ## NAME();

#define DECL_STATMVAR1(TYPE,NAME,CTORARGS...) enum { NAME ## _ID = __LINE__ }; \
static TYPE * p ## NAME ## _; \
static TYPE & GetInstance ## TYPE ## NAME() { return GetInstance<TYPE,NAME ## _ID, ##CTORARGS>(&p ## NAME ## _); }

#define DECL_STATMVAR2(TYPE,CONTAINER,NAME) TYPE * CONTAINER::p ## NAME ## _ = 0;

#define DECL_STATMPTR1(TYPE,CREATOR,NAME,CTORARGS...) enum { NAME ## _ID = __LINE__ }; \
static TYPE * p ## NAME ## _; \
static TYPE * GetInstancePtr ## TYPE ## NAME() { return GetInstancePtr<TYPE,CREATOR,NAME ## _ID, ##CTORARGS>(&p ## NAME ## _); }


#if defined (CPIX_ASYNC_MT)
/**
 * Macros for static mutex_pthread variables in classes, as well as
 * global mutex_pthread variables.
 */
#define GLOBAL_DEFINE_CRUCIAL_MUTEX(NAME) enum { NAME ## _ID = __LINE__ }; \
    static mutex_pthread * p ## NAME ## _ = 0; \
    mutex_pthread & GetInstancemutex_pthread ## NAME() { return GetInstance<mutex_pthread, NAME ## _ID>(&p ## NAME ## _); }


#define STATIC_DEFINE_CRUCIAL_MUTEX1(NAME) enum { NAME ## _ID = __LINE__ }; \
    static mutex_pthread * p ## NAME ## _; \
    static mutex_pthread & GetInstancemutex_pthread ## NAME () { return GetInstance<mutex_pthread, NAME ## _ID>(&p ## NAME ## _); }

#define STATIC_DEFINE_CRUCIAL_MUTEX2(CONTAINER,NAME) mutex_pthread * CONTAINER::p ## NAME ## _ = 0;

#endif

#endif


#endif
