package com.weaverplatform.connector.virtuoso;

import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.sysunite.weaver.connector.EmptyQueryResultException;
import com.sysunite.weaver.connector.NoQueryProvidedException;
import com.sysunite.weaver.connector.Query;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Created by gijs on 20/04/16.
 */
public class VirtuosoQuery implements AutoCloseable, Query {

  VirtuosoJDBC graphDatabaseService;
  ResultSet resultSet;

  public VirtuosoQuery(GraphDatabaseService graphDb) {

    this.graphDatabaseService = graphDb;
  }

  @Override
  public void literalQuery(String s) {

    resultSet = graphDatabaseService.jdbcSelect(s);
  }

  @Override
  public List<List<Object>> find() {

    if(resultSet == null) {
      throw new NoQueryProvidedException();
    }

    List<List<Object>> result = new ArrayList<>();
    List<String> columnNames = resultSet.getResultVars();
    if(columnNames.size()<1) {
      return result;
    }
    while(resultSet.hasNext()) {
      ArrayList<Object> resultRow = new ArrayList<>();
      QuerySolution row = resultSet.next();
      for(String colName : columnNames) {
        RDFNode node = row.get(colName);
        resultRow.add(node);
      }
      result.add(resultRow);
    }
    return result;
  }

  private Object toObject(QuerySolution querySolution) {

    return (Object) querySolution;
  }

  @Override
  public void getValueProperties(String objectID) {

    String query = "SELECT DISTINCT ?g AS ?graphs { GRAPH ?g { ?s ?p ?o .FILTER(?s=<"+objectID+">) }}";

    resultSet = graphDatabaseService.jdbcSelect(query);
  }

  @Override
  public List<Object> first() {

    if (resultSet == null) {
      throw new NoQueryProvidedException();
    }

    if (!resultSet.hasNext()) {
      throw new EmptyQueryResultException();
    }

    List<Object> theList = getRow();
    return theList;
  }

  private List<Object> getRow() {

    List<Object> r = new ArrayList<>();
    r.add(
      toObject(
        resultSet.next()
      ));

    return r;
  }

  @Override
  public int count() {

    if (resultSet == null) {
      throw new NoQueryProvidedException();
    }

    int r = 0;

    while(resultSet.hasNext()) {
      r++;
      resultSet.next();
    }

    return r;
  }

  /*
  Below are methods specified by the original weaver connector interface. These
  are heavily based on the use of a virtuoso database however, which is not an
  abstraction.
   */
  @Override
  public void filter() {
    throw new NotImplementedException();
  }

  @Override
  public void filter(Collection collection) {
    throw new NotImplementedException();
  }

  @Override
  public void equalTo() {
    throw new NotImplementedException();
  }

  @Override
  public void linksTo() {
    throw new NotImplementedException();
  }

  @Override
  public void ascending() {
    throw new NotImplementedException();
  }

  @Override
  public void descending() {
    throw new NotImplementedException();
  }

  @Override
  public void limit() {
    throw new NotImplementedException();
  }

  @Override
  public void skip() {
    throw new NotImplementedException();
  }

  @Override
  public void close() throws Exception {
    graphDatabaseService.closeDB();
  }
}