package de.siphalor.was.content.product.dynamic;

import de.siphalor.was.content.product.Product;
import de.siphalor.was.content.product.ProductType;
import de.siphalor.was.util.Util;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.function.IntPredicate;

/**
 * An implementation of {@link Product} that dynamically loads its data from a properties file
 */
public class DynamicProduct implements Product {
	/**
	 * The product's type
	 */
	private ProductType<?> type;
	/**
	 * The property values
	 */
	private final String[] properties;
	/**
	 * The depth of this product
	 */
	private int depth = 1;
	/**
	 * A function that checks if the product can go into the given y location
	 */
	@NotNull
	private IntPredicate yPredicate = Util.dummyIntPredicate();

	/**
	 * Constructs a new product with the given values as properties.
	 * @param properties The property values
	 */
	public DynamicProduct(String[] properties) {
		this.properties = properties;
	}

	/**
	 * Gets an identifier that uniquely represents the property values
	 * @return A concatenated list of the property values
	 */
	@Override
	@NotNull
	public String getPropertySpecifier() {
		return String.join("_", properties);
	}

	/**
	 * Gets the property values
	 * @return The property values
	 */
	@Override
	public String[] getProperties() {
		return properties;
	}

	/**
	 * Sets the depth of this product
	 * @param depth The depth
	 */
	public void setDepth(int depth) {
		this.depth = depth;
	}

	/**
	 * Gets the product's depth.
	 * @return The depth
	 */
	@Override
	public int getDepth() {
		return depth;
	}

	/**
	 * Test if the product can go into the given y layer.
	 * @param y The given y layer
	 * @return Whether the product is allowed to go into it
	 */
	@Override
	public boolean testY(int y) {
		return yPredicate.test(y);
	}

	/**
	 * Sets the type of this product. This is needed because the {@link DynamicProductType} needs to know all of its products and all products need to know their type
	 * @param type The products type
	 */
	void setType(ProductType<?> type) {
		this.type = type;
	}

	/**
	 * Gets the product's type.
	 * @return Returns the type.
	 */
	@Override
	@NotNull
	public ProductType<?> getType() {
		return type;
	}

	/**
	 * Checks if both products match.
	 * @param product The other product
	 * @return Returns whether both products match
	 */
	@Override
	public boolean equals(Product product) {
		return super.equals(product);
	}

	/**
	 * Sets the function for checking the y layer.
	 * @param yPredicate The function
	 */
	public void setYPredicate(@NotNull IntPredicate yPredicate) {
		this.yPredicate = yPredicate;
	}

	/**
	 * A toString function. Nothing to explain
	 * @return The object and its data converted to a string
	 */
	@Override
	public String toString() {
		return "DynamicProduct{" +
				"properties=" + Arrays.toString(properties) +
				", depth=" + depth +
				", yPredicate=" + yPredicate +
				'}';
	}
}
