# -*- coding: UTF-8 -*-
from __future__ import unicode_literals
import re
import json
import itertools
from rdflib import Graph
from rdflib.plugin import register, Serializer
register('json-ld', Serializer, 'rdflib_jsonld.serializer', 'JsonLDSerializer')


cases = []
def case(*args): cases.append(args)


case("""
@prefix dc: <http://purl.org/dc/terms/> .
<http://example.org/>
    dc:title "Homepage"@en .
""",
{
    "@context": {"@vocab": "http://purl.org/dc/terms/", "@language": "en"},
    "@id": "http://example.org/",
    "title": "Homepage"
}
)


case("""
@prefix dc: <http://purl.org/dc/terms/> .
<http://example.org/>
    dc:title "Homepage"@en, "Hemsida"@sv .
""",
{
    "@context": {"@vocab": "http://purl.org/dc/terms/", "title": {"@container": "@language"}},
    "@id": "http://example.org/",
    "title": {"en": "Homepage", "sv": "Hemsida"}
}
)


case("""
@prefix dc: <http://purl.org/dc/terms/> .
<http://example.org/>
    dc:title "Homepage"@en, "Hemsida"@sv .
""",
{
    "@context": {
        "@vocab": "http://purl.org/dc/terms/",
        "@language": "sv",
        "title_en": {"@id": "title", "@language": "en"}
    },
    "@id": "http://example.org/",
    "title_en": "Homepage",
    "title": "Hemsida"
}
)


# .. Requires set values to be sorted to be predictable
#case("""
#@prefix dc: <http://purl.org/dc/terms/> .
#<http://example.org/>
#    dc:title "Homepage"@en, "Home Page"@en, "Home Page"@en-GB, "Hemsida"@sv .
#""",
#{
#    "@context": "-||-",
#    "@id": "http://example.org/",
#    "title_en": ["Homepage", "Home Page"],
#    "title": [{"@language": "en-GB", "@value": "Home Page"}, "Hemsida"]
#}
#)


case("""
@prefix dc: <http://purl.org/dc/terms/> .
<http://example.org/easter_island>
    dc:title "Påskön"@sv .
""",
{
    "@context": {"@vocab": "http://purl.org/dc/terms/", "@language": "sv"},
    "@id": "http://example.org/easter_island",
    "title": "Påskön"
}
)


case("""
@prefix : <http://example.org/ns#> .
<http://example.org/> :has _:blank-1 .
""",
{
    "@context": {"has": {"@type": "@id", "@id": "http://example.org/ns#has"}},
    "@id": "http://example.org/",
    "has": "_:blank-1"
}
)


case("""
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix : <http://example.org/ns#> .
:Something rdfs:subClassOf :Thing .
""",
{
    "@context": {
        "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
        "v": "http://example.org/ns#",
        "rdfs:subClassOf": {"@container": "@set"}
    },
    "@id": "v:Something",
    "rdfs:subClassOf": [{"@id": "v:Thing"}]
}
)


case("""
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix : <http://example.org/ns#> .
:Something rdfs:subClassOf :Thing .
""",
{
    "@context": {
        "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
        "v": "http://example.org/ns#",
        "subClassOf": {"@id": "rdfs:subClassOf", "@type": "@id", "@container": "@set"}
    },
    "@id": "v:Something",
    "subClassOf": ["v:Thing"]
}
)


case("""
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix : <http://example.org/ns#> .
:World owl:unionOf (:Everyhing :Nothing) .
""",
{
    "@context": {
        "owl": "http://www.w3.org/2002/07/owl#",
        "v": "http://example.org/ns#"
    },
    "@id": "v:World",
    "owl:unionOf": {"@list": [{"@id": "v:Everyhing"}, {"@id": "v:Nothing"}]}
}
)


case("""
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix : <http://example.org/ns#> .
:World owl:unionOf (:Everyhing :Nothing) .
""",
{
    "@context": {
        "owl": "http://www.w3.org/2002/07/owl#",
        "v": "http://example.org/ns#",
        "unionOf": {"@id": "owl:unionOf", "@container": "@list"}
    },
    "@id": "v:World",
    "unionOf": [{"@id": "v:Everyhing"}, {"@id": "v:Nothing"}]
}
)


case("""
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix : <http://example.org/ns#> .
:World owl:unionOf (:Everyhing :Nothing) .
""",
{
    "@context": {
        "owl": "http://www.w3.org/2002/07/owl#",
        "v": "http://example.org/ns#",
        "unionOf": {"@id": "owl:unionOf", "@type": "@id", "@container": "@list"}
    },
    "@id": "v:World",
    "unionOf": ["v:Everyhing", "v:Nothing"]
}
)


# Shorten result IRIs by using @base
case("""
BASE <http://example.org/>
PREFIX : <http://example.org/vocab/>
<Thing> a :Class .
<Work> a :Class; :subClassOf <Thing> .
</some/path/> a :Thing .
</some/path/#this> a :Thing .
</some/path/#other> a :Thing .
""",
{
  "@context": {
    "@base": "http://example.org/some/path/#other",
    "@vocab": "http://example.org/vocab/"
  },
  "@graph": [
    {
      "@id": "/Thing",
      "@type": "Class"
    },
    {
      "@id": "/Work",
      "@type": "Class",
      "subClassOf": {
        "@id": "/Thing"
      }
    },
    {
      "@id": "",
      "@type": "Thing"
    },
    {
      "@id": "/some/path/#this",
      "@type": "Thing"
    },
    {
      "@id": "/some/path/#other",
      "@type": "Thing"
    }
  ]
}
)


json_kwargs = dict(indent=2, separators=(',', ': '), sort_keys=True, ensure_ascii=False)

def run(data, expected):
    g = Graph().parse(data=data, format='turtle')
    result = g.serialize(format='json-ld', context=expected['@context']).decode('utf-8')
    result = json.loads(result)

    sort_graph(result)
    result = json.dumps(result, **json_kwargs)
    incr = itertools.count(1)
    result = re.sub(r'"_:[^"]+"', lambda m: '"_:blank-%s"' % next(incr), result)

    sort_graph(expected)
    expected = json.dumps(expected, **json_kwargs)

    assert result == expected, "Expected not equal to result: %s" % result

def sort_graph(data):
    if '@graph' in data:
        data['@graph'].sort(key=lambda node: node.get('@id'))

def test_cases():
    for data, expected in cases:
        yield run, data, expected
