package joshie.harvest.api.crops;
import joshie.harvest.api.HFApi;
import joshie.harvest.api.animals.AnimalFoodType;
import joshie.harvest.api.calendar.Season;
import joshie.harvest.api.cooking.Ingredient;
import joshie.harvest.api.core.HFRegistry;
import joshie.harvest.api.core.ISpecialRules;
import joshie.harvest.api.crops.IStateHandler.PlantSection;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.common.EnumPlantType;
import net.minecraftforge.common.IPlantable;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
//TODO: Remove forge registry in 0.7+
//Do not call setRegistryName or anything
//This is only extending the old forge registry for 0.5 > 0.6 compatability reason
public class Crop extends HFRegistry<Crop> implements IPlantable {
public static final Map<ResourceLocation, Crop> REGISTRY = new HashMap<>();
private static final GrowthHandler SEASONAL = new GrowthHandler() {};
private static final DropHandler DROPS = new DropHandler();
private static final ISpecialRules RULES = (w, p, a) -> true;
public static final Crop NULL_CROP = new Crop();
//CropData
private IStateHandler stateHandler;
private GrowthHandler growthHandler;
private DropHandler dropHandler;
private ISpecialRules rules;
private AnimalFoodType foodType;
private EnumPlantType type;
private Ingredient ingredient;
private boolean needsWatering;
private boolean alternativeName;
private boolean requiresSickle;
private ItemStack item;
private Season[] seasons;
private long cost;
private long sell;
private int stages;
private int regrow;
private int maxHarvests;
private int bagColor;
private int doubleStage;
private int minCut;
private boolean skipRender;
private Crop() {
this(new ResourceLocation("harvestfestival", "null_crop"));
}
public Crop(ResourceLocation key) {
super(key);
this.seasons = new Season[] { Season.SPRING };
this.stages = 3;
this.foodType = AnimalFoodType.VEGETABLE;
this.bagColor = 0xFFFFFF;
this.stateHandler = new StateHandlerDefault(this);
this.dropHandler = Crop.DROPS;
this.rules = Crop.RULES;
this.growthHandler = SEASONAL;
this.needsWatering = true;
this.doubleStage = Integer.MAX_VALUE;
this.type = EnumPlantType.Crop;
this.maxHarvests = 1;
}
/** Set how much this tree costs to buy and sell
* @param cost the cost
* @param sell the sell value**/
public Crop setValue(long cost, long sell) {
this.cost = cost;
this.sell = sell;
return this;
}
/** Set the colour of the seeds
* @param color the color */
public Crop setSeedColours(int color) {
this.bagColor = color;
return this;
}
/** Set the seasons this tree grows in **/
public Crop setSeasons(Season... seasons) {
this.seasons = seasons;
return this;
}
/** Set the growth lengths for this tree
* @param stages the number of stages **/
public Crop setStages(int stages) {
this.stages = stages;
return this;
}
/**
* Set the stage at which crops regrow to
**/
public Crop setRegrow(int regrow) {
this.regrow = regrow;
return this;
}
/**
* Set the maximum amount of harvests this crop can have
**/
public Crop setMaxHarvests(int maxHarvests) {
this.maxHarvests = maxHarvests;
return this;
}
/**
* If the crop/seeds should have different names set this to true
**/
public Crop setHasAlternativeName() {
this.alternativeName = true;
return this;
}
/** Set the item for this crop
* @param item the item to set this as**/
public Crop setItem(ItemStack item) {
this.item = item;
if (this.item != null && this.item.getItem() instanceof ItemFood) {
ItemFood food = (ItemFood)this.item.getItem();
setIngredient(food.getHealAmount(item), food.getSaturationModifier(item));
}
return this;
}
/** Overloaded mehtod for setItem
* @param item the item **/
public Crop setItem(Item item) {
setItem(new ItemStack(item));
return this;
}
/**
* Set the state handler for this crop
**/
public Crop setStateHandler(IStateHandler handler) {
this.stateHandler = handler;
return this;
}
/**
* Creates a state handler based on the passed in values
*/
public Crop setStages(int... stages) {
this.stages = stages[stages.length - 1];
this.stateHandler = new StateHandlerBasic(stages);
return this;
}
/**
* Creates a state handler for this block, based on the passed in values
*/
public Crop setStages(Block block, int... stages) {
this.stages = stages[stages.length - 1];
this.stateHandler = new StateHandlerBlock(block, stages);
return this;
}
/**
* Make this crop require a sickle to be harvested
* Sets the minimum cut
* Used when a crop requires the sickle,
* The crop will only be destroyable/harvestable
* if it's below this stage
*/
public Crop setRequiresSickle(int minCut) {
if (minCut <= - 1) {
this.requiresSickle = false;
this.minCut = 0;
} else {
this.requiresSickle = true;
this.minCut = minCut;
}
return this;
}
/**
* Set what this plant counts as for feeding animals
* @param foodType the type of food
**/
public Crop setAnimalFoodType(AnimalFoodType foodType) {
this.foodType = foodType;
return this;
}
/**
* Set the plant type
* @param plantType the plant type of this crop
**/
public Crop setPlantType(EnumPlantType plantType) {
this.type = plantType;
return this;
}
/**
* Set the ingredient stats for this crop
**/
public Crop setIngredient(int hunger, float saturation) {
String name = getResource().getResourcePath();
if (Ingredient.INGREDIENTS.containsKey(name)) {
this.ingredient = Ingredient.INGREDIENTS.get(name);
} else this.ingredient = new Ingredient(name, hunger, saturation);
return this;
}
/**
* Make this crop need zero water to grow
**/
public Crop setNoWaterRequirements() {
this.needsWatering = false;
return this;
}
/**
* Make this crop need water to grow
**/
public Crop setWaterRequirements() {
this.needsWatering = true;
return this;
}
/**
* Set the growth handler, to determine when this plant can grow/where
* @param handler the growth handler
**/
public Crop setGrowthHandler(GrowthHandler handler) {
this.growthHandler = handler;
return this;
}
/**
* Set the stage at which this plant becomes two tall
* @param doubleStage the stage this plant becomes double
**/
public Crop setBecomesDouble(int doubleStage) {
this.doubleStage = doubleStage;
return this;
}
/**
* Set the drop handler for this crop
* @param handler the drop handler
**/
public Crop setDropHandler(DropHandler handler) {
this.dropHandler = handler;
return this;
}
/**
* Set the purchase rules for this crop
* @param rules the rules to set
* **/
public Crop setPurchaseRules(ISpecialRules rules) {
this.rules = rules;
return this;
}
/**
* This crop doesn't need to load it's renders,
* It's blocks will be tinted as well
**/
public Crop setSkipRender() {
this.skipRender = true;
return this;
}
@Override
public final Map<ResourceLocation, Crop> getRegistry() {
return REGISTRY;
}
/**
* This is the season this crop survives in
*
* @return the season that is valid for this crop
*/
public Season[] getSeasons() {
return seasons;
}
/**
* This is how much the seed costs in the store.
* If the seed isn't purchasable return 0
*
* @return the cost in gold
*/
public long getSeedCost() {
return cost;
}
/**
* This is how much this crop well sell for at level 1.
* If this crop cannot be sold return 0
*
* @return the sell value in gold
*/
public long getSellValue() {
return sell;
}
/**
* Return how many stages this crop has.
* A return value of 0, means the crop is instantly grown.
*
* @return the stage
*/
public int getStages() {
return stages;
}
/**
* Return the stage that the plant returns to when it's harvested.
* A return value of 0, means the crop is destroyed.
*
* @return the stage
*/
public int getRegrowStage() {
return regrow;
}
/**
* This is the maximum amount of times this crop can be harvested
* Once it's reached, the crop will be destroyed instead
*
* @return the max harvests
*/
public int getMaxHarvests() {
return maxHarvests;
}
/** Used when a crop requires the sickle,
* The crop will only be destroyable/harvestable
* if it's below this stage */
public int getMinimumCut() {
return minCut;
}
/**
* Return true if this crop required a sickle
* **/
public boolean requiresSickle() {
return requiresSickle;
}
/**
* Return true if this crop requires water
* **/
public boolean requiresWater() {
return needsWatering;
}
/**
* Return true if this crop is turning double crop at this stage
* @param stage the stage of the crop
* **/
public boolean isTurningToDouble(int stage) {
return stage == doubleStage;
}
/**
* Return true if this crop is a double crop at this stage
* @param stage the stage of the crop
* **/
public boolean isCurrentlyDouble(int stage) {
return stage >= doubleStage;
}
/**
* Return the growth handler for this crop
* **/
public GrowthHandler getGrowthHandler() {
return growthHandler;
}
/**
* Return the colour of the seed bag
**/
public int getColor() {
return bagColor;
}
/**
* The type of animal food this is
**/
public AnimalFoodType getFoodType() {
return foodType;
}
/**
* The ingredient this crop represents
**/
public Ingredient getIngredient() {
return ingredient;
}
/**
* This crop as a seed stack
**/
public ItemStack getSeedStack(int amount) {
return HFApi.crops.getSeedStack(this, amount);
}
/**
* This crop as a stack
**/
public ItemStack getCropStack(int amount) {
if (item != null) {
ItemStack copy = item.copy();
copy.stackSize = amount;
return copy;
} else return new ItemStack(Items.BRICK);
}
/**
* What this crop drops
**/
public DropHandler getDropHandler() {
return dropHandler;
}
/**
* What this crop rules for purchase are
**/
public ISpecialRules getRules() {
return rules;
}
/**
* The state handler for crop
**/
public IStateHandler getStateHandler() {
return stateHandler;
}
/**
* If the stack is this crop
**/
public boolean matches(ItemStack stack) {
return HFApi.crops.getCropFromStack(stack) == this;
}
/**
* The planty type of this crop
**/
public EnumPlantType getPlantType() {
return type;
}
/** Whether to skip the render loading of this crop **/
public boolean skipLoadingRender() {
return skipRender;
}
/**
* Gets the localized crop name for this crop
*
* @param isItem the item
* @return crop name
*/
@SuppressWarnings("deprecation")
public String getLocalizedName(boolean isItem) {
String suffix = alternativeName ? ((isItem) ? ".item" : ".block") : "";
return I18n.translateToLocal((getResource().getResourceDomain() + ".crop." + StringUtils.replace(getResource().getResourcePath(), "_", ".") + suffix));
}
/**
* Gets the localized seed name for this crop
*
* @return seed name
*/
@SuppressWarnings("deprecation")
public String getSeedsName() {
String name = alternativeName ? I18n.translateToLocalFormatted((getResource().getResourceDomain() + ".crop." + StringUtils.replace(getResource().getResourcePath(), "_", ".") + ".block")) : item == null ? "NULL" : item.getDisplayName();
String seeds = I18n.translateToLocal("harvestfestival.crop.seeds");
String format = I18n.translateToLocal("harvestfestival.crop.seeds.format");
return String.format(format, name, seeds);
}
@Override
public EnumPlantType getPlantType(IBlockAccess world, BlockPos pos) {
return getPlantType();
}
@Override
@SuppressWarnings("unchecked")
public IBlockState getPlant(IBlockAccess world, BlockPos pos) {
return getStateHandler().getState(world, pos, PlantSection.BOTTOM, this, 1, false);
}
@Override
public boolean equals(Object o) {
return o == this || o instanceof Crop && getResource().equals(((Crop) o).getResource());
}
@Override
public int hashCode() {
return getResource().hashCode();
}
}