/*
 * Copyright (c) 2000, Red Hat, Inc.
 * Copyright (c) 2005-2006 Tom N Harris.
 *
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 *
 *     A copy of the GNU General Public License can be found at
 *     http://www.gnu.org/
 *
 * Written by DJ Delorie <dj@cygnus.com>
 * and Robert Collins <rbtcollins@hotmail.com>
 * Written by Tom N Harris <telliamed@whoopdedo.org>
 *
 */

#ifndef SETUP_WIN32_H
#define SETUP_WIN32_H

/* The inital purpose of this file was limit the number of Win32 headers we
   actually have to parse.  The Setup program only uses a few of them,
   so there's no point in parsing them all (even lean-n-mean).  Doing
   this cuts compile time in half. Now it's also the header for the Win32
   class which provides runtime information about the OS
 */

#define NOCOMATTRIBUTE

#include <stdarg.h>

#define WIN32_LEAN_AND_MEAN
/* We want a minimum IE version of 3 */
#define _WIN32_IE 0x0300
/* libstdc++-v3 _really_ dislikes min & max defined as macros. */
/* As of gcc 3.3.1, it defines NOMINMAX itself, so test first,
 * to avoid a redefinition error */
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#if HAVE_ALLOCA_H
#include <alloca.h>
#else
#ifndef alloca
#define alloca __builtin_alloca
#endif
#endif
#ifndef _MAX_PATH 
#define _MAX_PATH MAX_PATH
#endif
#ifndef _access
#define _access access
#endif

#include <wininet.h>
//#include <windowsx.h>

/* =========================== */
#ifdef __cplusplus
#pragma interface "win32.h"

#include <string>

namespace Setup
{

class String;

class Win32
{
public:
	enum _os
	{
		Win00,
		Win95,
		Win98,
		WinME,
		WinNT,
		Win2K,
		WinXP
	};
	static enum _os OS();
	static bool IsNT();
	static const char* Locale();
	static String LocalizeString(const char* utf8, int len=-1);
	static String LocalizeString(const wchar_t* ucs2, int len=-1);
	static std::string AnsiString(const wchar_t* ucs2, int len=-1);

private:
	static char szLocale[8];
	static bool locale_is_valid;
};

class RECTWrapper : public RECT
{
public:
	RECTWrapper() { ::SetRectEmpty(this); };
	~RECTWrapper() { };
	RECTWrapper(RECT const & aRect) 
		{ ::CopyRect(this, &aRect); };
	RECTWrapper& operator=(RECT const & aRect) 
		{ ::CopyRect(this, &aRect); return *this; };

	bool operator==(RECT const & aRect) const
		{ return FALSE != ::EqualRect(this, &aRect); };
	bool operator!=(RECT const & aRect) const
		{ return FALSE == ::EqualRect(this, &aRect); };
	RECTWrapper operator+(RECT const & aRect) const
		{ RECTWrapper __r; ::UnionRect(&__r, this, &aRect); return __r; };
	RECTWrapper& operator+=(RECT const & aRect)
		{ ::UnionRect(this, this, &aRect); return *this; };
	RECTWrapper operator-(RECT const & aRect) const
		{ RECTWrapper __r; ::SubtractRect(&__r, this, &aRect); return __r; };
	RECTWrapper& operator-=(RECT const & aRect)
		{ ::SubtractRect(this, this, &aRect); return *this; };
	RECTWrapper operator^(RECT const & aRect) const
		{ RECTWrapper __r; ::IntersectRect(&__r, this, &aRect); return __r; };
	RECTWrapper& operator^=(RECT const & aRect)
		{ ::IntersectRect(this, this, &aRect); return *this; };

	LONG width() const
		{ return right - left; };
	LONG height() const
		{ return bottom - top; };
	bool empty() const
		{ return FALSE != ::IsRectEmpty(this); };
	void move(int __x, int __y)
		{ ::OffsetRect(this, __x, __y); };
	void grow(int __x, int __y)
		{ ::InflateRect(this, __x, __y); };
};

class HANDLEWrapper
{
public:
	HANDLEWrapper() : m_value(NULL) { };
	~HANDLEWrapper()
		{ if (m_value) ::CloseHandle(m_value); };
	
	inline HANDLE & theHANDLE() { return m_value; };
	inline HANDLE const & theHANDLE() const { return m_value; };
private:
	/* Prevent synthetics. If assignment is needed, we should duphandles, or refcount */
	HANDLEWrapper(HANDLEWrapper const &);
	HANDLEWrapper& operator=(HANDLEWrapper const &);
	HANDLE m_value;
};

class SIDWrapper
{
public:
	SIDWrapper() : m_value(NULL) { };
	~SIDWrapper()
		{ if (m_value) ::FreeSid(m_value); };

	/* We could look at doing weird typcast overloads here,
	but manual access is easier for now
	*/
	inline PSID& theSID() { return m_value; };
	inline PSID const& theSID() const { return m_value; };
private:
	/* Prevent synthetics. If assignment is needed, this should be refcounting  */
	SIDWrapper(SIDWrapper const &);
	SIDWrapper& operator=(SIDWrapper const &);
	PSID m_value;
};

inline bool operator==(FILETIME const& __a, FILETIME const& __b)
{
	return *reinterpret_cast<DWORDLONG const*>(&__a) == *reinterpret_cast<DWORDLONG const*>(&__b);
}
inline bool operator!=(FILETIME const& __a, FILETIME const& __b)
{
	return *reinterpret_cast<DWORDLONG const*>(&__a) != *reinterpret_cast<DWORDLONG const*>(&__b);
}
inline bool operator<(FILETIME const& __a, FILETIME const& __b)
{
	return *reinterpret_cast<DWORDLONG const*>(&__a) < *reinterpret_cast<DWORDLONG const*>(&__b);
}
inline bool operator>(FILETIME const& __a, FILETIME const& __b)
{
	return *reinterpret_cast<DWORDLONG const*>(&__a) > *reinterpret_cast<DWORDLONG const*>(&__b);
}
inline bool operator<=(FILETIME const& __a, FILETIME const& __b)
{
	return *reinterpret_cast<DWORDLONG const*>(&__a) <= *reinterpret_cast<DWORDLONG const*>(&__b);
}
inline bool operator>=(FILETIME const& __a, FILETIME const& __b)
{
	return *reinterpret_cast<DWORDLONG const*>(&__a) >= *reinterpret_cast<DWORDLONG const*>(&__b);
}

};

#endif //_cplusplus
#endif /* SETUP_WIN32_H */
