package com.austinv11.peripheralsplusplus.tiles;
import com.austinv11.peripheralsplusplus.cleverbot.AIChatRequest;
import com.austinv11.peripheralsplusplus.reference.Config;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaObject;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import com.google.code.chatterbotapi.*;
import java.util.*;
public class TileEntityAIChatBox extends MountedTileEntity {
public static String publicName = "aiChatBox";
private String name = "tileEntityAIChatBox";
private List<BotSessionLuaObject> sessions = new ArrayList<BotSessionLuaObject>();
private ChatterBotFactory factory = new ChatterBotFactory();
private List<IComputerAccess> computers = new ArrayList<IComputerAccess>();
public TileEntityAIChatBox() {
super();
}
public String getName() {
return name;
}
@Override
public String getType() {
return publicName;
}
@Override
public String[] getMethodNames() {
return new String[] { "newSession","getSession","getAllSessions" };
}
@Override
public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException {
if (!Config.enableAIChatBox)
throw new LuaException("AI Chat Boxes have been disabled");
if (isInvalid()) {
throw new LuaException("ERROR invalid tile entity");
}
// newSession
if (method == 0) {
// Run method
return Methods.newSession(computer, context, this);
}
// getSession
if (method == 1) {
// Get arguments
UUID uuid = ArgumentHelper.getUUID(arguments,0);
// Run method
return Methods.getSession(computer, context, this, uuid);
}
// getAllSessions
if (method == 2) {
// Run method
return Methods.getAllSessions(computer, context, this);
}
return new Object[0];
}
public void sendEvent(Object[] params) {
// Base arguments
List<Object> arguments = new ArrayList<Object>(Arrays.asList(params));
arguments.add(0,"SIDE");
for (IComputerAccess computer : computers) {
// Add the computer side
arguments.set(0,computer.getAttachmentName());
// Queue event
computer.queueEvent(AIChatRequest.EVENT,arguments.toArray());
}
}
@Override
public void attach(IComputerAccess computer) {
computers.add(computer);
super.attach(computer);
}
@Override
public void detach(IComputerAccess computer) {
computers.remove(computer);
super.detach(computer);
}
@Override
public boolean equals(IPeripheral other) {
return this == other;
}
public ChatterBotFactory getFactory() {
return factory;
}
public List<BotSessionLuaObject> getSessions() {
return sessions;
}
// Peripheral methods
public static class Methods {
// Lua arguments:
// string uuid = newSession()
public static Object[] newSession(IComputerAccess computer, ILuaContext context, TileEntityAIChatBox tileEntity) throws LuaException, InterruptedException {
// Get the factory and sessions from the tile entity
ChatterBotFactory factory = tileEntity.getFactory();
List<BotSessionLuaObject> sessions = tileEntity.getSessions();
try {
// Generate an UUID
UUID uuid = ArgumentHelper.randomUUID(sessions);
// Create the session
ChatterBot bot = factory.create(ChatterBotType.CLEVERBOT);
ChatterBotSession botSession = bot.createSession();
BotSessionLuaObject luaSession = new BotSessionLuaObject(uuid,bot,botSession,computer,tileEntity);
// Add the session to the tile entity's list
sessions.add(luaSession);
// Return corresponding UUID
return new Object[] { luaSession };
} catch (Exception e) {
e.printStackTrace();
throw new LuaException("ERROR creating session, make sure the server has internet access!");
}
}
// Lua arguments:
// BotSessionLuaObject session = getSession(string uuid)
public static Object[] getSession(IComputerAccess computer, ILuaContext context, TileEntityAIChatBox tileEntity, UUID uuid) throws LuaException, InterruptedException {
// Try to find a match
for (BotSessionLuaObject session : tileEntity.getSessions()) {
if (session.getUUID().equals(uuid))
return new Object[] { session };
}
return new Object[0];
}
// Lua arguments:
// table{[string uuid]=BotSessionLuaObject, [string uuid]=BotSessionLuaObject, ...} = getAllSessions()
public static Object[] getAllSessions(IComputerAccess computer, ILuaContext context, TileEntityAIChatBox tileEntity) throws LuaException, InterruptedException {
HashMap<String, BotSessionLuaObject> table = new HashMap<String, BotSessionLuaObject>();
for (BotSessionLuaObject sessionLuaObject : tileEntity.getSessions()) {
table.put(sessionLuaObject.getUUID().toString(), sessionLuaObject);
}
return new Object[] { table };
//return new Object[] { tileEntity.getSessions().toArray() };
}
}
public static class ArgumentHelper {
// Get a ChatterBotType, if there's no valid BotType at that index then it will throw a LuaException.
public static ChatterBotType getBotType(Object[] arguments, int index) throws LuaException, InterruptedException {
return getBotType(arguments, index, null);
}
public static ChatterBotType getBotType(Object[] arguments, int index, ChatterBotType defaultValue) throws LuaException, InterruptedException {
return stringToType(getString(arguments,index,defaultValue==null ? null : defaultValue.toString()));
}
// Get an UUID, if there's no valid uuid at that index then it will throw a LuaException.
public static UUID getUUID(Object[] arguments, int index) throws LuaException, InterruptedException {
return getUUID(arguments, index, null);
}
public static UUID getUUID(Object[] arguments, int index, UUID defaultValue) throws LuaException, InterruptedException{
return stringToUUID(getString(arguments,index,defaultValue==null ? null : defaultValue.toString()));
}
// Get a string, if there's no string at that index then it will throw a LuaException.
public static String getString(Object[] arguments, int index) throws LuaException, InterruptedException {
return getString(arguments,index,null);
}
public static String getString(Object[] arguments, int index, String defaultValue) throws LuaException, InterruptedException{
if (arguments == null || arguments.length <= index) {
if (defaultValue == null)
ErrorOut(index,"string","nil");
else
return defaultValue;
}
if (!(arguments[index] instanceof String)) {
// Not string...
if (defaultValue == null)
ErrorOut(index,"string");
else
return defaultValue;
}
return (String) arguments[index];
}
// Simplifies the LuaException
static void ErrorOut(int index, String expected) throws LuaException, InterruptedException {
// index+1 because lua...
throw new LuaException("Bad argument #"+(index+1)+" ("+expected+" expected)");
}
static void ErrorOut(int index, String expected, String got) throws LuaException, InterruptedException {
// index+1 because lua...
throw new LuaException("Bad argument #"+(index+1)+" ("+expected+" expected, got "+got+")");
}
// Get a randomly generated UUID, that's guaranteed to be unique (among its comrades).
public static UUID randomUUID(List<BotSessionLuaObject> existing) {
// Randomize an UUID
UUID uuid = UUID.randomUUID();
// Make sure it's 100% unique (in this set)
while (BotSessionLuaObject.containsUUID(existing,uuid)) {
// Regenerate the UUID
uuid = UUID.randomUUID();
}
return uuid;
}
// Try to convert a string variable to a ChatterBotType. If no match then return null.
static ChatterBotType stringToType(String string) throws LuaException, InterruptedException {
if (string != null)
string = string.toUpperCase();
// Loop through each type, find a match
for (ChatterBotType type : ChatterBotType.values() ) {
if (type.toString().equals(string))
return type;
}
// No match!
return null;
}
// Try to convert a string variable to an UUID. If the string is invalid then return null.
static UUID stringToUUID(String string) throws LuaException, InterruptedException {
if (string == null)
return null;
return UUID.fromString(string);
}
}
public static class BotSessionLuaObject implements ILuaObject {
private final UUID uuid;
private final ChatterBot bot;
private final ChatterBotSession session;
private final IComputerAccess computer;
private final TileEntityAIChatBox source;
private boolean removed = false;
public BotSessionLuaObject(final UUID uuid,final ChatterBot bot, final ChatterBotSession session,final IComputerAccess computer, TileEntityAIChatBox source) {
this.uuid = uuid;
this.bot = bot;
this.session = session;
this.computer = computer;
this.source = source;
}
public String[] getMethodNames() {
return new String[] { "think","thinkAsync","getUUID","remove" };
}
public Object[] callMethod(ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException {
if (removed) {
throw new LuaException("ERROR accessing removed session!");
}
if (source.isInvalid()) {
throw new LuaException("ERROR invalid tile entity!");
}
// boolean success, string response = think(string message)
if (method == 0) {
// Get arguments
String message = ArgumentHelper.getString(arguments, 0);
// Run method
thinkAsync(message);
// Wait for message
Object[] event = context.pullEvent(AIChatRequest.EVENT);
// ai_response: string side, bool success, string response, string uuid
// event[0] event[1] event[2] event[3] event[4]
// Make sure you get the right message and not someone else's
while (!uuid.toString().equals(event[4])) {
event = context.pullEvent(AIChatRequest.EVENT);
}
return new Object[] { event[2],event[3] };
}
// nil = thinkAsync(string message)
if (method == 1) {
// Get arguments
String message = ArgumentHelper.getString(arguments,0);
// Run method
thinkAsync(message);
}
// getUUID
if (method == 2) {
// Run method
return new Object[] { getUUID().toString() };
}
// remove
if (method == 3) {
// Run method
this.removed = true;
return new Object[] { source.getSessions().remove(this) };
}
return new Object[0];
}
public UUID getUUID() {
return uuid;
}
// Makes a new thread and "thinks" in that one.
// When finished it sends an event to the designated computer.
public void thinkAsync(String message) throws LuaException, InterruptedException {
AIChatRequest request = new AIChatRequest(source,this,message);
}
// Just a normal thinking process. Haults the computer until it gets a reply (or errors out)
// Called from AIChatRequest
public String think(String message) throws Exception {
return session.think(message);
}
// Check the entire list if there's a matching UUID inside it
public static boolean containsUUID(List<BotSessionLuaObject> list, UUID uuid) {
for (BotSessionLuaObject botSession : list) {
if (botSession.getUUID() == uuid)
return true;
}
return false;
}
}
}