/**
	\file
	\author Matthew Allen
	\date 27/3/2000
	\brief Common LGI include
	Copyright (C) 2000-2004, <a href="mailto:fret@memecode.com">Matthew Allen</a> 
*/

/**
 * \defgroup Base Foundation tools
 * \ingroup Lgi
 */
/**
 * \defgroup Text Text handling
 * \ingroup Lgi
 */

#ifndef _LGI_COMMON_H
#define _LGI_COMMON_H

#if defined LINUX
#include <sys/time.h>
#endif

#include "lgi/common/Mem.h"
#include "lgi/common/Array.h"
#include "lgi/common/LgiString.h"
#include "lgi/common/StringClass.h"
#include "lgi/common/CurrentTime.h"
#include "lgi/common/LgiUiBase.h"

/// Returns the system path specified
/// \ingroup Base
LgiExtern LString LGetSystemPath(
	/// Which path to retreive
	LSystemPath Which,
	int WordSize = 0
);

/// Gets the path of the currently running executable
/// \ingroup Base
LgiExtern LString LGetExePath();

/// Gets the file of the currently running executable
/// \ingroup Base
LgiExtern LString LGetExeFile();

/// Returns the mime type of the file
/// \ingroup Mime
LgiExtern LString LGetFileMimeType
(
	/// File to find mime type for
	const char *File
);

/// Finds a file in the applications directory or nearby
/// \ingroup Base
LgiExtern LString LFindFile(const char *Name);

/// Returns the application associated with the mime type
/// \ingroup Mime
LgiExtern LString LGetAppForMimeType
(
	/// Type of the file to find and app for
	const char *Mime
);

/// \return a formatted file size
LgiExtern LString LFormatSize(uint64 Size);

/// URL encode a string
LgiExtern LString LUrlEncode(const char *s, const char *delim);

/// URL decode a string
LgiExtern LString LUrlDecode(const char *s);

/// Gets the current user
LgiExtern LString LCurrentUserName();

/// Returns an environment variable.
LgiExtern LString LGetEnv(const char *Var);

/// Gets the system path..
LgiExtern LString::Array LGetPath();

/// Check for a valid email string
LgiExtern bool LIsValidEmail(LString Email);

/// Finds an application to handle a protocol request (e.g. 'mailto', 'http' etc)
LgiExtern LString LGetAppForProtocol(const char *Protocol);

/// Converts a string to the native 8bit charset of the OS from utf-8
/// \ingroup Text
LgiExtern LString LToNativeCp(const char *In, ssize_t InLen = -1);

/// Converts a string from the native 8bit charset of the OS to utf-8
/// \ingroup Text
LgiExtern LString LFromNativeCp(const char *In, ssize_t InLen = -1);

LgiExtern LString LStrConvertCp
(
	/// Output charset
	const char *OutCp,
	/// Input buffer
	const void *In,
	/// The input data's charset
	const char *InCp,
	/// Bytes of valid data in the input
	ssize_t InLen = -1
);

/// Converts an OS error code into a text string
LgiExtern LString LErrorCodeToString(uint32_t ErrorCode);

#ifdef __cplusplus
extern "C"
{
#endif

/////////////////////////////////////////////////////////////
// Externs

// Codepages

/// Converts a buffer of text to a different charset
/// \ingroup Text
/// \returns the bytes written to the location pointed to by 'Out'
LgiFunc ssize_t LBufConvertCp(void *Out, const char *OutCp, ssize_t OutLen, const void *&In, const char *InCp, ssize_t &InLen);

/// \brief Converts a string to a new charset
/// \return A dynamically allocate, null terminated string in the new charset
/// \ingroup Text
LgiFunc void *LNewConvertCp
(
	/// Output charset
	const char *OutCp,
	/// Input buffer
	const void *In,
	/// The input data's charset
	const char *InCp,
	/// Bytes of valid data in the input
	ssize_t InLen = -1
);

/// Return true if Lgi support the charset
/// \ingroup Text
LgiFunc bool LIsCpImplemented(const char *Cp);

/// Converts the ANSI code page to a charset name
/// \ingroup Text
LgiFunc const char *LAnsiToLgiCp(int AnsiCodePage = -1);

/// Calculate the number of characters in a string
/// \ingroup Text
LgiFunc int LCharLen(const void *Str, const char *Cp, int Bytes = -1);

/// Move a pointer along a utf-8 string by characters
/// \ingroup Text
LgiFunc char *LSeekUtf8
(
	/// Pointer to the current character
	const char *Ptr,
	/// The number of characters to move forward or back
	ssize_t D,
	/// The start of the memory buffer if you known
	char *Start = 0
);

/// Return true if the string is valid utf-8
/// \ingroup Text
LgiFunc bool LIsUtf8(const char *s, ssize_t len = -1);

/// Returns the next token in a string, leaving the argument pointing to the end of the token
/// \ingroup Text
LgiFunc char *LTokStr(const char *&s);

/// Formats a data size into appropriate units
/// \ingroup Base
LgiFunc void LFormatSize
(
	/// Output string
	char *Str,
	/// Output string buffer length
	int SLen,
	/// Input size in bytes
	uint64 Size
);

/// \returns true if the path is a volume root.
LgiFunc bool LIsVolumeRoot(const char *Path);

/// Converts a string from URI encoding (ala %20 -> ' ')
/// \returns a dynamically allocated string or NULL on error
/// \ingroup Text
LgiFunc char *LDecodeUri
(
	/// The URI
	const char *uri,
	/// The length or -1 if NULL terminated
	int len = -1
);

/// Converts a string to URI encoding (ala %20 -> ' ')
/// \returns a dynamically allocated string or NULL on error
/// \ingroup Text
LgiFunc char *LEncodeUri
(
	/// The URI
	const char *uri,
	/// The length or -1 if NULL terminated
	int len = -1
);

// Path
#if LGI_COCOA || defined(__GTK_H__) || defined(HAIKU)
	LgiExtern LString LgiArgsAppPath;
#endif

/// Returns the system path specified
/// \ingroup Base
LgiFunc bool LGetSystemPath
(
	/// Which path to retreive
	LSystemPath Which,
	/// The buffer to receive the path into 
	char *Dst,
	/// The size of the receive buffer in bytes
	ssize_t DstSize
);

/// Returns 0 to end search
/// \ingroup Base
typedef bool (*RecursiveFileSearch_Callback)(void *UserData, char *Path, class LDirectory *Dir);

/// \brief Recursively search for files
/// \return Non zero if something was found
/// \ingroup Base
LgiFunc bool LRecursiveFileSearch
(
	/// Start search in this dir
	const char *Root,
	/// Extensions to match
	LArray<const char*> *Ext = NULL,
	/// [optional] Output filenames
	LArray<char*> *Files = NULL,
	/// [optional] Output total size
	uint64 *Size = NULL,
	/// [optional] File count
	uint64 *Count = NULL,
	/// [optional] Callback for match
	RecursiveFileSearch_Callback Callback = NULL,
	/// [options] Callback user data
	void *UserData = NULL
);

// Resources

/// Gets the currently selected language
/// \ingroup Resources
LgiFunc struct LLanguage *LGetLanguageId();

// Os version functions

/// Gets the current operating system and optionally it's version.
/// \returns One of the defines starting with #LGI_OS_UNKNOWN in LgiDefs.h
/// \ingroup Base
LgiFunc int LGetOs(LArray<int> *Ver = 0);

/// Gets the current operation systems name.
/// \ingroup Base
LgiFunc const char *LGetOsName();

// System

/// \brief Opens a file or directory.
///
/// If the input is an executable then it is run. If the input file
/// is a document then an appropriate application is found to open the
/// file and the file is passed to that application. If the input is
/// a directory then the OS's file manager is openned to browse the
/// directory.
///
/// \ingroup Base
LgiFunc bool LExecute
(
	/// The file to open
	const char *File,
	/// The arguments to pass to the program
	const char *Arguments="",
	/// The directory to run in
	const char *Dir = 0,
	/// An error message
	LString *ErrorMsg = NULL
);

/// Initializes the random number generator
/// \ingroup Base
LgiFunc void LRandomize(uint Seed);

/// Returns a random number between 0 and Max-1
/// \ingroup Base
LgiFunc uint LRand(uint Max = 0);

LgiFunc bool _lgi_read_colour_config(const char *Tag, uint32_t *c);

#ifndef SND_ASYNC
#define SND_ASYNC	0x0001
#endif

/// Plays a sound
/// \ingroup Base
LgiFunc bool LPlaySound
(
	/// File name of the sound to play
	const char *FileName,
	/// 0 or SND_ASYNC. If 0 the function blocks till the sound finishes.
	int Flags
);

/**
 * \defgroup Mime Mime handling support.
 * \ingroup Lgi
 */

/// Returns the file extensions associated with the mimetype
/// \ingroup Mime
LgiExtern bool LGetMimeTypeExtensions
(
	/// The returned mime type
	const char *Mime,
	/// The extensions
	LArray<LString> &Ext
);

inline bool LGetAppForMimeType(const char *Mime, char *AppPath, int BufSize)
{
	LString p = LGetAppForMimeType(Mime);
	if (AppPath && p) strcpy_s(AppPath, BufSize, p);
	return p.Length() > 0;
}

/// Returns the all applications that can open a given mime type.
/// \ingroup Mime
LgiFunc bool LGetAppsForMimeType
(
	/// The type of files to match apps to.
	///
	/// Two special cases exist:
	/// - application/email gets the default email client
	/// - application/browser get the default web browser
	const char *Mime,
	/// The applications that can handle the 
	LArray<LAppInfo*> &Apps,
	/// Limit the length of the results, i.e. stop looking after 'Limit' matches.
	/// -1 means return all matches.
	int Limit = -1
);

// Debug

/// Returns true if the build is for release.
/// \ingroup Base
LgiFunc int LIsReleaseBuild();

#if defined WIN32

	/// Registers an active x control
	LgiFunc bool RegisterActiveXControl(const char *Dll);

	enum HWBRK_TYPE
	{
		HWBRK_TYPE_CODE,
		HWBRK_TYPE_READWRITE,
		HWBRK_TYPE_WRITE,
	};

	enum HWBRK_SIZE
	{
		HWBRK_SIZE_1,
		HWBRK_SIZE_2,
		HWBRK_SIZE_4,
		HWBRK_SIZE_8,
	};

	/// Set a hardware breakpoint.
	LgiFunc HANDLE SetHardwareBreakpoint
	(
		/// Use GetCurrentThread()
		HANDLE hThread,
		/// Type of breakpoint
		HWBRK_TYPE Type,
		/// Size of breakpoint
		HWBRK_SIZE Size,
		/// The pointer to the data to break on
		void *s
	);

	/// Deletes a hardware breakpoint
	LgiFunc bool RemoveHardwareBreakpoint(HANDLE hBrk);

#elif defined LINUX

	/// Window managers
	enum WindowManager
	{
		WM_Unknown,
		WM_Kde,
		WM_Gnome
	};

	/// Returns the currently running window manager
	WindowManager LGetWindowManager();

#elif defined(__OBJC__)

	LgiFunc NSCursor *LCocoaCursor(LCursor lc);

#endif

#ifdef __cplusplus
}
#endif

#endif
