package com.rs.game.player.cutscenes;

import com.rs.Settings;
import com.rs.cores.CoresManager;
import com.rs.game.WorldTile;
import com.rs.game.map.MapBuilder;
import com.rs.game.npc.NPC;
import com.rs.game.player.InterfaceManager;
import com.rs.game.player.Player;
import com.rs.game.player.cutscenes.actions.CutsceneAction;
import com.rs.game.player.dialogues.Dialogue;
import com.rs.game.tasks.WorldTask;
import com.rs.game.tasks.WorldTasksManager;
import com.rs.utils.Logger;

public abstract class Cutscene {

	public abstract boolean hiddenMinimap();

	public abstract CutsceneAction[] getActions(Player player);

	private int stage;
	private Object[] cache;
	private CutsceneAction[] actions;
	private int delay;
	private boolean constructingRegion;
	private int[] currentMapData;

	public Cutscene() {

	}

	private WorldTile endTile;

	public void stopCutscene(Player player) {
		if (player.getX() != endTile.getX() || player.getY() != endTile.getY() || player.getPlane() != endTile.getPlane())
			player.setNextWorldTile(endTile);
		if (hiddenMinimap())
			player.getPackets().sendBlackOut(0); // unblack
		player.getInterfaceManager().closeReplacedRealChatBoxInterface();
		player.getVarsManager().sendVar(1241, 0);
		player.getPackets().sendResetCamera();
		player.unlock();
		deleteCache();
		if (currentMapData != null) {
			CoresManager.slowExecutor.execute(new Runnable() {
				@Override
				public void run() {
					try {
						if (currentMapData != null)
							MapBuilder.destroyMap(currentMapData[0], currentMapData[1], currentMapData[1], currentMapData[2]);
					} catch (Throwable e) {
						Logger.handle(e);
					}
				}
			});
		}
	}

	public void startCutscene(Player player) {
		if (hiddenMinimap())
			player.getPackets().sendBlackOut(2); // minimap
		Dialogue.sendEmptyDialogue(player);
		player.getVarsManager().sendVar(1241, 1);
		player.lock();
		player.stopAll(true, false);
	}

	public void constructArea(final Player player, final int baseChunkX, final int baseChunkY, final int widthChunks, final int heightChunks) {
		constructingRegion = true;
		player.getPackets().sendRootInterface(56, 0);
		CoresManager.slowExecutor.execute(new Runnable() {
			@Override
			public void run() {
				try {
					final int[] oldData = currentMapData;
					int[] mapBaseChunks = MapBuilder.findEmptyChunkBound(widthChunks, heightChunks);
					MapBuilder.copyAllPlanesMap(baseChunkX, baseChunkY, mapBaseChunks[0], mapBaseChunks[1], widthChunks, heightChunks);
					currentMapData = new int[] { mapBaseChunks[0], mapBaseChunks[1], widthChunks, heightChunks };
					player.setNextWorldTile(new WorldTile(getBaseX() + widthChunks * 4, +getBaseY() + heightChunks * 4, 0));
					constructingRegion = false;
					if (Settings.DEBUG)
						Logger.log(this, "Bases: " + getBaseX() + ", " + getBaseY());
					WorldTasksManager.schedule(new WorldTask() {

						@Override
						public void run() {

							CoresManager.slowExecutor.execute(new Runnable() {
								@Override
								public void run() {
									player.getPackets().sendRootInterface(player.getInterfaceManager().hasRezizableScreen() ? InterfaceManager.RESIZABLE_WINDOW_ID : InterfaceManager.FIXED_WINDOW_ID, 0);
									if (oldData != null)
										MapBuilder.destroyMap(oldData[0], oldData[1], oldData[1], oldData[2]);
								}
							});
						}

					}, 1);
				} catch (Throwable e) {
					Logger.handle(e);
				}
			}
		});
	}

	public int getLocalX(Player player, int x) {
		return getX(player, (currentMapData == null ? 0 : getBaseX()) + x);
	}

	public int getLocalY(Player player, int y) {
		return getY(player, (currentMapData == null ? 0 : getBaseY()) + y);
	}

	public int getBaseX() {
		return currentMapData == null ? 0 : currentMapData[0] << 3;
	}

	public int getBaseY() {
		return currentMapData == null ? 0 : currentMapData[1] << 3;
	}

	public final void logout(Player player) {
		stopCutscene(player);
	}

	public final boolean process(Player player) {
		if (delay > 0) {
			delay--;
			return true;
		}
		while (true) {
			if (constructingRegion || (player.getNextWorldTile() != null && player.needMapUpdate(player.getNextWorldTile())))
				return true;
			if (stage == actions.length) {
				stopCutscene(player);
				return false;
			} else if (stage == 0)
				startCutscene(player);
			CutsceneAction action = actions[stage++];
			action.process(player, cache);
			int delay = action.getActionDelay();
			if (delay == -1)
				continue;
			this.delay = delay;
			return true;
		}
	}

	public void deleteCache() {
		for (Object object : cache)
			destroyCache(object);
	}

	public void destroyCache(Object object) {
		if (object instanceof NPC) {
			NPC n = (NPC) object;
			n.finish();
		}
	}

	public final void createCache(Player player) {
		actions = getActions(player);
		endTile = new WorldTile(player);
		int lastIndex = 0;
		for (CutsceneAction action : actions) {
			if (action.getCachedObjectIndex() > lastIndex)
				lastIndex = action.getCachedObjectIndex();
		}
		cache = new Object[lastIndex + 1];
		cache[0] = this;
	}

	public static int getX(Player player, int x) {
		return new WorldTile(x, 0, 0).getLocalX(player.getLastLoadedMapRegionTile(), player.getMapSize());
	}

	public static int getY(Player player, int y) {
		return new WorldTile(0, y, 0).getLocalY(player.getLastLoadedMapRegionTile(), player.getMapSize());
	}

	public final void updateDelay(int delay) {
		this.delay = delay;
	}
}
