#ifndef _JavaScriptCore_UnicodeUpp_h_
#define _JavaScriptCore_UnicodeUpp_h_

// some defines from ICU

#define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
#define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
#define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
#define U16_GET_SUPPLEMENTARY(lead, trail) \
    (((UChar32)(lead)<<10UL)+(UChar32)(trail)-U16_SURROGATE_OFFSET)

#define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0)
#define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00)
#define U16_LENGTH(c) ((uint32_t)(c) <= 0xffff ? 1 : 2)

#define U_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
#define U16_IS_SINGLE(c) !U_IS_SURROGATE(c)
#define U16_IS_SURROGATE(c) U_IS_SURROGATE(c)
#define U16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)

#define U16_NEXT(s, i, length, c) { \
    (c)=(s)[(i)++]; \
    if(U16_IS_LEAD(c)) { \
        uint16_t __c2; \
        if((i)<(length) && U16_IS_TRAIL(__c2=(s)[(i)])) { \
            ++(i); \
            (c)=U16_GET_SUPPLEMENTARY((c), __c2); \
        } \
    } \
}

#define U16_PREV(s, start, i, c) { \
    (c)=(s)[--(i)]; \
    if(U16_IS_TRAIL(c)) { \
        uint16_t __c2; \
        if((i)>(start) && U16_IS_LEAD(__c2=(s)[(i)-1])) { \
            --(i); \
            (c)=U16_GET_SUPPLEMENTARY(__c2, (c)); \
        } \
    } \
}

#define U_MASK(x) ((uint32_t)1<<(x))

#undef LOG
#undef ASSERT
#include <Core/Core.h>

// String conversions
//String::String(const Upp::String& str){
//    if (str.IsNull())
//        return;
//    m_impl = StringImpl::create(str);
//}
//
//String::operator Upp::String() const
//{
//    return Upp::String(reinterpret_cast<const char*>(characters()), length());
//}

// some enums

typedef Upp::uint16 UChar;
typedef Upp::int32 UChar32;

namespace WTF {
namespace Unicode {

enum Direction {
    LeftToRight,
    RightToLeft,
    EuropeanNumber,
    EuropeanNumberSeparator,
    EuropeanNumberTerminator,
    ArabicNumber,
    CommonNumberSeparator,
    BlockSeparator,
    SegmentSeparator,
    WhiteSpaceNeutral,
    OtherNeutral,
    LeftToRightEmbedding,
    LeftToRightOverride,
    RightToLeftArabic,
    RightToLeftEmbedding,
    RightToLeftOverride,
    PopDirectionalFormat,
    NonSpacingMark,
    BoundaryNeutral
};

enum DecompositionType {
    DecompositionNone,
    DecompositionCanonical,
    DecompositionCompat,
    DecompositionCircle,
    DecompositionFinal,
    DecompositionFont,
    DecompositionFraction,
    DecompositionInitial,
    DecompositionIsolated,
    DecompositionMedial,
    DecompositionNarrow,
    DecompositionNoBreak,
    DecompositionSmall,
    DecompositionSquare,
    DecompositionSub,
    DecompositionSuper,
    DecompositionVertical,
    DecompositionWide,
};

enum CharCategory {
    NoCategory =  0,
    Other_NotAssigned,
    Letter_Uppercase,
    Letter_Lowercase,
    Letter_Titlecase,
    Letter_Modifier,
    Letter_Other,

    Mark_NonSpacing,
    Mark_Enclosing,
    Mark_SpacingCombining,

    Number_DecimalDigit,
    Number_Letter,
    Number_Other,

    Separator_Space,
    Separator_Line,
    Separator_Paragraph,

    Other_Control,
    Other_Format,
    Other_PrivateUse,
    Other_Surrogate,

    Punctuation_Dash,
    Punctuation_Open,
    Punctuation_Close,
    Punctuation_Connector,
    Punctuation_Other,

    Symbol_Math,
    Symbol_Currency,
    Symbol_Modifier,
    Symbol_Other,

    Punctuation_InitialQuote,
    Punctuation_FinalQuote
};

UChar32 foldCase(UChar32 ch);
int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error);
int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error);
int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error);
Direction direction(UChar32 c);
int umemcasecmp(const UChar* a, const UChar* b, int len);

inline bool isSeparatorSpace(UChar32 c){
	return ((c==0x20)||(c==0xa0)||(c==0x1680)||(c==0x180e)||(c>=0x2000&&c<=0x200a)||(c==0x202f)||(c==0x205f)||(c==0x3000));
}

inline CharCategory category(UChar32 c)
{
	if(isSeparatorSpace(c)){return Separator_Space;}
	if(Upp::IsLower(c)){return Letter_Lowercase;}
	if(Upp::IsUpper(c)){return Letter_Uppercase;}
	if(Upp::IsDigit(c)){return Number_DecimalDigit;}
	if(c==0x2028){return Separator_Line;}
	if(c==0x2029){return Separator_Paragraph;}
	return NoCategory;
}


}
}
#endif
