# -*- coding: utf-8 -*-
"""
To check

+ styleitem auto - should be capitalised (layer)
+ Each of the units is different - [pixels|feet|inches|kilometers|meters|miles|nauticalmiles|dd] - standardise
"""
import logging
import json
import collections
import pytest
from mappyfile.parser import Parser
from mappyfile.pprint import PrettyPrinter
from mappyfile.transformer import MapfileToDict
from mappyfile.ordereddict import DefaultOrderedDict
import mappyfile


def test_nested_quotes():
    r"""
    If values contain quotes then make sure they are escaped
    shp2img -m C:\Temp\msautotest\misc\ogr_vrtconnect.tmp.map
    """
    s = """
    LAYER
        NAME shppoly
        TYPE polygon
        CONNECTIONTYPE OGR
        CONNECTION '<OGRVRTDataSource><OGRVRTLayer name="poly"><SrcDataSource relativeToVRT="0">data/shppoly</SrcDataSource><SrcLayer>poly</SrcLayer></OGRVRTLayer></OGRVRTDataSource>'
    END"""  # noqa: E501

    ast = mappyfile.loads(s)
    pp = PrettyPrinter(indent=0, quote='"', newlinechar=" ")  # expected
    res = pp.pprint(ast)
    print(res)
    exp = (
        'LAYER NAME "shppoly" TYPE POLYGON CONNECTIONTYPE OGR CONNECTION "<OGRVRTDataSource><OGRVRTLayer name="poly">'
        '<SrcDataSource relativeToVRT="0">data/shppoly</SrcDataSource><SrcLayer>poly</SrcLayer></OGRVRTLayer></OGRVRTDataSource>" END'
    )
    assert res == exp


def test_already_escaped():
    """
    Don't escape an already escaped quote
    """
    s = r'CLASS EXPRESSION "\"Tignish" END'
    ast = mappyfile.loads(s)
    pp = PrettyPrinter(indent=0, quote='"', newlinechar=" ")
    res = pp.pprint(ast)
    exp = r'CLASS EXPRESSION "\"Tignish" END'
    assert res == exp

    s = r"CLASS EXPRESSION '\'Tignish' END"
    ast = mappyfile.loads(s)
    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    res = pp.pprint(ast)
    exp = r"CLASS EXPRESSION '\'Tignish' END"
    assert res == exp


def test_unicode():
    s = """
    MAP
        METADATA
          "ows_title" "éúáí"
        END
    END
    """
    ast = mappyfile.loads(s)
    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    res = pp.pprint(ast)
    exp = "MAP METADATA 'ows_title' 'éúáí' END END"
    assert res == exp


def test_enumeration():
    s = """
    MAP
        EXTENT 0 0 100 100
        DEBUG on
        NAME Test
        shapepath "test/path"
        LAYER
            CLASSITEM "Test"
            CLASS
                EXPRESSION "Field"
                STYLE
                    SIZE [sizefield]
                END
            END
        END
    END
    """
    p = Parser()
    m = MapfileToDict()
    ast = p.parse(s)
    d = m.transform(ast)
    print(d)
    logging.debug(json.dumps(d, indent=4))
    pp = PrettyPrinter(indent=4, quote="'", newlinechar="\n")
    res = pp.pprint(d)
    print(res)


def test_points():
    d = {
        "points": [
            [[1, 1], [50, 50], [1, 50], [1, 1]],
            [[100, 100], [50, 50], [100, 50], [100, 100]],
        ],
        "__type__": "feature",
    }

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert (
        s
        == "FEATURE POINTS 1 1 50 50 1 50 1 1 END POINTS 100 100 50 50 100 50 100 100 END END"
    )


def test_style_pattern():
    d = {"pattern": [[10, 1], [50, 50], [1, 50], [1, 1]], "__type__": "style"}

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    assert s == "STYLE PATTERN 10 1 50 50 1 50 1 1 END END"


def test_scaletoken():
    sd = {"0": "ON", "255000000": "OFF"}

    sd = collections.OrderedDict(sorted(sd.items()))

    d = {"name": "%border%", "values": sd, "__type__": "scaletoken"}

    d = collections.OrderedDict(sorted(d.items()))

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert s == "SCALETOKEN NAME '%border%' VALUES '0' 'ON' '255000000' 'OFF' END END"


def test_metadata():
    md = {"MS_ENABLE_MODES": "!*", "WMS_ENABLE_REQUEST": "*"}

    md = collections.OrderedDict(sorted(md.items()))

    d = {"metadata": md, "__type__": "map"}

    d = collections.OrderedDict(sorted(d.items()))

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert s == "MAP METADATA 'MS_ENABLE_MODES' '!*' 'WMS_ENABLE_REQUEST' '*' END END"


def test_connectionoptions():
    values = {"FLATTEN_NESTED_ATTRIBUTES": "YES"}

    d = {"connectionoptions": values, "__type__": "layer"}

    d = collections.OrderedDict(sorted(d.items()))

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert s == "LAYER CONNECTIONOPTIONS 'FLATTEN_NESTED_ATTRIBUTES' 'YES' END END"


def test_config():
    cd = {"ms_nonsquare": "YES", "on_missing_data": "FAIL"}

    cd = collections.OrderedDict(sorted(cd.items()))

    d = {"config": cd, "__type__": "map"}

    d = collections.OrderedDict(sorted(d.items()))

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert s == "MAP CONFIG 'MS_NONSQUARE' 'YES' CONFIG 'ON_MISSING_DATA' 'FAIL' END"


def test_processing():
    d = {
        "name": "ProcessingLayer",
        "processing": ["BANDS=1", "CONTOUR_ITEM=elevation", "CONTOUR_INTERVAL=20"],
        "__type__": "layer",
    }

    d = collections.OrderedDict(sorted(d.items()))

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert (
        s
        == "LAYER NAME 'ProcessingLayer' PROCESSING 'BANDS=1' PROCESSING 'CONTOUR_ITEM=elevation' PROCESSING 'CONTOUR_INTERVAL=20' END"
    )


def test_multiple_layers():
    d = {
        "layers": [
            {"name": "Layer1", "__type__": "layer"},
            {"name": "Layer2", "__type__": "layer"},
        ],
        "__type__": "map",
    }

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert s == "MAP LAYER NAME 'Layer1' END LAYER NAME 'Layer2' END END"


def test_projection():
    d = {
        "projection": [
            "proj=utm",
            "ellps=GRS80",
            "datum=NAD83",
            "zone=15",
            "units=m",
            "north",
            "no_defs",
        ],
        "__type__": "map",
    }

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert (
        s
        == "MAP PROJECTION 'proj=utm' 'ellps=GRS80' 'datum=NAD83' 'zone=15' 'units=m' 'north' 'no_defs' END END"
    )


def test_auto_projection():
    d = {"projection": ["auto"], "__type__": "map"}

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert s == "MAP PROJECTION AUTO END END"


def test_single_string_projection():
    d = {"projection": "init=epsg:4326", "__type__": "map"}

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert s == "MAP PROJECTION 'init=epsg:4326' END END"


def test_print_boolean():
    d = {"transform": True, "__type__": "layer"}

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(d)
    print(s)
    assert s == "LAYER TRANSFORM TRUE END"


def test_join():
    d = {
        "__type__": "layer",
        "name": "Joined",
        "joins": [{"__type__": "join", "name": "table_join"}],
    }

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    d = collections.OrderedDict(sorted(d.items()))
    s = pp.pprint(d)
    assert s == "LAYER JOIN NAME 'table_join' END NAME 'Joined' END"


def test_class_list():
    d1 = {"text": "([area])", "expression": "([area])", "__type__": "class"}
    d2 = {"text": '("[area]")', "expression": '("[area]")', "__type__": "class"}

    od1 = collections.OrderedDict(sorted(d1.items()))
    od2 = collections.OrderedDict(sorted(d2.items()))

    classes = [od1, od2]

    pp = PrettyPrinter(indent=0, quote="'", newlinechar=" ")
    s = pp.pprint(classes)  # type: ignore
    print(s)
    assert (
        s
        == 'CLASS EXPRESSION ([area]) TEXT ([area]) END CLASS EXPRESSION ("[area]") TEXT ("[area]") END'
    )


def test_get_attribute_properties():
    pp = PrettyPrinter()
    props = pp.get_attribute_properties("layer", "connectiontype")
    print(props)
    assert len(props["enum"]) == 15


def test_get_ref_attribute_properties():
    pp = PrettyPrinter()
    props = pp.get_attribute_properties("layer", "labelcache")
    print(props)
    assert len(props["enum"]) == 2


def test_get_label_shadowcolor_properties():
    # check a single ref is resolved
    pp = PrettyPrinter()
    props = pp.get_attribute_properties("label", "shadowcolor")
    print(props)
    assert len(props["oneOf"]) == 2


def test_get_label_position_properties():
    pp = PrettyPrinter()
    props = pp.get_attribute_properties("label", "position")
    assert props["oneOf"][1]["enum"] == [
        "ul",
        "uc",
        "ur",
        "cl",
        "cc",
        "cr",
        "ll",
        "lc",
        "lr",
    ]


def test_map_layers_props():
    pp = PrettyPrinter()
    props = pp.get_attribute_properties("map", "layers")
    print(props)
    # assert(props["type"] == "object")
    assert props["type"] == "array"


def test_end_comment():
    s = "MAP LAYER TYPE POINT NAME 'Test' END END"
    ast = mappyfile.loads(s)
    pp = PrettyPrinter(indent=4, quote='"', newlinechar="\n", end_comment=True)
    res = pp.pprint(ast)
    print(res)
    exp = """MAP
    LAYER
        TYPE POINT
        NAME "Test"
    END # LAYER
END # MAP"""
    assert res == exp


def test_empty_composite():
    s = "MAP LAYER TYPE POINT NAME 'Test' END END"
    ast = mappyfile.loads(s)
    lyr = ast["layers"][0]

    # as we are using DefaultOrderedDict then checks like this example
    # will create an empty dictionary object
    if lyr["connectiontype"]:
        pass

    assert isinstance(lyr["connectiontype"], DefaultOrderedDict)

    pp = PrettyPrinter(indent=4, quote='"', newlinechar="\n", end_comment=True)
    error_thrown = False

    try:
        pp.pprint(ast)
    except ValueError:
        error_thrown = True

    assert error_thrown


def test_align_values():
    mapfile = """
    MAP
        EXTENT 0 0 100 100
        DEBUG on
        NAME Test
        shapepath "test/path"
    END
    """
    ast = mappyfile.loads(mapfile)
    pp = PrettyPrinter(indent=0, quote="'", newlinechar="\n", align_values=True)
    s = pp.pprint(ast)

    aligned_indexes = set()
    for line in s.splitlines():
        words = line.split()
        if len(words) > 1:
            aligned_indexes.add(line.index(words[1]))
    assert len(aligned_indexes) == 1


def test_separate_complex_types():
    s = """
    MAP
        EXTENT 0 0 100 100
        shapepath "test/path"
        LAYER
            CLASS
                EXPRESSION "Field"
                STYLE
                    SIZE [sizefield]
                END
                GROUP 'group1'
            END
            CLASSITEM "Test"
        END
        DEBUG on
        NAME Test
    END
    """
    ast = mappyfile.loads(s)
    pp = PrettyPrinter(
        indent=4, quote="'", newlinechar="\n", separate_complex_types=True
    )
    s = pp.pprint(ast)
    assert s.index("NAME ") < s.index("LAYER\n")
    assert s.index("DEBUG ") < s.index("LAYER\n")
    assert s.index("CLASSITEM ") < s.index("CLASS\n")
    assert s.index("GROUP") < s.index("STYLE\n")


def run_tests():
    # pytest.main(["tests/test_pprint.py::test_format_list"])
    pytest.main(["tests/test_pprint.py"])


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    test_empty_composite()
    # run_tests()
    print("Done!")
