/*
Copyright (C) 2012 Jonas Penno

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 3 of the License,
or any later version.

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, see http://www.gnu.org/licenses.

The Boost C++ Libraries are distributed under the Boost Software License, Version 1.0.
See also http://www.boost.org/LICENSE_1_0.txt.

***********************************************************
**                Codename Visual Dragon++               **
**                    Version: 1.0 Beta                  **
**             Copyright (c) 2012 Jonas Penno            **
**               GNU General Public License              **
**                   Boost C++ Libraries                 **
**                 http://cvd-project.org                **
***********************************************************
*/

#include "BitConverter.hpp"

namespace Codename_Visual_Dragon
{
	char BitConverter::GetHexValue(boost::int32_t Value)
	{
		if (Value < 10)
			return (char)(Value + 0x30);
		return (char)((Value - 10) + 0x41);
	};

	boost::int32_t BitConverter::FloatToInt32Bits(float Value)
	{
		return *(((boost::int32_t*)&Value));
	};

	boost::int64_t BitConverter::DoubleToInt64Bits(double Value)
	{
		return *(((boost::int64_t*)&Value));
	};

	char* BitConverter::GetBytes(bool Value)
	{
		char BoolAlpha[1] = { (Value ? ((char)1) : ((char)0)) };
		return BoolAlpha;
	};

	char* BitConverter::GetBytes(float Value)
	{
		return GetBytes(*((boost::int32_t*)&Value));
	};

	char* BitConverter::GetBytes(double Value)
	{
		return GetBytes(*((boost::int64_t*)&Value));
	};

	char* BitConverter::GetBytes(boost::int16_t Value)
	{
		char* Buffer = new char[2];
		*((boost::int16_t*)Buffer) = Value;
		return Buffer;
	};
	
	char* BitConverter::GetBytes(boost::int32_t Value)
	{
		char* Buffer = new char[4];
		*((boost::int32_t*)Buffer) = Value;
		return Buffer;
	};

	char* BitConverter::GetBytes(boost::int64_t Value)
	{
		char* Buffer = new char[8];
		*((boost::int64_t*)Buffer) = Value;
		return Buffer;
	};

	char* BitConverter::GetBytes(boost::uint16_t Value)
	{
		return GetBytes((boost::int16_t)Value);
	};

	char* BitConverter::GetBytes(boost::uint32_t Value)
	{
		return GetBytes((boost::int32_t)Value);
	};

	char* BitConverter::GetBytes(boost::uint64_t Value)
	{
		return GetBytes((boost::int64_t)Value);
	};

	float BitConverter::Int32BitsToFloat(boost::int32_t Value)
	{
		return *(((float*)&Value));
	};

	double BitConverter::Int64BitsToDouble(boost::int64_t Value)
	{
		return *(((double*)&Value));
	};

	bool BitConverter::ToBoolean(char* Value, boost::uint32_t StartIndex)
	{
		if (Value == nullptr)
			return 0;
		if (StartIndex < 0)
			return false;
		if (StartIndex > (sizeof(Value) - 1))
			return false;
		return (Value[StartIndex] != 0);
	};

	float BitConverter::ToFloat(char* Value, boost::uint32_t StartIndex)
	{
		if (Value == nullptr)
			return 0;
		boost::int32_t IValue = ToInt32(Value, StartIndex);
		return *(((float*)&IValue));
	};

	double BitConverter::ToDouble(char* Value, boost::uint32_t StartIndex)
	{
		if (Value == nullptr)
			return 0;
		boost::int64_t IValue = ToInt64(Value, StartIndex);
		return *(((double*)&IValue));
	};

	boost::int16_t BitConverter::ToInt16(char* Value, boost::uint32_t StartIndex)
	{
		 if (Value == nullptr)
			 return 0;
		 if (StartIndex >= sizeof(Value))
			 return 0;
		 if (StartIndex > (sizeof(Value) - 2))
			 return 0;
		 char* Buffer = &(Value[StartIndex]);
    
        if ((StartIndex % 2) == 0)
			return *(((boost::int16_t*)Buffer));   
#if defined(LITTLE_ENDIAN)
		return (boost::int16_t)(Buffer[0] | (Buffer[1] << 8));
#else
        return (boost::int16_t)((Buffer[0] << 8) | Buffer[1]);
#endif
	};
	
	boost::int32_t BitConverter::ToInt32(char* Value, boost::uint32_t StartIndex)
	{
		if (Value == nullptr)
			return 0;
		if (StartIndex >= sizeof(Value))
			return 0;
		if (StartIndex > (sizeof(Value) - 4))
			 return 0;
		char* Buffer = &(Value[StartIndex]);
		if ((StartIndex % 4) == 0)
			return *(((boost::int32_t*)Buffer));   
#if defined(LITTLE_ENDIAN)
		return (boost::int32_t)(((Buffer[0] | (Buffer[1] << 8)) | (Buffer[2] << 0x10)) | (Buffer[3] << 0x18));
#else
        return (boost::int32_t)((((Buffer[0] << 0x18) | (Buffer[1] << 0x10)) | (Buffer[2] << 8)) | Buffer[3]);
#endif
	};
	
	boost::int64_t BitConverter::ToInt64(char* Value, boost::uint32_t StartIndex)
	{
		if (Value == nullptr)
			return 0;
		if (StartIndex >= sizeof(Value))
			return 0;
		if (StartIndex > (sizeof(Value) - 8))
			return 0;
		char* Buffer = &(Value[StartIndex]);
        if ((StartIndex % 8) == 0)
			return *(((boost::int64_t*) Buffer));
#if defined(LITTLE_ENDIAN)
		boost::int32_t Num1 = (boost::int32_t)((Buffer[0] | (Buffer[1] << 8)) | (Buffer[2] << 0x10)) | (Buffer[3] << 0x18);
		boost::int32_t Num2 = (boost::int32_t)((Buffer[4] | (Buffer[5] << 8)) | (Buffer[6] << 0x10)) | (Buffer[7] << 0x18);
		return (((boost::int64_t)((boost::uint64_t)Num1)) | (Num2 << 0x20));
#else
        boost::int32_t Num3 = (boost::int32_t)(((Buffer[0] << 0x18) | (Buffer[1] << 0x10)) | (Buffer[2] << 8)) | Buffer[3];
        boost::int32_t Num4 = (boost::int32_t)(((Buffer[4] << 0x18) | (Buffer[5] << 0x10)) | (Buffer[6] << 8)) | Buffer[7];
        return (((boost::int64_t)((boost::uint64_t)Num4)) | (Num3 << 0x20));
#endif
	};

	boost::uint16_t BitConverter::ToUInt16(char* Value, boost::uint32_t StartIndex)
	{
		return (boost::uint16_t)ToInt16(Value, StartIndex);
	};

	boost::uint32_t BitConverter::ToUInt32(char* Value, boost::uint32_t StartIndex)
	{
		return (boost::uint32_t)ToInt32(Value, StartIndex);
	};

	boost::uint64_t BitConverter::ToUInt64(char* Value, boost::uint32_t StartIndex)
	{
		return (boost::uint64_t)ToInt64(Value, StartIndex);
	};
};