import os

from rdflib import ConjunctiveGraph

base_folder = "data"
product_path = "products.nq"


def make_graph_from_nquads(input_data):
    g = ConjunctiveGraph(identifier="Products")
    data = open(input_data, "rb")
    g.parse(data, format="nquads")

    return g

g = make_graph_from_nquads(os.path.join(base_folder, product_path))

"""
Explanation: SPARQL Queries for Local RDF Data
So you found some RDF data (yay!) from an archive somewhere, but there's no active SPARQL endpoint (it's all JSON APIs these days). You could use the methods implemented in the Python package rdflib to perform some lightweight searches of the triples, but what if you want to perform more complex queries without having to create a local triple store? In this post we'll see how to use the declarative language of SPARQL to perform complex queries on a local RDF file (inspired by this Stackoverflow post)? 
Note: If you want to follow along at home, check out the post on RDF basics to find out how to get the data used in this post, where it comes from, and what it's all about.
Make a ConjunctiveGraph
First, make sure you have pip installed rdflib. Now make a ConjunctiveGraph from the data. Here we specify that the data should be parsed as nquads, since that's the form that this specific dataset takes.
End of explanation
"""


from rdflib import URIRef, BNode

def get_products(graph):
    
    product = URIRef("http://schema.org/Product")

    sparql_query = """
        SELECT DISTINCT ?s
        WHERE {
        ?s ?p ?o .
        }
        """

    results = graph.query(sparql_query, initBindings={'o' : product})
    return [str(result[0]) for result in results]

"""
Explanation: Query the rdflib.graph.Graph()
Now that we have a graph, rdflib exposes a Graph.query module that we can use to pass in SPARQL queries.
Let's create a reusable function get_products, that takes as an argument the ConjunctiveGraph and returns a list of products.
End of explanation
"""


products = get_products(g)

print("{} total products".format(len(products)))
print("URI of first product: {}".format(list(products)[0]))

"""
Explanation: Now we can use our function to get all the unique products in the dataset:
End of explanation
"""


def get_product_details(graph, product_uri):
    
    sparql_query = """
    SELECT ?p ?o
    WHERE {
    ?s ?p ?o .
    }
    """
    
    return graph.query(sparql_query, initBindings={'s' : product_uri})

"""
Explanation: Now let's create a function get_product_details that takes as input the graph and a specific product's uri, and returns all the results containing the details available for that product:
End of explanation
"""


sample_product = BNode('N5ff6dab3a3ec40b4a040220b8f2effbe')
details = get_product_details(g, sample_product)
for detail in details:
    print(detail,'\n')

"""
Explanation: We can test out our function to explore a specific product from our dataset (in this case the one corresponding to the anonymous node 'N5ff6dab3a3ec40b4a040220b8f2effbe'):
End of explanation
"""


for product in products:
    print(product,':')
    for detail in get_product_details(g, BNode(product)):
        print('- ', detail)
    print('')

"""
Explanation: This tells that the product has some additional information, including a name ("sandcastle1"), a description ("Check out sandcastle1 on Cubify at http://cubify.com/Store/Design/AL98QAW7QL #getthereeasy"), and an image:

We can use the same function to get the details for every product in the dataset:
End of explanation
"""


generic = URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")
review_desc = URIRef('http://schema.org/Review/description')
product_review = URIRef('http://schema.org/Product/review')   


def get_review(graph, review_uri):
    
    sparql_query = """
    SELECT ?p ?o 
    WHERE {
    ?s ?p ?o .
    }
    """
    
    return graph.query(sparql_query, initBindings={'s': review_uri})
    

# make a dictionary to hold all of the product data
product_dict = {}
    
for product in products:
    product_dict[product] = {"http://schema.org/Product/name" : None,
                             "http://schema.org/Product/image": None,
                             "http://schema.org/Product/url" :  None,
                             "http://schema.org/Product/description": None,
                             "http://schema.org/Product/sku" : None,
                             "http://schema.org/Product/manufacturer": None,
                             "http://schema.org/Product/productID": None,
                             "http://schema.org/Product/dateModified": None,
                             "http://schema.org/Product/releaseDate": None,
                             "http://schema.org/Product/brand": None,
                             "http://schema.org/Product/model": None,
                             "http://schema.org/Product/offers": None,
                             "http://schema.org/Product/thumbnailUrl": None,
                             "http://schema.org/Product/logo": None,
                             "http://schema.org/Product/aggregateRating": None,
                             "http://schema.org/Product/reviews": [],
        }
    for detail_type, detail_content in get_product_details(g, BNode(product)):
        if detail_type == generic:
            continue
        # if the details indicate a product review:
        elif detail_type == product_review:
            for review_type, review_content in get_review(g, detail_content):
                if review_type == review_desc:
                    product_dict[product]["http://schema.org/Product/reviews"].append(
                        str(review_content)
                    )
                else:
                    continue
        else:
            product_dict[product][detail_type] = str(detail_content)

product_dict

"""
Explanation: Now let's say we want to go through each product and find not only the information contained in it's primary triples, but also information in related triples, such as the product reviews, which are stored separately, and of which there may be several or none for a given product.
End of explanation
"""


