/******************************************************************************
*
* Copyright 2014 Paphus Solutions Inc.
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
*
* 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 org.botlibre.thought;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import org.botlibre.api.knowledge.MemoryEventListener;
import org.botlibre.api.knowledge.Network;
import org.botlibre.api.knowledge.Vertex;
import org.botlibre.knowledge.Primitive;
import org.botlibre.thought.BasicThought;
/**
* A sub-conscious thought that processes active memory in the background.
*/
public abstract class SubconsciousThought extends BasicThought {
public int threshold = 200;
public int delay = 0;
protected Queue<Vertex> activeMemoryBackLog = new ConcurrentLinkedQueue<Vertex>();
protected MemoryEventListener listener;
public SubconsciousThought() { }
/**
* Determine if the thought should first wait for conscious thoughts to process the input.
*/
public boolean isConsciousProcessingRequired() {
return false;
}
/**
* Add a listener to the memory to be notified when new active memory.
*/
@Override
public void awake() {
super.awake();
this.listener = new MemoryEventListener() {
public void addActiveMemory(Vertex vertex) {
if (isStopped || !isEnabled || !bot.mind().isConscious()) {
return;
}
if (getActiveMemoryBackLog().size() > SubconsciousThought.this.threshold) {
bot.log(this, "Subconscious backlog threshold reached, clearing backlog", Level.WARNING);
getActiveMemoryBackLog().clear();
}
getActiveMemoryBackLog().add(vertex);
}
};
this.bot.memory().addListener(this.listener);
}
public void stop() {
super.stop();
this.bot.memory().removeListener(this.listener);
}
/**
* Analyze the active memory.
* Output the active article to the senses.
*/
@Override
public void think() {
if (this.isStopped || !this.isEnabled || !this.bot.mind().isConscious()) {
getActiveMemoryBackLog().clear();
return;
}
Vertex vertex = getActiveMemoryBackLog().poll();
if (vertex != null) {
try {
Thread.sleep(this.delay);
if (this.isStopped || !this.isEnabled || !this.bot.mind().isConscious()) {
getActiveMemoryBackLog().clear();
return;
}
Network memory = this.bot.memory().newMemory();
vertex = memory.createVertex(vertex);
int abort = 0;
if (isConsciousProcessingRequired()) {
while ((abort < 20) && !vertex.hasRelationship(Primitive.CONTEXT)) {
Thread.sleep(1000);
if (this.isStopped || !this.isEnabled || !this.bot.mind().isConscious()) {
getActiveMemoryBackLog().clear();
return;
}
memory = this.bot.memory().newMemory();
vertex = memory.createVertex(vertex);
abort++;
}
}
if (abort < 20) {
boolean commit = processInput(vertex, memory);
if (commit && isEnabled() && !isStopped() && this.bot.mind().isConscious()) {
memory.save();
}
}
} catch (Exception failed) {
log(failed);
}
}
}
/**
* Process the active memory in the isolated memory in the background.
* Return if memory should be saved, or discarded.
*/
public abstract boolean processInput(Vertex vertex, Network network);
/**
* Thoughts can be conscious or sub-conscious.
* A conscious thought is run by the mind single threaded with exclusive access to the short term memory.
* A sub-conscious thought is run concurrently, and must run in its own memory space.
*/
@Override
public boolean isConscious() {
return false;
}
public Queue<Vertex> getActiveMemoryBackLog() {
return activeMemoryBackLog;
}
public void setActiveMemoryBackLog(Queue<Vertex> activeMemoryBackLog) {
this.activeMemoryBackLog = activeMemoryBackLog;
}
}