package org.bukkit.conversations;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A ConversationFactory is responsible for creating a {@link Conversation}
* from a predefined template. A ConversationFactory is typically created when
* a plugin is instantiated and builds a Conversation each time a user
* initiates a conversation with the plugin. Each Conversation maintains its
* own state and calls back as needed into the plugin.
* <p>
* The ConversationFactory implements a fluid API, allowing parameters to be
* set as an extension to the constructor.
*/
public class ConversationFactory
{
protected Plugin plugin;
protected boolean isModal;
protected boolean localEchoEnabled;
protected ConversationPrefix prefix;
protected Prompt firstPrompt;
protected Map<Object, Object> initialSessionData;
protected String playerOnlyMessage;
protected List<ConversationCanceller> cancellers;
protected List<ConversationAbandonedListener> abandonedListeners;
/**
* Constructs a ConversationFactory.
*
* @param plugin The plugin that owns the factory.
*/
public ConversationFactory(Plugin plugin)
{
this.plugin = plugin;
isModal = true;
localEchoEnabled = true;
prefix = new NullConversationPrefix();
firstPrompt = Prompt.END_OF_CONVERSATION;
initialSessionData = new HashMap<Object, Object>();
playerOnlyMessage = null;
cancellers = new ArrayList<ConversationCanceller>();
abandonedListeners = new ArrayList<ConversationAbandonedListener>();
}
/**
* Sets the modality of all {@link Conversation}s created by this factory.
* If a conversation is modal, all messages directed to the player are
* suppressed for the duration of the conversation.
* <p>
* The default is True.
*
* @param modal The modality of all conversations to be created.
* @return This object.
*/
public ConversationFactory withModality(boolean modal)
{
isModal = modal;
return this;
}
/**
* Sets the local echo status for all {@link Conversation}s created by
* this factory. If local echo is enabled, any text submitted to a
* conversation gets echoed back into the submitter's chat window.
*
* @param localEchoEnabled The status of local echo.
* @return This object.
*/
public ConversationFactory withLocalEcho(boolean localEchoEnabled)
{
this.localEchoEnabled = localEchoEnabled;
return this;
}
/**
* Sets the {@link ConversationPrefix} that prepends all output from all
* generated conversations.
* <p>
* The default is a {@link NullConversationPrefix};
*
* @param prefix The ConversationPrefix to use.
* @return This object.
*/
public ConversationFactory withPrefix(ConversationPrefix prefix)
{
this.prefix = prefix;
return this;
}
/**
* Sets the number of inactive seconds to wait before automatically
* abandoning all generated conversations.
* <p>
* The default is 600 seconds (5 minutes).
*
* @param timeoutSeconds The number of seconds to wait.
* @return This object.
*/
public ConversationFactory withTimeout(int timeoutSeconds)
{
return withConversationCanceller(new InactivityConversationCanceller(plugin, timeoutSeconds));
}
/**
* Sets the first prompt to use in all generated conversations.
* <p>
* The default is Prompt.END_OF_CONVERSATION.
*
* @param firstPrompt The first prompt.
* @return This object.
*/
public ConversationFactory withFirstPrompt(Prompt firstPrompt)
{
this.firstPrompt = firstPrompt;
return this;
}
/**
* Sets any initial data with which to populate the conversation context
* sessionData map.
*
* @param initialSessionData The conversation context's initial
* sessionData.
* @return This object.
*/
public ConversationFactory withInitialSessionData(Map<Object, Object> initialSessionData)
{
this.initialSessionData = initialSessionData;
return this;
}
/**
* Sets the player input that, when received, will immediately terminate
* the conversation.
*
* @param escapeSequence Input to terminate the conversation.
* @return This object.
*/
public ConversationFactory withEscapeSequence(String escapeSequence)
{
return withConversationCanceller(new ExactMatchConversationCanceller(escapeSequence));
}
/**
* Adds a {@link ConversationCanceller} to constructed conversations.
*
* @param canceller The {@link ConversationCanceller} to add.
* @return This object.
*/
public ConversationFactory withConversationCanceller(ConversationCanceller canceller)
{
cancellers.add(canceller);
return this;
}
/**
* Prevents this factory from creating a conversation for non-player
* {@link Conversable} objects.
*
* @param playerOnlyMessage The message to return to a non-play in lieu of
* starting a conversation.
* @return This object.
*/
public ConversationFactory thatExcludesNonPlayersWithMessage(String playerOnlyMessage)
{
this.playerOnlyMessage = playerOnlyMessage;
return this;
}
/**
* Adds a {@link ConversationAbandonedListener} to all conversations
* constructed by this factory.
*
* @param listener The listener to add.
* @return This object.
*/
public ConversationFactory addConversationAbandonedListener(ConversationAbandonedListener listener)
{
abandonedListeners.add(listener);
return this;
}
/**
* Constructs a {@link Conversation} in accordance with the defaults set
* for this factory.
*
* @param forWhom The entity for whom the new conversation is mediating.
* @return A new conversation.
*/
public Conversation buildConversation(Conversable forWhom)
{
//Abort conversation construction if we aren't supposed to talk to non-players
if(playerOnlyMessage != null && !(forWhom instanceof Player))
{
return new Conversation(plugin, forWhom, new NotPlayerMessagePrompt());
}
//Clone any initial session data
Map<Object, Object> copiedInitialSessionData = new HashMap<Object, Object>();
copiedInitialSessionData.putAll(initialSessionData);
//Build and return a conversation
Conversation conversation = new Conversation(plugin, forWhom, firstPrompt, copiedInitialSessionData);
conversation.setModal(isModal);
conversation.setLocalEchoEnabled(localEchoEnabled);
conversation.setPrefix(prefix);
//Clone the conversation cancellers
for(ConversationCanceller canceller : cancellers)
{
conversation.addConversationCanceller(canceller.clone());
}
//Add the ConversationAbandonedListeners
for(ConversationAbandonedListener listener : abandonedListeners)
{
conversation.addConversationAbandonedListener(listener);
}
return conversation;
}
private class NotPlayerMessagePrompt extends MessagePrompt
{
public String getPromptText(ConversationContext context)
{
return playerOnlyMessage;
}
@Override
protected Prompt getNextPrompt(ConversationContext context)
{
return Prompt.END_OF_CONVERSATION;
}
}
}