package thebetweenlands.common.world.gen.feature;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Stack;

import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import thebetweenlands.common.block.terrain.BlockHanger;
import thebetweenlands.common.registries.BlockRegistry;
import thebetweenlands.util.CubicBezier;

public class WorldGenCaveHangers extends WorldGenCave {
	private static final CubicBezier HEIGHT_CDF = new CubicBezier(0.75F, 0.25F, 0.9F, 1);

	private static final int MIN_RADIUS = 4;

	private static final int MAX_RADIUS = 8;

	private static final int MAX_HEIGHT = 8;

	public WorldGenCaveHangers() {
		super(false);
	}

	@Override
	public boolean generate(World world, Random random, BlockPos origin) {
		if (!isGoodStart(world, origin)) {
			return false;
		}
		int radius = random.nextInt(MAX_RADIUS - MIN_RADIUS + 1) + MIN_RADIUS;
		int radiusSq = radius * radius;
		Stack<BlockPos> searching = new Stack<BlockPos>();
		List<BlockPos> checked = new ArrayList<BlockPos>();
		List<PlantLocation> locations = new ArrayList<PlantLocation>();
		BlockPos start = origin.add(0, -1, 0);
		searching.push(start);
		checked.add(start);
		while (!searching.isEmpty()) {
			BlockPos pos = searching.pop();
			double distSq = pos.distanceSq(origin.getX(), origin.getY(), origin.getZ());
			if (random.nextFloat() > distSq / radiusSq) {
				locations.add(new PlantLocation(world, pos));
			}
			for (EnumFacing dir : directions) {
				BlockPos offsetPos = pos.offset(dir);
				if (offsetPos.distanceSq(origin.getX(), origin.getY(), origin.getZ()) > radiusSq) {
					continue;
				}
				if (supports(world, offsetPos.add(0, 1, 0))) {
					if (!checked.contains(offsetPos)) {
						searching.push(offsetPos);
						checked.add(offsetPos);
					}
				}
			}
		}
		if (locations.size() < 3) {
			return false;
		}
		float[] heights = new float[locations.size()];
		for (int i = 0; i < locations.size(); i++) {
			heights[i] = HEIGHT_CDF.eval(i / (float) (locations.size() - 1));
		}
		Collections.shuffle(locations, random);
		for (int i = 0; i < locations.size(); i++) {
			PlantLocation location = locations.get(i);
			BlockPos pos = location.getPos();
			int height = location.getHeight();
			if (height > MAX_HEIGHT) {
				height = MAX_HEIGHT;
			}
			height = (int) (heights[i] * (height - 1) + 1);
			for (int dy = 0; dy < height; dy++) {
				this.setBlockAndNotifyAdequately(world, pos.add(0, -dy, 0), BlockRegistry.HANGER.getDefaultState().withProperty(BlockHanger.CAN_GROW, false));
			}
		}
		return true;
	}
}
