/*
* Copyright 2014 Igor Maznitsa (http://www.igormaznitsa.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.igormaznitsa.prol.containers;
import com.igormaznitsa.prol.data.Term;
import com.igormaznitsa.prol.data.TermStruct;
import java.io.PrintWriter;
/**
* A special system class which allows to save clauses as a list
*
* @author Igor Maznitsa (igor.maznitsa@igormaznitsa.com)
*/
final class KnowledgeBaseInsideClauseList {
/**
* The link to the first list element, can be null (only if the last is null
* too)
*/
private InsideClauseListItem first;
/**
* The link to the last list element, can be null (only if the first is null
* too)
*/
private InsideClauseListItem last;
/**
* The constructor
*/
KnowledgeBaseInsideClauseList() {
super();
first = null;
last = null;
}
/**
* To assert a clause as the A-Clause into the list
*
* @param struct the clause to be inserted into the list as the first element
* (must not be null)
* @return true if the operation is successfull else false
*/
boolean asserta(final TermStruct struct) {
first = new InsideClauseListItem(null, first, struct);
if (last == null) {
last = first;
}
return true;
}
/**
* To assert a clause as the Z-Clause into the list
*
* @param struct the struct to be inserted into the list as the last element
* (must not be null)
* @return true if the operation is successfull else false
*/
boolean assertz(final TermStruct struct) {
last = new InsideClauseListItem(last, null, struct);
if (first == null) {
first = last;
}
return true;
}
/**
* To retract the first found clause which compatible with a template
*
* @param template the template to find a clause, must not be null
* @return true if the operation is successfull else false
*/
boolean retracta(final TermStruct template) {
InsideClauseListItem container = null;
while ((container = findDirect(template, container)) != null) {
container.remove();
if (first == container) {
first = container.getNext();
}
return true;
}
return false;
}
/**
* To retract the last found clause which compatible with a template
*
* @param template the template to find a clause, must not be null
* @return true if the operation is successfull else false
*/
boolean retractz(final TermStruct template) {
InsideClauseListItem container = null;
while ((container = findBack(template, container)) != null) {
container.remove();
if (last == container) {
last = container.getPrevious();
}
return true;
}
return false;
}
/**
* To retract all found clauses which compatible with a template
*
* @param template the template to find clauses, must not be null
* @return true if the operation is successfull else false
*/
int retractall(final TermStruct template) {
InsideClauseListItem container = null;
int result = 0;
while ((container = findDirect(template, container)) != null) {
container.remove();
if (first == container) {
first = container.getNext();
}
if (last == container) {
last = container.getPrevious();
}
result++;
}
return result;
}
/**
* Calculate the size of the list
*
* @return the list size as integer
*/
int size() {
int size = 0;
if (first == null) {
return 0;
}
InsideClauseListItem curContainer = first;
while (curContainer != null) {
curContainer = curContainer.getNext();
size++;
}
return size;
}
/**
* Find next compatible clause with a template
*
* @param template the template to find a compatible clause
* @param sinceContainer the item container which will be used as the first
* for the search
* @return the first found container contains a potentially compatible clause
* or null if it has not been found
*/
InsideClauseListItem findDirect(final TermStruct template, InsideClauseListItem sinceContainer) {
if (sinceContainer == null) {
sinceContainer = first;
}
else {
sinceContainer = sinceContainer.getNext();
}
InsideClauseListItem result = null;
while (sinceContainer != null) {
final Term keyTerm = sinceContainer.getKeyTerm();
if (keyTerm.equWithoutSet(template)) {
// looks similar but we need to check a bit deeper to be ensure
if (template.makeClone().Equ(keyTerm.makeClone())) {
result = sinceContainer;
break;
}
}
sinceContainer = sinceContainer.getNext();
}
return result;
}
/**
* Find next compatible clause with a template
*
* @param template the template to find a compatible clause
* @param sinceContainer the item container which will be used as the first
* for the search
* @return the first found container contains a compatible clause or null if
* it has not been found
*/
InsideClauseListItem findBack(final TermStruct template, InsideClauseListItem sinceContainer) {
if (sinceContainer == null) {
sinceContainer = last;
}
else {
sinceContainer = sinceContainer.getPrevious();
}
InsideClauseListItem result = null;
while (sinceContainer != null) {
final Term keyterm = sinceContainer.getKeyTerm();
if (keyterm.equWithoutSet(template)) {
// check deeper because equWithoutSet is not precise for speed
if (keyterm.makeClone().Equ(template.makeClone())) {
result = sinceContainer;
break;
}
}
sinceContainer = sinceContainer.getPrevious();
}
return result;
}
/**
* Write current saved clauses as a prolog source into the writer
*
* @param writer the write which will be used to out clauses, must not be null
*/
void write(final PrintWriter writer) {
if (writer == null) {
throw new NullPointerException("Writer is null");
}
InsideClauseListItem item = first;
while (true) {
if (item == null) {
break;
}
writer.print(item.getClause().getSourceLikeRepresentation());
writer.println('.');
item = item.getNext();
}
writer.println();
}
/**
* Make a copy of the list, it copies only structure.
*
* @return the copy of the clause list
*/
public KnowledgeBaseInsideClauseList makeCopy() {
final KnowledgeBaseInsideClauseList copy = new KnowledgeBaseInsideClauseList();
InsideClauseListItem current = first;
while (true) {
if (current == null) {
break;
}
else {
copy.assertz(current.getClause());
current = current.getNext();
}
}
return copy;
}
}