<commit_before>package ch.zhaw.photoflow.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.MenuButton;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.TilePane;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import ch.zhaw.photoflow.Main;
import ch.zhaw.photoflow.core.DaoException;
import ch.zhaw.photoflow.core.FileHandler;
import ch.zhaw.photoflow.core.FileHandlerException;
import ch.zhaw.photoflow.core.PhotoDao;
import ch.zhaw.photoflow.core.ProjectDao;
import ch.zhaw.photoflow.core.domain.Photo;
import ch.zhaw.photoflow.core.domain.PhotoState;
import ch.zhaw.photoflow.core.domain.PhotoWorkflow;
import ch.zhaw.photoflow.core.domain.Project;
import ch.zhaw.photoflow.core.domain.ProjectState;
import ch.zhaw.photoflow.core.domain.ProjectWorkflow;

import com.google.common.annotations.VisibleForTesting;

public class ProjectController extends BorderPane implements Initializable {
	private final ProjectWorkflow projectWorkflow;
	private final PhotoWorkflow photoWorkflow;
	private final ProjectDao projectDao;
	private final PhotoDao photoDao;
	private Project project;
	private List<Photo> photos;
	private FileHandler fileHandler;
	/** Daemon threads for background task execution */
	private final ExecutorService background;

	@FXML
	private PhotoController photoController;
	
	@FXML
	TextField projectNameField;
	@FXML
	Button workflowNextButton, workflowPauseButton, workflowBackButton, importPhotoButton, archiveProjectButton, exportProjectButton;
	@FXML
	MenuButton todoButton;
	@FXML
	TilePane photosPane;

	public ProjectController() {
		this(Main.photoFlow.getProjectDao(), Main.photoFlow.getPhotoDao(), Main.photoFlow.getProjectWorkflow(), Main.photoFlow.getPhotoWorkflow());
		URL gui = getClass().getResource("../view/project.fxml");
		FXMLLoader fxmlLoader = new FXMLLoader(gui);
		fxmlLoader.setController(this);
		fxmlLoader.setRoot(this);
		fxmlLoader.setController(this);
		try {
			fxmlLoader.load();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}
	
	public ProjectController(ProjectDao projectDao, PhotoDao photoDao, ProjectWorkflow workflow, PhotoWorkflow photoWorkflow) {
		this.projectWorkflow = workflow;
		this.photoWorkflow = photoWorkflow;
		this.photos = new ArrayList<Photo>();
		this.projectDao = projectDao;
		this.photoDao = photoDao;
		
		this.background = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), runnable -> {
			Thread thread = Executors.defaultThreadFactory().newThread(runnable);
			thread.setDaemon(true);
			return thread;
		});
	}
	
	public void setProject(Project project) {
		projectNameField.setText(project.getName());
		System.out.println("Project \"" + project.getName() + "\" has been selected.");
		this.project = project;
		try {
			fileHandler = new FileHandler(project);
		} catch (FileHandlerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		loadPhotos();
		displayPhotos();
	}
	
	private void loadPhotos() {
		try {
			List<Photo> loadedPhotos = this.photoDao.loadAll(project.getId().get());
			this.photos.clear();
			this.photos.addAll(loadedPhotos);
		} catch (DaoException e) {
			// TODO: Inform user that loading failed
		}
	}
	
	private void displayPhotos() {
		photosPane.getChildren().clear();
		
		photos.stream().forEach(photo -> {
			Task<Image> task = new ImageLoadingTask(photo, fileHandler);
			
			task.valueProperty().addListener((observable, oldImage, image) -> {
				System.out.println("Creating ImageView for image");
				ImageView view = new ImageView(image);
				view.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
					photoController.setPhoto(photo);
				});
				photosPane.getChildren().add(view);
			});
			
			//imageTask.onFailedProperty().addListener(TODO);
			
			background.execute(task);
		});
	}

	public void addPhoto(Photo photo) {<commit_msg>Kill image loading threads on displayPhotos() to prevent getting stuck.<commit_after>package ch.zhaw.photoflow.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.MenuButton;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.TilePane;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import ch.zhaw.photoflow.Main;
import ch.zhaw.photoflow.core.DaoException;
import ch.zhaw.photoflow.core.FileHandler;
import ch.zhaw.photoflow.core.FileHandlerException;
import ch.zhaw.photoflow.core.PhotoDao;
import ch.zhaw.photoflow.core.ProjectDao;
import ch.zhaw.photoflow.core.domain.Photo;
import ch.zhaw.photoflow.core.domain.PhotoState;
import ch.zhaw.photoflow.core.domain.PhotoWorkflow;
import ch.zhaw.photoflow.core.domain.Project;
import ch.zhaw.photoflow.core.domain.ProjectState;
import ch.zhaw.photoflow.core.domain.ProjectWorkflow;

import com.google.common.annotations.VisibleForTesting;

public class ProjectController extends BorderPane implements Initializable {
	private final ProjectWorkflow projectWorkflow;
	private final PhotoWorkflow photoWorkflow;
	private final ProjectDao projectDao;
	private final PhotoDao photoDao;
	private Project project;
	private List<Photo> photos;
	private FileHandler fileHandler;
	/** Daemon threads for background task execution */
	private ExecutorService imageLoaderService;

	@FXML
	private PhotoController photoController;
	
	@FXML
	TextField projectNameField;
	@FXML
	Button workflowNextButton, workflowPauseButton, workflowBackButton, importPhotoButton, archiveProjectButton, exportProjectButton;
	@FXML
	MenuButton todoButton;
	@FXML
	TilePane photosPane;

	public ProjectController() {
		this(Main.photoFlow.getProjectDao(), Main.photoFlow.getPhotoDao(), Main.photoFlow.getProjectWorkflow(), Main.photoFlow.getPhotoWorkflow());
		URL gui = getClass().getResource("../view/project.fxml");
		FXMLLoader fxmlLoader = new FXMLLoader(gui);
		fxmlLoader.setController(this);
		fxmlLoader.setRoot(this);
		fxmlLoader.setController(this);
		try {
			fxmlLoader.load();
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}
	
	public ProjectController(ProjectDao projectDao, PhotoDao photoDao, ProjectWorkflow workflow, PhotoWorkflow photoWorkflow) {
		this.projectWorkflow = workflow;
		this.photoWorkflow = photoWorkflow;
		this.photos = new ArrayList<Photo>();
		this.projectDao = projectDao;
		this.photoDao = photoDao;
	}
	
	public void setProject(Project project) {
		projectNameField.setText(project.getName());
		System.out.println("Project \"" + project.getName() + "\" has been selected.");
		this.project = project;
		try {
			fileHandler = new FileHandler(project);
		} catch (FileHandlerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		loadPhotos();
		displayPhotos();
	}
	
	private void loadPhotos() {
		try {
			List<Photo> loadedPhotos = this.photoDao.loadAll(project.getId().get());
			this.photos.clear();
			this.photos.addAll(loadedPhotos);
		} catch (DaoException e) {
			// TODO: Inform user that loading failed
		}
	}
	
	private void displayPhotos() {
		if (imageLoaderService != null) {
			imageLoaderService.shutdownNow();
		}
		imageLoaderService = newImageLoaderService();
		
		photosPane.getChildren().clear();
		
		photos.stream().forEach(photo -> {
			Task<Image> task = new ImageLoadingTask(photo, fileHandler);
			
			task.valueProperty().addListener((observable, oldImage, image) -> {
				System.out.println("Creating ImageView for image");
				ImageView view = new ImageView(image);
				view.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
					photoController.setPhoto(photo);
				});
				photosPane.getChildren().add(view);
			});
			
			//imageTask.onFailedProperty().addListener(TODO);
			
			imageLoaderService.execute(task);
		});
	}
	
	private ExecutorService newImageLoaderService () {
		
		return Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), runnable -> {
			Thread thread = Executors.defaultThreadFactory().newThread(runnable);
			thread.setDaemon(true);
			return thread;
		});
	}

	public void addPhoto(Photo photo) {
{'fraction_non_alphanumeric': 0.1104978354978355, 'fraction_numerical': 0.0, 'mean_word_length': 5.231287929871882, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 18}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5326348', 'n_tokens_mistral': 3068, 'n_tokens_neox': 2815, 'n_words': 551}