package de.rico.adventure.conversation;

import java.util.LinkedHashMap;
import java.util.LinkedList;

import javax.media.opengl.GL;

import de.rico.adventure.actions.AbstractAction;
import de.rico.adventure.actions.ActionScheduler;
import de.rico.adventure.actions.custom.RunCode;
import de.rico.adventure.actions.custom.Say;
import de.rico.adventure.enums.State;
import de.rico.adventure.structure.Chapter;
import de.rico.adventure.structure.StateManager;
import de.rico.engine.effect.ortho.ListMenuRenderer;
import de.rico.engine.enums.Font;
import de.rico.engine.input.InputAction;
import de.rico.engine.input.InputManager;
import de.rico.engine.material.Color4f;

/**
 * This class represents a conversation between the player and
 * a non-player-character (NPC) based on a question and answer system.
 * The player can choose a question from a list menu that triggers
 * a series of sentences spoken by the participants of the conversation.
 * @author Frank Bruns
 *
 */
public class Conversation
{
	private boolean run = false;

	private LinkedHashMap<String,Branch> branches = null;
	private LinkedList<Branch> branchesToAdd = null;

	private InputManager input = null;

	private ListMenuRenderer listMenu = null;
	private String id = null;
	private Chapter chapter = null;

	private State backupState = null;

	/**
	 * Creates a new conversation with the specified parameters.
	 * @param id script id of the conversation
	 * @param chapter the chapter this conversation belongs to
	 * @param input input manager object
	 */
	public Conversation(String id, Chapter chapter, InputManager input)
	{
		this.id = id;
		this.branches = new LinkedHashMap<String, Branch>();
		this.branchesToAdd = new LinkedList<Branch>();

		this.input = input;
		this.chapter = chapter;
		this.listMenu = new ListMenuRenderer(100,300,10,10,new Color4f(1f,1f,0f,1f),new Color4f(),new Color4f(0f,0f,0f,0.65f),Font.HELVETICA_18);
	}

	/**
	 * Returns the script id of the conversation.
	 * @return script id of the conversation
	 */
	public String getScriptId()
	{
		return this.id;
	}

	/**
	 * Adds a branch to the conversation.
	 * @param branch branch to add
	 */
	public void addBranch(Branch branch)
	{
		this.branchesToAdd.add(branch);

		// call the update method once to finalize the add operation
		this.update(0L);
	}

	/**
	 * Returns the branch with the specified branch id.
	 * @param id id of the branch to retrieve
	 * @return branch with the specified id
	 */
	public Branch getBranch(String id)
	{
		return this.branches.get(id);
	}

	/**
	 * Starts the conversation.
	 *
	 */
	public void start()
	{
		this.run = true;
	}

	/**
	 * Updates the conversation object.
	 * @param elapsedTime time between two frames
	 */
	public void update(long elapsedTime)
	{
		// add branches
		for(Branch b : this.branchesToAdd)
			this.branches.put(b.getId(), b);
		this.branchesToAdd.clear();

		if(this.run == false) return; // leave, if not running

		// clear the question dialog
		this.listMenu.clear();

		// reinit the question dialog (with possible changes)
		for(Branch b : this.branches.values())
		{
			if(b.isAvailable())
				this.listMenu.add(b.getTitle(), b.getId());
		}
	}

	/**
	 * Draws the questions dialog to the screen.
	 * @param gl
	 */
	public void draw(GL gl)
	{
		if(this.run == false) return; // leave, if not running

		// save original game state
		if(this.backupState == null)
			this.backupState = StateManager.getInstance().getState();

		// set to conversation state
		StateManager.getInstance().setState(State.TALK);

		// don't draw, if someone is talking at the moment
		AbstractAction action = ActionScheduler.getInstance().getFirst();
		if(action != null) return;

		this.listMenu.draw(
				this.input.getMouseX(),
				this.input.getMouseY());


		// check if left mouse button was pressed
		InputAction leftBtn = null;
		for(InputAction ia : this.input.getMouseActions())
		{
			if(ia != null && ia.getName().equals("left click"))
				leftBtn = ia;
		}
		// choose the menu entry under the mouse, if clicked
		// Note: the mouse click gets consumed, when checked for
		if(leftBtn != null && leftBtn.isPressed() == true)
		{
			String entryId = this.listMenu.getEntryId(
					this.input.getMouseX(),
					this.input.getMouseY());
			if(entryId != null)
			{
				for(Sentence  sent : this.branches.get(entryId).getSentences())
				{
					// don't remove the branch, if its the "quit" branch
					if(entryId.equals("quit") == false)
					{
						this.branches.get(entryId).setAvailable(false);
						this.branches.get(entryId).markAsSaid();
						ActionScheduler.getInstance().add(new Say(sent));

						// run scripted code, if available
						if(sent.getScriptCode() != null)
							ActionScheduler.getInstance().add(
									new RunCode(
											sent.getScriptCode(),
											this.chapter.getScriptInterpreter()));
					}
					else
					{
						this.run = false;
						// set to original state
						StateManager.getInstance().setState(this.backupState);
						ActionScheduler.getInstance().add(new Say(sent));

						// run scripted code, if available
						if(sent.getScriptCode() != null)
							ActionScheduler.getInstance().add(
									new RunCode(
											sent.getScriptCode(),
											this.chapter.getScriptInterpreter()));
					}
				}
			}
		}
	}
}
