/*
 * 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/>.
 */
package uk.co.gardennotebook;

import java.util.List;
import javafx.collections.MapChangeListener;
import javafx.scene.control.ResizeFeaturesBase;
import javafx.scene.control.TableColumnBase;
import javafx.scene.control.TableView;
import javafx.scene.control.TreeTableView;
import javafx.util.Callback;

/**
 *	A column resize policy for the various tables used in the interface.
 * 
 * When the table width is adjusted or a column is resized (e.g. by dragging)
 * the right-most column is resized to accommodate the change; all other columns 
 * are left at their current width.
 * 
 * @author Andy Gegg
*	@version	1.0
*	@since	1.0
 */
final class NotebookResizer {
	
	private NotebookResizer()
	{	}
	
	private static class TreeTableNotebookResizer
	{
		private double contentWidth;
		private final TreeTableView table;
		
		TreeTableNotebookResizer(TreeTableView table)
		{
			table.getProperties().addListener((MapChangeListener<Object, Object>) c -> {
					if (c.wasAdded() && "TableView.contentWidth".equals(c.getKey()))
					{
						if (c.getValueAdded() instanceof Number) {
							this.contentWidth = (Double)c.getValueAdded();
							}
					}
						});
			this.table = table;
		}
		private Callback<TreeTableView.ResizeFeatures, Boolean> getResizer()
		{
			return	ftr -> {
				TreeTableView<?> mytable = ftr.getTable();
				if (mytable != this.table) throw new IllegalStateException("NotebookResizer: initial table not equal called table: "+this.table+", "+mytable);
				List<? extends TableColumnBase<?,?>> visibleLeafColumns = mytable.getVisibleLeafColumns();
				if (contentWidth <= 0)
				{// on first call, contentWidth tends to be 0, which will give the last col a negative prefSize and it's not displayed
					return doResize(ftr, visibleLeafColumns, mytable.getWidth());
				}
				else
				{
					return doResize(ftr, visibleLeafColumns, contentWidth);
				}
			};
		}
	}
	
	private static class TableNotebookResizer
	{
		private double contentWidth;
		private final TableView table;
		
		TableNotebookResizer(TableView table)
		{
			table.getProperties().addListener((MapChangeListener<Object, Object>) c -> {
						if (c.getValueAdded() instanceof Number) {
							this.contentWidth = (Double)c.getValueAdded();
							}
						});
			this.table = table;
		}
		private Callback<TableView.ResizeFeatures, Boolean> getResizer()
		{
			return	ftr -> {
				TableView<?> mytable = ftr.getTable();
				if (mytable != this.table) throw new IllegalStateException("NotebookResizer: initial table not equal called table: "+this.table+", "+mytable);
				List<? extends TableColumnBase<?,?>> visibleLeafColumns = mytable.getVisibleLeafColumns();
				if (contentWidth <= 0)
				{// on first call, contentWidth tends to be 0, which will give the last col a negative prefSize and it's not displayed
					return doResize(ftr, visibleLeafColumns, mytable.getWidth());
				}
				else
				{
					return doResize(ftr, visibleLeafColumns, contentWidth);
				}
			};

		}
	}
	
	final static Callback<TreeTableView.ResizeFeatures, Boolean> using(TreeTableView table)
	{
		return new TreeTableNotebookResizer(table).getResizer();
	}

	final static Callback<TableView.ResizeFeatures, Boolean> using(TableView table)
	{
		return new TableNotebookResizer(table).getResizer();
	}

	private static boolean doResize(
		ResizeFeaturesBase<?> ftr,
		List<? extends TableColumnBase<?,?>> visibleLeafColumns,
		double contentWidth)
	{
		TableColumnBase<?,?> column = ftr.getColumn();
        double delta = ftr.getDelta();	// may be negative!
		TableColumnBase<?,?> firstColumn = visibleLeafColumns.get(0);
		int lastColPos = visibleLeafColumns.size()-1;
		TableColumnBase<?,?> lastColumn = visibleLeafColumns.get(lastColPos);
		
		if ( (ftr.getColumn() == null) ||	//resizing whole table
			(ftr.getColumn() == lastColumn))
		{
			double free = contentWidth;
			for (int ix = 0;  ix < lastColPos; ix++)
			{
				free -= visibleLeafColumns.get(ix).getWidth();
			}
			lastColumn.setPrefWidth(free);
			if (free < 0) return false;
		}
		else
		{
			column.setPrefWidth(column.getWidth()+delta);
			lastColumn.setPrefWidth(lastColumn.getWidth()-delta);
			if (!column.isResizable())
				return true;
			
			double spWidth = column.getWidth();
			if (spWidth+delta < 10)	// delta negative
				delta = 10-spWidth ;
			if (spWidth+delta < column.getMinWidth())	// delta negative
				delta = column.getMinWidth() - spWidth;
			if (spWidth+delta > column.getMaxWidth())	// delta positive
				delta = column.getMaxWidth() - spWidth;
			column.setPrefWidth(column.getWidth()+delta);
			lastColumn.setPrefWidth(lastColumn.getWidth()-ftr.getDelta());
		}
		return true;
	}
}
