package cn.nukkit.level.generator.object.ore;

import cn.nukkit.block.Block;
import cn.nukkit.level.ChunkManager;
import cn.nukkit.math.NukkitRandom;
import cn.nukkit.math.Vector2;
import cn.nukkit.math.VectorMath;

/**
 * author: MagicDroidX
 * Nukkit Project
 */
public class ObjectOre {

    private final NukkitRandom random;
    public final OreType type;
    private int replaceId;

    public ObjectOre(NukkitRandom random, OreType type) {
        this(random, type, Block.STONE);
    }

    public ObjectOre(NukkitRandom random, OreType type, int replaceId) {
        this.type = type;
        this.random = random;
        this.replaceId = replaceId;
    }

    public OreType getType() {
        return type;
    }

    public boolean canPlaceObject(ChunkManager level, int x, int y, int z) {
        return (level.getBlockIdAt(x, y, z) == replaceId);
    }

    public void placeObject(ChunkManager level, int x, int y, int z) {
        int clusterSize = this.type.clusterSize;
        double angle = this.random.nextFloat() * Math.PI;
        Vector2 offset = VectorMath.getDirection2D(angle).multiply(clusterSize).divide(8);
        double x1 = x + 8 + offset.x;
        double x2 = x + 8 - offset.x;
        double z1 = z + 8 + offset.y;
        double z2 = z + 8 - offset.y;
        double y1 = y + this.random.nextBoundedInt(3) + 2;
        double y2 = y + this.random.nextBoundedInt(3) + 2;
        for (int count = 0; count <= clusterSize; ++count) {
            double seedX = x1 + (x2 - x1) * count / clusterSize;
            double seedY = y1 + (y2 - y1) * count / clusterSize;
            double seedZ = z1 + (z2 - z1) * count / clusterSize;
            double size = ((Math.sin(count * (Math.PI / clusterSize)) + 1) * this.random.nextFloat() * clusterSize / 16 + 1) / 2;

            int startX = (int) (seedX - size);
            int startY = (int) (seedY - size);
            int startZ = (int) (seedZ - size);
            int endX = (int) (seedX + size);
            int endY = (int) (seedY + size);
            int endZ = (int) (seedZ + size);

            for (x = startX; x <= endX; ++x) {
                double sizeX = (x + 0.5 - seedX) / size;
                sizeX *= sizeX;

                if (sizeX < 1) {
                    for (y = startY; y <= endY; ++y) {
                        double sizeY = (y + 0.5 - seedY) / size;
                        sizeY *= sizeY;

                        if (y > 0 && (sizeX + sizeY) < 1) {
                            for (z = startZ; z <= endZ; ++z) {
                                double sizeZ = (z + 0.5 - seedZ) / size;
                                sizeZ *= sizeZ;

                                if ((sizeX + sizeY + sizeZ) < 1 && level.getBlockIdAt(x, y, z) == replaceId) {
                                    level.setBlockIdAt(x, y, z, this.type.material.getId());
                                    if (this.type.material.getDamage() != 0) {
                                        level.setBlockDataAt(x, y, z, this.type.material.getDamage());
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}