package de.prob2.ui.internal;

import java.util.List;

import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

import de.prob2.ui.MainController;
import de.prob2.ui.consoles.ConsoleInstruction;
import de.prob2.ui.consoles.ConsoleInstructionOption;
import de.prob2.ui.consoles.groovy.GroovyInterpreter;
import de.prob2.ui.consoles.groovy.objects.GroovyObjectItem;
import de.prob2.ui.consoles.groovy.objects.GroovyObjectStage;
import de.prob2.ui.menu.MenuController;

import javafx.geometry.BoundingBox;
import javafx.stage.Stage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public final class UIPersistence {
	private static final Logger LOGGER = LoggerFactory.getLogger(UIPersistence.class);
	
	private final UIState uiState;
	private final Injector injector;
	
	@Inject
	private UIPersistence(UIState uiState, Injector injector) {
		this.uiState = uiState;
		this.injector = injector;
	}
	
	private static void sizeStage(Stage stage, BoundingBox box) {
		stage.setX(box.getMinX());
		stage.setY(box.getMinY());
		stage.setWidth(box.getWidth());
		stage.setHeight(box.getHeight());
	}
	
	private void restoreStage(final String id, BoundingBox box) {
		LOGGER.info("Restoring stage with ID {} and bounding box {}", id, box);
		if (id == null) {
			LOGGER.warn("Stage identifier is null, cannot restore window");
			return;
		}
		
		switch (id) {
			case "de.prob2.ui.ProB2":
				// The main stage's size is restored in the application start method.
				return;
			
			case "de.prob2.ui.consoles.groovy.objects.GroovyObjectStage":
				injector.getInstance(GroovyInterpreter.class).exec(new ConsoleInstruction("inspect", ConsoleInstructionOption.ENTER));
				return;
			
			case "de.prob2.ui.menu.MenuController$DetachViewStageController":
				injector.getInstance(MenuController.class).handleLoadDetached();
				return;
			
			default:
				LOGGER.info("No special handling for stage identifier {}, will use injection", id);
		}
		
		Class<?> clazz;
		try {
			clazz = Class.forName(id);
		} catch (ClassNotFoundException e) {
			LOGGER.warn("Class not found, cannot restore window", e);
			return;
		}
		
		Class<? extends Stage> stageClazz;
		try {
			stageClazz = clazz.asSubclass(Stage.class);
		} catch (ClassCastException e) {
			LOGGER.warn("Class is not a subclass of javafx.stage.Stage, cannot restore window", e);
			return;
		}
		
		try {
			final Stage stage = injector.getInstance(stageClazz);
			stage.show();
		} catch (RuntimeException e) {
			LOGGER.warn("Failed to restore window", e);
		}
	}
	
	public void open() {
		final MenuController menu = injector.getInstance(MenuController.class);
		final MainController main = injector.getInstance(MainController.class);
		if("detached".equals(uiState.getGuiState())) {
			menu.applyDetached();
		} else {
			menu.loadPreset(uiState.getGuiState());
		}
		
		for (final String id : uiState.getSavedVisibleStages()) {
			this.restoreStage(id, uiState.getSavedStageBoxes().get(id));
		}
		
		List<GroovyObjectItem> groovyObjects = injector.getInstance(GroovyObjectStage.class).getItems();
		int j = 0;
		for (GroovyObjectItem groovyObject : groovyObjects) {
			if (uiState.getSavedStageBoxes().containsKey("#GroovyObjectId:" + groovyObject.getName())) {
				sizeStage(groovyObject.getStage(), uiState.getSavedStageBoxes().get("#GroovyObjectId:" + groovyObject.getName()));
				groovyObject.show(GroovyObjectItem.ShowEnum.PERSISTENCE, j);
				j++;
			}
		}
		
 		String[] expandedTitledPanes = new String[]{"Operations", "History", "Animations", "Model Check", "Statistics"};
 	 
		
		for(String titledPane : expandedTitledPanes) {
			if(uiState.getExpandedTitledPanes().contains(titledPane)) {
				main.expandTitledPane(titledPane);
			}
		}
		
	}
}

@@ -963,204 +963,8 @@
 %7D%0A%09%0A
-%09private static void sizeStage(Stage stage, BoundingBox box) %7B%0A%09%09stage.setX(box.getMinX());%0A%09%09stage.setY(box.getMinY());%0A%09%09stage.setWidth(box.getWidth());%0A%09%09stage.setHeight(box.getHeight());%0A%09%7D%0A%09%0A
 %09pri
@@ -1201,16 +1201,111 @@
 %0A%09%09%7D%0A%09%09%0A
+%09%09if (id.startsWith(%22#GroovyObjectId:%22)) %7B%0A%09%09%09// Handled elsewhere in open()%0A%09%09%09return;%0A%09%09%7D%0A%09%09%0A
 %09%09switch
@@ -3181,127 +3181,8 @@
 ) %7B%0A
-%09%09%09%09sizeStage(groovyObject.getStage(), uiState.getSavedStageBoxes().get(%22#GroovyObjectId:%22 + groovyObject.getName()));%0A
 %09%09%09%09
@@ -3267,29 +3267,22 @@
 %0A%09%09%0A
- 
 %09%09
+for(
 String
-%5B%5D expandedT
+ t
 itle
@@ -3286,19 +3286,18 @@
 tledPane
-s =
+ :
  new Str
@@ -3301,16 +3301,17 @@
 String%5B%5D
+ 
 %7B%22Operat
@@ -3374,62 +3374,8 @@
 cs%22%7D
-;%0A %09 %0A%09%09%0A%09%09for(String titledPane : expandedTitledPanes
 ) %7B%0A
@@ -3379,16 +3379,17 @@
  %7B%0A%09%09%09if
+ 
 (uiState
@@ -3486,16 +3486,13 @@
 %09%09%7D%0A%09%09%7D%0A
-%09%09%0A
 %09%7D%0A%7D%0A

Clean up a few things in UIPersistence