/*	Copyright  (c)	Günter Woigk 2010 - 2021
					mailto:kio@little-bat.de

	This file is free software.

	Permission to use, copy, modify, distribute, and sell this software
	and its documentation for any purpose is hereby granted without fee,
	provided that the above copyright notice appears in all copies and
	that both that copyright notice, this permission notice and the
	following disclaimer appear in supporting documentation.

	THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY,
	NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
	A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE COPYRIGHT HOLDER
	BE LIABLE FOR ANY DAMAGES ARISING FROM THE USE OF THIS SOFTWARE,
	TO THE EXTENT PERMITTED BY APPLICABLE LAW.
*/

#include <cmath>
//#include <limits>
#include "kio/kio.h"
#include "cstrings/utf8.h"
#include "Ival.h"
#include "Type.h"
//#include "globals.h"


inline cType* intForSize (int64 n)
{
	if (n < 0) n = ~n;
	return n <= 7 ? tint8 : n <= 15 ? tint16 : n<=31 ? tint32 : tint64;
}

inline cType* uintForSize (uint64 n)
{
	return n <= 8 ? tuint8 : n <= 16 ? tuint16 : n<=32 ? tuint32 : tuint64;
}

inline int64 maskValue (int64 n, uint bits)
{
	switch(bits>>4)
	{
	case 0: return int8(n);
	case 1:	return int16(n);
	case 2:	return int32(n);
	default:return n;
	}
}

inline uint64 maskValue (uint64 n, uint bits)
{
	switch(bits>>4)
	{
	case 0: return uint8(n);
	case 1:	return uint16(n);
	case 2:	return uint32(n);
	default:return n;
	}
}

//Ival::Ival (uint64 n) noexcept
//:	type(uintForSize(n)),
//	value(n)
//{}

//Ival::Ival (int64 n) noexcept
//:	type(intForSize(n)),
//	value(n)
//{}

Ival::Ival (cType* t, float128 n) noexcept
:	type(t),
	value(n)
{
	assert(t->isNumeric() || t->isChar());
	assert(!t->isSignedInt() || value == int64(value));
	assert(!t->isUnsignedInt() || value == uint64(value));
	assert(!t->isChar() || value == uint32(value));
}

Ival::Ival (cstr utf8string) noexcept	 // sets errno
:	type(tcstr),
	value(0)
{
	string = newcopy(utf8string);
	if (tchar->bits==8)  { if(!utf8::fits_in_ucs1(string)) errno = notindestcharset; }
	if (tchar->bits==16) { if(!utf8::fits_in_ucs2(string)) errno = notindestcharset; }
}

Ival::~Ival()
{
	if (isString())	delete[] string;
}

//Ival::Ival (Ival const& q)
//:	type(q.type),
//	value(q.value)
//{
//	if (isString()) string = newcopy(q.string);
//}

Ival::Ival (Ival&& q)
:	type(q.type),
	value(q.value)
{
	if(isString()) { string = q.string; q.string = nullptr; }
}

//Ival& Ival::operator= (Ival const& q)
//{
//	if(this != &q)
//	{
//		this->~Ival();
//		new(this) Ival(q);
//	}
//	return *this;
//}

Ival& Ival::operator= (Ival&& q)
{
	assert(this != &q);

	this->~Ival();
	new(this) Ival(std::move(q));

	return *this;
}


/* --------------------------------------------------------------
	Rechnen mit konstanten Zahlen

	Gerechnet wird mit int64, uint64 und float128.
	Typen werden möglichst beibehalten.
	Integer-Typen werden ggf. in Richtung int/uint vergrößert, selten verkleinert.
	Bei ungeeigneten Datentypen für eine Operation wird ein cstring geworfen.
-------------------------------------------------------------- */

Ival floatValue ( cType* t1, cType* t2, float128 value)
{
	assert(t1->isFloat() || t2->isFloat());
	assert(t1->isNumeric() && t2->isNumeric());

	if (t1->isInteger()) t1 = t2; else
	if (t2->isInteger()) t2 = t1; else
	if (t2->bits > t1->bits) t1 = t2;

	return Ival(t1,value);
}




cstr Ival::toString () const
{
	if (isChar())
	{
		uint32 c = getChar();
		if (ucs4::is_printable(c))
		{
			char bu[8]; *utf8::_ucs4char_to_utf8(c,bu) = 0;
			return usingstr("'%s'",bu);
		}
		if (c<32) return usingstr("'\\x%02X'",c);
		if (c<=0xffff) return usingstr("'\\u%04X'",c);
		else return usingstr("'\\U%08X'",c);
	}

	if(isSignedInt())	return tostr(i64Value());
	if(isUnsignedInt())	return tostr(u64Value());
	if(type==tlfloat)	return tostr(f128Value());
	if(isFloat())		return tostr(f64Value());
	if(isString())		return quotedstr(getString());

	IERR();
}






















