/********************************************************************
	Minecraft: Pocket Edition - Decompilation Project
	Copyright (C) 2023 iProgramInCpp
	
	The following code is licensed under the BSD 1 clause license.
	SPDX-License-Identifier: BSD-1-Clause
 ********************************************************************/

#include "Feature.hpp"
#include "world/level/Level.hpp"

bool TreeFeature::place(Level* level, Random* random, int x, int y, int z)
{
	if (y <= C_MIN_Y)
		return false;

	int treeHeight = int(random->nextInt(3) + 4); // Between 4 and 6 blocks tall.

	if (y + treeHeight >= C_MAX_Y)
		return false;

	// Ensure that we can place this tree
	bool bCanPlace = true;
	for (int ay = y; ay <= y + treeHeight; ay++)
	{
		int x1 = 1;
		if (y + treeHeight - 1 <= ay)
			x1 = 2;
		else if (ay == y)
			x1 = 0;

		for (int ax = x - x1; ax <= x + x1 && bCanPlace; ax++)
		{
			for (int az = z - x1; az <= z + x1 && bCanPlace; az++)
			{
				if (ay < C_MIN_Y || ay >= C_MAX_Y)
				{
					bCanPlace = false;
					break;
				}

				TileID tile = level->getTile(ax, ay, az);

				// other trees can overlap with this one, apparently
				if (tile != TILE_AIR && tile != Tile::leaves->m_ID)
				{
					bCanPlace = false;
					break;
				}
			}
		}
	}

	// If not, let our caller know.
	if (!bCanPlace)
		return false;

	TileID tileBelow = level->getTile(x, y - 1, z);

	// If grass or dirt aren't below us, we can't possibly grow!
	if (tileBelow != Tile::grass->m_ID && tileBelow != Tile::dirt->m_ID)
		return false;

	// @NOTE: Redundant check
	if (y >= C_MAX_Y - treeHeight)
		return false;

	level->setTileNoUpdate(x, y - 1, z, Tile::dirt->m_ID);

	int upperY = y + treeHeight;
	int lowerY = y + treeHeight - 3;
	int diff = lowerY - upperY;

	for (int i = lowerY; i <= upperY; i++, diff = i - upperY)
	{
		int c1 = 1 - diff / 2;
		int c2 = diff / 2 - 1;
		for (int ax = x - c1; ax <= x + c1; ax++)
		{
			int c3 = c2;
			int c4 = diff / 2 - 1;
			if (c2 < 0)
				c3 = -c2;

			//int c5 = c3;

			for (int az = z - c1; az <= z + c1; az++, c4++)
			{
                if ((abs(ax - x) != c1 || abs(az - z) != c1 || (random->nextInt(2) != 0 && diff != 0)) && !Tile::solid[level->getTile(ax, i, az)])
				{
					level->setTileNoUpdate(ax, i, az, Tile::leaves->m_ID);
				}
			}
		}
	}

	for (int i = 0; i < treeHeight; i++)
	{
		//int y1 = i + y;
		TileID tile = level->getTile(x, y + i, z);
		if (tile && tile != Tile::leaves->m_ID)
			continue;

		level->setTileNoUpdate(x, y + i, z, Tile::treeTrunk->m_ID);
	}

	return true;
}
