# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from fontTools import unicodedata

_openClosePairText = """
# This was automatically generated from UnicodeData.txt and then
# tweaked by hand to handle the special exceptions.

0028;LEFT PARENTHESIS;Ps
0029;RIGHT PARENTHESIS;Pe

005B;LEFT SQUARE BRACKET;Ps
005D;RIGHT SQUARE BRACKET;Pe

007B;LEFT CURLY BRACKET;Ps
007D;RIGHT CURLY BRACKET;Pe

00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi
00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf

0F3A;TIBETAN MARK GUG RTAGS GYON;Ps
0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe

0F3C;TIBETAN MARK ANG KHANG GYON;Ps
0F3D;TIBETAN MARK ANG KHANG GYAS;Pe

169B;OGHAM FEATHER MARK;Ps
169C;OGHAM REVERSED FEATHER MARK;Pe

2018;LEFT SINGLE QUOTATION MARK;Pi
2019;RIGHT SINGLE QUOTATION MARK;Pf

201C;LEFT DOUBLE QUOTATION MARK;Pi
201D;RIGHT DOUBLE QUOTATION MARK;Pf

2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi
203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf

2045;LEFT SQUARE BRACKET WITH QUILL;Ps
2046;RIGHT SQUARE BRACKET WITH QUILL;Pe

207D;SUPERSCRIPT LEFT PARENTHESIS;Ps
207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe

208D;SUBSCRIPT LEFT PARENTHESIS;Ps
208E;SUBSCRIPT RIGHT PARENTHESIS;Pe

2308;LEFT CEILING;Ps
2309;RIGHT CEILING;Pe

230A;LEFT FLOOR;Ps
230B;RIGHT FLOOR;Pe

2329;LEFT-POINTING ANGLE BRACKET;Ps
232A;RIGHT-POINTING ANGLE BRACKET;Pe

2768;MEDIUM LEFT PARENTHESIS ORNAMENT;Ps
2769;MEDIUM RIGHT PARENTHESIS ORNAMENT;Pe

276A;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT;Ps
276B;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT;Pe

276C;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps
276D;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe

276E;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT;Ps
276F;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT;Pe

2770;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps
2771;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe

2772;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT;Ps
2773;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT;Pe

2774;MEDIUM LEFT CURLY BRACKET ORNAMENT;Ps
2775;MEDIUM RIGHT CURLY BRACKET ORNAMENT;Pe

27C5;LEFT S-SHAPED BAG DELIMITER;Ps
27C6;RIGHT S-SHAPED BAG DELIMITER;Pe

27E6;MATHEMATICAL LEFT WHITE SQUARE BRACKET;Ps
27E7;MATHEMATICAL RIGHT WHITE SQUARE BRACKET;Pe

27E8;MATHEMATICAL LEFT ANGLE BRACKET;Ps
27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe

27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps
27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe

27EC;MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET;Ps
27ED;MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET;Pe

27EE;MATHEMATICAL LEFT FLATTENED PARENTHESIS;Ps
27EF;MATHEMATICAL RIGHT FLATTENED PARENTHESIS;Pe

2983;LEFT WHITE CURLY BRACKET;Ps
2984;RIGHT WHITE CURLY BRACKET;Pe

2985;LEFT WHITE PARENTHESIS;Ps
2986;RIGHT WHITE PARENTHESIS;Pe

2987;Z NOTATION LEFT IMAGE BRACKET;Ps
2988;Z NOTATION RIGHT IMAGE BRACKET;Pe

2989;Z NOTATION LEFT BINDING BRACKET;Ps
298A;Z NOTATION RIGHT BINDING BRACKET;Pe

298B;LEFT SQUARE BRACKET WITH UNDERBAR;Ps
298C;RIGHT SQUARE BRACKET WITH UNDERBAR;Pe

298D;LEFT SQUARE BRACKET WITH TICK IN TOP CORNER;Ps
298E;RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Pe

298F;LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Ps
2990;RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER;Pe

2991;LEFT ANGLE BRACKET WITH DOT;Ps
2992;RIGHT ANGLE BRACKET WITH DOT;Pe

2993;LEFT ARC LESS-THAN BRACKET;Ps
2994;RIGHT ARC GREATER-THAN BRACKET;Pe

2995;DOUBLE LEFT ARC GREATER-THAN BRACKET;Ps
2996;DOUBLE RIGHT ARC LESS-THAN BRACKET;Pe

2997;LEFT BLACK TORTOISE SHELL BRACKET;Ps
2998;RIGHT BLACK TORTOISE SHELL BRACKET;Pe

29D8;LEFT WIGGLY FENCE;Ps
29D9;RIGHT WIGGLY FENCE;Pe

29DA;LEFT DOUBLE WIGGLY FENCE;Ps
29DB;RIGHT DOUBLE WIGGLY FENCE;Pe

29FC;LEFT-POINTING CURVED ANGLE BRACKET;Ps
29FD;RIGHT-POINTING CURVED ANGLE BRACKET;Pe

2E02;LEFT SUBSTITUTION BRACKET;Pi
2E03;RIGHT SUBSTITUTION BRACKET;Pf

2E04;LEFT DOTTED SUBSTITUTION BRACKET;Pi
2E05;RIGHT DOTTED SUBSTITUTION BRACKET;Pf

2E09;LEFT TRANSPOSITION BRACKET;Pi
2E0A;RIGHT TRANSPOSITION BRACKET;Pf

2E0C;LEFT RAISED OMISSION BRACKET;Pi
2E0D;RIGHT RAISED OMISSION BRACKET;Pf

2E1C;LEFT LOW PARAPHRASE BRACKET;Pi
2E1D;RIGHT LOW PARAPHRASE BRACKET;Pf

2E20;LEFT VERTICAL BAR WITH QUILL;Pi
2E21;RIGHT VERTICAL BAR WITH QUILL;Pf

2E22;TOP LEFT HALF BRACKET;Ps
2E23;TOP RIGHT HALF BRACKET;Pe

2E24;BOTTOM LEFT HALF BRACKET;Ps
2E25;BOTTOM RIGHT HALF BRACKET;Pe

2E26;LEFT SIDEWAYS U BRACKET;Ps
2E27;RIGHT SIDEWAYS U BRACKET;Pe

2E28;LEFT DOUBLE PARENTHESIS;Ps
2E29;RIGHT DOUBLE PARENTHESIS;Pe

3008;LEFT ANGLE BRACKET;Ps
3009;RIGHT ANGLE BRACKET;Pe

300A;LEFT DOUBLE ANGLE BRACKET;Ps
300B;RIGHT DOUBLE ANGLE BRACKET;Pe

300C;LEFT CORNER BRACKET;Ps
300D;RIGHT CORNER BRACKET;Pe

300E;LEFT WHITE CORNER BRACKET;Ps
300F;RIGHT WHITE CORNER BRACKET;Pe

3010;LEFT BLACK LENTICULAR BRACKET;Ps
3011;RIGHT BLACK LENTICULAR BRACKET;Pe

3014;LEFT TORTOISE SHELL BRACKET;Ps
3015;RIGHT TORTOISE SHELL BRACKET;Pe

3016;LEFT WHITE LENTICULAR BRACKET;Ps
3017;RIGHT WHITE LENTICULAR BRACKET;Pe

3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps
3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe

301A;LEFT WHITE SQUARE BRACKET;Ps
301B;RIGHT WHITE SQUARE BRACKET;Pe

301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps
301E;DOUBLE PRIME QUOTATION MARK;Pe

FD3F;ORNATE RIGHT PARENTHESIS;Ps
FD3E;ORNATE LEFT PARENTHESIS;Pe

FE17;PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET;Ps
FE18;PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET;Pe

FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps
FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe

FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps
FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe

FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps
FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe

FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps
FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe

FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps
FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe

FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps
FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe

FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps
FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe

FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps
FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe

FE47;PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET;Ps
FE48;PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET;Pe

FE59;SMALL LEFT PARENTHESIS;Ps
FE5A;SMALL RIGHT PARENTHESIS;Pe

FE5B;SMALL LEFT CURLY BRACKET;Ps
FE5C;SMALL RIGHT CURLY BRACKET;Pe

FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps
FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe

FF08;FULLWIDTH LEFT PARENTHESIS;Ps
FF09;FULLWIDTH RIGHT PARENTHESIS;Pe

FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps
FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe

FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps
FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe

FF5F;FULLWIDTH LEFT WHITE PARENTHESIS;Ps
FF60;FULLWIDTH RIGHT WHITE PARENTHESIS;Pe

FF62;HALFWIDTH LEFT CORNER BRACKET;Ps
FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe

# Special Exceptions
# These have flipped relatives that are already mapped above.

201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi
201D;RIGHT DOUBLE QUOTATION MARK;Pf # already mapped

201E;DOUBLE LOW-9 QUOTATION MARK;Ps
201D;RIGHT DOUBLE QUOTATION MARK;Pf # already mapped

201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi
2019;RIGHT SINGLE QUOTATION MARK;Pf # already mapped

201A;SINGLE LOW-9 QUOTATION MARK;Ps
2019;RIGHT SINGLE QUOTATION MARK;Pf # already mapped

2E42;DOUBLE LOW-REVERSED-9 QUOTATION MARK;Ps
201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi # already mapped

301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps  # already mapped
301F;LOW DOUBLE PRIME QUOTATION MARK;Pe
"""

# load the data

_openToClose = {}
_closeToOpen = {}

openValue = None
for line in _openClosePairText.splitlines():
    line = line.split("#")[0].strip()
    if not line:
        continue
    value, name, category = line.split(";")
    value = int(value, 16)
    if openValue is not None:
        closeValue = value
        if openValue not in _openToClose:
            _openToClose[openValue] = closeValue
        if closeValue not in _closeToOpen:
            _closeToOpen[closeValue] = openValue
        openValue = None
    else:
        openValue = value

# ordered sets
orderedScripts = []
for value in unicodedata.Scripts.VALUES:
    value = unicodedata.script_name(value)
    if value == "Unknown":
        continue
    if value not in orderedScripts:
        orderedScripts.append(value)
orderedScripts.append("Unknown")

orderedBlocks = []
for value in unicodedata.Blocks.VALUES:
    if value == "No_Block":
        continue
    if value not in orderedBlocks:
        orderedBlocks.append(value)

orderedCategories = """Lu
Ll
Lt
Lm
Lo
Mn
Mc
Me
Nd
Nl
No
Pc
Pd
Ps
Pe
Pi
Pf
Po
Sm
Sc
Sk
So
Zs
Zl
Zp
Cc
Cf
Cs
Co
Cn""".splitlines()

# functions

def decompositionBase(value):
    letterCategories = ("Ll", "Lu", "Lt", "Lo")
    try:
        c = chr(value)
    # see not in category function
    except ValueError:
        return -1
    decomposition = unicodedata.decomposition(c)
    if decomposition.startswith("<"):
        return -1
    if " " not in decomposition:
        return -1
    parts = decomposition.split(" ")
    unichrs = [chr(int(i, 16)) for i in parts if i]
    letters = [ord(i) for i in unichrs if unicodedata.category(i) in letterCategories]
    letterCount = len(letters)
    if letterCount != 1:
        return -1
    decomposedUniValue = letters[0]
    furtherDecomposedUniValue = decompositionBase(decomposedUniValue)
    if furtherDecomposedUniValue != -1:
        furtherFurtherDecomposedUniValue = decompositionBase(furtherDecomposedUniValue)
        if furtherFurtherDecomposedUniValue != -1:
            decomposedUniValue = furtherFurtherDecomposedUniValue
        else:
            decomposedUniValue = furtherDecomposedUniValue
    return decomposedUniValue

def openRelative(value):
    return _closeToOpen.get(value)

def closeRelative(value):
    return _openToClose.get(value)

def category(value):
    c = chr(value)
    return unicodedata.category(c)

def script(value):
    char = chr(value)
    return unicodedata.script_name(unicodedata.script(char), default="Unknown")

def block(value):
    char = chr(value)
    return unicodedata.block(char)
