/**
 * 
 */
package studio.junk.jam.coloritum;

import java.util.LinkedList;

import com.badlogic.ashley.core.Entity;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;


/**
 * Script base class which describes a level.
 * <p>
 * This is used as a base class for groovy scripts.
 * 
 * @author held03
 */
public abstract class LevelScript extends NamedScript implements Level {

	/**
	 * Creates and add a new entity of given type.
	 * 
	 * @param name
	 *            the name of the type to create
	 * @return the new entity
	 */

	protected Entity entity(String name) {
		return entity(name, new Object[0]);
	}

	protected Entity entity(String name, Object... args) {
		//println("Create " + name);
		Entity e = GameState.state.types.get(name).create(name, args);

		return e;
	}

	/**
	 * Loads an entity or an entity index list.
	 * 
	 * @param path
	 *            the entity type script or index
	 */
	protected void useEntity(String path) {
		GameState.state.types.parseScripts(Gdx.files.internal(path));
	}

	/**
	 * Loads an asset set.
	 * 
	 * @param path
	 *            the asset mapper file
	 */
	protected void useAsset(String path) {
		GameState.state.assets.parseScripts(Gdx.files.internal(path));
	}

	/*
	 * (non-Javadoc)
	 * @see groovy.lang.Script#run()
	 */
	@Override
	public void addEnvironment() {
		run();
	}

	protected void bulidCorner(Vector2 pos, int turn) {
		Sprite s = new Sprite((TextureRegion) GameState.state.assets.get("obstacle45"));

		for (int i = 0; i < turn; i++)
			s.rotate90(true);

		entity("obstacle", pos.x, pos.y, s);
	}

	protected void buildWall(Vector2 from, Vector2 to) {
		Sprite s = new Sprite((TextureRegion) GameState.state.assets.get("obstacle90"));
		if (from.x == to.x) {
			int minY = (int) Math.min(from.y, to.y);
			int maxY = (int) Math.max(from.y, to.y);
			for (int i = minY; i <= maxY; i++) {
				entity("obstacle", from.x, i, s);
			}
			return;
		} else if (from.y == to.y) {
			s.rotate90(true);
			int minX = (int) Math.min(from.x, to.x);
			int maxX = (int) Math.max(from.x, to.x);
			for (int i = minX; i <= maxX; i++) {
				entity("obstacle", i, from.y, s);
			}
			return;
		}
		throw new IllegalArgumentException("Vectors must be in one line!");
	}

	private WallBuilder wallBuilder;

	protected WallBuilder wall(WallBuilder wallBuilder) {
		return wallBuilder;
	}

	protected WallBuilder from(int x, int y) {
		return wallBuilder;
	}

	class WallBuilder extends Builder {
		public WallBuilder from(int x, int y) {
			return this;
		}

		public WallBuilder to(int x, int y) {
			return this;
		}

		public WallBuilder over(int x, int y) {
			return this;
		}

		public WallBuilder and(String go) {
			wallBuilder = this;
			return this;
		}
	}

	protected void addHorizontalWall(int y, int start, int end) {
		int min = Math.min(start, end);
		int max = Math.max(start, end);

		for (int i = min; i <= max; i++) {
			this.entity("obstacle", i, y);
		}

		//build(wall).from(0, 0).to(4, 4);

	}

	protected void addVerticalWall(int x, int start, int end) {
		int min = Math.min(start, end);
		int max = Math.max(start, end);

		for (int i = min; i <= max; i++) {
			this.entity("obstacle", x, i);
		}
	}

	class Builder {
		public WallBuilderTest wall() {
			return new WallBuilderTest();
		}
	}


	private enum WallState {
		from, to, over
	}

	class WallBuilderTest {
		public boolean illegal = true;

		private WallState state = WallState.from;

		public final TextureRegion	tr90	= (TextureRegion) GameState.state.assets.get("obstacle90");
		public final TextureRegion	tr45	= (TextureRegion) GameState.state.assets.get("obstacle45");

		public LinkedList<Sprite> obstacleSprites = new LinkedList<Sprite>();

		private void addSprite(TextureRegion tr, int x, int y, float angle) {
			Sprite toAdd = new Sprite(tr);
			toAdd.setPosition(x, y);
			toAdd.setSize(1f, 1f);
			toAdd.setRotation(angle);
			obstacleSprites.add(toAdd);
		}

		private void addSprite(TextureRegion tr, int x, int y) {
			addSprite(tr, x, y, 0);
		}

		public WallBuilderTest from(int x, int y) {
			illegal = true;
			obstacleSprites.clear();
			addSprite(tr90, x, y);
			state = WallState.from;
			return this;
		}

		public WallBuilderTest to(int x, int y) {
			illegal = true;

			int lastX = (int) obstacleSprites.getLast().getX();
			int lastY = (int) obstacleSprites.getLast().getX();
			int minY = Math.min(y, lastY);
			int maxY = Math.max(y, lastY);
			int minX = Math.min(x, lastX);
			int maxX = Math.max(x, lastX);

			switch (state) {
			case from:

				if (lastX == x) {
					for (int i = minY + 1; i <= maxY; i++) {
						addSprite(tr90, i, y);

					}
					illegal = false;
				} else if (lastY == y) {
					for (int i = minX + 1; i <= maxX; i++) {
						addSprite(tr90, x, i, 90);
					}
					illegal = false;
				} else {
					addSprite(tr90, x, y);
					illegal = true;

				}
				break;
			case over:
			case to:
				if (lastX == x) {
					if (obstacleSprites.getLast().getRotation() == 90) {
						obstacleSprites.getLast().setTexture(tr45.getTexture());
					}
					for (int i = minY + 1; i <= maxY; i++) {
						addSprite(tr90, i, y);
					}
					illegal = false;
				} else if (lastY == y) {
					if (obstacleSprites.getLast().getRotation() == 0) {
						obstacleSprites.getLast().setTexture(tr45.getTexture());
					}
					for (int i = minY + 1; i <= maxY; i++) {
						addSprite(tr90, i, y, 90);
					}
					illegal = false;
				} else {
					addSprite(tr90, x, y);
					illegal = true;

				}
				break;
			default:
				illegal = true;
				break;

			}
			state = WallState.to;
			return this;
		}

		public WallBuilderTest over(int x, int y) {

			int lastX = (int) obstacleSprites.getLast().getX();
			int lastY = (int) obstacleSprites.getLast().getX();
			int minY = Math.min(y, lastY);
			int maxY = Math.max(y, lastY);
			int minX = Math.min(x, lastX);
			int maxX = Math.max(x, lastX);

			switch (state) {
			case from:
				if (lastX == x) {
					for (int i = minY + 1; i <= maxY; i++) {
						addSprite(tr90, i, y);

					}
					illegal = false;
				} else if (lastY == y) {
					for (int i = minX + 1; i <= maxX; i++) {
						addSprite(tr90, x, i, 90);
					}
					illegal = false;
				} else {
					addSprite(tr90, x, y);
					illegal = true;

				}
				break;
			case over:
				if (lastX == x) {
					if (obstacleSprites.getLast().getRotation() == 90) {
						obstacleSprites.getLast().setTexture(tr45.getTexture());
					}
					for (int i = minY + 1; i <= maxY; i++) {
						addSprite(tr90, i, y);
					}
					illegal = false;
				} else if (lastY == y) {
					if (obstacleSprites.getLast().getRotation() == 0) {
						obstacleSprites.getLast().setTexture(tr45.getTexture());
					}
					for (int i = minY + 1; i <= maxY; i++) {
						addSprite(tr90, i, y, 90);
					}
					illegal = false;
				} else {
					addSprite(tr90, x, y);
					illegal = true;

				}
				break;
			case to:
				if (lastX == x) {
					if (obstacleSprites.getLast().getRotation() == 90) {
						obstacleSprites.getLast().setTexture(tr45.getTexture());
					}
					for (int i = minY + 1; i <= maxY; i++) {
						addSprite(tr90, i, y);
					}
					illegal = false;
				} else if (lastY == y) {
					if (obstacleSprites.getLast().getRotation() == 0) {
						obstacleSprites.getLast().setTexture(tr45.getTexture());
					}
					for (int i = minY + 1; i <= maxY; i++) {
						addSprite(tr90, i, y, 90);
					}
					illegal = false;
				} else {
					obstacleSprites.pollLast();
					if (lastX == x) {
						if (obstacleSprites.getLast().getRotation() == 90) {
							obstacleSprites.getLast().setTexture(tr45.getTexture());
						}
						for (int i = minY + 1; i <= maxY; i++) {
							addSprite(tr90, i, y);
						}
						illegal = false;
					} else if (lastY == y) {
						if (obstacleSprites.getLast().getRotation() == 0) {
							obstacleSprites.getLast().setTexture(tr45.getTexture());
						}
						for (int i = minY + 1; i <= maxY; i++) {
							addSprite(tr90, i, y, 90);
						}
						illegal = false;
					} else {
						addSprite(tr90, x, y);
						illegal = true;
					}
				}
				break;
			default:
				illegal = true;
				break;

			}
			state = WallState.over;
			return this;
		}

		public void _() {
			for (Sprite s : obstacleSprites) {
				System.out.println(s.getX() + ", " + s.getY());
				LevelScript.this.entity("obstacle", s.getX(), s.getY(), s);
			}
		}

	}
}
