/*
 * Copyright (C) 2018 Andrew Gegg
 *
 *	This file is part of the Garden Notebook application
 *
 * The Garden Notebook application is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl.html>.
 */

/*
	WARNING
	This file is NOT generated.
 */

package uk.co.gardennotebook;

import uk.co.gardennotebook.spi.TrugServer;
import uk.co.gardennotebook.spi.IPlantSpecies;
import uk.co.gardennotebook.spi.IPlantSpeciesLister;
import uk.co.gardennotebook.spi.IComment;
import uk.co.gardennotebook.spi.IPlantVariety;
import uk.co.gardennotebook.spi.ITrug;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import uk.co.gardennotebook.spi.GNDBException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.EntryMessage;

/**
 *	An aggregate and facade on the various plant specific classes
 *	Used to show the plant catalogue
 * 
 * REPLACED BY PlantCatalogueBean
 * 
	*	@author Andy Gegg
	*	@version	1.1.1
	*	@since	1.0
 */
final class PlantCatalogueItem {
	
	private static final Logger LOGGER = LogManager.getLogger();

	private IPlantSpecies plantSpecies = null;
	private IPlantVariety plantVariety = null;
	
	private String nodeType = "";	// PS for PlantSpecies, PV for PlantVariety, PY for PlantSynonym
	
	private List<PlantCatalogueItem> speciesChildren = null;
	private List<PlantCatalogueItem> varietyChildren = null;
	
	private SimpleStringProperty commonName = null;
	private SimpleStringProperty latinName = null;
	private SimpleStringProperty description = null;
	
	PlantCatalogueItem(IPlantSpecies val)
	{
		plantSpecies = val;
		nodeType = "PS";
	}
	
	PlantCatalogueItem(IPlantVariety val)
	{	
		plantVariety = val;
		nodeType = "PV";
	}
	
	static List<PlantCatalogueItem> getPlantCatalogue()
	{
        ITrug server = TrugServer.getTrugServer().getTrug();
        IPlantSpeciesLister gal = server.getPlantSpeciesLister()/*.commonName("acidanthera")*/;
		List<PlantCatalogueItem> pc = Collections.emptyList();
		try {
			pc = gal.fetch().stream()
				.collect(ArrayList::new, (c, e) -> c.add(new PlantCatalogueItem(e)), ArrayList::addAll);
		} catch (GNDBException ex) {
			PanicHandler.panic(ex);
		}
		
		return pc;
	}
	
	Object getItem()
	{
		switch (nodeType)
		{
			case "PS": return plantSpecies;
			case "PV": return plantVariety;
			default:
				LOGGER.debug("PlantCatalogueItem: getItem(): unknown node type: {}", nodeType);
				return null;
		}
	}
	
	String getCommonName()
	{
		return commonNameProperty().getValue();
	}
	
	void setCommonName(String val)
	{
		commonNameProperty().setValue(val);
	}
	
	StringProperty commonNameProperty()
	{
		if (commonName == null)
		{
			commonName = new SimpleStringProperty(){
				@Override
				public String getValue() {
					switch (nodeType)
					{
						case "PS": return plantSpecies.getCommonName();
						case "PV": return plantVariety.getCommonName();
						default:
							LOGGER.debug("PlantCatalogueItem: getCommonName: Unknown node type: {}", nodeType);
							return "Unknown node type: "+ nodeType;
					}
				}

				@Override
				public String get() {
					return this.getValue();
				}

				@Override
				public void setValue(String v) 
				{
					try {
						switch (nodeType)
						{
							case "PS":  plantSpecies = TrugServer.getTrugServer().getTrug()
											.getPlantSpeciesBuilder(plantSpecies).commonName(v).save();
										break;
							case "PV":  plantVariety = TrugServer.getTrugServer().getTrug()
											.getPlantVarietyBuilder(plantVariety).commonName(v).save();
										break;
							case "PY":  break;
							default:
								LOGGER.debug("PlantCatalogueItem: getCommonName: Unknown node type: {}", nodeType);
						}
					} catch (IllegalArgumentException ex) {
						throw(ex);
					} catch (GNDBException ex) {
						PanicHandler.panic(ex);
					}
					fireValueChangedEvent();
				}

				@Override
				public void set(String newValue) {
					this.setValue(newValue);
				}

			};
		}
		return commonName;
	}

	final String getLatinName()
	{
		return latinNameProperty().getValue();
	}
	
	final void setLatinName(String val)
	{
		latinNameProperty().setValue(val);
	}
	
	StringProperty latinNameProperty()
	{
		if (latinName == null)
		{
			latinName = new SimpleStringProperty(){
				@Override
				public String getValue() {
					switch (nodeType)
					{
						case "PS": return plantSpecies.getLatinName().orElse("");
						case "PV": return plantVariety.getLatinName().orElse("");
						case "PY": return "";
						default:
System.out.println("PlantCatalogueItem: getLatinName: Unknown node type: "+ nodeType);
							return "Unknown node type: "+ nodeType;
					}
				}

				@Override
				public String get() {
					return this.getValue();
				}

				@Override
				public void setValue(String v)
				{
					try {
						switch (nodeType)
						{
							case "PS":  plantSpecies = TrugServer.getTrugServer().getTrug()
											.getPlantSpeciesBuilder(plantSpecies).latinName(v).save();
										break;
							case "PV":  plantVariety = TrugServer.getTrugServer().getTrug()
											.getPlantVarietyBuilder(plantVariety).latinName(v).save();
										break;
							case "PY":  break;
							default:
								LOGGER.debug("PlantCatalogueItem: getLatinName: Unknown node type: {}", nodeType);
						}
					} catch (GNDBException ex) {
						PanicHandler.panic(ex);
					}
					fireValueChangedEvent();
				}

				@Override
				public void set(String newValue) {
					this.setValue(newValue);
				}

			};
		}
		return latinName;
	}
	
	final String getDescription()
	{
		return descriptionProperty().getValue();
	}
	
	final void setDescription(String val)
	{
		latinNameProperty().setValue(val);
	}
	
	StringProperty descriptionProperty()
	{
		if (description == null)
		{
			description = new SimpleStringProperty(){
				@Override
				public String getValue()
				{
					switch (nodeType)
					{
						case "PS": return plantSpecies.getDescription().orElse("");
						case "PV": return plantVariety.getDescription().orElse("");
						case "PY": return "";
						default:
System.out.println("PlantCatalogueItem: getDescription: Unknown node type: "+ nodeType);
							return "Unknown node type: "+ nodeType;
					}
				}

				@Override
				public String get() {
					return this.getValue(); //To change body of generated methods, choose Tools | Templates.
				}

				@Override
				public void setValue(String v)
				{
					try {
						switch (nodeType)
						{
							case "PS":  plantSpecies = TrugServer.getTrugServer().getTrug()
											.getPlantSpeciesBuilder(plantSpecies).description(v).save();
										break;
							case "PV":  plantVariety = TrugServer.getTrugServer().getTrug()
											.getPlantVarietyBuilder(plantVariety).description(v).save();
										break;
							case "PY":  break;
							default:
								LOGGER.debug("PlantCatalogueItem: getDescription: Unknown node type: {}", nodeType);
						}
					} catch (GNDBException ex) {
						PanicHandler.panic(ex);
					}
					fireValueChangedEvent();
				}

				@Override
				public void set(String newValue) {
					this.setValue(newValue); //To change body of generated methods, choose Tools | Templates.
				}

			};
		}
		return description;
	}
	
	String getComments()
	{
		List<IComment> comments = null;
		switch (nodeType)
		{
			case "PS": comments = plantSpecies.getComments();
				break;
			case "PV": comments = plantVariety.getComments();
				break;
			default:
					LOGGER.debug("PlantCatalogueItem: getComments: Unknown node type: {}", nodeType);
				return "Unknown node type: " + nodeType;
		}
		StringBuilder out = new StringBuilder();
		boolean first = true;
		for (IComment ct : comments)
		{
			if (!first)
			{
				out.append("\n");
			}
			out.append(ct.getDate()).append(" ").append(ct.getComment());
			first = false;
		}
		return out.toString();
	}
	
	List<PlantCatalogueItem> getChildren()
	{
		switch (nodeType)
		{
			case "PS": 
				if (speciesChildren == null)
				{
					speciesChildren = new ArrayList<>();
					List<IPlantVariety> pvList = Collections.emptyList();
					try {
						pvList = plantSpecies.getPlantVariety().fetch();
					} catch (GNDBException ex) {
						PanicHandler.panic(ex);
					}
					for (IPlantVariety pv : pvList)
					{
						speciesChildren.add(new PlantCatalogueItem(pv));
					}
				}
				return speciesChildren;
			case "PV":
				if (varietyChildren == null)
				{
					varietyChildren = new ArrayList<>();
				}
				return varietyChildren;
			case "PY": return Collections.emptyList();
		}
		LOGGER.debug("PlantCatalogueItem: getChildren: Unknown node type: {}", nodeType);
		return Collections.emptyList();
	}
	
	boolean isLeaf()
	{
		// this called from isLeaf() on the TreeItem A LOT so actually getting the childrn is delayed until requested
		switch (nodeType)
		{
			case "PS": 
				if (speciesChildren == null)
				{
					return false;
				}
				return speciesChildren.isEmpty();
			case "PV":
				if (varietyChildren == null)
				{
					return false;
				}
				return varietyChildren.isEmpty();
			case "PY": return true;
		}
System.out.println("PlantCatalogueItem: isLeaf: Unknown node type: "+ nodeType);
		return true;
	}
	
	@Override
	public String toString()
	{
		switch (nodeType)
		{
			case "PS": return "PlantCatalogueItem of: " + plantSpecies.toString();
			case "PV": return "PlantCatalogueItem of: " +plantVariety.toString();
		}
		return "Unknown type: " + nodeType;
	}
}
