/*
 * Copyright (C) 2018-2020, 2022 Andrew Gegg
 *
 *	This file is part of the Garden Notebook application
 *
 * 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>.
 */

/*
	Change log
	2.4.0   Use version string embedded in GardenNotebook class
    2.6.0   Fix divider position in outer split pane
    2.8.0   Top level menu options to add a single event
    2.8.1   Disable JSON import unless DB is empty - easy to hit it by accident!
    2.9.0   Implement a Help system
    3.0.2	Convenience features on ToDoList
    3.0.3	Fix (I hope) problem setting paneOuterSplit divider position.  See the FXML for details.
	3.0.5	Use factory pattern DiaryBean
	3.1.0	Trap DateTimeParseException to avoid pointless stack trace (JavaFX bug)
	3.1.1	Use PanicHandler in last gasp Exception handling
 */

package uk.co.gardennotebook;

import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;

import javafx.stage.WindowEvent;
import uk.co.gardennotebook.fxbean.HusbandryBean;
import uk.co.gardennotebook.spi.TrugServer;

import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.prefs.Preferences;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SplitPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.ToolBar;
//import javafx.scene.input.KeyCode;
//import javafx.scene.input.KeyEvent;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import uk.co.gardennotebook.fxbean.ToDoListBean;
import uk.co.gardennotebook.spi.ITrug;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.EntryMessage;
import static uk.co.gardennotebook.GardenNotebook.NOTEBOOK_VERSION;
import uk.co.gardennotebook.spi.GNDBException;
import uk.co.gardennotebook.util.StoryLineTree;

/**
 * The top level window for the Garden Notebook
 *
 * @author Andy Gegg
*	@version	3.1.1
*	@since	1.0
* */
public final class TopController
{
	private static final Logger LOGGER = LogManager.getLogger();
    
    @FXML
    MenuItem mnuJSONLoad;
    
    @FXML
    private SplitPane paneOuterSplit;
    @FXML
    private SplitPane paneTopSplit;
    @FXML
    private AnchorPane paneTop;
    @FXML
    private AnchorPane paneTopSub1;
    @FXML
    private TabPane tabPaneNav;
    @FXML
    private TabPane tabPaneTop;
	@FXML
	private ToolBar toolBarTop;
	@FXML
	private TableView<ToDoListBean> todoList;
	@FXML
	private TableColumn<ToDoListBean, String> todoHusbandryClass; 
	@FXML
	private TableColumn<ToDoListBean, String> todoGroundworkActivity; 
	@FXML
	private TableColumn<ToDoListBean, String> todoPlantSpecies; 
	@FXML
	private TableColumn<ToDoListBean, String> todoPlantVariety; 
	@FXML
	private TableColumn<ToDoListBean, String> todoDescription;

	@FXML
	private MenuItem ctxmnuToDoPriorHistory;
	@FXML
	private MenuItem ctxmnuToDoOrigin;

	private Consumer<Node> loadSplit;
	private Consumer<Node> clearSplit;
	private BiConsumer<String, Node> loadTab;
	private Consumer<Node> clearTab;
	@FXML
	private AnchorPane topNavBox;
	
	@FXML
	private ResourceBundle resources;
	
	/**
     * Initializes the controller class.
     */
	@FXML
    private void initialize() {
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("initialize()");

		SplitPane.setResizableWithParent(topNavBox, false);
		loadSplit = (con) -> {
			for (Node o : paneTopSplit.getItems())
				if (o.getClass().equals(con.getClass())) return;
			int numSplits = paneTopSplit.getItems().size();
			paneTopSplit.getItems().add(numSplits-1, con);
            con.requestFocus();
			double splitPos = paneTopSplit.getDividers().get(0).getPosition();
			int jx = 1;
			for (SplitPane.Divider div : paneTopSplit.getDividers())
			{
				div.setPosition((jx++)*splitPos);
			}
			((INotebookLoadable)con).setLoadSplit(loadSplit);
			((INotebookLoadable)con).setClearSplit(clearSplit);
			((INotebookLoadable)con).setLoadTab(loadTab);
		};
		
		clearSplit = (con) -> {
			for (Node o : paneTopSplit.getItems())
				if (o.getClass().equals(con.getClass())) {
					paneTopSplit.getItems().remove(o);
					return;
				}
		};
		
		loadTab = (name, con) -> {
			Tab fred = new Tab(name);
			fred.setContent(con);
			fred.setOnCloseRequest(e -> ((INotebookLoadable)con).clearUpOnClose(e));
			tabPaneTop.getTabs().add(fred);
			tabPaneTop.getSelectionModel().select(fred);
            con.requestFocus();
			((INotebookLoadable)con).setLoadSplit(loadSplit);
			((INotebookLoadable)con).setClearSplit(clearSplit);
			((INotebookLoadable)con).setLoadTab(loadTab);
			((INotebookLoadable)con).setClearTab(x->tabPaneTop.getTabs().remove(fred) );
		};

		// set a custom resize policy so that the Comments column takes up all available space on the right
		todoList.setColumnResizePolicy(NotebookResizer.using(todoList));
		todoHusbandryClass.setCellValueFactory(cdf -> cdf.getValue().hasHusbandryClass() ? cdf.getValue().getHusbandryClass().nameProperty() : null	);
		todoGroundworkActivity.setCellValueFactory(cdf -> cdf.getValue().hasGroundworkActivity() ? cdf.getValue().getGroundworkActivity().nameProperty() : null	);
		todoPlantSpecies.setCellValueFactory(cdf -> cdf.getValue().hasPlantSpecies() ? cdf.getValue().getPlantSpecies().commonNameProperty() : null );
		todoPlantVariety.setCellValueFactory(cdf -> cdf.getValue().hasPlantVariety() ? cdf.getValue().getPlantVariety().commonNameProperty() : null );
		todoDescription.setCellValueFactory(cdf -> cdf.getValue().descriptionProperty());

		getTodoList();
        
        mnuJSONLoad.setDisable(!isDatabaseEmpty());
		
        final Preferences prefs = Preferences.userNodeForPackage(GardenNotebook.class);
        LOGGER.debug("init: prefs: windowOuterSplitDivide: {}", prefs.getDouble("windowOuterSplitDivide", 0.90));
       //  2.6.0
        // NB need to use runLater or it doesn't (always) take
//        Platform.runLater(() -> {
			paneOuterSplit.setDividerPositions(prefs.getDouble("windowOuterSplitDivide", 0.90));
//				}
//        );
        // handle F1 for help - really difficult to determine the intended target
//        Platform.runLater(() -> {
//                final Scene scene = paneOuterSplit.getScene();
//                LOGGER.info("scene: {}", scene);
//                scene.addEventFilter(KeyEvent.KEY_PRESSED, ev->{
////                    var src = ev.getSource(); // src is always the scene
////                    LOGGER.info("src: {}", src);
//                    var target = ev.getTarget();
//                    LOGGER.info("target: {}", target);
//                    
//                    KeyCode key = ev.getCode();
//                    LOGGER.info("key: {}", key.getName());
//                    if (key.equals(KeyCode.F1))
//                    {
//                        LOGGER.info("got an F1");
//                        ev.consume();
//                    }
//                });
//            }
//        );

		Thread.setDefaultUncaughtExceptionHandler((thread, throwable)-> {
			if (throwable instanceof DateTimeParseException dtp)
			{
				//	tabbing out of a DatePicker with a garbled text throws an Exception which cannot be caught anywhere else
				//	This is bug JDK-8303478 in DatePicker
				LOGGER.debug("TopController: last gasp Exception handler: DateTimeParseException ignored: message: {}, date text: {}", dtp.getMessage(), dtp.getParsedString());
				return;
			}
			LOGGER.info("TopController: last gasp Exception handler: Uncaught exception in thread: {}", thread);
			LOGGER.info("TopController: last gasp Exception handler: Throwable: {}", throwable);
			PanicHandler.panic(throwable);
		});

		LOGGER.traceExit(log4jEntryMsg);
    }
    
    private boolean isDatabaseEmpty()
    {
        boolean emptyValue = false;
		try {
			emptyValue = TrugServer.getTrugServer().getTrug().isDatabaseEmpty();
		} catch (GNDBException ex) {
			PanicHandler.panic(ex);
		}
        return emptyValue;
    }
	
	private void getTodoList()
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("getTodoList()");
		List<ToDoListBean> actions = FXCollections.emptyObservableList();
		try {
			actions = ToDoListBean.fetchAll();
		} catch (GNDBException ex) {
			PanicHandler.panic(ex);
		}
		if (actions.isEmpty())
		{
			todoList.setVisible(false);
			return;
		}

//        // set a custom resize policy so that the Comments column takes up all available space on the right
//		todoList.setColumnResizePolicy(NotebookResizer.using(todoList));
//		todoHusbandryClass.setCellValueFactory(cdf -> cdf.getValue().hasHusbandryClass() ? cdf.getValue().getHusbandryClass().nameProperty() : null	);
//		todoGroundworkActivity.setCellValueFactory(cdf -> cdf.getValue().hasGroundworkActivity() ? cdf.getValue().getGroundworkActivity().nameProperty() : null	);
//		todoPlantSpecies.setCellValueFactory(cdf -> cdf.getValue().hasPlantSpecies() ? cdf.getValue().getPlantSpecies().commonNameProperty() : null );
//		todoPlantVariety.setCellValueFactory(cdf -> cdf.getValue().hasPlantVariety() ? cdf.getValue().getPlantVariety().commonNameProperty() : null );
//		todoDescription.setCellValueFactory(cdf -> cdf.getValue().descriptionProperty());
//
		todoList.getItems().setAll(actions);
		LOGGER.traceExit(log4jEntryMsg);
	}

    @FXML
    private void btnTopShoppingOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("btnTopShoppingOnAction()");
		ShopCatalogues customTest = new ShopCatalogues();
		SplitPane.setResizableWithParent(customTest, false);
		loadSplit.accept(customTest);
	}

    @FXML
    private void btnTopDiaryOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("btnTopDiaryOnAction()");
		DiarySelector customTest = new DiarySelector();
		loadTab.accept(resources.getString("tab.diaryselector"), customTest);
	}

    @FXML
    private void btnTopPlantCatalogueOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("btnTopPlantCatalogueOnAction()");
		PlantCatalogueTab customTest = new PlantCatalogueTab();
		loadTab.accept(resources.getString("tab.plantcatalogue"), customTest);
	}

    @FXML
    private void btnTopCataloguesOnAction(ActionEvent event) 
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("btnTopCataloguesOnAction()");
		TopCatalogues customTest = new TopCatalogues();
		SplitPane.setResizableWithParent(customTest, false);
		loadSplit.accept(customTest);
	}

    @FXML
    private void btnTopRemindersOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("btnTopRemindersOnAction()");
		ReminderCat customTest = new ReminderCat();
		loadTab.accept(resources.getString("tab.remindercatalogue"), customTest);
	}

	@FXML
	private void btnTopReviewsOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("btnTopReviewsOnAction()");
		try
		{
			TrugServer.getTrugServer().getTrug().getReviewLister().fetch();
		}
		catch (GNDBException e)
		{
			e.printStackTrace();
		}
		ReviewCat customTest = new ReviewCat();
		loadTab.accept(resources.getString("tab.reviewcatalogue"), customTest);
	}

	@FXML
	private void btnTopPlanningOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("btnTopPlanningOnAction()");
		PlanningCatalogues customTest = new PlanningCatalogues();
		SplitPane.setResizableWithParent(customTest, false);
		loadSplit.accept(customTest);
	}

	@FXML
    /*
    *  When the Help button is clicked it has the focus, so make a guess at what is wanted:
    *   - the selected tab in the work area, if any
    *   - the right-most nav tab if present
    *   - the start here nav tab (which is always present)
    */
    private void btnHelpOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("btnHelpOnAction()");
        
        String webPage = "MainPage";
        String anchor = null;
        
        final Tab focusedTopTab = tabPaneTop.getSelectionModel().getSelectedItem();
        LOGGER.debug("focusedTopTab: {}", focusedTopTab);
        if (focusedTopTab != null)
        {
            webPage = focusedTopTab.getContent().getClass().getSimpleName();
        }
        else
        {// there are always at least 2 splits, the first always has the 'start here tab' and the last is the working area tab pane
            List<Node> topTabs = paneTopSplit.getItems();
            final int cnt = topTabs.size();
            if (cnt < 3)
            {// only 'start here' and 'working area'
                anchor = "startHereTab";
            }
            else
            {
                anchor = topTabs.get(cnt-2).getClass().getSimpleName();
            }
        }

        LOGGER.debug("webPage: {}, anchor: {}", webPage, anchor);

        Parent root = new NotebookHelp(webPage, anchor);
		Scene scene = new Scene(root);
		Stage stage = new Stage();

        stage.setTitle(String.format(resources.getString("app.title"), NOTEBOOK_VERSION));  //  2.4.0
		stage.setScene(scene);
		stage.show();
	}

    @FXML
    private void mnuJsonDumpOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuJsonDumpOnAction()");
		Preferences prefs = Preferences.userNodeForPackage(GardenNotebook.class).node("JSON");
		final ITrug server = TrugServer.getTrugServer().getTrug();
		this.paneTop.getScene().setCursor(Cursor.WAIT);
		Task<Void> task = new Task<>()
		{
			@Override
			protected Void call() throws Exception
			{
				try
				{
					server.toJson(prefs);
				}
				catch (IOException ex)
				{
					LOGGER.error("Failed to create dump directory: {}", ex);
					throw new GNDBException(ex);
				}
				catch (GNDBException ex)
				{
					LOGGER.error("Database Error");
					this.failed();
					Platform.runLater(() -> PanicHandler.panic(ex));
				}
				return null;
			}
		};
		task.setOnSucceeded(e -> this.paneTop.getScene().setCursor(Cursor.DEFAULT));
        task.setOnFailed(e -> this.paneTop.getScene().setCursor(Cursor.DEFAULT));
		new Thread(task).start();
		LOGGER.traceExit(log4jEntryMsg);
	}

    @FXML
    private void mnuJsonLoadOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuJsonLoadOnAction()");
		Preferences prefs = Preferences.userNodeForPackage(GardenNotebook.class).node("JSON");
		if (!checkJSONLoadDirValid(prefs))
		{
			Alert checkValid = new Alert(Alert.AlertType.INFORMATION, resources.getString("alert.jsonLoadInvalid"), ButtonType.OK);
			Optional<ButtonType> result = checkValid.showAndWait();
			LOGGER.debug("directory not valid for JSON load");
			return;

		}
		final ITrug server = TrugServer.getTrugServer().getTrug();
		this.paneTop.getScene().setCursor(Cursor.WAIT);
		Task<Void> task = new Task<>()
		{
			@Override
			protected Void call() throws Exception
			{
				try
				{
					server.fromJson(prefs);
				}
				catch (IOException ex)
				{
					LOGGER.error("IO error: " + ex.getMessage());
					LOGGER.error("The JSON Load Directory {} is not a directory", prefs.get("JSONLoadDir", "JSONLoadDir"));
					Platform.runLater(() -> PanicHandler.panic(ex));
				}
				catch (GNDBException ex)
				{
					LOGGER.error("Database Error", ex);
					this.failed();
					Platform.runLater(() -> PanicHandler.panic(ex));
				}
				return null;
			}
		};
		task.setOnSucceeded(e -> this.paneTop.getScene().setCursor(Cursor.DEFAULT));
        task.setOnFailed(e -> this.paneTop.getScene().setCursor(Cursor.DEFAULT));
		new Thread(task).start();
		LOGGER.traceExit(log4jEntryMsg);
	}

	private boolean checkJSONLoadDirValid(Preferences prefs)
	{
		File loadDir = new File(prefs.get("loadDir", "JSONLoadDir"));
		if (!loadDir.isDirectory())
		{
			return false;
		}
		File jsonFile = new File(loadDir, "PlantSpecies.json");
		return jsonFile.exists();
	}

    @FXML
    private void btnExitOnAction(ActionEvent event) 
	{
        final Preferences prefs = Preferences.userNodeForPackage(GardenNotebook.class);
        prefs.putDouble("windowHeight", this.paneTop.getScene().getWindow().getHeight());
        prefs.putDouble("windowWidth", this.paneTop.getScene().getWindow().getWidth());
        prefs.putDouble("windowOuterSplitDivide", paneOuterSplit.getDividerPositions()[0]);
		Platform.exit();
	}
	
     @FXML
    private void mnuExitOnAction(ActionEvent event) 
	{
        final Preferences prefs = Preferences.userNodeForPackage(GardenNotebook.class);
        prefs.putDouble("windowHeight", this.paneTop.getScene().getWindow().getHeight());
        prefs.putDouble("windowWidth", this.paneTop.getScene().getWindow().getWidth());
        prefs.putDouble("windowOuterSplitDivide", paneOuterSplit.getDividerPositions()[0]);
		Platform.exit();
	}
	
   @FXML
    private void mnuConfigOnAction(ActionEvent event) 
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuConfigOnAction()");
		Parent root = new NotebookConfig(false);
		Scene scene = new Scene(root);
		Stage stage = new Stage();

        stage.setTitle(String.format(resources.getString("app.title"), NOTEBOOK_VERSION));  //  2.4.0
		stage.setScene(scene);
		stage.show();
	}
	
   @FXML
    private void mnuHelpAboutOnAction(ActionEvent event) 
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuHelpAboutOnAction()");
		Parent root = new NotebookAbout();
		Scene scene = new Scene(root);
		Stage stage = new Stage();

        stage.setTitle(String.format(resources.getString("app.title"), NOTEBOOK_VERSION));  //  2.4.0
		stage.setScene(scene);
		stage.show();
	}

	@FXML
	private void ctxmnuToDoTop (WindowEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("ctxmnuToDoTop()");
		ToDoListBean tdb = todoList.getSelectionModel().getSelectedItem();
		ctxmnuToDoOrigin.setDisable(!tdb.hasHusbandry());
		ctxmnuToDoPriorHistory.setDisable(!tdb.hasHusbandry());
	}

	@FXML
    private void ctxmnuToDoCompleteOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("ctxmnuToDoCompleteOnAction()");
		final ToDoListBean tdb = todoList.getSelectionModel().getSelectedItem();
		try {
			tdb.completeAction(hb -> {
				HusbandryEditor customTest = new HusbandryEditor(hb);
				loadTab.accept(resources.getString("tab.husbandry"), customTest);
			},
					gb -> {
						GroundworkEditor customTest = new GroundworkEditor(gb);
						loadTab.accept(resources.getString("tab.groundwork"), customTest);
					});
		} catch (GNDBException ex) {
			PanicHandler.panic(ex);
		}
		todoList.getItems().remove(tdb);
		if (todoList.getItems().isEmpty())
		{
			todoList.setVisible(false);
		}
	}
	
	@FXML
    private void ctxmnuToDoDismissOnAction(ActionEvent event)
	{
		Alert checkDelete = new Alert(Alert.AlertType.CONFIRMATION, resources.getString("alert.confirmdelete"), ButtonType.NO, ButtonType.YES);
		Optional<ButtonType> result = checkDelete.showAndWait();
		if (result.isPresent() && result.get() == ButtonType.YES)
		{
			final ToDoListBean tdb = todoList.getSelectionModel().getSelectedItem();
			try {
				tdb.delete();
			} catch (GNDBException ex) {
				PanicHandler.panic(ex);
			}
			todoList.getItems().remove(tdb);
			if (todoList.getItems().isEmpty())
			{
				todoList.setVisible(false);
			}
		}
	}

	@FXML
	private void ctxmnuToDoDelayOnAction(ActionEvent event)
	{
		Alert checkDelay = new Alert(Alert.AlertType.CONFIRMATION, resources.getString("alert.confirmdelay"), ButtonType.NO, ButtonType.YES);
		Optional<ButtonType> result = checkDelay.showAndWait();
		if (result.isPresent() && result.get() == ButtonType.YES)
		{
			final ToDoListBean tdb = todoList.getSelectionModel().getSelectedItem();
			try
			{
				tdb.delayAction();
			} catch (GNDBException ex)
			{
				PanicHandler.panic(ex);
			}
			todoList.getItems().remove(tdb);
			if (todoList.getItems().isEmpty())
			{
				todoList.setVisible(false);
			}
		}
	}

	@FXML
	private void ctxmnuToDoOrigin (ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("ctxmnuToDoOrigin()");
		final ToDoListBean tdb = todoList.getSelectionModel().getSelectedItem();
		if (tdb.hasHusbandry())
		{
			final HusbandryBean hb = tdb.getHusbandry();
			final HusbandryEditor customTest = new HusbandryEditor(hb);
			loadTab.accept(resources.getString("tab.husbandry"), customTest);
		}
	}

	@FXML
	private void ctxmnuToDoPriorHistory (ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("ctxmnuToDoPriorHistory()");
		final ToDoListBean tdb = todoList.getSelectionModel().getSelectedItem();
		if (tdb.hasHusbandry())
		{
			final HusbandryBean hb = tdb.getHusbandry();
			try
			{
				if (hb.hasAncestor())
				{
					final DiaryBean diaryBean = DiaryBean.from(hb);
					final StoryLineTree<DiaryBean> history = diaryBean.getAncestors();
					final StoryLineTab tabCon = new StoryLineTab();
					loadTab.accept(resources.getString("tab.ancestors"), tabCon);
					tabCon.setHistory(history);
				}
			}
			catch (GNDBException ex)
			{
				PanicHandler.panic(ex);
			}
		}
	}

	@FXML
	private void ctxmnuToDoRefresh(ActionEvent event)
	{
		getTodoList();
	}

	@FXML
    private void mnuNewAfflictionOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuNewAfflictionOnAction()");
		AfflictionEventEditor customTest = new AfflictionEventEditor();
		loadTab.accept(resources.getString("tab.affliction"), customTest);
	}
	
	@FXML
    private void mnuNewGroundworkOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuNewGroundworkOnAction()");
		GroundworkEditor customTest = new GroundworkEditor();
		loadTab.accept(resources.getString("tab.groundwork"), customTest);
	}
	
	@FXML
    private void mnuNewHusbandryOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuNewHusbandryOnAction()");
		HusbandryEditor customTest = new HusbandryEditor();
		loadTab.accept(resources.getString("tab.husbandry"), customTest);
	}
	
	@FXML
    private void mnuNewPurchaseOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuNewPurchaseOnAction()");
		PurchaseEditor customTest = new PurchaseEditor();
		loadTab.accept(resources.getString("tab.purchase"), customTest);
	}
	
	@FXML
    private void mnuNewSaleOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuNewSaleOnAction()");
		SaleEditor customTest = new SaleEditor();
		loadTab.accept(resources.getString("tab.sales"), customTest);
	}
	
	@FXML
    private void mnuNewWeatherOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuNewWeatherOnAction()");
		WeatherEditor customTest = new WeatherEditor();
		loadTab.accept(resources.getString("tab.weather"), customTest);
	}
	
	@FXML
    private void mnuNewWildlifeOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuNewWildlifeOnAction()");
		WildlifeEditor customTest = new WildlifeEditor();
		loadTab.accept(resources.getString("tab.wildlife"), customTest);
	}

	@FXML
	private void mnuNewJournalOnAction(ActionEvent event)
	{
		EntryMessage log4jEntryMsg = LOGGER.traceEntry("mnuNewWildlifeOnAction()");
		JournalEditor customTest = new JournalEditor();
		loadTab.accept(resources.getString("tab.journal"), customTest);
	}

	private void shutdown(int errCode)
	{
		System.exit(errCode);
	}

    @FXML
    private void btnTestJSONOnAction(ActionEvent event)
	{
		Preferences prefs = Preferences.userNodeForPackage(GardenNotebook.class).node("JSON");
        ITrug server = TrugServer.getTrugServer().getTrug();
		try {
			server.toJson(prefs);
		} catch (IOException ex) {
			LOGGER.error("The JSON Dump Directory {} is not a directory", prefs.get("JSONDumpDir", "JSONDumpDir"));
			Alert errBox = new Alert(Alert.AlertType.ERROR, MessageFormat.format(resources.getString("alert.config.dumpdirectoryinvalid"), prefs.get("JSONDumpDir", "JSONDumpDir")), ButtonType.OK);
			errBox.showAndWait();
		} catch (GNDBException ex) {
			PanicHandler.panic(ex);
		}
	}
    
//    @FXML
//    private void startTabOnKeyPressed(KeyEvent ev)
//    {
//        System.out.println("startTabOnKeyPressed: ev: " + ev);
//    }

//    @FXML
//    private void btnTestMoneyOnAction(ActionEvent event) {
//		SimpleMoney fred = SimpleMoney.parse("£12.34");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '£12.34': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("£ 12.34");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '£ 12.34': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("   £	12.34    ");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '   £	12.34    ': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("£ 12");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '£ 12': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("£ 12.3");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '£ 12.3': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("€12.34");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '€12.34': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("12.34");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '12.34': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("GBP 12.34");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): 'GBP 12.34': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("EUR 12.34");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): 'EUR 12.34': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("EUR 1234567.89");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): 'EUR 1234567.89': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("USD 12.34");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): 'USD 12.34': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("$12.34");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '$12.34': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("US$12.34");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): 'US$12.34': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("£ 1234567.89");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '£ 1234567.89': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("£ 1,234,567.89");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '£ 1,234,567.89': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse(null);
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): 'null': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("     ");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): '     ': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//		System.out.println("");
//		fred = SimpleMoney.parse("rubbish");
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): 'rubbish': "+fred.toString());
//		System.out.println("notebook.TopController.btnTestMoneyOnAction(): check it can read its own writing: "+SimpleMoney.parse(fred.toString()));
//	}
    
}
