import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class TestApp extends Application {

	private static final int ITEM_COUNT = 100;
	private static final int COLUMN_COUNT = 100;
	private static final int TAIL_LENGTH = 10;

	public static void main(String[] args) {
		launch(args);
	}

	@Override
	public void start(Stage stage) {

		TableView<String> table = new TableView<>();
		table.getColumns().setAll(createColumns());
		table.setItems(FXCollections.observableArrayList());
		table.getItems().addAll(createItems());

		ProgressBar progressBar = new ProgressBar();
		progressBar.setVisible(false);

		Button buttonExecuteTestCase = new Button("Execute Test-Case");
		buttonExecuteTestCase.setOnAction(event -> {
			buttonExecuteTestCase.setDisable(true);
			progressBar.setVisible(true);

			table.scrollToColumnIndex(table.getColumns().size() - 1);

			toggleTailColumns(table);
			toggleItems(table);

			Executors.newSingleThreadExecutor().execute(() -> {
// Ensure that there is at least one pulse in between.
				sleep();
				Platform.runLater(() -> {
					toggleTailColumns(table);
					toggleItems(table);

					buttonExecuteTestCase.setDisable(false);
					progressBar.setVisible(false);
				});
			});
		});

		ToolBar toolbar = new ToolBar(buttonExecuteTestCase, progressBar);

		BorderPane root = new BorderPane();
		root.setTop(toolbar);
		root.setCenter(table);

		stage.setTitle("Hello World!");
		stage.setScene(new Scene(root, 800, 500));
		stage.show();
	}

	private static List<TableColumn<String, ?>> createColumns() {
		List<TableColumn<String, ?>> columns = new ArrayList<>(COLUMN_COUNT);
		for (int i = 1; i <= COLUMN_COUNT; i++) {
			String name = "C" + i;
			TableColumn<String, String> column = new TableColumn<>(name);
			column.setCellValueFactory(
					cellDataFeatrues -> new SimpleStringProperty(name + " " + cellDataFeatrues.getValue()));

			columns.add(column);
		}
		return columns;
	}

	private static List<String> createItems() {
		List<String> items = new ArrayList<>(ITEM_COUNT);
		for (int i = 1; i <= ITEM_COUNT; i++) {
			items.add("R" + i);
		}
		return items;
	}

	private void toggleTailColumns(TableView<String> table) {
// Temporary store for the columns, while they're not attached to the table.
		List<TableColumn<String, ?>> tail = (List<TableColumn<String, ?>>) table.getProperties()
				.computeIfAbsent("column-tail", key -> new ArrayList<>(TAIL_LENGTH));
		if (tail.isEmpty()) {
			int from = table.getColumns().size() - TAIL_LENGTH;
			int to = table.getColumns().size();
			tail.addAll(table.getColumns().subList(from, to));
			table.getColumns().remove(from, to);
		} else {
			table.getColumns().addAll(tail);
			tail.clear();
		}
	}

	private void toggleItems(TableView<String> table) {
		if (table.getItems().isEmpty()) {
			table.getItems().addAll(createItems());
		} else {
			table.getItems().clear();
		}
	}

	private static void sleep() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException exception) {
			Thread.currentThread().interrupt();
		}
	}

}
