JplQuery.java
/*
* #%L
* prolobjectlink-jpi-jpl
* %%
* Copyright (C) 2019 Prolobjectlink Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/
package io.github.prolobjectlink.prolog.jpl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import io.github.prolobjectlink.prolog.AbstractEngine;
import io.github.prolobjectlink.prolog.AbstractIterator;
import io.github.prolobjectlink.prolog.AbstractQuery;
import io.github.prolobjectlink.prolog.PrologError;
import io.github.prolobjectlink.prolog.PrologQuery;
import io.github.prolobjectlink.prolog.PrologTerm;
import jpl.PrologException;
import jpl.Query;
import jpl.Term;
import jpl.Util;
import jpl.Variable;
/**
*
* @author Jose Zalacain
* @since 1.0
*/
final class JplQuery extends AbstractQuery implements PrologQuery {
private String stringQuery;
private Map<String, PrologTerm>[] solutions;
private Iterator<Map<String, PrologTerm>> iter;
private final List<String> variables = new ArrayList<String>();
private void enumerateVariables(List<String> vector, Term term) {
if (!(term instanceof Variable)) {
Term[] terms = term.args();
for (Term t : terms) {
enumerateVariables(vector, t);
}
} else if (!vector.contains(term.name())) {
vector.add(term.name());
}
}
JplQuery(AbstractEngine engine, String file, String stringQuery) {
super(engine);
if (stringQuery != null && stringQuery.length() > 0) {
this.stringQuery = stringQuery;
// saving variable order
enumerateVariables(variables, Util.textToTerm(stringQuery));
try {
Query.hasSolution("consult('" + file + "')");
Query query = new Query(stringQuery);
Map<String, Term>[] solve = query.allSolutions();
solutions = toTermMapArray(solve, PrologTerm.class);
iter = new JplQueryIter(solutions);
} catch (PrologException e) {
// getLogger().error(getClass(), PrologLogger.RUNTIME_ERROR, e)
Map<String, PrologTerm> m = new HashMap<String, PrologTerm>();
JplReference prologexception = new JplReference(getProvider(), e);
Term error = e.term();
Term exception = error.arg(1);
Term ref = exception.arg(1);
if (ref.isJRef()) {
Object object = ref.jrefToObject();
if (object instanceof Throwable) {
Throwable k = (Throwable) object;
// getLogger().error(getClass(), PrologLogger.RUNTIME_ERROR, k)
JplReference javaexception = new JplReference(getProvider(), k);
m.put("PrologException", prologexception);
m.put("JavaException", javaexception);
solutions = new Map[] { m };
}
}
}
}
}
public boolean hasSolution() {
return iter != null && iter.hasNext();
}
public boolean hasMoreSolutions() {
return iter != null && iter.hasNext();
}
public PrologTerm[] oneSolution() {
int index = 0;
Map<String, PrologTerm> solution = oneVariablesSolution();
PrologTerm[] array = new PrologTerm[solution.size()];
for (Iterator<String> i = variables.iterator(); i.hasNext();) {
array[index++] = solution.get(i.next());
}
return array;
}
public Map<String, PrologTerm> oneVariablesSolution() {
return solutions.length > 0 ? solutions[0] : new HashMap<String, PrologTerm>();
}
public PrologTerm[] nextSolution() {
int index = 0;
Map<String, PrologTerm> solution = nextVariablesSolution();
PrologTerm[] array = new PrologTerm[solution.size()];
for (Iterator<String> i = variables.iterator(); i.hasNext();) {
array[index++] = solution.get(i.next());
}
return array;
}
public Map<String, PrologTerm> nextVariablesSolution() {
return iter.next();
}
public PrologTerm[][] nSolutions(int n) {
if (n > 0) {
// m:solutionSize
int m = 0;
int index = 0;
ArrayList<PrologTerm[]> all = new ArrayList<PrologTerm[]>();
while (hasNext() && index < n) {
PrologTerm[] solution = nextSolution();
m = solution.length > m ? solution.length : m;
index++;
all.add(solution);
}
PrologTerm[][] allSolutions = new PrologTerm[n][m];
for (int i = 0; i < n; i++) {
PrologTerm[] solution = all.get(i);
for (int j = 0; j < m; j++) {
allSolutions[i][j] = solution[j];
}
}
return allSolutions;
}
throw new PrologError("Impossible find " + n + " solutions");
}
public Map<String, PrologTerm>[] nVariablesSolutions(int n) {
return Arrays.copyOf(solutions, n);
}
public PrologTerm[][] allSolutions() {
// n:solutionCount, m:solutionSize
int n = 0;
int m = 0;
ArrayList<PrologTerm[]> all = new ArrayList<PrologTerm[]>();
while (hasMoreSolutions()) {
PrologTerm[] solution = nextSolution();
m = solution.length > m ? solution.length : m;
n++;
all.add(solution);
}
PrologTerm[][] allSolutions = new PrologTerm[n][m];
for (int i = 0; i < n; i++) {
PrologTerm[] solution = all.get(i);
for (int j = 0; j < m; j++) {
allSolutions[i][j] = solution[j];
}
}
return allSolutions;
}
public Map<String, PrologTerm>[] allVariablesSolutions() {
return solutions;
}
public void dispose() {
iter = null;
variables.clear();
int l = solutions.length;
for (int i = 0; i < l; i++) {
solutions[i].clear();
solutions[i] = null;
}
solutions = null;
}
public List<Map<String, PrologTerm>> all() {
List<Map<String, PrologTerm>> l = new ArrayList<Map<String, PrologTerm>>();
for (Map<String, PrologTerm> map : solutions) {
l.add(map);
}
return l;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + stringQuery.hashCode();
result = prime * result + variables.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
JplQuery other = (JplQuery) obj;
return variables.equals(other.variables);
}
@Override
public String toString() {
return stringQuery;
}
private class JplQueryIter extends AbstractIterator<Map<String, PrologTerm>>
implements Iterator<Map<String, PrologTerm>> {
private int nextIndex;
private final Map<String, PrologTerm>[] maps;
private JplQueryIter(Map<String, PrologTerm>[] maps) {
this.maps = maps;
}
public boolean hasNext() {
return nextIndex < maps.length;
}
public Map<String, PrologTerm> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return maps[nextIndex++];
}
}
}