// Copyright (c) 2018 - 2025 kio@little-bat.de
// BSD-2-Clause license
// https://opensource.org/licenses/BSD-2-Clause

#include "ucs1.h"
#include <cmath>

#ifndef NAN
static const float NAN(0.0f / 0.0f);
#endif


namespace ucs1
{
const uint8 gc_table[256] = {
	// map code ranges -> General Category property
	// created from data generated by script GeneralCategory.vs
	// --> http://www.unicode.org/Public/12.0.0/ucd/UnicodeData.txt
	//     http://www.unicode.org/Public/12.0.0/ucd/UCD.html#General_Category_Values

	// 0x00
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	// 0x20
	GcSpaceSeparator,
	GcOtherPunctuation,
	GcOtherPunctuation,
	GcOtherPunctuation,
	GcCurrencySymbol,
	GcOtherPunctuation,
	GcOtherPunctuation,
	GcOtherPunctuation,
	GcOpenPunctuation,
	GcClosePunctuation,
	GcOtherPunctuation,
	GcMathSymbol,
	GcOtherPunctuation,
	GcDashPunctuation,
	GcOtherPunctuation,
	GcOtherPunctuation,
	GcDecimalNumber,
	GcDecimalNumber,
	GcDecimalNumber,
	GcDecimalNumber,
	GcDecimalNumber,
	GcDecimalNumber,
	GcDecimalNumber,
	GcDecimalNumber,
	GcDecimalNumber,
	GcDecimalNumber,
	GcOtherPunctuation,
	GcOtherPunctuation,
	GcMathSymbol,
	GcMathSymbol,
	GcMathSymbol,
	GcOtherPunctuation,
	// 0x40
	GcOtherPunctuation,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcOpenPunctuation,
	GcOtherPunctuation,
	GcClosePunctuation,
	GcModifierSymbol,
	GcConnectorPunctuation,
	// 0x60
	GcModifierSymbol,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcOpenPunctuation,
	GcMathSymbol,
	GcClosePunctuation,
	GcMathSymbol,
	GcControl,
	// 0x80
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	GcControl,
	// 0xA0
	GcSpaceSeparator,
	GcOtherPunctuation,
	GcCurrencySymbol,
	GcCurrencySymbol,
	GcCurrencySymbol,
	GcCurrencySymbol,
	GcOtherSymbol,
	GcOtherPunctuation,
	GcModifierSymbol,
	GcOtherSymbol,
	GcOtherLetter,
	GcInitialPunctuation,
	GcMathSymbol,
	GcFormat,
	GcOtherSymbol,
	GcModifierSymbol,
	GcOtherSymbol,
	GcMathSymbol,
	GcOtherNumber,
	GcOtherNumber,
	GcModifierSymbol,
	GcLowercaseLetter,
	GcOtherPunctuation,
	GcOtherPunctuation,
	GcModifierSymbol,
	GcOtherNumber,
	GcOtherLetter,
	GcFinalPunctuation,
	GcOtherNumber,
	GcOtherNumber,
	GcOtherNumber,
	GcOtherPunctuation,
	// 0xC0
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcMathSymbol,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcUppercaseLetter,
	GcLowercaseLetter,
	// 0xE0
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcMathSymbol,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
	GcLowercaseLetter,
};

float numeric_value(ucs1char c) noexcept
{
	// Get Digit, Number & Decorated Number value.
	// returns Value for all codes for which has_numeric_value() returnes true.
	// returns NaN for all others

	if (is_in_range('0', c, '9')) return c - '0';

	switch (c)
	{
	case 0xb2: return 2;	 // ²
	case 0xb3: return 3;	 // ³
	case 0xb9: return 1;	 // ¹
	case 0xbc: return 0.25f; // ¼
	case 0xbd: return 0.5f;	 // ½
	case 0xbe: return 0.75f; // ¾
	}

	return NAN;
}

bool isupperstr(ucs1cstr s) noexcept
{
	// Test if string is all upper case

	if (s)
		while (*s)
		{
			if (is_uppercase(*s++)) continue;
			else return no;
		}
	return yes;
}

bool islowerstr(ucs1cstr s) noexcept
{
	// Test if string is all lower case

	if (s)
		while (*s)
		{
			if (is_lowercase(*s++)) continue;
			else return no;
		}
	return yes;
}

ucs1str lowerstr(ucs1cstr s) throws
{
	// Convert a string to all lower case

	ucs1str t = dupstr(s);
	tolower(t);
	return t;
}

ucs1str upperstr(ucs1cstr s) throws
{
	// Convert a string to all upper case
	// 'µ', 'ÿ' and 'ß' are not converted, because they don't have an uppercase version in UCS-1

	ucs1str t = dupstr(s);
	toupper(t);
	return t;
}


} // namespace ucs1
