snpviewer.SnpViewer.java Source code

Java tutorial

Introduction

Here is the source code for snpviewer.SnpViewer.java

Source

/*
 * Snp Viewer - a program for viewing SNP data and identifying regions of homozygosity
 * Copyright (C) 2013 David A. Parry
 * d.a.parry@leeds.ac.uk
 * https://sourceforge.net/projects/snpviewer/
 * 
This program 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 snpviewer;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.URL;
import java.nio.file.Files;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.ResourceBundle;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.concurrent.WorkerStateEvent;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Window;
import javafx.scene.control.Dialogs;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.shape.Line;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import static java.nio.file.StandardCopyOption.*;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.concurrent.ExecutionException;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.geometry.Rectangle2D;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.Dialogs.DialogResponse;
import javafx.scene.control.Menu;
import javafx.scene.control.RadioMenuItem;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ToggleGroup;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Modality;
import javafx.stage.Screen;
import org.apache.commons.io.FileUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ComparisonOperator;
import org.apache.poi.ss.usermodel.ConditionalFormattingRule;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.PatternFormatting;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.SheetConditionalFormatting;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * FXML Controller class
 *
 * @author david
 * 
 * 
 */
public class SnpViewer extends Application implements Initializable, Serializable {

    String VERSION = "0.9.2";

    ArrayList<SnpFile> affFiles = new ArrayList<>();
    ObservableList<SnpFile> affObserve = FXCollections.observableList(affFiles);

    ArrayList<SnpFile> unFiles = new ArrayList<>();
    ObservableList<SnpFile> unObserve = FXCollections.observableList(unFiles);

    ArrayList<HashMap<String, ArrayList<Line>>> genotypeLineMap = new ArrayList<>();
    //keys are lowercase call codes (e.g. "aa"), values are list of lines to draw
    Object chromosomeBoxList[]; //list of available chromosomes in choicebox
    String genomeVersion = "";
    NumberFormat nf = NumberFormat.getIntegerInstance(); //number formatting for positionIndicator

    boolean projectRunning = false; //becomes true once we click newProjectButton
    boolean progressMode = false; //becomes true when in progressMode
    File snpViewSaveDirectory;// directory for program files
    File projectFile;

    //regions found automatically and/or manually saved
    ArrayList<RegionSummary> savedRegions = new ArrayList<>();
    //graphical display of savedRegions for current chromosome view
    ArrayList<Rectangle> savedRegionsDisplay = new ArrayList<>();
    //RegionSummaries corresponding to each displayed saved region
    ArrayList<RegionSummary> savedRegionsReference = new ArrayList<>();

    //panes and labels
    @FXML
    StackPane mainPane;
    @FXML
    Window mainWindow;
    @FXML
    SplitPane horizontalSplit;
    @FXML
    SplitPane chromSplitPane;
    @FXML
    SplitPane labelSplitPane;
    @FXML
    Label positionIndicator;
    @FXML
    TextField selectionIndicator;
    @FXML
    Label buildLabel;
    @FXML
    Label projectLabel;
    @FXML
    Label qualityLabel;

    //menu componants
    @FXML
    MenuBar mainMenu;
    @FXML
    Menu fileMenu;
    @FXML
    Menu sampleMenu;
    @FXML
    Menu goMenu;
    @FXML
    Menu helpMenu;
    @FXML
    MenuItem closeMenu;
    @FXML
    MenuItem cacheChromsMenu;
    @FXML
    MenuItem saveToPngMenu;
    @FXML
    MenuItem newProjectMenu;
    @FXML
    MenuItem loadProjectMenu;
    @FXML
    MenuItem saveColoursMenu;
    @FXML
    MenuItem loadColoursMenu;
    @FXML
    MenuItem resetColoursMenu;
    @FXML
    MenuItem autoFindRegions;
    @FXML
    MenuItem nextChromMenu;
    @FXML
    MenuItem prevChromMenu;
    @FXML
    MenuItem firstChromMenu;
    @FXML
    MenuItem lastChromMenu;
    @FXML
    MenuItem addAffSampleMenu;
    @FXML
    MenuItem addUnSampleMenu;
    @FXML
    MenuItem removeSampleMenu;
    @FXML
    MenuItem redrawMenu;
    @FXML
    CheckMenuItem hideSavedRegionsMenu;
    @FXML
    MenuItem outputSavedRegionsMenu;
    @FXML
    MenuItem displaySavedsRegionsMenu;
    @FXML
    MenuItem clearSavedRegionsMenu;
    @FXML
    MenuItem aboutMenu;
    @FXML
    RadioMenuItem noFilteringRadio;
    @FXML
    RadioMenuItem filter99;
    @FXML
    RadioMenuItem filter95;
    @FXML
    RadioMenuItem filter90;
    @FXML
    RadioMenuItem filter85;

    //buttons etc.
    @FXML
    Button cacheChromsButton;
    @FXML
    Button findRegionsButton;
    @FXML
    Button addAffected;
    @FXML
    Button addUnaffected;
    @FXML
    Button newProjectButton;
    @FXML
    Button loadProjectButton;
    @FXML
    Button saveProjectButton;
    @FXML
    Button redrawButton;
    @FXML
    CheckBox redrawCheckBox;
    @FXML
    ProgressIndicator loadProgress;
    @FXML
    ChoiceBox chromosomeSelector;

    //progress components
    @FXML
    ProgressBar progressBar;
    @FXML
    Button cancelButton;
    @FXML
    Label progressTitle;
    @FXML
    Label progressMessage;

    //Genotype and selection colours
    @FXML
    ColorPicker colorPicker = new ColorPicker();
    @FXML
    ChoiceBox colorComponantSelector;
    @FXML
    Color aaColor = Color.BLACK;
    @FXML
    Color bbColor = Color.web("#4d4d4d");
    @FXML
    Color abColor = Color.DEEPPINK;
    @FXML
    Color dragSelectLineColor = Color.web("#8099ff");
    @FXML
    Color dragSelectFillColor = Color.YELLOW;
    @FXML
    Color savedRegionsLineColor = Color.CYAN;
    @FXML
    Color savedRegionsFillColor = Color.LIME;
    Color[] colorComponants = { aaColor, bbColor, abColor, dragSelectLineColor, dragSelectFillColor,
            savedRegionsLineColor, savedRegionsFillColor };
    ArrayList<Color> colorComp = new ArrayList<>();
    ObservableList<Color> colorObserve;

    //Selections
    @FXML
    Pane selectionOverlayPane = new Pane();
    @FXML
    Rectangle dragSelectRectangle = new Rectangle();
    SimpleDoubleProperty dragSelectRectInitX = new SimpleDoubleProperty();
    SimpleDoubleProperty dragSelectRectInitY = new SimpleDoubleProperty();
    SimpleDoubleProperty dragSelectRectX = new SimpleDoubleProperty();
    SimpleDoubleProperty dragSelectRectY = new SimpleDoubleProperty();
    SimpleDoubleProperty anchorInitX = new SimpleDoubleProperty();
    ContextMenu ocm;

    Double qualityFilter = null;

    public static void main(String[] args) {

        Application.launch(SnpViewer.class, (java.lang.String[]) null);

    }

    @Override
    public void start(final Stage primaryStage) {
        try {
            //FXMLLoader loader = new FXMLLoader(SnpViewer.class.getResource("SnpView.fxml"));
            AnchorPane page = (AnchorPane) FXMLLoader.load(SnpViewer.class.getResource("SnpView.fxml"));

            Scene scene = new Scene(page);
            primaryStage.setScene(scene);
            primaryStage.setTitle("SNP Viewer");
            scene.getStylesheets().add(SnpViewer.class.getResource("SnpViewerStyleSheet.css").toExternalForm());
            primaryStage.show();
            primaryStage.getIcons().add(new Image(this.getClass().getResourceAsStream("icon.png")));

            /*primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent event) {
                try{
                    DialogResponse response = Dialogs.showConfirmDialog(primaryStage,
                               "Any unsaved changes will be lost",
                               "Really quit?", "SNP View", DialogOptions.OK_CANCEL);
                    if (DialogResponse.OK.equals(response)){
                        stop();
                    }else {
                        event.consume();
                    }
                }catch (Exception ex) {
                    Logger.getLogger(SnpViewer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            });*/
        } catch (Exception ex) {
            Logger.getLogger(SnpViewer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        labelSplitPane.setDividerPositions();
        chromSplitPane.setDividerPositions();
        Pane lpane = (Pane) horizontalSplit.getItems().get(0);
        SplitPane.setResizableWithParent(lpane, false);
        //mnemonics/shortcuts for menus        
        mainMenu.useSystemMenuBarProperty().set(true);
        fileMenu.setMnemonicParsing(true);
        sampleMenu.setMnemonicParsing(true);
        goMenu.setMnemonicParsing(true);
        helpMenu.setMnemonicParsing(true);
        newProjectMenu.setAccelerator(new KeyCodeCombination(KeyCode.N, KeyCombination.SHORTCUT_DOWN));
        loadProjectMenu.setAccelerator(new KeyCodeCombination(KeyCode.L, KeyCombination.SHORTCUT_DOWN));
        addAffSampleMenu.setAccelerator(
                new KeyCodeCombination(KeyCode.A, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
        addUnSampleMenu.setAccelerator(
                new KeyCodeCombination(KeyCode.U, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
        nextChromMenu.setAccelerator(new KeyCodeCombination(KeyCode.EQUALS, KeyCombination.SHORTCUT_DOWN));
        prevChromMenu.setAccelerator(new KeyCodeCombination(KeyCode.MINUS, KeyCombination.SHORTCUT_DOWN));
        firstChromMenu.setAccelerator(new KeyCodeCombination(KeyCode.DIGIT1, KeyCombination.SHORTCUT_DOWN));
        lastChromMenu.setAccelerator(new KeyCodeCombination(KeyCode.DIGIT0, KeyCombination.SHORTCUT_DOWN));
        redrawMenu.setAccelerator(new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN));
        cacheChromsMenu.setAccelerator(
                new KeyCodeCombination(KeyCode.C, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
        saveToPngMenu.setAccelerator(
                new KeyCodeCombination(KeyCode.S, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
        autoFindRegions.setAccelerator(new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN));
        //need to disable hideSavedRegionsMenu accelerator for linux - doesn't work for check menus
        hideSavedRegionsMenu.setAccelerator(
                new KeyCodeCombination(KeyCode.H, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
        clearSavedRegionsMenu.setAccelerator(
                new KeyCodeCombination(KeyCode.X, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
        displaySavedsRegionsMenu.setAccelerator(new KeyCodeCombination(KeyCode.T, KeyCombination.SHORTCUT_DOWN));
        outputSavedRegionsMenu.setAccelerator(new KeyCodeCombination(KeyCode.O, KeyCombination.SHORTCUT_DOWN));
        removeSampleMenu.setAccelerator(
                new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN, KeyCombination.SHIFT_DOWN));
        //set radio menu item toggle group
        ArrayList<RadioMenuItem> callQualityRadios = new ArrayList<>(
                Arrays.asList(noFilteringRadio, filter99, filter95, filter90, filter85));
        ToggleGroup callQualityToggle = new ToggleGroup();
        for (RadioMenuItem r : callQualityRadios) {
            r.setToggleGroup(callQualityToggle);
        }
        noFilteringRadio.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                setQualityFilter(null);
            }
        });

        filter99.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                setQualityFilter(0.01);
            }
        });

        filter95.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                setQualityFilter(0.05);
            }
        });

        filter90.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                setQualityFilter(0.10);
            }
        });

        filter85.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                setQualityFilter(0.15);
            }
        });

        nextChromMenu.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                selectNextChromosome(true);
            }
        });

        prevChromMenu.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                selectNextChromosome(false);
            }
        });

        firstChromMenu.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                if (!cancelButton.isDisabled()) {
                    cancelButton.fire();
                }
                if (!chromosomeSelector.isDisabled()) {

                    chromosomeSelector.getSelectionModel().selectFirst();
                }
            }
        });

        lastChromMenu.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                if (!cancelButton.isDisabled()) {
                    cancelButton.fire();
                }
                if (!chromosomeSelector.isDisabled()) {
                    chromosomeSelector.getSelectionModel().selectLast();
                }
            }
        });

        hideSavedRegionsMenu.setOnAction(new EventHandler() {
            @Override
            public void handle(Event ev) {
                showHideSavedRegions();
            }
        });

        colorComp.addAll(Arrays.asList(colorComponants));

        //selection context menu
        final ContextMenu scm = new ContextMenu();
        final MenuItem scmItem1 = new MenuItem("Display Flanking SNP IDs");
        scmItem1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                /* get coordinates of selection and report back
                 * flanking snp ids and coordinates
                 */
                displayFlankingSnpIDs(dragSelectRectangle);

            }
        });
        final MenuItem scmItem2 = new MenuItem("Write Selected Region to File");
        scmItem2.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        /* get coordinates of selection and report back
                         * write SNPs in region to file
                         */
                        writeRegionToFile(dragSelectRectangle);
                    }
                });
            }
        });
        final MenuItem scmItem3 = new MenuItem("Add To Saved Regions");
        scmItem3.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                /* get coordinates of selection and report back
                 * write SNPs in region to file
                 */
                saveSelection();
            }
        });
        final MenuItem scmItem4 = new MenuItem("Show/Hide Saved Regions");
        scmItem4.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                /* get coordinates of selection and report back
                 * write SNPs in region to file
                 */
                hideSavedRegionsMenu.selectedProperty().setValue(!hideSavedRegionsMenu.isSelected());
                hideSavedRegionsMenu.fire();
            }
        });
        final MenuItem scmItem5 = new MenuItem("Zoom Region");
        scmItem5.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        /* get coordinates of selection and report back
                         * write SNPs in region to file
                         */
                        zoomRegion(dragSelectRectangle);
                    }
                });
            }
        });
        final MenuItem scmItem6 = new MenuItem("Write Saved Regions to File");
        scmItem6.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        /* get coordinates of selection and report back
                         * write SNPs in region to file
                         */
                        writeSavedRegionsToFile();
                    }
                });
            }
        });

        scm.getItems().add(scmItem1);
        scm.getItems().add(scmItem2);
        scm.getItems().add(scmItem3);
        scm.getItems().add(scmItem4);
        scm.getItems().add(scmItem5);
        scm.getItems().add(scmItem6);
        //overlayPane context menu
        ocm = new ContextMenu();
        final MenuItem ocmItem1 = new MenuItem("Save Image to File");
        ocmItem1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        drawPaneToPng();
                    }
                });
            }
        });

        ocm.getItems().add(ocmItem1);
        ocm.getItems().add(scmItem4);
        ocm.getItems().add(scmItem6);

        //color selections
        colorComponantSelector.getItems().clear();
        colorComponantSelector.getItems().add("AA");
        colorComponantSelector.getItems().add("BB");
        colorComponantSelector.getItems().add("AB");
        colorComponantSelector.getItems().add("Selection Outline");
        colorComponantSelector.getItems().add("Selection Fill");
        colorComponantSelector.getItems().add("Saved Region Outline");
        colorComponantSelector.getItems().add("Saved Region Fill");
        colorComponantSelector.getSelectionModel().selectFirst();
        colorPicker.setValue(colorComponants[0]);
        colorComponantSelector.getSelectionModel().selectedIndexProperty()
                .addListener(new ChangeListener<Number>() {
                    @Override
                    public void changed(ObservableValue ov, Number value, Number new_value) {
                        colorPicker.setValue(colorComp.get(new_value.intValue()));
                        colorPicker.fireEvent(new ActionEvent());
                    }
                });
        colorPicker.setOnAction(new EventHandler() {
            @Override
            public void handle(Event t) {
                if (!colorComp.get(colorComponantSelector.getSelectionModel().getSelectedIndex())
                        .equals(colorPicker.getValue())) {
                    colorComp.set(colorComponantSelector.getSelectionModel().getSelectedIndex(),
                            colorPicker.getValue());
                    saveProject();
                    //colorComponants[colorComponantSelector.getSelectionModel().getSelectedIndex()] = colorPicker.getValue();
                    if (colorComponantSelector.getSelectionModel().getSelectedIndex() == Colors.fill.value) {
                        dragSelectRectangle.setFill(colorPicker.getValue());
                    } else if (colorComponantSelector.getSelectionModel().getSelectedIndex() == Colors.line.value) {
                        dragSelectRectangle.setStroke(colorPicker.getValue());
                    } else if (colorComponantSelector.getSelectionModel()
                            .getSelectedIndex() == Colors.saveLine.value) {
                        for (Rectangle r : savedRegionsDisplay) {
                            r.setStroke(colorPicker.getValue());
                        }
                    } else if (colorComponantSelector.getSelectionModel()
                            .getSelectedIndex() == Colors.saveFill.value) {
                        for (Rectangle r : savedRegionsDisplay) {
                            r.setFill(colorPicker.getValue());
                        }
                    } else {
                        removeSavedChromosomeImages();
                        if (redrawCheckBox.isSelected()) {
                            refreshView(null, true);
                        }
                    }
                }
            }
        });

        /*perform appropriate action when user selects a chromosome
         * from the chromosome choice box
         */
        chromosomeSelector.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue ov, Number value, Number new_value) {
                chromosomeBoxList = chromosomeSelector.getItems().toArray();

                if (new_value.intValue() > -1) {
                    chromosomeSelected((String) chromosomeBoxList[new_value.intValue()]);
                }
            }
        });

        chromosomeSelector.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent ke) {
                if (ke.getCode() == KeyCode.UP) {
                    ke.consume();
                    chromosomeSelector.show();
                }
            }
        });

        selectionOverlayPane.heightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observableValue, Number oldSceneWidth,
                    Number newSceneWidth) {
                windowResized(new ActionEvent());

            }
        });

        selectionOverlayPane.widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observableValue, Number oldSceneWidth,
                    Number newSceneWidth) {
                windowResized(new ActionEvent());
            }
        });

        /*upon addition of a new affected file adjust components accordingly
         * i.e. ensure appropriate chromosomes are in the choice box
         * adjust the split panes to fit all files and redisplay
         */

        affObserve.addListener(new ListChangeListener() {
            @Override
            public void onChanged(ListChangeListener.Change change) {
                change.next();/*from the javadoc 
                              * 'Go to the next change. In initial state is invalid a require 
                              * a call to next() before calling other methods. The first 
                              * next() call will make this object represent the first change.
                              */
                if (change.getRemovedSize() > 0) {
                    List<SnpFile> both = new ArrayList<>(unFiles);
                    both.addAll(affFiles);
                    recheckChromosomeSelector(both);//need to check all files again, not just affFiles
                } else if (change.getAddedSize() > 0) {
                    addToChromosomeSelector(affFiles);
                }
            }
        });

        /*as above 
         * but for unaffected files
         */
        unObserve.addListener(new ListChangeListener() {
            @Override
            public void onChanged(ListChangeListener.Change change) {
                change.next();
                if (change.getRemovedSize() > 0) {
                    List<SnpFile> both = new ArrayList<>(unFiles);
                    both.addAll(affFiles);
                    recheckChromosomeSelector(both);//need to check all files again, not just unFiles
                } else if (change.getAddedSize() > 0) {
                    addToChromosomeSelector(unFiles);
                }

            }
        });

        selectionOverlayPane.addEventHandler(MouseEvent.MOUSE_MOVED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                if (!genomeVersion.equals("") && chromosomeSelector.getSelectionModel().getSelectedIndex() > -1) {
                    try {
                        ChromosomeLength chromLength = new ChromosomeLength(genomeVersion);
                        String currentChrom = (String) chromosomeBoxList[chromosomeSelector.getSelectionModel()
                                .getSelectedIndex()];
                        double coordinate = chromLength.getLength(currentChrom) / chromSplitPane.getWidth()
                                * e.getX();
                        positionIndicator.setText(nf.format(coordinate));

                    } catch (Exception ex) {
                        positionIndicator.setText("Build Error!");
                    }

                }
            }
        });
        /*handle mouse dragging and effect on dragSelectRectangle
         * 
         */
        dragSelectRectangle.widthProperty().bind(dragSelectRectX.subtract(dragSelectRectInitX));
        dragSelectRectangle.heightProperty().bind(selectionOverlayPane.heightProperty());
        //dragSelectRectangle.strokeProperty().set(colorComponants[Colors.line.value]);
        dragSelectRectangle.setStrokeWidth(4.0);

        //dragSelectRectangle.setBlendMode(BlendMode.SCREEN);
        dragSelectRectangle.setOpacity(0.45);
        dragSelectRectangle.setVisible(false);
        selectionOverlayPane.getChildren().add(dragSelectRectangle);

        selectionOverlayPane.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                if (scm.isShowing()) {
                    scm.hide();
                }
                if (!e.isPrimaryButtonDown()) {
                    if (e.isSecondaryButtonDown()) {
                        //check we're not overlapping selection
                        if (e.getX() >= dragSelectRectangle.getX()
                                && e.getX() <= (dragSelectRectangle.getX() + dragSelectRectangle.getWidth())) {
                            return;
                        }
                        //check we're not overlapping saved regions
                        for (Rectangle r : savedRegionsDisplay) {
                            if (r.isVisible() && e.getX() >= r.getX() && e.getX() <= r.getX() + r.getWidth()) {
                                return;
                            }
                        }
                        if (chromosomeSelector.getSelectionModel().isEmpty()) {
                            ocmItem1.setDisable(true);
                        } else {
                            ocmItem1.setDisable(false);
                        }
                        ocm.show(selectionOverlayPane, e.getScreenX(), e.getScreenY());

                        return;
                    }
                }
                if (ocm.isShowing()) {
                    ocm.hide();
                }

                dragSelectRectangle.strokeProperty().set(colorComp.get(Colors.line.value));
                dragSelectRectangle.fillProperty().set(colorComp.get(Colors.fill.value));
                dragSelectRectX.set(0);
                dragSelectRectangle.setVisible(true);
                dragSelectRectangle.setX(e.getX());
                dragSelectRectangle.setY(0);
                dragSelectRectInitX.set(e.getX());
                anchorInitX.set(e.getX());

            }
        });
        selectionOverlayPane.addEventHandler(MouseEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                if (!e.isPrimaryButtonDown()) {
                    return;
                }
                dragSelectRectangle.setVisible(true);
                if (e.getX() > anchorInitX.doubleValue()) {//dragging to the right
                    if (e.getX() <= selectionOverlayPane.getLayoutX() + selectionOverlayPane.getWidth()) {
                        //mouse is before the edge of the pane
                        dragSelectRectInitX.set(anchorInitX.doubleValue());
                        dragSelectRectX.set(e.getX());
                    } else {
                        //mouse is over the edge
                        dragSelectRectX.set(selectionOverlayPane.getWidth());
                    }
                } else {
                    if (e.getX() > selectionOverlayPane.getLayoutX()) {
                        dragSelectRectInitX.set(e.getX());
                        dragSelectRectangle.setX(e.getX());
                        dragSelectRectX.set(anchorInitX.doubleValue());
                    } else {
                        dragSelectRectInitX.set(0);
                        dragSelectRectangle.setX(0);
                        /* the two lines below are just to trigger 
                        * dragSelectRectangle.widthProperty listener 
                        * so that start coordinate changes to 1
                        */
                        dragSelectRectX.set(anchorInitX.doubleValue() + 1);
                        dragSelectRectX.set(anchorInitX.doubleValue() + 1);

                    }
                }
            }
        });

        selectionOverlayPane.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                //dragSelectRectX.set(e.getX());
                if (!e.isPrimaryButtonDown()) {
                    return;
                }
                dragSelectRectangle.setVisible(true);
                if (dragSelectRectangle.getWidth() == 0) {
                    clearDragSelectRectangle();
                }
            }
        });

        dragSelectRectangle.widthProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observableValue, Object oldValue, Object newRectWidth) {
                if (!genomeVersion.equals("") && chromosomeSelector.getSelectionModel().getSelectedIndex() > -1
                        && dragSelectRectangle.getWidth() > 0) {
                    try {
                        ChromosomeLength chromLength = new ChromosomeLength(genomeVersion);
                        String currentChrom = (String) chromosomeBoxList[chromosomeSelector.getSelectionModel()
                                .getSelectedIndex()];
                        double startCoordinate = chromLength.getLength(currentChrom)
                                / selectionOverlayPane.getWidth() * dragSelectRectangle.getX();
                        double selectionWidth = chromLength.getLength(currentChrom)
                                / selectionOverlayPane.getWidth() * dragSelectRectangle.getWidth();
                        if (dragSelectRectangle.getX() == 0) {
                            startCoordinate = 1;
                        }
                        selectionIndicator.setText("chr" + currentChrom + ":" + nf.format(startCoordinate) + "-"
                                + nf.format(startCoordinate + selectionWidth));
                    } catch (Exception ex) {
                        selectionIndicator.setText("Build Error!");
                    }
                } else {
                    selectionIndicator.setText("");
                }

            }
        });

        dragSelectRectangle.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                if (e.getButton() == MouseButton.SECONDARY) {
                    if (chromosomeSelector.getSelectionModel().isEmpty()) {
                        scmItem1.setDisable(true);
                        scmItem2.setDisable(true);
                    } else {
                        scmItem1.setDisable(false);
                        scmItem2.setDisable(false);
                    }
                    if (ocm.isShowing()) {
                        ocm.hide();
                    }

                    scm.show(selectionOverlayPane, e.getScreenX(), e.getScreenY());
                }
            }
        });

    }//end initialize

    /* value for quality filter in all SnpFiles - score is liklihood genotype is
     * wrong, hence lower is better.  Set to null for no filtering
     */
    private void setQualityFilter(Double d) {
        if (qualityFilter == null && d == null) {
            setQualityLabel();
            return;
        }
        if (qualityFilter != null && d != null) {
            if (qualityFilter.equals(d)) {
                return;
            }
        }

        qualityFilter = d;
        ArrayList<SnpFile> both = new ArrayList<>();
        both.addAll(affObserve);
        both.addAll(unObserve);
        ArrayList<String> noQualityField = new ArrayList<>();
        for (SnpFile s : both) {
            if (s.hasQualityField) {
                s.setQualityFilter(qualityFilter);
            } else {
                noQualityField.add(s.getInputFileName());
            }
        }
        if (!noQualityField.isEmpty()) {
            StringBuilder noQual = new StringBuilder();
            for (String s : noQualityField) {
                noQual.append(s).append("\n");
            }
            Dialogs.showWarningDialog(null,
                    "The following input file(s) do not " + "have call confidence information:\n\n"
                            + noQual.toString() + "\nChanging call quality filters will have no effect on these"
                            + " files.  To get quality fields ensure you include them "
                            + "when producing birdseed files with the Affymetrix Genotyping" + " Console software.",
                    "File(s) without call confidences", "SnpViewer");
        }
        setQualityLabel();
        saveProject();
        refreshView(null, redrawCheckBox.isSelected());
    }

    private void setQualityLabel() {
        if (qualityFilter != null) {
            Integer percent = 100 - (int) (100 * qualityFilter);
            qualityLabel.setText(percent.toString() + " % confidence or greater");
        } else {
            qualityLabel.setText("None");
        }
    }

    public ArrayList<Color> getColors() {
        return colorComp;
    }

    public void resetColours(ActionEvent e) {
        colorComp.clear();
        colorComp.addAll(Arrays.asList(colorComponants));
        for (int ci = 0; ci < colorComp.size(); ci++) {
            colorComponantSelector.getSelectionModel().clearAndSelect(ci);
            colorPicker.setValue(colorComp.get(ci));
            colorPicker.fireEvent(new ActionEvent());
        }
        colorComponantSelector.getSelectionModel().selectFirst();
        removeSavedChromosomeImages();
        refreshView((String) chromosomeSelector.getSelectionModel().getSelectedItem(), true);
    }

    public void saveColours(ActionEvent e) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Save Colour Scheme (.svcols) As...");
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("SNP Viewer Colour Scheme",
                "*.svcols");
        fileChooser.getExtensionFilters().add(extFilter);
        File colorFile = fileChooser.showSaveDialog(mainWindow);
        if (colorFile != null) {
            if (!colorFile.getName().endsWith(".svcols")) {
                colorFile = new File(colorFile.getAbsolutePath() + ".svcols");
            }

            try {
                FileOutputStream fos = new FileOutputStream(colorFile);
                try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(fos))) {
                    for (Color c : colorComp) {
                        out.writeObject(c.toString());
                    }
                    out.close();
                    projectLabel.setText("Project: " + projectFile.getName());
                }
            } catch (IOException ex) {
                Dialogs.showErrorDialog(null, "Could not save colour scheme - IO error", "Save Failed",
                        "SNP Viewer", ex);
            }
        }
    }

    public void loadColourScheme(ActionEvent e) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters()
                .add(new FileChooser.ExtensionFilter("SNP Viewer Colour Scheme", "*.svcols"));
        fileChooser.setTitle("Open SNP Viewer Colour Scheme (.svcols) file");
        File loadFile = fileChooser.showOpenDialog(mainWindow);
        if (loadFile != null) {
            try {
                ObjectInputStream is = new ObjectInputStream(
                        new BufferedInputStream(new FileInputStream(loadFile)));
                ArrayList<Color> loadedColors = new ArrayList<>();
                for (Color c : colorComp) {
                    String colorString = (String) is.readObject();
                    loadedColors.add(Color.valueOf(colorString));
                }
                for (int ci = 0; ci < loadedColors.size(); ci++) {
                    colorComponantSelector.getSelectionModel().clearAndSelect(ci);
                    colorPicker.setValue(loadedColors.get(ci));
                    colorPicker.fireEvent(new ActionEvent());
                }
                colorComponantSelector.getSelectionModel().selectFirst();
                colorComp.clear();
                colorComp.addAll(loadedColors);
                is.close();
                saveProject();
                removeSavedChromosomeImages();
                refreshView((String) chromosomeSelector.getSelectionModel().getSelectedItem(), true);
            } catch (IOException | ClassNotFoundException ex) {

            }
        }
    }

    private void zoomRegion(Rectangle rectangle) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("ZoomRegionView.fxml"));
            ChromosomeLength chromLength = new ChromosomeLength(genomeVersion);
            String currentChrom = (String) chromosomeBoxList[chromosomeSelector.getSelectionModel()
                    .getSelectedIndex()];
            double startCoordinate = chromLength.getLength(currentChrom) / selectionOverlayPane.getWidth()
                    * rectangle.getX();
            double selectionWidth = chromLength.getLength(currentChrom) / selectionOverlayPane.getWidth()
                    * rectangle.getWidth();
            if (rectangle.getX() == 0) {
                startCoordinate = 1;
            }

            Pane page = (Pane) loader.load();
            Scene scene = new Scene(page);
            Stage stage = new Stage();
            stage.setScene(scene);
            stage.setTitle("chr" + currentChrom + ":" + nf.format(startCoordinate) + "-"
                    + nf.format(startCoordinate + selectionWidth));
            scene.getStylesheets().add(SnpViewer.class.getResource("SnpViewerStyleSheet.css").toExternalForm());
            String subPath = "zoom";
            stage.initModality(Modality.NONE);
            stage.getIcons().add(new Image(this.getClass().getResourceAsStream("icon.png")));
            stage.show();
            ZoomRegionViewController zoomController = (ZoomRegionViewController) loader.getController();
            ArrayList<SnpFile> bothFiles = new ArrayList<>();
            bothFiles.addAll(affFiles);
            bothFiles.addAll(unFiles);
            ArrayList<Pane> zoomPanes = zoomController.setPanes(bothFiles);
            zoomController.setParentController(this);
            zoomController.setLoadingRectangle(rectangle);
            zoomController.setRegionLength(selectionWidth);
            zoomController.setRegionStart(startCoordinate);
            zoomController.setChromosome(currentChrom);
            SplitPane zoomSplit = zoomController.getSplitPane();
            Iterator<SnpFile> sIter = bothFiles.iterator();
            Iterator<Pane> pIter = zoomPanes.iterator();
            if (!sIter.hasNext() || !pIter.hasNext()) {
                return;
            }
            SnpFile firstFile = sIter.next();
            Pane firstPane = pIter.next();
            drawCoordinatesWithIterator(firstFile, firstPane, subPath, sIter, pIter, 1, bothFiles.size(),
                    currentChrom, startCoordinate, startCoordinate + selectionWidth, true, zoomSplit);
            zoomController.tidyPanes();

        } catch (ChromosomeLength.ChromosomeLengthException | IOException ex) {
            Dialogs.showErrorDialog(null, "Please see details for stack trace.", "Error displaying zoomed region",
                    "SnpViewer", ex);
        }
    }

    private void clearDragSelectRectangle() {
        dragSelectRectangle.setX(0);
        dragSelectRectX.set(0);
        dragSelectRectInitX.set(0);
        dragSelectRectangle.setVisible(false);
    }

    public void selectNextChromosome(boolean next) {
        if (!cancelButton.isDisabled()) {
            cancelButton.fire();
        }
        if (next) {
            chromosomeSelector.getSelectionModel().selectNext();
        } else {
            chromosomeSelector.getSelectionModel().selectPrevious();
        }
    }

    private void removeSavedChromosomeImages() {
        ArrayList<SnpFile> bothFiles = new ArrayList<>(affFiles);
        bothFiles.addAll(unFiles);
        for (SnpFile f : bothFiles) {
            for (Iterator it = chromosomeSelector.getItems().iterator(); it.hasNext();) {
                String chrom = (String) it.next();
                /*below is a horrible cludgy fix to remove the sub folders - 
                * need to set up an enum or global variable for the call values 
                * to be used in different contexts at some point 
                */
                ArrayList<String> quals = new ArrayList<>(Arrays.asList(null, "85", "90", "95", "99"));
                for (String sub : quals) {
                    File pngFile = new File(f.getOutputDirectoryName() + "/" + chrom + ".png");
                    if (sub != null) {
                        pngFile = new File(f.getOutputDirectoryName() + "/" + sub + "/" + chrom + ".png");
                    }
                    if (pngFile.exists()) {
                        boolean deleted = pngFile.delete();
                        if (!deleted) {
                            Dialogs.showErrorDialog(null,
                                    "Unable to delete old chromosome " + "image " + pngFile.getPath()
                                            + ". Please check" + " permissions.",
                                    "Error deleting old chromosome images", "SnpViewer");
                            return;
                        }
                    }
                }

            }
        }
    }

    public void chromosomeSelected(String chrom) {
        clearDragSelectRectangle();
        selectionOverlayPane.getChildren().clear();
        savedRegionsDisplay.clear();
        savedRegionsReference.clear();
        refreshView(chrom, redrawCheckBox.isSelected());
        drawSavedRegions(chrom);
        showHideSavedRegions();

    }

    public void showSavedRegionsTable() {
        if (savedRegions.size() > 0) {
            FXMLLoader tableLoader = new FXMLLoader(getClass().getResource("MultiRegionReporter.fxml"));
            try {
                Pane tablePane = (Pane) tableLoader.load();
                MultiRegionReporterController multiReg = (MultiRegionReporterController) tableLoader
                        .getController();
                Scene tableScene = new Scene(tablePane);
                Stage tableStage = new Stage();
                tableStage.setScene(tableScene);
                tableScene.getStylesheets()
                        .add(SnpViewer.class.getResource("SnpViewerStyleSheet.css").toExternalForm());
                tableStage.getIcons().add(new Image(this.getClass().getResourceAsStream("icon.png")));
                multiReg.displayData(savedRegions);
                tableStage.setTitle("Saved Regions");
                tableStage.initModality(Modality.NONE);

                tableStage.show();
            } catch (Exception ex) {
                Dialogs.showErrorDialog(null, "Error displaying" + " Saved Regions - see Details for stack trace.",
                        "Saved Regions Display Error!", "SnpViewer", ex);
            }
        } else {
            Dialogs.showInformationDialog(null, "No regions " + "found.", "Saved Regions", "SnpViewer");
        }
    }

    private void clearSavedRegions() {
        savedRegions.clear();
        savedRegionsDisplay.clear();
        savedRegionsReference.clear();
        selectionOverlayPane.getChildren().clear();
        selectionOverlayPane.getChildren().add(dragSelectRectangle);
        saveProject();
    }

    private void showHideSavedRegions() {
        for (Rectangle rect : savedRegionsDisplay) {
            rect.setVisible(!hideSavedRegionsMenu.isSelected());
        }

    }

    private void drawSavedRegions(String chrom) {
        selectionOverlayPane.getChildren().clear();
        if (savedRegions.isEmpty()) {
            selectionOverlayPane.getChildren().add(dragSelectRectangle);
            return;
        }
        for (RegionSummary r : savedRegions) {
            if (r.getChromosome() == null) {
                selectionOverlayPane.getChildren().add(dragSelectRectangle);
                return;
            }
            if (r.getChromosome().equalsIgnoreCase(chrom)) {
                drawRegionSummary(r, chrom);
            }
        }
        int rectCounter = 0;
        for (final Rectangle rect : savedRegionsDisplay) {
            final int counter = rectCounter;
            final ContextMenu scm = new ContextMenu();
            final MenuItem scmItem1 = new MenuItem("Display Flanking SNP IDs");
            scmItem1.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    /* get coordinates of selection and report back
                     * flanking snp ids and coordinates
                     */
                    displayFlankingSnpIDs(rect);

                }
            });
            final MenuItem scmItem2 = new MenuItem("Write Region to File");
            scmItem2.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            /* get coordinates of selection and 
                             * write SNPs in region to file
                             */
                            writeRegionToFile(rect);
                        }
                    });
                }
            });
            final MenuItem scmItem3 = new MenuItem("Remove this Saved Region");
            scmItem3.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    /* get coordinates of selection and 
                     * write SNPs in region to file
                     */
                    removeSavedRegion(counter);

                }
            });
            final MenuItem scmItem4 = new MenuItem("Show/Hide Saved Regions");
            scmItem4.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    /* get coordinates of selection and report back
                     * write SNPs in region to file
                     */
                    hideSavedRegionsMenu.selectedProperty().setValue(!hideSavedRegionsMenu.isSelected());
                    hideSavedRegionsMenu.fire();
                }
            });
            final MenuItem scmItem5 = new MenuItem("Zoom Region");
            scmItem5.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    /* get coordinates of selection and report back
                     * write SNPs in region to file
                     */
                    zoomRegion(rect);
                }
            });
            final MenuItem scmItem6 = new MenuItem("Write Saved Regions to File");
            scmItem6.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            /* get coordinates of selection and report back
                             * write SNPs in region to file
                             */
                            writeSavedRegionsToFile();
                        }
                    });
                }
            });

            scm.getItems().add(scmItem1);
            scm.getItems().add(scmItem2);
            scm.getItems().add(scmItem3);
            scm.getItems().add(scmItem4);
            scm.getItems().add(scmItem5);
            scm.getItems().add(scmItem6);
            rect.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent e) {
                    ocm.hide();

                    if (scm.isShowing()) {
                        scm.hide();
                    }
                    if (e.getButton() == MouseButton.SECONDARY) {
                        if (chromosomeSelector.getSelectionModel().isEmpty()) {
                            for (MenuItem mi : scm.getItems()) {
                                mi.setDisable(true);
                            }
                        } else {
                            for (MenuItem mi : scm.getItems()) {
                                mi.setDisable(false);
                            }
                        }

                        scm.show(selectionOverlayPane, e.getScreenX(), e.getScreenY());
                    }
                }

            });
            rect.setVisible(true);
            selectionOverlayPane.getChildren().add(rect);
            rectCounter++;
        }
        selectionOverlayPane.getChildren().add(dragSelectRectangle);
    }

    private void removeSavedRegion(int index) {
        RegionSummary regionToRemove = savedRegionsReference.get(index);
        if (savedRegions.contains(regionToRemove)) {
            savedRegions.remove(regionToRemove);
            saveProject();
            savedRegionsDisplay.clear();
            savedRegionsReference.clear();
            selectionOverlayPane.getChildren().clear();
            selectionOverlayPane.getChildren().add(dragSelectRectangle);
            drawSavedRegions((String) chromosomeBoxList[chromosomeSelector.getSelectionModel().getSelectedIndex()]);
        } else {
            Dialogs.showErrorDialog(null, "Can't find item for removal! Please " + "report this error.", "ERROR",
                    "SnpViewer");
        }
    }

    private void drawRegionSummary(RegionSummary reg, String currentChrom) {
        if (currentChrom == null) {
            if (reg.getChromosome() != null) {
                currentChrom = reg.getChromosome();
            } else {
                return;
            }
        }
        ChromosomeLength chromLength;
        try {
            chromLength = new ChromosomeLength(genomeVersion);
        } catch (Exception ex) {
            chromLength = new ChromosomeLength();
        }
        double x;
        double width;
        double cLength;
        try {
            cLength = chromLength.getLength(currentChrom);
        } catch (Exception ex) {
            ex.printStackTrace();
            return;
        }
        int startPos = reg.getStartPos();
        int rLength = reg.getLength();
        x = chromSplitPane.getWidth() / cLength * startPos;
        width = chromSplitPane.getWidth() / cLength * rLength;

        Rectangle regionRectangle = new Rectangle();
        regionRectangle.setX(x);
        regionRectangle.setWidth(width);
        regionRectangle.setY(0);
        regionRectangle.xProperty().bind(selectionOverlayPane.widthProperty().divide(cLength).multiply(startPos));
        regionRectangle.heightProperty().bind(selectionOverlayPane.heightProperty());
        regionRectangle.widthProperty()
                .bind(selectionOverlayPane.widthProperty().divide(cLength).multiply(rLength));
        regionRectangle.strokeProperty().set(colorComp.get(Colors.saveLine.value));
        regionRectangle.fillProperty().set(colorComp.get(Colors.saveFill.value));
        regionRectangle.setOpacity(0.40);
        regionRectangle.setStrokeWidth(2);
        savedRegionsDisplay.add(regionRectangle);
        savedRegionsReference.add(reg);
    }

    public void cacheChromsFired() {
        DialogResponse response = Dialogs.showConfirmDialog(null,
                "Caching chromsome" + " images can take a long time. Once finished you will have quick "
                        + "access to each chromosome image.\n\nClick 'OK' to continue.",
                "Continue caching chromosome images?", "SNP Viewer", Dialogs.DialogOptions.OK_CANCEL);
        if (response != DialogResponse.OK) {
            return;
        }
        List chroms = chromosomeSelector.getItems();
        setProgressMode(true);
        Iterator chromIter = chroms.iterator();
        ArrayList<SnpFile> bothFiles = new ArrayList<>(affFiles);
        bothFiles.addAll(unFiles);
        Pane tempPane = new Pane();
        tempPane.setMinWidth(chromSplitPane.getWidth());
        tempPane.setMinHeight(chromSplitPane.getHeight());
        //tempPane.setCache(true);
        chromSplitPane.getItems().clear();
        chromSplitPane.getItems().add(tempPane);
        final Iterator fileIter = bothFiles.iterator();
        String firstChrom = (String) chromIter.next();
        SnpFile firstFile = (SnpFile) fileIter.next();
        Stage stage = (Stage) chromSplitPane.getScene().getWindow();
        //stage.setResizable(false);
        fixStageSize(stage, true);
        progressBar.progressProperty().unbind();
        progressBar.progressProperty().setValue(0);
        String pngPath = null;
        if (qualityFilter != null) {
            Integer percent = new Integer(100 - (int) (qualityFilter * 100));
            pngPath = percent.toString();
        }
        cacheChromsWithIterator(chromIter, firstFile, tempPane, pngPath, fileIter, 1,
                bothFiles.size() * chroms.size(), firstChrom);

    }

    public void cacheChromsWithIterator(final Iterator chromIter, final SnpFile sfile, final Pane pane,
            final String pngPath, final Iterator sIter, final int currentFile, final int totalFiles,
            final String chrom) {
        final DrawSnpsToPane draw = new DrawSnpsToPane(pane, sfile, chrom, Colors.aa.value, Colors.bb.value,
                Colors.ab.value);

        progressBar.progressProperty().unbind();
        //progressBar.progressProperty().bind(draw.progressProperty());
        progressTitle.setText("Processing chr" + chrom);
        progressMessage.setText("File " + sfile.inputFile.getName());
        cancelButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                draw.cancel();

            }
        });

        draw.setOnCancelled(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                progressBar.progressProperty().unbind();
                progressBar.setProgress(0);
                progressTitle.setText("Drawing Cancelled");
                progressMessage.textProperty().unbind();
                progressMessage.setText("Drawing Cancelled");
                setProgressMode(false);
                Stage stage = (Stage) chromSplitPane.getScene().getWindow();
                fixStageSize(stage, false);
                // stage.setResizable(true);
            }
        });
        draw.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                ArrayList<HashMap<String, Double>> result = (ArrayList<HashMap<String, Double>>) t.getSource()
                        .getValue();
                progressBar.progressProperty().unbind();
                progressBar.setProgress((double) currentFile / ((double) totalFiles * 2));
                progressTitle.setText("");
                progressMessage.textProperty().unbind();
                progressMessage.setText("");
                pane.getChildren().clear();
                /*if (pane.getMinHeight() < 200){
                   pane.setMinHeight(200);
                }
                if (pane.getMinWidth() < 800){
                   pane.setMinWidth(800);
                }*/
                if (result != null) {
                    List<Line> lines = drawLinesToPane(pane, result);
                    pane.getChildren().addAll(lines);
                    convertSampleViewToImage(sfile, pane, chrom, pngPath);
                    lines.clear();
                }
                progressBar.setProgress((double) currentFile / (double) totalFiles);
                if (sIter.hasNext()) {
                    cacheChromsWithIterator(chromIter, (SnpFile) sIter.next(), pane, pngPath, sIter,
                            currentFile + 1, totalFiles, chrom);
                } else {
                    if (chromIter.hasNext()) {
                        ArrayList<SnpFile> bothFiles = new ArrayList<>(affFiles);
                        bothFiles.addAll(unFiles);
                        Iterator sIterNew = bothFiles.iterator();
                        cacheChromsWithIterator(chromIter, (SnpFile) sIterNew.next(), pane, pngPath, sIterNew,
                                currentFile + 1, totalFiles, (String) chromIter.next());
                    } else {
                        progressBar.progressProperty().unbind();
                        progressBar.setProgress(0);
                        setProgressMode(false);
                        redrawCheckBox.setSelected(false);
                        chromosomeSelector.getSelectionModel().selectFirst();
                        refreshView((String) chromosomeSelector.getSelectionModel().getSelectedItem(), false);
                        Stage stage = (Stage) chromSplitPane.getScene().getWindow();
                        fixStageSize(stage, false);
                        stage.setResizable(true);
                    }
                }
            }
        });
        draw.setOnFailed(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                progressBar.progressProperty().unbind();
                progressBar.setProgress(0);
                progressTitle.setText("ERROR!");
                progressMessage.textProperty().unbind();
                progressMessage.setText("Drawing failed!");
                setProgressMode(false);
                Stage stage = (Stage) chromSplitPane.getScene().getWindow();
                stage.setResizable(true);
                fixStageSize(stage, false);
            }

        });
        draw.start();
    }

    private void clearSplitPanes() {
        for (Iterator it = chromSplitPane.getItems().iterator(); it.hasNext();) {
            Object child = it.next();
            if (child instanceof Pane) {
                Pane p = (Pane) child;
                for (Iterator pit = p.getChildren().iterator(); pit.hasNext();) {
                    Object pChild = pit.next();
                    if (pChild instanceof ImageView) {
                        ImageView i = (ImageView) pChild;
                        i.fitHeightProperty().unbind();
                        i.fitWidthProperty().unbind();
                    } else if (pChild instanceof Line) {
                        Line l = (Line) pChild;
                        l.startXProperty().unbind();
                        l.endXProperty().unbind();
                        l.startYProperty().unbind();
                        l.endYProperty().unbind();
                    }
                }
                p.minWidthProperty().unbind();
                p.minHeightProperty().unbind();
            }
        }
        for (Iterator it = labelSplitPane.getItems().iterator(); it.hasNext();) {
            Object child = it.next();
            if (child instanceof Pane) {
                Pane p = (Pane) child;
                p.minWidthProperty().unbind();
                p.minHeightProperty().unbind();
            }
        }
        chromSplitPane.getItems().clear();
        labelSplitPane.getItems().clear();
    }

    public void refreshView(String chrom, boolean forceRedraw) {
        //if forceRedraw is false look for existing png files for each snpFile
        if (chrom == null) {
            /*if null is passed then select/reselect chromosome from 
             * chromosomeSelector, return and let chromosomeSelector's 
             * listener refire this method
             */
            if (chromosomeSelector.getSelectionModel().isEmpty()) {
                chromosomeSelector.getSelectionModel().selectFirst();
            } else {
                int sel = chromosomeSelector.getSelectionModel().getSelectedIndex();
                chromosomeSelector.getSelectionModel().clearSelection();
                chromosomeSelector.getSelectionModel().select(sel);
            }
            return;
        }
        int totalFiles = affFiles.size() + unFiles.size();
        if (totalFiles < 1) {
            return;
        }
        ArrayList<Pane> panesToAdd = new ArrayList<>();
        ArrayList<ScrollPane> labelsToAdd = new ArrayList<>();
        clearSplitPanes();

        setProgressMode(true);
        nextChromMenu.setDisable(false);
        nextChromMenu.setDisable(false);
        for (final SnpFile f : affFiles) {
            Pane sPane = new Pane();
            sPane.setMinHeight(chromSplitPane.getHeight() / totalFiles);
            sPane.setMinWidth(chromSplitPane.getWidth());
            sPane.setVisible(true);
            panesToAdd.add(sPane);
            ScrollPane labelPane = new ScrollPane();
            Label fileLabel = new Label(f.inputFile.getName() + "\n(Affected)");
            fileLabel.setTextFill(Color.WHITE);
            labelPane.setMinHeight(labelSplitPane.getHeight() / totalFiles);
            labelPane.setPrefWidth(labelSplitPane.getWidth());
            labelPane.minHeightProperty().bind(labelSplitPane.heightProperty().divide(totalFiles));
            VBox vbox = new VBox();
            vbox.setSpacing(10);
            vbox.getChildren().add(fileLabel);
            final TextField textField = new TextField();
            textField.setStyle("-fx-text-fill: white; -fx-background-color: "
                    + "rgba(90%,90%,90%,0.3); -fx-border-color:white");
            textField.setPromptText("Sample Name");
            if (f.getSampleName() != null) {
                textField.setText(f.getSampleName());
            }
            textField.setFocusTraversable(true);
            textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
                @Override
                public void handle(KeyEvent ke) {
                    if (ke.getCode().equals(KeyCode.ENTER)) {
                        if (!textField.getText().isEmpty()) {
                            String name = textField.getText().trim();
                            if (name.length() > 0) {
                                f.setSampleName(name);
                            }
                            textField.getParent().requestFocus();
                            saveProject();
                        }
                    }
                }
            });
            textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
                @Override
                public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
                        Boolean newValue) {
                    if (!textField.isFocused()) {
                        if (!textField.getText().isEmpty()) {
                            String name = textField.getText().trim();
                            if (name.length() > 0) {
                                f.setSampleName(name);
                            }
                            saveProject();
                        }
                    }
                }
            });
            vbox.getChildren().add(textField);
            Label noCalls = new Label();
            if (f.getPercentNoCall() != null) {
                noCalls.setText("No Calls: " + DecimalFormat.getInstance().format(f.getPercentNoCall()) + " %");
            } else {
                noCalls.setText("No Calls: none");
            }
            Label meanQual = new Label();
            if (f.getMeanQuality() != null) {
                meanQual.setText("Av. Call Conf: "
                        + DecimalFormat.getInstance().format(100 - (f.getMeanQuality() * 100)) + " %");
            } else {
                meanQual.setText("No Call Confidence Data");
            }
            vbox.getChildren().add(noCalls);
            vbox.getChildren().add(meanQual);
            labelPane.setContent(vbox);
            //            labelPane.getChildren().add(fileLabel);
            //            labelPane.getChildren().add(new TextField());
            labelsToAdd.add(labelPane);
        }
        for (final SnpFile f : unFiles) {
            Pane sPane = new Pane();
            sPane.setMinHeight(chromSplitPane.getHeight() / totalFiles);
            sPane.setMinWidth(chromSplitPane.getWidth());
            sPane.setVisible(true);
            panesToAdd.add(sPane);
            ScrollPane labelPane = new ScrollPane();
            Label fileLabel = new Label(f.inputFile.getName() + "\n(Unaffected)");
            fileLabel.setStyle("-fx-text-fill: black");
            labelPane.setMinHeight(labelSplitPane.getHeight() / totalFiles);
            labelPane.setPrefWidth(labelSplitPane.getWidth());
            labelPane.minHeightProperty().bind(labelSplitPane.heightProperty().divide(totalFiles));
            VBox vbox = new VBox();
            vbox.setSpacing(10);
            vbox.getChildren().add(fileLabel);
            final TextField textField = new TextField();
            textField.setStyle("-fx-text-fill: black; " + "-fx-background-color: rgba(90%,90%,90%,0.3);"
                    + " -fx-border-color:white");
            textField.setPromptText("Sample Name");
            if (f.getSampleName() != null) {
                textField.setText(f.getSampleName());
            }
            textField.setFocusTraversable(true);
            textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
                @Override
                public void handle(KeyEvent ke) {
                    if (ke.getCode().equals(KeyCode.ENTER)) {
                        if (!textField.getText().isEmpty()) {
                            f.setSampleName(textField.getText());
                            textField.getParent().requestFocus();
                            saveProject();
                        }
                    }
                }
            });
            textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
                @Override
                public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
                        Boolean newValue) {
                    if (!textField.isFocused()) {
                        if (!textField.getText().isEmpty()) {
                            f.setSampleName(textField.getText());
                            saveProject();
                        }
                    }
                }
            });
            vbox.getChildren().add(textField);
            Label noCalls = new Label();
            if (f.getPercentNoCall() != null) {
                noCalls.setText("No Calls: " + DecimalFormat.getInstance().format(f.getPercentNoCall()) + " %");
            } else {
                noCalls.setText("No Calls: none");
            }
            Label meanQual = new Label();
            if (f.getMeanQuality() != null) {
                meanQual.setText("Av. Call Conf: "
                        + DecimalFormat.getInstance().format(100 - (f.getMeanQuality() * 100)) + " %");
            } else {
                meanQual.setText("No Call Confidence Data");
            }
            vbox.getChildren().add(noCalls);
            vbox.getChildren().add(meanQual);
            labelPane.setContent(vbox);
            //            labelPane.getChildren().add(fileLabel);
            labelsToAdd.add(labelPane);
        }
        if (panesToAdd.size() > 0) {
            chromSplitPane.getItems().addAll(panesToAdd);
            labelSplitPane.getItems().addAll(labelsToAdd);

            ArrayList<SnpFile> bothFiles = new ArrayList<>(affFiles);
            bothFiles.addAll(unFiles);
            final Iterator<SnpFile> fileIter = bothFiles.iterator();
            final Iterator<Pane> paneIter = panesToAdd.iterator();
            SnpFile firstFileToProcess = fileIter.next();
            Pane firstPaneToProcess = paneIter.next();
            String pngPath = null;
            if (qualityFilter != null) {
                Integer percent = new Integer(100 - (int) (qualityFilter * 100));
                pngPath = percent.toString();
            }
            drawWithIterator(firstFileToProcess, firstPaneToProcess, pngPath, fileIter, paneIter, 1, totalFiles,
                    chrom, forceRedraw, chromSplitPane);
        } else {
            setProgressMode(false);
        }
    }//end of refreshView

    private void fixStageSize(Stage stage, boolean fix) {
        /*provides a fix for annoying bug which means that 
         * setResizable(false) causing windows to grow in size in Windows
         */
        if (fix) {
            stage.setMaxHeight(stage.getHeight());
            stage.setMinHeight(stage.getHeight());
            stage.setMaxWidth(stage.getWidth());
            stage.setMinWidth(stage.getWidth());
        } else {
            Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
            stage.setMaxHeight(primaryScreenBounds.getHeight());
            stage.setMinHeight(300);
            stage.setMaxWidth(primaryScreenBounds.getWidth());
            stage.setMinWidth(500);
        }
    }

    public void drawWithIterator(final SnpFile sfile, final Pane pane, final String pngPath,
            final Iterator<SnpFile> sIter, final Iterator<Pane> pIter, final int currentFile, final int totalFiles,
            final String chrom, final boolean forceRedraw, final SplitPane splitPane) {
        drawCoordinatesWithIterator(sfile, pane, pngPath, sIter, pIter, currentFile, totalFiles, chrom, null, null,
                forceRedraw, splitPane);
    }

    public void drawCoordinatesWithIterator(final SnpFile sfile, final Pane pane, final String pngPath,
            final Iterator<SnpFile> sIter, final Iterator<Pane> pIter, final int currentFile, final int totalFiles,
            final String chrom, final Double start, final Double end, final boolean forceRedraw,
            final SplitPane splitPane) {
        Stage stage = (Stage) splitPane.getScene().getWindow();
        fixStageSize(stage, true);

        //stage.setResizable(false);//we have to disable this when using windows due to a bug (in javafx?)
        File pngFile = new File(sfile.getOutputDirectoryName() + "/" + chrom + ".png");
        if (pngPath != null && pngPath.length() > 0) {
            pngFile = new File(sfile.getOutputDirectoryName() + "/" + pngPath + "/" + chrom + ".png");
        }
        if (!forceRedraw && pngFile.exists()) {
            try {
                progressBar.progressProperty().unbind();
                progressBar.setProgress((double) currentFile / (double) totalFiles);
                BufferedImage bufferedImage = ImageIO.read(pngFile);
                Image image = SwingFXUtils.toFXImage(bufferedImage, null);
                ImageView chromImage = new ImageView(image);
                //chromImage.setCache(true);
                pane.getChildren().clear();
                pane.getChildren().add(chromImage);
                //pane.setCache(true);
                chromImage.fitWidthProperty().bind(pane.widthProperty());
                chromImage.fitHeightProperty().bind(pane.heightProperty());
                pane.minHeightProperty().bind(splitPane.heightProperty().divide(totalFiles));
                pane.minWidthProperty().bind(splitPane.widthProperty());

                if (sIter.hasNext()) {
                    SnpFile nextFile = sIter.next();
                    Pane nextPane = pIter.next();
                    drawCoordinatesWithIterator(nextFile, nextPane, pngPath, sIter, pIter, currentFile + 1,
                            totalFiles, chrom, start, end, forceRedraw, splitPane);
                } else {
                    progressBar.progressProperty().unbind();
                    progressBar.setProgress(0);
                    setProgressMode(false);
                    fixStageSize(stage, false);//for windows only
                    stage.setResizable(true);
                }
            } catch (IOException ex) {
                Dialogs.showErrorDialog(null, "IO error reading cached image", "Error displaying chromosome image",
                        "SnpViewer", ex);
                return;
            }

        } else {

            final DrawSnpsToPane draw = new DrawSnpsToPane(pane, sfile, chrom, Colors.aa.value, Colors.bb.value,
                    Colors.ab.value, start, end);

            progressBar.progressProperty().unbind();
            //progressBar.setProgress(0);
            //progressBar.progressProperty().bind(draw.progressProperty());
            progressTitle.setText("Drawing " + currentFile + " of " + totalFiles);
            progressMessage.textProperty().bind(draw.messageProperty());
            cancelButton.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent actionEvent) {
                    draw.cancel();
                }
            });

            draw.setOnCancelled(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {

                    progressBar.progressProperty().unbind();
                    progressBar.setProgress(0);
                    progressTitle.setText("Drawing Cancelled");
                    progressMessage.textProperty().unbind();
                    progressMessage.setText("Drawing Cancelled");
                    setProgressMode(false);
                    selectionOverlayPane.getChildren().clear();
                    selectionOverlayPane.getChildren().add(dragSelectRectangle);
                    Stage stage = (Stage) splitPane.getScene().getWindow();
                    stage.setResizable(true);
                    fixStageSize(stage, false);//for windows only
                }
            });
            draw.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {
                    ArrayList<HashMap<String, Double>> result = (ArrayList<HashMap<String, Double>>) t.getSource()
                            .getValue();
                    progressBar.progressProperty().unbind();
                    progressBar.setProgress((double) currentFile / (2 * (double) totalFiles));
                    progressTitle.setText("");
                    progressMessage.textProperty().unbind();
                    progressMessage.setText("");
                    /*if (pane.getMinHeight() < 200){
                    pane.setMinHeight(200);
                    }
                    if (pane.getMinWidth() < 800){
                        pane.setMinWidth(800);
                    }*/
                    if (result != null) {
                        List<Line> lines = drawLinesToPane(pane, result);
                        pane.getChildren().addAll(lines);
                        pane.setVisible(true);
                        convertSampleViewToImage(sfile, pane, chrom, pngPath);
                        /*for (Line l: lines){
                            l.startXProperty().unbind();
                            l.startYProperty().unbind();
                            l.endXProperty().unbind();
                            l.endYProperty().unbind();
                        }*/
                        lines.clear();
                    }
                    progressBar.setProgress((double) currentFile / (double) totalFiles);
                    pane.minWidthProperty().bind(splitPane.widthProperty());
                    pane.minHeightProperty().bind(splitPane.heightProperty().divide(totalFiles));
                    // pane.setCache(true);
                    if (sIter.hasNext()) {
                        SnpFile nextFile = sIter.next();
                        Pane nextPane = pIter.next();
                        drawCoordinatesWithIterator(nextFile, nextPane, pngPath, sIter, pIter, currentFile + 1,
                                totalFiles, chrom, start, end, forceRedraw, splitPane);
                    } else {
                        setProgressMode(false);
                        progressBar.progressProperty().unbind();
                        progressBar.setProgress(0);

                        Stage stage = (Stage) splitPane.getScene().getWindow();
                        stage.setResizable(true);
                        fixStageSize(stage, false);//for windows only
                    }
                }
            });
            draw.setOnFailed(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {
                    draw.reset();
                    progressBar.progressProperty().unbind();
                    progressBar.setProgress(0);
                    progressTitle.setText("ERROR!");
                    progressMessage.textProperty().unbind();
                    progressMessage.setText("Drawing failed!");
                    setProgressMode(false);
                    selectionOverlayPane.getChildren().clear();
                    selectionOverlayPane.getChildren().add(dragSelectRectangle);
                    //     Stage stage = (Stage) chromSplitPane.getScene().getWindow();
                    //     stage.setResizable(true);
                }

            });
            draw.start();
        }
    }

    public List<Line> drawLinesToPane(Pane pane, final ArrayList<HashMap<String, Double>> linemap) {
        List<Line> lines = new ArrayList();
        for (HashMap<String, Double> l : linemap) {
            double width = pane.getWidth();
            double coord = l.get("x");
            Line line = new Line(l.get("x"), 0, l.get("x"), pane.getMinHeight());
            line.setStroke(colorComp.get(l.get("color").intValue()));
            /*line.startXProperty().bind((pane.widthProperty().divide(width)).multiply(coord) );
            line.endXProperty().bind((pane.widthProperty().divide(width)).multiply(coord) );
            line.endYProperty().bind(pane.heightProperty().subtract(1));*/
            lines.add(line);
            //pane.getChildren().add(l);
        }
        return lines;

    }

    public void convertSampleViewToImage(final SnpFile s, final Pane pane, final String chrom, final String path) {
        WritableImage image;
        try {
            image = pane.snapshot(null, null);
        } catch (IllegalStateException ex) {
            Dialogs.showErrorDialog(null, "Error while attempting to convert" + " view to image file",
                    "PNG conversion failed", "SNP Viewer", ex);
            return;
        }

        final DrawPaneToPng drawToPng = new DrawPaneToPng(image);
        drawToPng.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                File pngFile;
                if (path != null && path.length() > 0) {
                    pngFile = new File(s.getOutputDirectoryName() + "/" + path + "/" + chrom + ".png");
                } else {
                    pngFile = new File(s.getOutputDirectoryName() + "/" + chrom + ".png");
                }
                try {
                    if (!pngFile.getParentFile().exists()) {
                        boolean madeDir = pngFile.getParentFile().mkdir();
                        if (madeDir == false) {
                            Dialogs.showErrorDialog(null, "Unable to make sub directory"
                                    + " when converting dynamic view to image file. Please " + "check permissions.",
                                    "PNG conversion failed", "SNP Viewer");
                            return;
                        }
                    }
                    Files.copy(drawToPng.getImageFile().toPath(), pngFile.toPath(), REPLACE_EXISTING);
                    BufferedImage bufferedImage = ImageIO.read(pngFile);
                    Image image = SwingFXUtils.toFXImage(bufferedImage, null);

                    ImageView chromImage = new ImageView(image);
                    // chromImage.setCache(true);
                    for (Iterator it = pane.getChildren().iterator(); it.hasNext();) {
                        Object line = it.next();
                        if (line instanceof Line) {
                            /*Line l = (Line) line;
                            l.startXProperty().unbind();
                            l.endXProperty().unbind();
                            l.endYProperty().unbind();*/
                        } else if (line instanceof ImageView) {
                            ImageView l = (ImageView) line;
                            l.fitHeightProperty().unbind();
                            l.fitWidthProperty().unbind();
                        }
                    }
                    pane.getChildren().clear();
                    pane.getChildren().add(chromImage);

                    chromImage.fitWidthProperty().bind(pane.widthProperty());
                    chromImage.fitHeightProperty().bind(pane.heightProperty());
                } catch (IOException ex) {
                    Dialogs.showErrorDialog(null,
                            "IOException while attempting to convert" + " dynamic view to image file",
                            "PNG conversion failed", "SNP Viewer", ex);
                }
            }
        });
        drawToPng.setOnFailed(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                Dialogs.showErrorDialog(null, "Error attempting to convert" + " dynamic view to image file",
                        "PNG conversion failed", "SNP Viewer");

            }
        });
        drawToPng.start();
    }//end of convertSampleViewToImage

    public void drawPaneToPng() {
        if (chromosomeSelector.getSelectionModel().isEmpty()) {
            return;
        }
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("PNG Image Files (*.png)", "*.png");
        fileChooser.getExtensionFilters().add(extFilter);
        fileChooser.setTitle("Save View as Image (.png) File...");
        File pngFile = fileChooser.showSaveDialog(mainWindow);
        if (pngFile == null) {
            return;
        } else if (!pngFile.getName().endsWith(".png")) {
            pngFile = new File(pngFile.getAbsolutePath() + ".png");
        }
        WritableImage image = chromSplitPane.snapshot(null, null);
        if (image == null) {
            Dialogs.showErrorDialog(null, "Error attempting to convert" + " dynamic view to image file",
                    "PNG conversion failed", "SNP Viewer");
            return;
        }
        try {
            ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", pngFile);
            Dialogs.showInformationDialog(null, "Sucessfully saved current view " + "to " + pngFile.getName(),
                    "Image Saved", "SNP Viewer");
        } catch (IOException ex) {
            Dialogs.showErrorDialog(null, "Error attempting to convert" + " dynamic view to image file",
                    "PNG conversion failed", "SNP Viewer", ex);
        }
    }

    public void newProjectFired(ActionEvent event) {
        newProjectButton.setDisable(true);
        loadProjectButton.setDisable(true);
        if (projectRunning) {
            DialogResponse response = Dialogs.showConfirmDialog(null,
                    "Your current project will be closed. Its data will be saved.", "Close Current Project?",
                    "SNP Viewer", Dialogs.DialogOptions.YES_NO);
            if (!DialogResponse.YES.equals(response)) {
                newProjectButton.setDisable(false);
                loadProjectButton.setDisable(false);
                return;
            }
        }
        boolean success = startNewProject();
        newProjectButton.setDisable(false);
        loadProjectButton.setDisable(false);
        if (success) {
            projectRunning = true;
            Dialogs.showInformationDialog(null,
                    "Your project will automatically" + " save itself as you make changes.",
                    "Project " + projectFile.getName() + " Created", "SNP Viewer");
            setProgressMode(false);
        } else {
            projectLabel.setText("Project: none");
            Dialogs.showErrorDialog(null, "Could not create new project", "Project Creation Failed", "SNP Viewer");
            projectRunning = false;
        }

    }

    public void closeButtonFired(ActionEvent ev) {

        Stage stage = (Stage) mainMenu.getScene().getWindow();
        stage.close();

    }

    public boolean startNewProject() {
        affFiles.clear();
        unFiles.clear();
        resetObservables();
        genomeVersion = "";
        qualityFilter = null;
        noFilteringRadio.setSelected(true);
        chromSplitPane.getItems().clear();
        labelSplitPane.getItems().clear();
        chromosomeSelector.getItems().clear();
        snpViewSaveDirectory = null;
        clearDragSelectRectangle();
        savedRegions.clear();
        savedRegionsDisplay.clear();
        savedRegionsReference.clear();
        selectionOverlayPane.getChildren().clear();
        selectionOverlayPane.getChildren().add(dragSelectRectangle);

        if (projectRunning) {
            setProgressMode(true);
        }
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("SNP Viewer Projects (*.svproj)",
                "*.svproj");
        fileChooser.getExtensionFilters().add(extFilter);
        fileChooser.setTitle("Save New SNP Viewer (.svproj) Project As...");
        projectFile = fileChooser.showSaveDialog(mainWindow);
        if (projectFile != null) {
            if (!projectFile.getName().endsWith(".svproj")) {
                projectFile = new File(projectFile.getAbsolutePath() + ".svproj");
            }
            try {
                String projectName = projectFile.getName().replaceAll(".svproj", "");
                File snpViewDir = new File(projectFile.getParentFile() + "/" + projectName + " SNP Viewer files");
                if (snpViewDir.exists()) {
                    FileUtils.deleteDirectory(snpViewDir);
                }
                boolean madeDir = snpViewDir.mkdir();
                if (madeDir) {
                    snpViewSaveDirectory = snpViewDir;
                } else {
                    //display error?
                    return false;
                }
            } catch (Exception ex) {
                Dialogs.showErrorDialog(null, "Project Directory Creation Failed", "Error Creating New Project",
                        "Snp Viewer", ex);
            }
            return saveProject(projectFile);
        } else {
            resetView();
            return false;
        }

    }

    public void windowResized(ActionEvent event) {
        if (dragSelectRectangle.getWidth() > 0) {
            dragSelectRectangle.setX(0);
            dragSelectRectX.set(0);
            dragSelectRectInitX.set(0);
            dragSelectRectangle.setVisible(false);
        }
    }

    public void saveButtonFired(ActionEvent event) {
        boolean success = saveProject();
        if (success) {
            Dialogs.showInformationDialog(null, projectFile.getName() + " saved sucessfully", "Save Successful",
                    "SNP Viewer");
        }
    }

    public void affButtonFired(ActionEvent event) {
        addInputFiles(true);
    }

    public void unButtonFired(ActionEvent event) {
        addInputFiles(false);
    }

    public void redrawButtonFired(ActionEvent event) {
        refreshView((String) chromosomeSelector.getSelectionModel().getSelectedItem(), true);
    }

    public void clearSavedRegionsFired(ActionEvent event) {
        clearSavedRegions();
    }

    public void removeSamples(ActionEvent event) {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("RemoveSamplesInterface.fxml"));
        try {
            Pane pane = (Pane) loader.load();
            RemoveSamplesInterfaceController removeController = (RemoveSamplesInterfaceController) loader
                    .getController();
            Scene scene = new Scene(pane);
            Stage stage = new Stage();
            stage.setScene(scene);
            scene.getStylesheets().add(SnpViewer.class.getResource("SnpViewerStyleSheet.css").toExternalForm());
            stage.getIcons().add(new Image(this.getClass().getResourceAsStream("icon.png")));
            stage.setTitle("Remove Samples");
            removeController.setSamples(affObserve, unObserve);
            stage.initModality(Modality.APPLICATION_MODAL);
            stage.showAndWait();
            List<Integer> indicesToRemove = removeController.getSamplesToRemove();
            //System.out.println(indicesToRemove.toString());
            if (indicesToRemove.isEmpty()) {
                return;
            }
            ArrayList<Integer> affsToRemove = new ArrayList<>();
            ArrayList<Integer> unsToRemove = new ArrayList<>();
            for (Integer r : indicesToRemove) {
                if (r < affObserve.size()) {//index corresponds to affFiles
                    affsToRemove.add(r);
                } else {//index corresponds to unFiles
                    r -= affObserve.size();
                    unsToRemove.add(r);
                }
            }
            ArrayList<File> dirsToDelete = new ArrayList<>();
            if (!affsToRemove.isEmpty()) {
                Collections.sort(affsToRemove, Collections.reverseOrder());
                for (int i : affsToRemove) {
                    dirsToDelete.add(affObserve.get(i).getOutputDirectory());
                    affObserve.remove(i);
                }
            }
            if (!unsToRemove.isEmpty()) {
                Collections.sort(unsToRemove, Collections.reverseOrder());
                for (int i : unsToRemove) {
                    dirsToDelete.add(unObserve.get(i).getOutputDirectory());
                    unObserve.remove(i);
                }
            }
            if (affObserve.isEmpty() && unObserve.isEmpty()) {
                resetView();
            } else {
                refreshView(null, false);
            }
            saveProject();
            for (File dir : dirsToDelete) {
                FileUtils.deleteDirectory(dir);
            }
        } catch (Exception ex) {
            Dialogs.showErrorDialog(null,
                    "Sample removal failed - please see " + "details for stack trace and report this error.",
                    "Remove Samples Failed!", "SnpViewer", ex);
        }
    }

    private void resetView() {
        chromSplitPane.getItems().clear();
        labelSplitPane.getItems().clear();
        newProjectMenu.setDisable(false);
        loadProjectMenu.setDisable(false);
        addAffected.setDisable(false);
        addUnaffected.setDisable(false);
        addAffSampleMenu.setDisable(false);
        addUnSampleMenu.setDisable(false);
        loadProjectButton.setDisable(false);
        newProjectButton.setDisable(false);
        saveToPngMenu.setDisable(true);
        chromosomeSelector.setDisable(true);
        redrawButton.setDisable(true);
        colorPicker.setDisable(true);
        colorComponantSelector.setDisable(true);
        cacheChromsButton.setDisable(true);

        cacheChromsMenu.setDisable(true);
        nextChromMenu.setDisable(true);
        prevChromMenu.setDisable(true);
        firstChromMenu.setDisable(true);
        lastChromMenu.setDisable(true);
        redrawMenu.setDisable(true);
        autoFindRegions.setDisable(true);
        displaySavedsRegionsMenu.setDisable(true);
        clearSavedRegionsMenu.setDisable(true);
        hideSavedRegionsMenu.setDisable(true);
        outputSavedRegionsMenu.setDisable(true);
        findRegionsButton.setDisable(true);
        removeSampleMenu.setDisable(true);
        noFilteringRadio.setDisable(true);
        filter99.setDisable(true);
        filter95.setDisable(true);
        filter90.setDisable(true);
        filter85.setDisable(true);
        cancelButton.setDisable(true);
    }

    public void addInputFiles(final boolean isAffected) {
        setProgressMode(true);
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters()
                .add(new FileChooser.ExtensionFilter("Text Files", "*.txt", "AutoSNPa Files", "*.xls"));
        fileChooser.setTitle("Select one or more input (birdseed) files");
        List<File> chosen = fileChooser.showOpenMultipleDialog(null);
        if (chosen == null) {
            setProgressMode(false);
            return;
        }
        cancelButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                setProgressMode(false);
            };
        });
        ArrayList<File> inputFiles = new ArrayList<>();
        inputFiles.addAll(chosen);
        ArrayList<File> duplicates = new ArrayList<>();
        ArrayList<Integer> indicesToRemove = new ArrayList<>();
        for (int i = 0; i < inputFiles.size(); i++) {
            for (SnpFile s : affFiles) {
                if (inputFiles.get(i).getName().equals(s.getInputFileName())) {
                    duplicates.add(inputFiles.get(i));
                    indicesToRemove.add(i);
                }
            }
            for (SnpFile s : unFiles) {
                if (inputFiles.get(i).getName().equals(s.getInputFileName())) {
                    duplicates.add(inputFiles.get(i));
                    indicesToRemove.add(i);
                }
            }
        }
        if (!duplicates.isEmpty()) {
            StringBuilder duplicateString = new StringBuilder();
            for (File d : duplicates) {
                duplicateString.append(d.getName()).append("\n");
            }
            Collections.sort(indicesToRemove, Collections.reverseOrder());
            for (int i : indicesToRemove) {
                inputFiles.remove(i);
            }
            DialogResponse response = Dialogs.showWarningDialog(null,
                    "This project already includes the following file(s) with "
                            + "matching names to the file(s) you have just tried to add:" + "\n\n" + duplicateString
                            + "\nIf you want to change the affected "
                            + "status of a file please remove it first.  Any remaining "
                            + "(non-duplicate) files will be processed if you click 'OK'.",
                    "Duplicate Input File", "SnpViewer", Dialogs.DialogOptions.OK_CANCEL);
            if (!response.equals(DialogResponse.OK)) {
                setProgressMode(false);
                return;
            }
        }
        if (inputFiles.isEmpty()) {
            setProgressMode(false);
            return;
        }
        final Iterator iter = inputFiles.iterator();
        File input = (File) iter.next();
        int fileCounter = 1;
        if (snpViewSaveDirectory == null) {
            Dialogs.showWarningDialog(null, "Before processing input files " + "please create a project",
                    "Create Project", "SNP Viewer");

            boolean success = startNewProject();

            if (!success) {
                setProgressMode(false);
                return;
            }
        }

        addInputFilesWithIterator(isAffected, input, iter, fileCounter, inputFiles.size());
    }

    private void addInputFilesWithIterator(final boolean isAffected, final File input, final Iterator it,
            final int fileCounter, final int totalFiles) {
        try {
            String subDir = input.getName().replaceFirst("[.][^.]+$", "");
            File outputDirectory = new File(snpViewSaveDirectory + "/" + subDir);
            try {
                outputDirectory.mkdir();
            } catch (Exception ex) {
                ex.printStackTrace();
                setProgressMode(false);
                return;
            }
            final SnpFile snpFile = new SnpFile(input, outputDirectory);
            progressBar.progressProperty().unbind();
            progressBar.setProgress(0);
            progressBar.progressProperty().bind(snpFile.progressProperty());
            progressTitle.setText("Processing " + fileCounter + " of " + totalFiles);
            progressMessage.textProperty().bind(snpFile.messageProperty());
            cancelButton.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent actionEvent) {
                    snpFile.cancel();
                    progressBar.progressProperty().unbind();
                    progressBar.setProgress(0);
                    progressTitle.setText("Cancelled");
                    progressMessage.textProperty().unbind();
                    progressMessage.setText("Cancelled");
                    setProgressMode(false);

                }
            });
            snpFile.start();
            snpFile.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {
                    if (snpFile.buildVersion == null) {//need to manually identify snp build for autoSNPa files
                        BuildInferrer buildInferrer = new BuildInferrer();
                        String build = buildInferrer.inferBuild(snpFile);
                        if (build == null) {
                            Dialogs.showErrorDialog(null, "Failed to process file " + input.getName()
                                    + ".  Could not determine " + "genome build. Only hg19 and hg18 builds "
                                    + "are supported and in the absence of a "
                                    + "header containing build information only "
                                    + "Affymetrix Genome-Wide Human SNP Array 5.0" + " or 6.0 chips are supported.",
                                    "Failure while adding input file.", "SnpViewer");
                            setProgressMode(false);
                            saveProject();
                            return;
                        } else {
                            snpFile.setBuildVersion(build);
                        }
                    }
                    progressBar.progressProperty().unbind();
                    progressBar.setProgress(0);
                    progressTitle.setText("");
                    progressMessage.textProperty().unbind();
                    progressMessage.setText("");
                    if (genomeVersion.equals("")) {
                        genomeVersion = snpFile.getBuildVersion();
                        buildLabel.setText(genomeVersion);
                    } else {
                        if (!snpFile.getBuildVersion().equalsIgnoreCase(genomeVersion)) {
                            progressTitle.setText("");
                            progressMessage.setText("");
                            Dialogs.showErrorDialog(null,
                                    "Genome versions do " + "not match between input files. Error while"
                                            + " adding input file " + input.getName(),
                                    "Genome Version Error", "SnpViewer");
                            setProgressMode(false);
                            saveProject();
                            return;
                        }
                    }
                    if (isAffected) {
                        affObserve.add(snpFile);
                    } else {
                        unObserve.add(snpFile);
                    }

                    if (it.hasNext()) {
                        addInputFilesWithIterator(isAffected, (File) it.next(), it, fileCounter + 1, totalFiles);
                    } else {
                        setProgressMode(false);
                        saveProject();
                        refreshView(null, redrawCheckBox.isSelected());
                    }
                }
            });
            final String fileNameForFailure = input.getName();
            snpFile.setOnFailed(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {
                    progressBar.progressProperty().unbind();
                    progressBar.setProgress(0);
                    progressTitle.setText("");
                    progressMessage.textProperty().unbind();
                    // progressMessage.setText("");
                    Dialogs.showErrorDialog(null, "Failed to process file " + fileNameForFailure,
                            "Failure while adding input file.", "SnpViewer", t.getSource().getException());
                    setProgressMode(false);
                    saveProject();
                }

            });
            snpFile.setOnCancelled(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {
                    progressBar.progressProperty().unbind();
                    progressBar.setProgress(0);
                    progressTitle.setText("ERROR!");
                    progressMessage.textProperty().unbind();
                    progressMessage.setText("Processing of " + fileNameForFailure + " failed!");
                    setProgressMode(false);
                    saveProject();
                }

            });

        } catch (Exception ex) {
            ex.printStackTrace();
            //display error here
        }
    }

    private void setProgressMode(boolean running) {
        /*simple method to put UI into one state when a process is running
         * and another when it is idle
         */
        if (!running) {
            progressMode = false;
            //addAffected.setDefaultButton(true);
            //addAffected.requestFocus();
            addAffected.setDisable(false);
            addUnaffected.setDisable(false);
            chromosomeSelector.setDisable(false);
            loadProjectButton.setDisable(false);
            newProjectButton.setDisable(false);
            //saveProjectButton.setDisable(false);
            redrawButton.setDisable(false);
            colorPicker.setDisable(false);
            colorComponantSelector.setDisable(false);
            selectionIndicator.setDisable(false);
            cacheChromsButton.setDisable(false);
            newProjectMenu.setDisable(false);
            loadProjectMenu.setDisable(false);
            cacheChromsMenu.setDisable(false);
            saveToPngMenu.setDisable(false);
            addAffSampleMenu.setDisable(false);
            addUnSampleMenu.setDisable(false);
            nextChromMenu.setDisable(false);
            prevChromMenu.setDisable(false);
            firstChromMenu.setDisable(false);
            lastChromMenu.setDisable(false);
            redrawMenu.setDisable(false);
            autoFindRegions.setDisable(false);
            displaySavedsRegionsMenu.setDisable(false);
            clearSavedRegionsMenu.setDisable(false);
            hideSavedRegionsMenu.setDisable(false);
            outputSavedRegionsMenu.setDisable(false);
            findRegionsButton.setDisable(false);
            removeSampleMenu.setDisable(false);
            noFilteringRadio.setDisable(false);
            filter99.setDisable(false);
            filter95.setDisable(false);
            filter90.setDisable(false);
            filter85.setDisable(false);
            cancelButton.setDisable(true);
        } else {
            progressMode = true;
            addAffected.setDisable(true);
            addUnaffected.setDisable(true);
            chromosomeSelector.setDisable(true);
            loadProjectButton.setDisable(true);
            newProjectButton.setDisable(true);
            saveToPngMenu.setDisable(true);
            //saveProjectButton.setDisable(true);
            redrawButton.setDisable(true);
            colorPicker.setDisable(true);
            colorComponantSelector.setDisable(true);
            cacheChromsButton.setDisable(true);
            newProjectMenu.setDisable(true);
            loadProjectMenu.setDisable(true);
            cacheChromsMenu.setDisable(true);
            addAffSampleMenu.setDisable(true);
            addUnSampleMenu.setDisable(true);
            nextChromMenu.setDisable(true);
            prevChromMenu.setDisable(true);
            firstChromMenu.setDisable(true);
            lastChromMenu.setDisable(true);
            redrawMenu.setDisable(true);
            autoFindRegions.setDisable(true);
            displaySavedsRegionsMenu.setDisable(true);
            clearSavedRegionsMenu.setDisable(true);
            hideSavedRegionsMenu.setDisable(true);
            outputSavedRegionsMenu.setDisable(true);
            findRegionsButton.setDisable(true);
            removeSampleMenu.setDisable(true);
            noFilteringRadio.setDisable(true);
            filter99.setDisable(true);
            filter95.setDisable(true);
            filter90.setDisable(true);
            filter85.setDisable(true);
            cancelButton.setDisable(false);
        }
    }

    public void addToChromosomeSelector(ArrayList<SnpFile> sFiles) {

        for (SnpFile f : sFiles) {
            List<String> chromsToAdd = new ArrayList<>();
            for (String c : f.chromFiles.keySet()) {
                if (!chromosomeSelector.getItems().contains(c)) {
                    chromsToAdd.add(c);
                }
            }
            ChromComparator chromCompare = new ChromComparator();
            java.util.Collections.sort(chromsToAdd, chromCompare);
            chromosomeSelector.getItems().addAll(chromsToAdd);

            if (chromosomeSelector.getSelectionModel().isEmpty()) {
                //chromosomeSelector.getSelectionModel().selectFirst();
            } else {
                int sel = chromosomeSelector.getSelectionModel().getSelectedIndex();
                //chromosomeSelector.getSelectionModel().clearSelection();
                //chromosomeSelector.getSelectionModel().select(sel);
            }
            chromosomeSelector.requestFocus();
        }
    }

    public void recheckChromosomeSelector(List<SnpFile> sFiles) {
        /*in case a SnpFile has been removed we clear the menu first
         */

        chromosomeSelector.getItems().clear();
        for (SnpFile f : sFiles) {
            List<String> chromsToAdd = new ArrayList<>();
            for (String c : f.chromFiles.keySet()) {
                if (!chromosomeSelector.getItems().contains(c)) {
                    chromsToAdd.add(c);
                }
            }
            ChromComparator chromCompare = new ChromComparator();
            java.util.Collections.sort(chromsToAdd, chromCompare);
            chromosomeSelector.getItems().addAll(chromsToAdd);

            if (chromosomeSelector.getSelectionModel().isEmpty()) {
                //chromosomeSelector.getSelectionModel().selectFirst();
            } else {
                int sel = chromosomeSelector.getSelectionModel().getSelectedIndex();
                //chromosomeSelector.getSelectionModel().clearSelection();
                //chromosomeSelector.getSelectionModel().select(sel);
            }
            chromosomeSelector.requestFocus();
        }
    }

    public boolean saveProject() {
        if (projectFile != null) {
            return saveProject(projectFile);
        } else {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Save Snp Viewer Project (.svproj) As...");
            FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("SNP Viewer Projects",
                    "*.svproj");
            fileChooser.getExtensionFilters().add(extFilter);
            projectFile = fileChooser.showSaveDialog(mainWindow);
            if (projectFile != null) {
                if (!projectFile.getName().endsWith(".svproj")) {
                    projectFile = new File(projectFile.getAbsolutePath() + ".svproj");
                }
                return saveProject(projectFile);

            } else {
                return false;
            }
        }
    }

    public boolean saveProject(File saveFile) {
        try {
            FileOutputStream fos = new FileOutputStream(saveFile);
            try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(fos))) {
                out.writeObject(projectFile);
                out.writeObject(affFiles);
                out.writeObject(unFiles);
                out.writeObject(genomeVersion);
                out.writeObject(qualityFilter);
                out.writeObject(snpViewSaveDirectory);
                out.writeObject(savedRegions);
                for (Color c : colorComp) {
                    out.writeObject(c.toString());
                }

                out.close();
                projectLabel.setText("Project: " + projectFile.getName());
            }
            return true;
        } catch (IOException ex) {
            //ex.printStackTrace();
            Dialogs.showErrorDialog(null, "Could not save project file - IO error", "Save Failed", "SNP Viewer",
                    ex);
            return false;
        }
    }

    public void loadProject() {
        if (projectRunning) {
            /*setProgressMode(true);
            DialogResponse response = Dialogs.showConfirmDialog(null,
            "Do you want to save your current project before starting a new one?", 
                "Save Current Project?", "SNP View");
            if (DialogResponse.YES.equals(response)){
            boolean saved = saveProject();
            if (! saved){
                setProgressMode(false);
                return;
            }else{
                Dialogs.showInformationDialog(null, projectFile.getName() + " saved sucessfully", 
                        "Save Successful", "SNP View");
            }
            }else if (DialogResponse.CANCEL.equals(response)){
            setProgressMode(false);
            return;
            }*/
        }
        loadProjectButton.setDisable(true);
        newProjectButton.setDisable(true);
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("SNP Viewer Projects", "*.svproj"));
        fileChooser.setTitle("Open SNP Viewer Project (.svproj) file");
        //setProgressMode(false);
        File loadFile = fileChooser.showOpenDialog(mainWindow);
        loadProjectButton.setDisable(false);
        newProjectButton.setDisable(false);
        if (loadFile != null) {
            try {
                ObjectInputStream is = new ObjectInputStream(
                        new BufferedInputStream(new FileInputStream(loadFile)));
                try {
                    projectFile = null;
                    projectLabel.setText("Project: none");
                    chromSplitPane.getItems().clear();
                    labelSplitPane.getItems().clear();
                    clearDragSelectRectangle();
                    savedRegions.clear();
                    savedRegionsDisplay.clear();
                    savedRegionsReference.clear();
                    selectionOverlayPane.getChildren().clear();
                    selectionOverlayPane.getChildren().add(dragSelectRectangle);

                    resetObservables();
                    genomeVersion = "";
                    qualityFilter = null;
                    noFilteringRadio.setSelected(true);
                    chromosomeSelector.getItems().clear();
                    projectFile = (File) is.readObject();//get rid of this?
                    projectFile = loadFile;//allow relative referencing

                    ArrayList<Color> loadedColors = new ArrayList<>();
                    ArrayList<SnpFile> tempAff = new ArrayList<>();
                    ArrayList<SnpFile> tempUn = new ArrayList<>();
                    tempAff.addAll((ArrayList<SnpFile>) is.readObject());
                    tempUn.addAll((ArrayList<SnpFile>) is.readObject());
                    ArrayList<SnpFile> tempBoth = new ArrayList<>();
                    tempBoth.addAll(tempAff);
                    tempBoth.addAll(tempUn);
                    genomeVersion = (String) is.readObject();
                    qualityFilter = (Double) is.readObject();
                    buildLabel.setText(genomeVersion);
                    snpViewSaveDirectory = (File) is.readObject();
                    savedRegions = (ArrayList<RegionSummary>) is.readObject();
                    String projectName = projectFile.getName().replaceAll(".svproj", "");
                    if (!snpViewSaveDirectory.exists()) {
                        snpViewSaveDirectory = new File(
                                projectFile.getParentFile() + "/" + projectName + " SNP Viewer files");
                        if (!snpViewSaveDirectory.exists()) {
                            DialogResponse response = Dialogs.showErrorDialog(null,
                                    "Can't find project directory (" + snpViewSaveDirectory.getName()
                                            + ") - do you " + "want to try to find it?",
                                    "Project directory " + "not found", "SnpViewer", Dialogs.DialogOptions.YES_NO);
                            if (DialogResponse.YES.equals(response)) {
                                DirectoryChooser dirChooser = new DirectoryChooser();
                                dirChooser.setTitle("Locate Project Folder");
                                snpViewSaveDirectory = dirChooser.showDialog(mainWindow);
                                if (snpViewSaveDirectory == null) {
                                    returnToInitialState();
                                    return;
                                }
                            } else {
                                returnToInitialState();
                                return;
                            }
                        }
                    }
                    boolean check = checkProjectFolder(snpViewSaveDirectory, tempBoth);
                    if (!check) {
                        Dialogs.showErrorDialog(null, "Corrupt project" + " folder - missing files.",
                                "Invalid " + "project folder.", "SnpViewer");
                        returnToInitialState();
                        return;
                    }
                    for (Color c : colorComp) {
                        String colorString = (String) is.readObject();
                        loadedColors.add(Color.valueOf(colorString));
                    }
                    for (int ci = 0; ci < loadedColors.size(); ci++) {
                        colorComponantSelector.getSelectionModel().clearAndSelect(ci);
                        colorPicker.setValue(loadedColors.get(ci));
                        colorPicker.fireEvent(new ActionEvent());
                    }
                    affObserve.addAll(tempAff);
                    unObserve.addAll(tempUn);
                    colorComponantSelector.getSelectionModel().selectFirst();
                    colorComp.clear();
                    colorComp.addAll(loadedColors);
                    is.close();
                    setQualityLabel();
                    checkQualitySelection();
                    saveProject();
                    projectLabel.setText("Project: " + projectFile.getName());
                    //addToChromosomeSelector(affFiles);
                    //addToChromosomeSelector(unFiles);
                    if (!chromosomeSelector.getItems().isEmpty()) {
                        chromosomeSelector.getSelectionModel().selectFirst();
                    }
                    if (chromosomeSelector.isDisabled()) {
                        chromosomeSelector.setDisable(false);
                    }
                    //setProgressMode(false);
                    if (affObserve.isEmpty() && unObserve.isEmpty()) {
                        resetView();
                    }
                    projectRunning = true;

                } catch (IOException | ClassNotFoundException ex) {
                    resetView();
                    projectLabel.setText("Project: none");
                    savedRegions.clear();
                    savedRegionsDisplay.clear();
                    savedRegionsReference.clear();
                    resetObservables();
                    genomeVersion = "";
                    qualityFilter = null;
                    noFilteringRadio.setSelected(true);
                    chromosomeSelector.getItems().clear();
                    ex.printStackTrace();
                    Dialogs.showErrorDialog(null, "Could not load project file", "Load Failed", "SNP Viewer", ex);
                }
            } catch (IOException ex) {
                resetView();
                projectLabel.setText("Project: none");
                savedRegions.clear();
                savedRegionsDisplay.clear();
                savedRegionsReference.clear();
                resetObservables();
                genomeVersion = "";
                qualityFilter = null;
                noFilteringRadio.setSelected(true);
                chromosomeSelector.getItems().clear();
                ex.printStackTrace();
                Dialogs.showErrorDialog(null, "Could not load project file - IO error", "Load Failed", "SNP Viewer",
                        ex);
            }
        }
    }

    private void resetObservables() {
        affObserve.clear();
        unObserve.clear();
        affObserve = FXCollections.observableList(affFiles);
        unObserve = FXCollections.observableList(unFiles);
        affObserve.addListener(new ListChangeListener() {
            @Override
            public void onChanged(ListChangeListener.Change change) {
                change.next();/*from the javadoc 
                              * 'Go to the next change. In initial state is invalid a require 
                              * a call to next() before calling other methods. The first 
                              * next() call will make this object represent the first change.
                              */
                if (change.getRemovedSize() > 0) {
                    List<SnpFile> both = new ArrayList<>(unFiles);
                    both.addAll(affFiles);
                    recheckChromosomeSelector(both);
                } else if (change.getAddedSize() > 0) {
                    addToChromosomeSelector(affFiles);
                }
            }
        });

        /*as above 
         * but for unaffected files
         */
        unObserve.addListener(new ListChangeListener() {
            @Override
            public void onChanged(ListChangeListener.Change change) {
                change.next();
                if (change.getRemovedSize() > 0) {
                    List<SnpFile> both = new ArrayList<>(unFiles);
                    both.addAll(affFiles);
                    recheckChromosomeSelector(both);
                } else if (change.getAddedSize() > 0) {
                    addToChromosomeSelector(unFiles);
                }

            }
        });

    }

    public void saveRegion(final String chromosome, final double startCoordinate, final double endCoordinate) {
        final Task<RegionSummary> saveSelectionTask = new Task<RegionSummary>() {
            @Override
            protected RegionSummary call() throws Exception {
                try {
                    updateProgress(-1, -1);
                    updateTitle("Finding flanking SNPs");
                    updateMessage("Searching for nearest SNP in all files...");

                    /* read SnpFiles to find closest SNPs - use binary search
                     * to find nearby SNP and refine to closest
                     */
                    List<SnpFile.SnpLine> startAndEndSnps = searchCoordinate(chromosome, (int) startCoordinate,
                            (int) endCoordinate);
                    if (startAndEndSnps == null) {
                        System.out.println("Start and End SNPS ARE NULL!");
                        //DISPLAY ERROR HERE?
                        return null;
                    }
                    RegionSummary region = new RegionSummary(chromosome, startAndEndSnps.get(0).getPosition(),
                            startAndEndSnps.get(1).getPosition(), 0, 0, startAndEndSnps.get(0).getId(),
                            startAndEndSnps.get(1).getId());
                    return region;

                } catch (NumberFormatException ex) {
                    Dialogs.showErrorDialog(null,
                            "Can't display flanking SNP IDs"
                                    + " - missing required componant!\n\nPlease report this error.",
                            "Error!", "SNP Viewer", ex);
                }
                return null;
            }
        };
        setProgressMode(true);
        progressBar.progressProperty().bind(saveSelectionTask.progressProperty());
        progressMessage.textProperty().unbind();
        progressMessage.textProperty().bind(saveSelectionTask.messageProperty());
        progressTitle.textProperty().unbind();
        progressTitle.textProperty().bind(saveSelectionTask.titleProperty());
        saveSelectionTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                setProgressMode(false);
                RegionSummary result = (RegionSummary) e.getSource().getValue();
                savedRegions.add(result);
                RegionSummary sorter = new RegionSummary();
                sorter.mergeRegionsByPosition(savedRegions);
                saveProject();
                clearDragSelectRectangle();
                savedRegionsDisplay.clear();
                savedRegionsReference.clear();
                drawSavedRegions(
                        (String) chromosomeBoxList[chromosomeSelector.getSelectionModel().getSelectedIndex()]);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressTitle.textProperty().unbind();
                progressMessage.textProperty().unbind();
                progressTitle.setText("");
                progressMessage.setText("");
            }

        });
        saveSelectionTask.setOnFailed(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressTitle.textProperty().unbind();
                progressMessage.textProperty().unbind();
                progressTitle.setText("");
                progressMessage.setText("");
                Dialogs.showErrorDialog(null, "Error finding flanking SNPs\n", "Save Region error", "SNP Viewer",
                        saveSelectionTask.getException());

            }

        });
        saveSelectionTask.setOnCancelled(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                progressMessage.setText("Region write cancelled");
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressTitle.textProperty().unbind();
                progressMessage.textProperty().unbind();
                progressTitle.setText("");
                progressMessage.setText("");
                Dialogs.showErrorDialog(null, "User cancelled region save.", "Save Region", "SNP Viewer",
                        saveSelectionTask.getException());
            }

        });
        cancelButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                saveSelectionTask.cancel();

            }
        });
        new Thread(saveSelectionTask).start();
    }

    private void saveSelection() {
        /* get coordinates of selection and create a RegionSummary object.
         * Add RegionSummary to saved regions and merge all saved regions
         * in case of overlaps.  Refresh view to reflect new saved region
         */

        try {
            if (!genomeVersion.equals("") && chromosomeSelector.getSelectionModel().getSelectedIndex() > -1
                    && dragSelectRectangle.getWidth() > 0) {

                //work out coordinates based on chromosome and pane sizes
                ChromosomeLength chromLength = new ChromosomeLength(genomeVersion);
                String currentChrom = (String) chromosomeBoxList[chromosomeSelector.getSelectionModel()
                        .getSelectedIndex()];
                double startCoordinate = chromLength.getLength(currentChrom) / selectionOverlayPane.getWidth()
                        * dragSelectRectangle.getX();
                double selectionWidth = chromLength.getLength(currentChrom) / selectionOverlayPane.getWidth()
                        * dragSelectRectangle.getWidth();
                if (dragSelectRectangle.getX() == 0) {
                    startCoordinate = 1;
                }
                saveRegion(currentChrom, startCoordinate, startCoordinate + selectionWidth);
            }
        } catch (Exception ex) {
            Dialogs.showErrorDialog(null,
                    "Error determing selection coordinates" + " - see details for stack trace", "Save Region Error",
                    "SnpViewer", ex);
        }

    }

    private void displayFlankingSnpIDs(final Rectangle rectangle) {
        /* get coordinates of selection and report back
         * flanking snp ids and coordinates
         */
        try {
            if (!genomeVersion.equals("") && chromosomeSelector.getSelectionModel().getSelectedIndex() > -1
                    && rectangle.getWidth() > 0) {

                //work out coordinates based on chromosome and pane sizes
                ChromosomeLength chromLength = new ChromosomeLength(genomeVersion);
                String currentChrom = (String) chromosomeBoxList[chromosomeSelector.getSelectionModel()
                        .getSelectedIndex()];
                double startCoordinate = chromLength.getLength(currentChrom) / selectionOverlayPane.getWidth()
                        * rectangle.getX();
                double selectionWidth = chromLength.getLength(currentChrom) / selectionOverlayPane.getWidth()
                        * rectangle.getWidth();
                if (rectangle.getX() == 0) {
                    startCoordinate = 1;
                }
                displayFlankingSnpIDs(currentChrom, startCoordinate, startCoordinate + selectionWidth);
            }
        } catch (Exception ex) {
            Dialogs.showErrorDialog(null, "Couldn't display flanking SNP IDs - " + "build error?",
                    "Error Displaying flanking SNPs", "SnpViewer", ex);
        }
    }

    public void displayFlankingSnpIDs(final String chrom, final double start, final double end) {
        final Task<List<String>> displayTask = new Task<List<String>>() {
            @Override
            protected List<String> call() {
                updateProgress(-1, -1);
                updateTitle("Finding flanking SNPs");
                updateMessage("Searching for nearest SNP in all files...");
                //work out coordinates based on chromosome and pane sizes
                /* read SnpFiles to find closest SNPs - use binary search
                * to find nearby SNP and refine to closest
                */
                List<SnpFile.SnpLine> startAndEndSnps = searchCoordinate(chrom, (int) start, (int) end);
                if (startAndEndSnps == null) {
                    //DISPLAY ERROR HERE?
                    return null;
                }
                String coordResult = "chr" + chrom + ":" + nf.format(startAndEndSnps.get(0).getPosition()) + "-"
                        + nf.format(startAndEndSnps.get(1).getPosition());
                String idResult = startAndEndSnps.get(0).getId() + ";" + startAndEndSnps.get(1).getId();
                List<String> result = new ArrayList();
                result.add(coordResult);
                result.add(idResult);
                return result;
            }
        };

        setProgressMode(true);
        progressBar.progressProperty().bind(displayTask.progressProperty());
        progressMessage.textProperty().unbind();
        progressMessage.textProperty().bind(displayTask.messageProperty());
        progressTitle.textProperty().unbind();
        progressTitle.textProperty().bind(displayTask.titleProperty());
        displayTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressTitle.textProperty().unbind();
                progressMessage.textProperty().unbind();
                progressTitle.setText("");
                progressMessage.setText("");
            }

        });
        displayTask.setOnFailed(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressTitle.textProperty().unbind();
                progressMessage.textProperty().unbind();
                progressTitle.setText("");
                progressMessage.setText("");
                Dialogs.showErrorDialog(null, "Error displaying flanking SNPs\n", "Display error", "SNP Viewer",
                        displayTask.getException());

            }

        });
        displayTask.setOnCancelled(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                progressMessage.setText("Display flanking SNPs cancelled");
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressTitle.textProperty().unbind();
                progressMessage.textProperty().unbind();
                progressTitle.setText("");
                progressMessage.setText("");
                Dialogs.showErrorDialog(null, "User cancelled display.", "Display error", "SNP Viewer",
                        displayTask.getException());
            }

        });
        cancelButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                displayTask.cancel();

            }
        });
        new Thread(displayTask).start();
        try {
            List<String> result = displayTask.get();
            FXMLLoader loader = new FXMLLoader(getClass().getResource("RegionReporter.fxml"));
            Stage stage = new Stage();
            Pane page = (Pane) loader.load();
            Scene scene = new Scene(page);
            stage.setScene(scene);
            stage.setTitle("SNP Viewer Region Summary");
            stage.getIcons().add(new Image(this.getClass().getResourceAsStream("icon.png")));
            RegionReporterController regionReporter = loader.<RegionReporterController>getController();
            if (result == null) {
                regionReporter.setCoordinates("Error!");
                regionReporter.setIds("Error!");
            } else {
                regionReporter.setCoordinates(result.get(0));
                regionReporter.setIds(result.get(1));
            }
            scene.getStylesheets().add(SnpViewer.class.getResource("SnpViewerStyleSheet.css").toExternalForm());
            stage.setResizable(false);
            stage.initModality(Modality.NONE);

            stage.show();
        } catch (InterruptedException | ExecutionException | IOException ex) {
            Dialogs.showErrorDialog(null,
                    "Can't display flanking SNP IDs" + " - exception caught!\n\nPlease report this error.",
                    "Error!", "SNP Viewer", ex);
        }

    }

    public void writeSavedRegionsToFile() {
        if (savedRegions.size() < 1) {
            Dialogs.showErrorDialog(null, "No Saved Regions exist to write!", "No Saved Regions", "SnpViewer");
            return;
        }
        final int flanks = 10;
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("Excel (*.xlsx)", "*.xlsx");
        fileChooser.getExtensionFilters().add(extFilter);
        fileChooser.setTitle("Write regions to Excel file (.xlsx)...");
        File rFile = fileChooser.showSaveDialog(mainWindow);
        if (rFile == null) {
            return;
        } else if (!rFile.getName().endsWith(".xlsx")) {
            rFile = new File(rFile.getAbsolutePath() + ".xlsx");
        }
        final File regionFile = rFile;
        final Task<Boolean> writeTask = new Task() {
            @Override
            protected Boolean call() throws Exception {
                try {
                    updateProgress(-1, -1);
                    BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(regionFile));
                    Workbook wb = new XSSFWorkbook();
                    //first create a summary sheet of all regions
                    Sheet sheet = wb.createSheet();
                    Row row = null;
                    int rowNo = 0;
                    int sheetNo = 0;
                    wb.setSheetName(sheetNo++, "Summary");
                    row = sheet.createRow(rowNo++);
                    String header[] = { "Coordinates", "rsIDs", "Size (Mb)" };
                    for (int col = 0; col < header.length; col++) {
                        Cell cell = row.createCell(col);
                        cell.setCellValue(header[col]);
                    }
                    for (int i = 0; i < savedRegions.size(); i++) {
                        row = sheet.createRow(rowNo++);
                        int col = 0;
                        Cell cell = row.createCell(col++);
                        cell.setCellValue("chr" + savedRegions.get(i).getCoordinateString());
                        cell = row.createCell(col++);
                        cell.setCellValue(savedRegions.get(i).getIdLine());
                        cell = row.createCell(col++);
                        double mB = (double) savedRegions.get(i).getLength() / 1000000;
                        cell.setCellValue(mB);
                    }

                    ArrayList<SnpFile> bothFiles = new ArrayList<>();
                    bothFiles.addAll(affFiles);
                    bothFiles.addAll(unFiles);
                    String prevChrom = new String();
                    double prog = 0;
                    double total = savedRegions.size() * bothFiles.size() * 2;
                    updateProgress(prog, total);
                    int regCounter = 0;
                    for (RegionSummary reg : savedRegions) {
                        updateMessage("Writing region " + ++regCounter + " of " + savedRegions.size());
                        //create a sheet for each chromosome
                        if (!reg.getChromosome().equalsIgnoreCase(prevChrom)) {
                            if (!prevChrom.isEmpty()) {

                                CellRangeAddress[] regions = {
                                        new CellRangeAddress(0, rowNo, 2, 2 + bothFiles.size()) };
                                SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();

                                ConditionalFormattingRule rule1 = sheetCF
                                        .createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"AA\"");
                                PatternFormatting fill1 = rule1.createPatternFormatting();
                                fill1.setFillBackgroundColor(IndexedColors.LIGHT_GREEN.index);
                                fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
                                ConditionalFormattingRule rule2 = sheetCF
                                        .createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"BB\"");
                                PatternFormatting fill2 = rule2.createPatternFormatting();
                                fill2.setFillBackgroundColor(IndexedColors.PALE_BLUE.index);
                                fill2.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
                                ConditionalFormattingRule rule3 = sheetCF
                                        .createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"AB\"");
                                PatternFormatting fill3 = rule3.createPatternFormatting();
                                fill3.setFillBackgroundColor(IndexedColors.ROSE.index);
                                fill3.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
                                sheetCF.addConditionalFormatting(regions, rule3, rule2);
                                sheetCF.addConditionalFormatting(regions, rule1);
                            }
                            rowNo = 0;
                            sheet = wb.createSheet();
                            wb.setSheetName(sheetNo++, reg.getChromosome());
                            prevChrom = reg.getChromosome();

                        } else {//pad regions with an empty line
                            rowNo++;
                        }
                        TreeMap<Integer, HashMap<String, String>> coordMap = new TreeMap();
                        /*coordmap - key is position, key of hashmap 
                         * is input filename and value call
                         */
                        HashMap<Integer, String> coordToId = new HashMap<>();
                        //coordinate to rs ID

                        try {
                            for (SnpFile f : bothFiles) {
                                updateProgress(prog++, total);
                                if (isCancelled()) {
                                    return false;
                                }
                                List<SnpFile.SnpLine> lines = f.getSnpsInRegion(reg.getChromosome(),
                                        reg.getStartPos(), reg.getEndPos(), flanks);
                                for (SnpFile.SnpLine snpLine : lines) {
                                    if (isCancelled()) {
                                        return false;
                                    }
                                    Integer coord = snpLine.getPosition();
                                    if (!coordMap.containsKey(coord)) {
                                        coordMap.put(coord, new HashMap<String, String>());
                                    }
                                    String filename = f.inputFile.getName();
                                    String rsId = snpLine.getId();
                                    String call = snpLine.getCall();
                                    coordMap.get(coord).put(filename, call);
                                    coordToId.put(coord, rsId);
                                }
                            }
                            row = sheet.createRow(rowNo++);
                            Cell cell = row.createCell(0);
                            cell.setCellValue(reg.getCoordinateString());
                            row = sheet.createRow(rowNo++);
                            cell = row.createCell(0);
                            cell.setCellValue(reg.getIdLine());

                            int col = 0;
                            row = sheet.createRow(rowNo++);
                            cell = row.createCell(col++);
                            cell.setCellValue("Position");
                            cell = row.createCell(col++);
                            cell.setCellValue("rsID");
                            for (SnpFile f : bothFiles) {
                                updateProgress(prog++, total);
                                cell = row.createCell(col++);
                                if (f.getSampleName() != null && !f.getSampleName().isEmpty()) {
                                    cell.setCellValue(f.getSampleName());
                                } else {
                                    cell.setCellValue(f.inputFile.getName());
                                }
                            }
                            for (Entry current : coordMap.entrySet()) {
                                if (isCancelled()) {
                                    return false;
                                }
                                col = 0;
                                Integer coord = (Integer) current.getKey();
                                row = sheet.createRow(rowNo++);
                                cell = row.createCell(col++);
                                cell.setCellValue(coord);
                                cell = row.createCell(col++);
                                cell.setCellValue(coordToId.get(coord));
                                HashMap<String, String> fileToCall = (HashMap<String, String>) current.getValue();
                                for (SnpFile f : bothFiles) {
                                    cell = row.createCell(col++);
                                    if (fileToCall.containsKey(f.inputFile.getName())) {
                                        cell.setCellValue(fileToCall.get(f.inputFile.getName()));
                                    } else {
                                        cell.setCellValue("-");
                                    }
                                }
                            }
                        } catch (Exception ex) {
                            return false;
                        }

                    }
                    CellRangeAddress[] regions = { new CellRangeAddress(0, rowNo, 2, 2 + bothFiles.size()) };
                    SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();

                    ConditionalFormattingRule rule1 = sheetCF
                            .createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"AA\"");
                    PatternFormatting fill1 = rule1.createPatternFormatting();
                    fill1.setFillBackgroundColor(IndexedColors.LIGHT_GREEN.index);
                    fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
                    ConditionalFormattingRule rule2 = sheetCF
                            .createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"BB\"");
                    PatternFormatting fill2 = rule2.createPatternFormatting();
                    fill2.setFillBackgroundColor(IndexedColors.PALE_BLUE.index);
                    fill2.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
                    ConditionalFormattingRule rule3 = sheetCF
                            .createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"AB\"");
                    PatternFormatting fill3 = rule3.createPatternFormatting();
                    fill3.setFillBackgroundColor(IndexedColors.ROSE.index);
                    fill3.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
                    sheetCF.addConditionalFormatting(regions, rule3, rule2);
                    sheetCF.addConditionalFormatting(regions, rule1);
                    wb.write(out);
                    updateProgress(total, total);
                    out.close();
                } catch (IOException | NumberFormatException ex) {
                    ex.printStackTrace();
                    return false;
                }
                return true;
            }
        };//end of task

        setProgressMode(true);
        progressBar.progressProperty().bind(writeTask.progressProperty());
        progressMessage.textProperty().bind(writeTask.messageProperty());
        writeTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                if (e.getSource().getValue() == true) {
                    Dialogs.showInformationDialog(null,
                            "Saved regions written " + "to file " + "(" + regionFile.getName() + ")successfully",
                            "Regions Written", "SNP Viewer");
                } else {
                    Dialogs.showErrorDialog(null, "Region write failed.", "Write Failed", "SNP Viewer");
                }
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressMessage.textProperty().unbind();
                progressMessage.setText("");
                progressTitle.setText("");

            }

        });
        writeTask.setOnFailed(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressMessage.textProperty().unbind();
                progressMessage.setText("");
                progressTitle.setText("Region write failed!");
                Dialogs.showErrorDialog(null, "Error writing region to file\n", "Region write error", "SNP Viewer",
                        e.getSource().getException());

            }

        });
        writeTask.setOnCancelled(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                progressMessage.setText("Region write cancelled");
                progressTitle.setText("Cancelled");
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                Dialogs.showErrorDialog(null, "Error writing region to file\n", "Region write error", "SNP Viewer");
            }

        });
        cancelButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                writeTask.cancel();

            }
        });
        progressTitle.setText("Writing regions to .xlsx file");
        new Thread(writeTask).start();
    }

    public void writeRegionToFile(final Rectangle rectangle) {
        try {
            ChromosomeLength chromLength = new ChromosomeLength(genomeVersion);
            String currentChrom = (String) chromosomeBoxList[chromosomeSelector.getSelectionModel()
                    .getSelectedIndex()];
            double startCoordinate = chromLength.getLength(currentChrom) / selectionOverlayPane.getWidth()
                    * rectangle.getX();
            double selectionWidth = chromLength.getLength(currentChrom) / selectionOverlayPane.getWidth()
                    * rectangle.getWidth();
            if (rectangle.getX() == 0) {
                startCoordinate = 1;
            }
            writeRegionToFile(currentChrom, startCoordinate, startCoordinate + selectionWidth);
        } catch (Exception ex) {
            Dialogs.showErrorDialog(null, "Region write failed while assessing " + "region properties.",
                    "Write Failed", "SNP Viewer", ex);
        }
    }

    public void writeRegionToFile(final String chromosome, final double start, final double end) {
        /* get coordinates of selection and report back
         * write SNPs in region to file
         */
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("Excel  (*.xlsx)", "*.xlsx");
        fileChooser.getExtensionFilters().add(extFilter);
        fileChooser.setTitle("Write region to Excel file (.xlsx)...");
        File rFile = fileChooser.showSaveDialog(mainWindow);
        if (rFile == null) {
            return;
        } else if (!rFile.getName().endsWith(".xlsx")) {
            rFile = new File(rFile.getAbsolutePath() + ".xlsx");
        }
        final File regionFile = rFile;
        final Task<Boolean> writeTask = new Task() {
            @Override
            protected Boolean call() throws Exception {
                try {

                    updateProgress(-1, -1);
                    ArrayList<SnpFile> bothFiles = new ArrayList<>();
                    bothFiles.addAll(affFiles);
                    bothFiles.addAll(unFiles);
                    TreeMap<Integer, HashMap<String, String>> coordMap = new TreeMap();
                    /*coordmap - key is position, key of hashmap 
                     * is input filename and value call
                     */
                    HashMap<Integer, String> coordToId = new HashMap<>();
                    double progress = 0;
                    double total = bothFiles.size() * 5;
                    try {
                        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(regionFile));
                        Workbook wb = new XSSFWorkbook();
                        Sheet sheet = wb.createSheet();
                        int rowNo = 0;
                        Row row = sheet.createRow(rowNo++);
                        for (SnpFile f : bothFiles) {
                            if (isCancelled()) {
                                return false;
                            }
                            updateProgress(++progress, total);
                            updateMessage("Reading region in " + f.inputFile.getName());
                            List<SnpFile.SnpLine> lines = f.getSnpsInRegion(chromosome, (int) start, (int) end);
                            for (SnpFile.SnpLine snpLine : lines) {
                                if (isCancelled()) {
                                    return false;
                                }
                                Integer coord = snpLine.getPosition();
                                if (!coordMap.containsKey(coord)) {
                                    coordMap.put(coord, new HashMap<String, String>());
                                }
                                String filename = f.inputFile.getName();
                                String rsId = snpLine.getId();
                                String call = snpLine.getCall();
                                coordMap.get(coord).put(filename, call);
                                coordToId.put(coord, rsId);
                            }
                        }
                        Cell cell = row.createCell(0);
                        cell.setCellValue(
                                "chr" + chromosome + ":" + coordMap.firstKey() + "-" + coordMap.lastKey());
                        row = sheet.createRow(rowNo++);
                        cell = row.createCell(0);
                        cell.setCellValue(
                                coordToId.get(coordMap.firstKey()) + ";" + coordToId.get(coordMap.lastKey()));
                        row = sheet.createRow(rowNo++);
                        int colNo = 0;
                        cell = row.createCell(colNo++);
                        cell.setCellValue("Position");
                        cell = row.createCell(colNo++);
                        cell.setCellValue("rsID");
                        for (SnpFile f : bothFiles) {
                            cell = row.createCell(colNo++);
                            if (f.getSampleName() != null && f.getSampleName().length() > 0) {
                                cell.setCellValue(f.getSampleName());
                            } else {
                                cell.setCellValue(f.getInputFileName());
                            }
                        }
                        progress = coordMap.size();
                        total = 5 * coordMap.size();
                        updateMessage("Writing region to file...");
                        for (Entry current : coordMap.entrySet()) {
                            if (isCancelled()) {
                                return false;
                            }
                            progress += 4;
                            updateProgress(progress, total);
                            row = sheet.createRow(rowNo++);
                            colNo = 0;
                            Integer coord = (Integer) current.getKey();
                            cell = row.createCell(colNo++);
                            cell.setCellValue(coord);
                            String rsId = coordToId.get(coord);
                            cell = row.createCell(colNo++);
                            cell.setCellValue(rsId);
                            HashMap<String, String> fileToCall = (HashMap<String, String>) current.getValue();
                            for (SnpFile f : bothFiles) {
                                cell = row.createCell(colNo++);
                                if (fileToCall.containsKey(f.inputFile.getName())) {
                                    cell.setCellValue(fileToCall.get(f.inputFile.getName()));
                                } else {
                                    cell.setCellValue("-");
                                }
                            }
                        }
                        CellRangeAddress[] regions = { new CellRangeAddress(0, rowNo, 2, 2 + bothFiles.size()) };
                        SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();

                        ConditionalFormattingRule rule1 = sheetCF
                                .createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"AA\"");
                        PatternFormatting fill1 = rule1.createPatternFormatting();
                        fill1.setFillBackgroundColor(IndexedColors.LIGHT_GREEN.index);
                        fill1.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
                        ConditionalFormattingRule rule2 = sheetCF
                                .createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"BB\"");
                        PatternFormatting fill2 = rule2.createPatternFormatting();
                        fill2.setFillBackgroundColor(IndexedColors.PALE_BLUE.index);
                        fill2.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
                        ConditionalFormattingRule rule3 = sheetCF
                                .createConditionalFormattingRule(ComparisonOperator.EQUAL, "\"AB\"");
                        PatternFormatting fill3 = rule3.createPatternFormatting();
                        fill3.setFillBackgroundColor(IndexedColors.ROSE.index);
                        fill3.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
                        sheetCF.addConditionalFormatting(regions, rule3, rule2);
                        sheetCF.addConditionalFormatting(regions, rule1);
                        wb.write(out);
                        out.close();
                        return true;
                    } catch (IOException ex) {
                        return false;
                    }
                } catch (Exception ex) {
                    return false;
                }
            }
        };//end of task

        setProgressMode(true);
        progressBar.progressProperty().bind(writeTask.progressProperty());
        progressMessage.textProperty().bind(writeTask.messageProperty());
        writeTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                if (e.getSource().getValue() == true) {
                    Dialogs.showInformationDialog(null,
                            "Region written to file " + "(" + regionFile.getName() + ") successfully",
                            "Region Written", "SNP Viewer");
                } else {
                    Dialogs.showErrorDialog(null, "Region write failed.", "Write Failed", "SNP Viewer");
                }
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressMessage.textProperty().unbind();
                progressMessage.setText("");
                progressTitle.setText("");

            }

        });
        writeTask.setOnFailed(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                progressMessage.textProperty().unbind();
                progressMessage.setText("");
                progressTitle.setText("Region write failed!");
                Dialogs.showErrorDialog(null, "Error writing region to file\n", "Region write error", "SNP Viewer",
                        e.getSource().getException());

            }

        });
        writeTask.setOnCancelled(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent e) {
                progressMessage.setText("Region write cancelled");
                progressTitle.setText("Cancelled");
                setProgressMode(false);
                progressBar.progressProperty().unbind();
                progressBar.progressProperty().set(0);
                Dialogs.showErrorDialog(null, "Error writing region to file\n", "Region write error", "SNP Viewer");
            }

        });
        cancelButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                writeTask.cancel();

            }
        });
        progressTitle.setText("Writing region to .xlsx file");
        new Thread(writeTask).start();
    }

    private List<SnpFile.SnpLine> searchCoordinate(String chrom, int start, int end) {
        List<SnpFile.SnpLine> foundSnps = new ArrayList<>();
        List<SnpFile> bothFiles = new ArrayList<>();
        bothFiles.addAll(affFiles);
        bothFiles.addAll(unFiles);
        for (SnpFile f : bothFiles) {
            List<SnpFile.SnpLine> snps = f.getFlankingSnps(chrom, start, end);
            if (foundSnps.isEmpty()) {
                foundSnps = snps;
            } else if (snps != null) {

                if (foundSnps.get(0).getPosition() > start && snps.get(0).getPosition() <= start) {
                    foundSnps.set(0, snps.get(0));
                } else {
                    if (Math.abs(snps.get(0).getPosition()) < Math.abs(foundSnps.get(0).getPosition())) {
                        foundSnps.set(0, snps.get(0));
                    }
                }
                if (foundSnps.get(1).getPosition() < end && snps.get(0).getPosition() >= end) {
                    foundSnps.set(1, snps.get(1));
                } else {
                    if (Math.abs(snps.get(1).getPosition()) < Math.abs(foundSnps.get(1).getPosition())) {
                        foundSnps.set(0, snps.get(1));
                    }
                }
            }
        }
        return foundSnps;
    }

    public void autoFindRegions() {
        if (affObserve.isEmpty()) {
            Dialogs.showErrorDialog(null,
                    "Find Regions can only be run when there "
                            + "is at least one Affected sample in the project.  Use the "
                            + "'Add Affected' button/menu item to add  Affected samples.",
                    "No Affected samples to analyze!", "SnpViewer");
            return;
        }
        Stage stage = new Stage();
        FXMLLoader loader = new FXMLLoader(getClass().getResource("FindRegionsInterface.fxml"));
        try {
            Pane page = (Pane) loader.load();
            FindRegionsInterfaceController findReg = (FindRegionsInterfaceController) loader.getController();
            Scene scene = new Scene(page);
            stage.setScene(scene);
            scene.getStylesheets().add(SnpViewer.class.getResource("SnpViewerStyleSheet.css").toExternalForm());
            setProgressMode(true);
            stage.initModality(Modality.APPLICATION_MODAL);
            stage.getIcons().add(new Image(this.getClass().getResourceAsStream("icon.png")));
            stage.showAndWait();
            if (findReg.getCancelled()) {
                setProgressMode(false);
                return;
            }

            //int w, double r, boolean con, int refWind, double refCut,
            //int minReportSize, int minReportRun, double het, double dischord)
            int window = Integer.parseInt(findReg.getWindow());
            double regionLength = Double.parseDouble(findReg.getRegionLength());
            boolean checkConcordant = findReg.getCheckConcordance();
            int refineWindow = Integer.parseInt(findReg.getRefineSize());
            double refineTolerance = Double.parseDouble(findReg.getRefineTolerance());
            int minReport = Integer.parseInt(findReg.getReportLength());
            int minReportRun = Integer.parseInt(findReg.getReportMinSnps());
            double hetTolerance = Double.parseDouble(findReg.getHetTolerance());
            double dischordTolerance = Double.parseDouble(findReg.getDischordTolerance());
            boolean autosomesOnly = findReg.getAutosomesOnly();
            LinkedHashSet<String> c = new LinkedHashSet();
            for (Object item : chromosomeSelector.getItems()) {
                if (item instanceof String) {
                    String chrom = (String) item;
                    if (autosomesOnly) {
                        if (chrom.matches("\\d+")) {//only add autosomes
                            c.add(chrom);
                        }
                    } else {
                        c.add(chrom);
                    }
                }
            }

            final RegionFinder regionFinder = new RegionFinder(c, affFiles, unFiles, window, regionLength,
                    checkConcordant, refineWindow, refineTolerance, minReport, minReportRun, hetTolerance,
                    dischordTolerance);

            regionFinder.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {
                    progressBar.progressProperty().unbind();
                    progressMessage.textProperty().unbind();
                    progressMessage.setText("Done");
                    progressTitle.textProperty().unbind();
                    setProgressMode(false);
                    Object result = t.getSource().getValue();
                    ArrayList<RegionSummary> foundRegions = new ArrayList<>();
                    if (result instanceof ArrayList) {
                        for (Object r : (ArrayList) result) {
                            if (r instanceof RegionSummary) {
                                RegionSummary reg = (RegionSummary) r;
                                foundRegions.add(reg);
                            }
                        }
                        if (foundRegions.size() > 0) {
                            FXMLLoader tableLoader = new FXMLLoader(
                                    getClass().getResource("MultiRegionReporter.fxml"));
                            try {
                                Pane tablePane = (Pane) tableLoader.load();
                                MultiRegionReporterController multiReg = (MultiRegionReporterController) tableLoader
                                        .getController();
                                Scene tableScene = new Scene(tablePane);
                                Stage tableStage = new Stage();
                                tableStage.setScene(tableScene);
                                tableScene.getStylesheets().add(
                                        SnpViewer.class.getResource("SnpViewerStyleSheet.css").toExternalForm());
                                multiReg.displayData(foundRegions);
                                tableStage.setTitle("Find Regions Results");
                                tableStage.getIcons()
                                        .add(new Image(this.getClass().getResourceAsStream("icon.png")));
                                tableStage.initModality(Modality.NONE);
                                tableStage.show();
                            } catch (Exception ex) {
                                Dialogs.showErrorDialog(null,
                                        "Error displaying" + " results from Find Regions Method.",
                                        "Find Regions Error!", "SnpViewer", ex);
                            }
                        } else {
                            Dialogs.showInformationDialog(null, "No regions " + "found.", "Find Regions",
                                    "SnpViewer");
                        }
                        savedRegions.addAll(foundRegions);
                        RegionSummary sorter = new RegionSummary();
                        sorter.mergeRegionsByPosition(savedRegions);
                    }
                    saveProject();
                    int c = chromosomeSelector.getSelectionModel().getSelectedIndex();
                    if (c > -1) {
                        selectionOverlayPane.getChildren().clear();
                        selectionOverlayPane.getChildren().add(dragSelectRectangle);
                        drawSavedRegions((String) chromosomeBoxList[c]);
                    }
                    progressMessage.setText("");
                    progressTitle.setText("");
                    progressBar.progressProperty().set(0);
                }
            });
            regionFinder.setOnFailed(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {
                    progressBar.progressProperty().unbind();
                    progressMessage.textProperty().unbind();
                    progressMessage.setText("Failed!");
                    progressTitle.textProperty().unbind();
                    Dialogs.showErrorDialog(null, "Find Regions method failed.", "Error!", "SnpViewer",
                            t.getSource().getException());
                    setProgressMode(false);
                    progressMessage.setText("");
                    progressTitle.setText("");
                    progressBar.progressProperty().set(0);
                }
            });
            regionFinder.setOnCancelled(new EventHandler<WorkerStateEvent>() {
                @Override
                public void handle(WorkerStateEvent t) {
                    progressBar.progressProperty().unbind();
                    progressMessage.textProperty().unbind();
                    progressMessage.setText("Cancelled");
                    progressTitle.textProperty().unbind();
                    Dialogs.showErrorDialog(null, "Find Regions method Cancelled.", "Cancelled", "SnpViewer");
                    setProgressMode(false);
                    progressMessage.setText("");
                    progressTitle.setText("");
                    progressBar.progressProperty().set(0);

                }
            });
            cancelButton.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent actionEvent) {
                    regionFinder.cancel();

                }
            });
            progressBar.progressProperty().unbind();
            progressMessage.textProperty().unbind();
            progressTitle.textProperty().unbind();
            progressBar.progressProperty().bind(regionFinder.progressProperty());
            progressMessage.textProperty().bind(regionFinder.messageProperty());
            progressTitle.textProperty().bind(regionFinder.titleProperty());
            regionFinder.start();

        } catch (IOException ex) {
            Dialogs.showErrorDialog(null, "Error starting Find Regions method.", "Error!", "SnpViewer", ex);
            progressBar.progressProperty().unbind();
            progressMessage.textProperty().unbind();
            progressTitle.textProperty().unbind();
            setProgressMode(false);
        }

    }

    public void returnToInitialState() {
        setProgressMode(false);
        projectRunning = false;
        chromSplitPane.getItems().clear();
        labelSplitPane.getItems().clear();
        clearDragSelectRectangle();
        savedRegions.clear();
        savedRegionsDisplay.clear();
        savedRegionsReference.clear();
        selectionOverlayPane.getChildren().clear();
        selectionOverlayPane.getChildren().add(dragSelectRectangle);
        resetObservables();
        newProjectMenu.setDisable(false);
        loadProjectMenu.setDisable(false);
        addAffected.setDisable(true);
        addUnaffected.setDisable(true);
        loadProjectButton.setDisable(false);
        newProjectButton.setDisable(false);
        saveToPngMenu.setDisable(true);
        chromosomeSelector.setDisable(true);
        redrawButton.setDisable(true);
        colorPicker.setDisable(true);
        colorComponantSelector.setDisable(true);
        cacheChromsButton.setDisable(true);
        cacheChromsMenu.setDisable(true);
        addAffSampleMenu.setDisable(true);
        addUnSampleMenu.setDisable(true);
        nextChromMenu.setDisable(true);
        prevChromMenu.setDisable(true);
        firstChromMenu.setDisable(true);
        lastChromMenu.setDisable(true);
        redrawMenu.setDisable(true);
        autoFindRegions.setDisable(true);
        displaySavedsRegionsMenu.setDisable(true);
        clearSavedRegionsMenu.setDisable(true);
        hideSavedRegionsMenu.setDisable(true);
        outputSavedRegionsMenu.setDisable(true);
        findRegionsButton.setDisable(true);
        removeSampleMenu.setDisable(true);
        cancelButton.setDisable(true);
        projectLabel.setText("");
    }

    public boolean checkProjectFolder(File directory, ArrayList<SnpFile> snpFiles) {
        for (SnpFile f : snpFiles) {
            String fileDir = f.outputDirectory.getName();
            File dirCheck = new File(directory.getAbsolutePath() + "/" + fileDir);
            if (!dirCheck.exists()) {
                return false;
            } else {
                f.setOutputDirectory(dirCheck);
            }
            HashMap<String, File> chromFileReplace = new HashMap<>();
            for (String c : f.chromFiles.keySet()) {
                File snpViewFile = new File(dirCheck.getAbsolutePath() + "/chr" + c + ".snpview");
                if (!snpViewFile.exists()) {
                    return false;
                } else {
                    chromFileReplace.put(c, snpViewFile);
                }
            }
            f.clearChromFiles();
            for (String c : chromFileReplace.keySet()) {
                f.addChromFile(c, chromFileReplace.get(c));
            }
        }
        return true;
    }

    private void checkQualitySelection() {
        ArrayList<RadioMenuItem> callQualityRadios = new ArrayList<>(
                Arrays.asList(noFilteringRadio, filter99, filter95, filter90, filter85));
        ArrayList<Double> callQuals = new ArrayList<>(Arrays.asList(null, 0.01, 0.05, 0.10, 0.15));
        for (int i = 0; i < callQuals.size(); i++) {
            if (callQuals.get(i) != null && qualityFilter != null) {
                if (callQuals.get(i).equals(qualityFilter)) {
                    callQualityRadios.get(i).setSelected(true);
                    break;
                }
            } else {
                if (callQuals.get(i) == null && qualityFilter == null) {
                    callQualityRadios.get(i).setSelected(true);
                    break;
                }
            }
        }
    }

    public void showAbout(ActionEvent ev) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("about.fxml"));
            Pane page = (Pane) loader.load();
            Scene scene = new Scene(page);
            Stage stage = new Stage();
            stage.setScene(scene);
            scene.getStylesheets().add(SnpViewer.class.getResource("SnpViewerStyleSheet.css").toExternalForm());
            AboutController controller = loader.getController();
            controller.setVersion(VERSION);
            stage.initModality(Modality.APPLICATION_MODAL);
            stage.getIcons().add(new Image(this.getClass().getResourceAsStream("icon.png")));
            stage.setTitle("About SnpViewer");

            stage.show();
        } catch (Exception ex) {
            Dialogs.showErrorDialog(null, "Error showing about information - see" + " details for stack trace",
                    "ERROR!", "SnpViewer", ex);
        }
    }

    public enum Colors {
        aa(0), bb(1), ab(2), line(3), fill(4), saveLine(5), saveFill(6);

        public int value;

        private Colors(int value) {
            this.value = value;
        }
    }

}//end of class