package de.rico.adventure.structure;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.media.opengl.GL;

import de.rico.adventure.conversation.Conversation;
import de.rico.adventure.script.ScriptInterpreter;
import de.rico.engine.camera.Camera;
import de.rico.engine.effect.light.LightIface;

/**
 * This class is used for structuring different rooms into a chaper.
 * @author Frank Bruns
 *
 */
public class Chapter
{
	private HashMap<String, Room> rooms = null;
	private String activeRoomId = null;

	private HashMap<String, Conversation> conversations = null;

	private ScriptInterpreter scriptInterpreter = null;

	/**
	 * Creates a new chapter.
	 */
	public Chapter()
	{
		this.rooms = new HashMap<String, Room>();
		this.conversations = new HashMap<String, Conversation>();
	}

	/**
	 * Adds a room to the chapter.
	 * <br>
	 * <br>
	 * <b>Note:</b> The added room will be the new
	 * active room. So be careful, if you don't want this room to be
	 * the active.
	 * @param room room to add to the chapter
	 */
	public void addRoom(Room room)
	{
		this.rooms.put(room.getScriptId(), room);

		// assign the chapter, so that it can be retrieved from
		// the room object later on
		room.setChapter(this);

		// set the last added room to the new active room.
		this.setActiveRoom(room.getScriptId());
	}



	/**
	 * Returns the currently active room of the chapter.
	 * @return active room of the chapter
	 */
	public Room getActiveRoom()
	{
		return this.rooms.get(this.activeRoomId);
	}

	/**
	 * Sets the new active room of the chapter.
	 * @param roomId script id of the room to set active
	 */
	public void setActiveRoom(String roomId)
	{
		// call the currently active room's onExit() method
		if(this.getScriptInterpreter() != null)
		{
			// only call the OnExit() method, if the room has
			// been entered before
			if(this.rooms.get(this.activeRoomId).hasBeenEnteredAlready() == true)
				this.getScriptInterpreter().invokeMethod(
					this.rooms.get(this.activeRoomId).getScriptId()+"OnExit()");
		}

		// disable the current room's lights
		if(this.activeRoomId != null)
		{
			for(LightIface light : this.rooms.get(this.activeRoomId).getLights())
				light.setEnabled(false);
		}

		// set new active room
		this.activeRoomId = roomId;

		// enable the new room's lights
		for(LightIface light : this.rooms.get(this.activeRoomId).getLights())
			light.setEnabled(true);

		// initialite the camera with the room's special
		// camera perspectives
		Camera.getInstance().clearCameraPerspectives();
		Camera.getInstance().addCameraPerspectives(
				this.rooms.get(this.activeRoomId).getCameraPerspectives());

		// only set the initial camera perspective, if the room has
		// not been entered before, i.e is entered for the first time
		//if(this.rooms.get(this.activeRoomId).hasBeenEnteredAlready() == false)
			Camera.getInstance().setToCameraPerspective(
				this.rooms.get(this.activeRoomId).getInitialCamPerspective());


		// call the script's roomOnEnter() method, if the room was
		// entered the first time
		if(this.getScriptInterpreter() != null)
		{
			this.getScriptInterpreter().invokeMethod(
					this.rooms.get(this.activeRoomId).getScriptId()+"OnEnter()");
		}
	}

	/**
	 * Returns a list of all the rooms of the chapter.
	 * @return list of rooms
	 */
	public List<Room> getRooms()
	{
		List<Room> list = new ArrayList<Room>();

		for(Room room : this.rooms.values())
			list.add(room);

		return list;
	}

	/**
	 * Adds the specified conversation object to the chapter.
	 * @param con conversation object
	 */
	public void addConversation(Conversation con)
	{
		this.conversations.put(con.getScriptId(), con);
	}

	/**
	 * Adds the conversations of the specified list to the chapter.
	 * @param cons list of conversations
	 */
	public void addConversations(List<Conversation> cons)
	{
		for(Conversation con : cons)
			this.conversations.put(con.getScriptId(), con);
	}

	/**
	 * Returns the conversation that corresponds to the specified id.
	 * @param id id of the conversation to retrieve
	 * @return conversation with the specified id
	 */
	public Conversation getConversation(String id)
	{
		return this.conversations.get(id);
	}

	/**
	 * Initializes scripting for the rooms of this chapter.
	 * <b>Note:</b> Please call this method after every room has
	 * been added to the chapter (completely initialized), because you
	 * can only access things from within a script file that are
	 * part of the chapter's rooms after you call this method.
	 */
	public void initScripting()
	{
		List<Room> roomsList = new ArrayList<Room>();

		// assign the rooms to a list to be able to pass it
		// to the constructor
		for(Room room : this.rooms.values())
			roomsList.add(room);

		List<Conversation> conList = new ArrayList<Conversation>();

		// assign the conversations to a list to be able to pass it
		// to the constructor
		for(Conversation con : this.conversations.values())
			conList.add(con);

		this.scriptInterpreter = new ScriptInterpreter(roomsList,conList);
	}

	/**
	 * Returns the script interpreter of this room, if it has been
	 * initialized with a script file before. Otherwise the method
	 * will return <code>null</code>.
	 *
	 */
	public ScriptInterpreter getScriptInterpreter()
	{
		return this.scriptInterpreter;
	}

	/**
	 * Updates the currently active room.
	 * @param elapsedTime time between two frames.
	 */
	public void update(long elapsedTime)
	{
		this.rooms.get(this.activeRoomId).update(elapsedTime);

		for(Conversation con : this.conversations.values())
			con.update(elapsedTime);
	}

	/**
	 * Draws the currently active room.
	 * @param gl
	 */
	public void draw(GL gl)
	{
		this.rooms.get(this.activeRoomId).draw(gl);

		for(Conversation con : this.conversations.values())
			con.draw(gl);
	}
}
