
"""MyelinJ graphical user interface
This script provides a GUI to set and adjust settings for the analysis of
micrographs of myelinating cultures. The GUI accepts images in .tif format
where the neurite and myelin micrographs have been merged together.
The GUI saves all of the user defined settings in a comma separated values
(.csv) file using the imported module MyelinJanalysis.
Some basic functions are also imported from the module basicfunctions
This script contains the following functions:
    * analysed - saves settings in .csv file and runs image analysis
    * getNext - this allows the user to select the next image in a large
    file of images, so analysis settings can be checked on mutiple images
    * getimage - this opens an image from the file selected by the user.
    Can be used in conjunction with getNext to open the next image in a file.
This scipt contains the folowing Dialog boxes:
    * Dialog1 - if a username has already been made then this can be
    selected and the settings will be used for image analysis. Otherwise a
    new user can be made.
    * DialogStats - the user can define the number of experimental
    conditions and which experimental condition each folder of images
    belongs to. This is required because statistical analysis requires
    at least three repeats for each experimental condition.
    * Dialog2 - enter a username
    * Dialog3 - define which channel in merged .tif corresponds to neurites
    and which corresponds to myelin.
    * Dialog4 - define analysis settings for myelin micrographs
    * Dialog5 - define analysis settings for neurite micropgraphs
    * Dialog6 - alternative settings for the analysis of neurite micrographs
"""
from __future__ import with_statement, division
from ij import IJ, ImagePlus, WindowManager, Prefs
from ij.plugin import ImageCalculator, ChannelSplitter, Duplicator
from ij.process import ImageConverter, ImageProcessor
import os
import csv
from ij import IJ, ImagePlus
from ij.gui import DialogListener, GenericDialog, ImageWindow, \
                   MessageDialog, YesNoCancelDialog
from java.awt.event import ActionListener, ActionEvent, \
     ItemListener, ItemEvent, WindowAdapter
from ij.plugin.frame.Editor import actionPerformed
from java.awt import Button, Checkbox, TextField, \
                     BorderLayout, Font, Color, \
                     Dimension, Cursor
from java.util import Random, Vector
from java.lang import String
from javax.swing import JFrame, JButton, JOptionPane, \
                        BorderFactory, JFrame, JLabel, JPanel, \
                        JTextArea, JSlider, JCheckBox, JComboBox, \
                        JTextField, JScrollBar
from loci.common.DebugTools import enableIJLogging
from ij.plugin.filter import RankFilters
from javax.swing.AbstractButton import setBorderPainted
from ij.io import FileSaver
import time
from javax.swing import ImageIcon
import sys
from ij.macro import Interpreter as IJ1
import mpicbg.ij.clahe.Flat
from java.lang import Runtime, System
from inra.ijpb.morphology.attrfilt import BoxDiagonalOpeningQueue
from inra.ijpb.morphology import Morphology
SN = False
w = WindowManager
OS = System.getProperty("os.name")
cwd = os.getcwd()

# set folder containing the macro as the current working directory i.e
# location for username CSV (which  should be in Fiji's plugin file) based
# on the operating system bein used
if "Windows" in OS:
    cwdR = cwd+"\\plugins\\MyelinJ\\MyelinJstats.R"
    cwdR = '"'+cwdR+'"'
    cwd = cwd+"\\plugins\\MyelinJ\\"
elif "Mac" in OS:
    cwdR = cwd + "/plugins/MyelinJ/MyelinJstats.R"
    cwd = cwd+"/plugins/MyelinJ/"
sys.path.append(cwd)

import MyelinJanalysis
import basicfunctions
import config

settings = ""

# select file containing images for analysis
imagefolder = IJ.getDirectory("Choose a Directory")
basicfunctions.closeallimages()  # close any images already open
username = []
usernamepath = []
g = 0
r = 0

def neuritesubtract():
        """ Subtract neurites from myelin channel
        duplicates the current myelin channel image, subtracts neurites
        (red) using the ImageCalculator and then displays image.
        """
        green3 = IJ.getImage()
        green3 = green3.duplicate()
        green3 = ImageCalculator().run("Subtract create", green3, red)
        ImageWindow.setNextLocation(int(IJ.getScreenSize().width * 1/3),
                                        int(IJ.getScreenSize().height * 1/14))
        basicfunctions.closeimagebg()
        green3.show()


def analysed():
        """
        Runs image analysis using settings defined by the user. If a new
        user name has been created a .csv file will first be created.
        Analyse will then read settings from the user name .csv file and
        perform the analysis. The imported module MyelinJ analysis is used
        for this function.
        """
        if config.newusercb is True:
            MyelinJanalysis.newUser(cwd, config.greyscaleMinVal, g, r, config.backgroundsubRolling,
                                     config.cellbodycb, config.user, config.SN, config.mCLAHE,
                                     config.backgroundsubNeurite, config.setpixels, config.stats,
                                     config.threshChoice, config.despeckle, config.contrast,
                                     config.Min, config.Max, config.radius, config.Min2,
                                     config.Max2, config.threshChoice2, config.mCLAHE2,
                                     config.Sbgcbstate)
                                     
        MyelinJanalysis.analyse(cwd, config.user, imagefolder, config.stats,
                                 config.experiments, config.multi, config.RscriptPath,
                                 config.subfoldernames, config.names, config.statsfolderPath,
                                 cwdR)

      
def getNext():
    """
        Gets the next image in the selected folder. Goes back to the first
        image if all images have been opened.
        Parameters
        ----------
        imagecount: int
            Total number of images in selected folder. From Dialog1.onOK.
        returns (global in config)
        ----------
        imageposition : int
            Position of the current image in the selected folder.
        """
    config.imageposition = config.imageposition + 1
    if config.imageposition > config.imagecount - 1:
        config.imageposition = 0


def getimage():
        """
        Opens image in folder. Position of the image opened in the folder
        is defined by the function getNext. Alternativly, if the user has
        chosen to use an image they have opened themselves, then this image
        will be selected as the current image.
        Parameters
        ----------
        userimage2 : checkbox
            if True then the user has opened an image themselves to test
            the settings on rather than using an image from the folder they
            selected.
        userimagename : imp
            reference to image opened by the user. This image is the current
            active image.
        g: int
            position of the myelin micrograph after the image has been
            split into separate channels.
        r: int
            position of the myelin micrograph after the image has been
            split into separate channels.
        """
        global red, green
        if config.userimage2 is True:
            imp = userimagename
        else:
            imp = IJ.openImage(config.listAllImages[config.imageposition])
        imp = ChannelSplitter.split(imp)
        green = imp[g]
        conv = ImageConverter(green)
        conv.convertToGray8()
        red = imp[r]
        conv = ImageConverter(red)
        conv.convertToGray8()
        IJ.run(red, "Grays", "")
        green.setTitle("original")
        ImageWindow.setNextLocation(int(IJ.getScreenSize().width * 1/3),
                                            int(IJ.getScreenSize().height * 1/14))


def applybackground():
         """ background subtraction
          Performs any background settings defined by the user the image
          currently being displayed. Changes title of the image.
          Parameters
          ----------
          mCLAHE : bool
           Perform CLAHE?
          backgroundsubRolling: bool
              perform rolling ball background subtraction?
          backgroundsubNeurite: bool
              perform neurite subtraction
          setpixels: string
              value for pixel subtraction?
         """
         if config.mCLAHE is True:
                basicfunctions.CLAHE()
         if config.backgroundsubRolling is True:
                basicfunctions.rollingsubtract()
         elif config.backgroundsubNeurite is True:
                neuritesubtract()
         if config.setpixels != "0":
                IJ.run("Subtract...", "value="+config.setpixels)
         green = IJ.getImage()
         green.setTitle("original + background subtraction")


def removecellbodies():
            if config.cellbodycb is True:
                getimage()
                green.show()
                if (config.Min != 0) or (config.Max != 255):
                    IJ.setAutoThreshold(green, config.threshChoice+" dark")
                    IJ.setRawThreshold(green, config.Min, config.Max, None)
                    Prefs.blackBackground = True
                    IJ.run(green, "Convert to Mask", "")
                if config.radius != "0" or "":
                        IJ.run(green, "Remove Outliers...",
                                "radius="+config.radius+" threshold=50 which=Bright")
                green.setTitle("cell body selection")


def frangifilter(self):
            """ Frangi vesselness
            Performs frangi vesselness for myelin channel image.If cell
            bodies have been selected this is assumed to be the
            activeimage. A new image with any background subtraction is
            performed, any cellbodies selected are removed using image
            calculator and frangi vesselness is performed.
            Parameters
            ----------
            cellbodycb : bool
                  remove cell bodies?
            attrival2: string
                  value for performing grey scale morphology filtering.
            """
            global green
            self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
            # if cell bodies removal is selected then a new a new myelin channel
            # image is opened and any background subtraction selected by user
            # is performed.
            if config.cellbodycb is True:
                bg = IJ.getImage()
                bg = bg.duplicate()
                getimage()
                green.show()
                applybackground()
            ImageWindow.setNextLocation(int(IJ.getScreenSize().width * 1/3),
                                            int(IJ.getScreenSize().height * 1/14))
            self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
            IJ.run("Frangi Vesselness (imglib, experimental)",
                    "number=1 minimum=0.454009 maximum=0.454009")
            g = IJ.getImage()
            g.setTitle("original + background subtraction + vesselness")
            g = g.duplicate()
            conv = ImageConverter(g)
            conv.convertToGray8()
            IJ.run(g, "Convert to Mask", "")
            self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
            if config.cellbodycb is True:
                green = ImageCalculator().run("Subtract create", g, bg)
                ImageWindow.setNextLocation(int(IJ.getScreenSize().width * 1/3),
                                                int(IJ.getScreenSize().height * 1/14))
                green.show()
                green.setTitle("original + background subtraction + vesselness + cell body subtraction")
                self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
            ImageWindow.setNextLocation(int(IJ.getScreenSize().width * 1/3),
                                            int(IJ.getScreenSize().height * 1/14))
            if config.greyscaleMinVal != "0" or "":
                IJ.run(green, "Gray Scale Attribute Filtering", "operation=Opening attribute=[Box Diagonal] minimum="+config.greyscale.MinVal+" connectivity=4")
                green = IJ.getImage()
                green.setTitle("original + background subtraction + vesselness + cell body subtraction")
            self.setCursor(Cursor.getDefaultCursor())


basicfunctions.closeallimages()  # close any images already open
username = []
usernamepath = []
# find all of the CSV files for user names (if any) - gets the name of the
# file (user name) and the location of the file
for root, dirs, files in os.walk(cwd):
    for name in files:
        if name.endswith((".csv")):
            username.append(name)
            usernamepath.append(os.path.join(root, name))


class Dialog1(JFrame):
    def __init__(self):
        super(Dialog1, self).__init__()
        self.initUI()
        """
        Select previously made user settings and run image analysis or make
        a new user name. Select whether multiple experimental conditions or
        statistical analysis will be performed (this is not saved in the user
        name settings and so has to be defined everytime an analysis is
        performed - this is to allow more flexbility so less user names are
        required for the same analysis settings).
        Attributes
        ----------
         selectuser: combobox
            Drop down box listing all previous user names as .csv files.
        newuser : checkbox
           check if making a new user name.
        multicb: checkbox
            check if multiple experimental conditions are to be analysed at
            the same time.
        statcb: checkbox
            check if statistical analysis will be performed
        Okbutton: button
            if a user name has been selected image analysis will be started.
            Otherwise more Dialogs will open to imput required analysis
            settings.
        Cancelbutton:
            Dialog box will close and the macro will stop.
        Raises
        ------
        error - if a folder is not selected
        """
    def initUI(self):
        panel = JPanel()
        self.getContentPane().add(panel)
        panel.setBackground(Color.WHITE)
        panel.setLayout(None)
        self.setTitle("Choose user name")
        self.setSize(300, 200)

        self.selectuser = JComboBox(username)
        self.selectuser.setBounds(50, 10, 180, 20)
        panel.add(self.selectuser)

        newusercb = JCheckBox("New user?", True,
                                actionPerformed=self.onNewuser)
        newusercb.setBounds(20, 50, 100, 20)
        newusercb.setSelected(False)
        panel.add(newusercb)

        self. multicb = JCheckBox("Multiple experimental conditions?", True)
        self.multicb.setBounds(20, 70, 250, 20)
        self.multicb.setSelected(False)
        panel.add(self.multicb)

        self.statcb = JCheckBox("Perform statistics?", True)
        self.statcb.setBounds(20, 90, 170, 20)
        self.statcb.setSelected(False)
        panel.add(self.statcb)

        OKbutton = JButton("OK", actionPerformed=self.onOK)
        OKbutton.setBackground(Color.BLACK)
        OKbutton.setBounds(20, 120, 100, 30)
        panel.add(OKbutton)

        Cancelbutton = JButton("Cancel", actionPerformed=self.onCancel)
        Cancelbutton.setBackground(Color.BLACK)
        Cancelbutton.setBounds(150, 120, 100, 30)
        panel.add(Cancelbutton)

        self.setLocationRelativeTo(None)
        self.setLocation(int(IJ.getScreenSize().width * 0.01),
                              int(IJ.getScreenSize().height * 3/10))
        self.setVisible(True)
        # error if user has not selected a folder
        global imagefolder
        if imagefolder is None:
            IJ.showMessage("Error: please selected a folder first")
            imagefolder = IJ.getDirectory("Choose a Directory")
 
    def onNewuser(self, cb2):
        newusercb = cb2.getSource()
        config.newusercb = newusercb.isSelected()

    def onCancel(self, b):
        self.dispose()

    def onOK(self, cb2):
        """Runs username analysis or starts input of new user
        Starts image analysis if a previously defined user name has been
        selected. Otherwise starts the input of a new user name and
        settings. Multicb allows analysis of multiple experimental
        conditiosn simultaneously (where each conditionis analysed
        individually). statcb = True will start. Dialogstat to define
        settings for statistical analysis with R.
        Parameters
        ----------
        newuser: bool
            create a new user profile?
        returns (global in config.py)
        --------------------------
        multi: bool
            multiple experiments to be analysed?
        stats: bool
            statistical analysis to be performed by R?
        subfoldernames: list
            list of all subdirectories within a folder
        test: list
            list of all .tif images in selected folder
        imagecount: int
            total number of .tif images within selected folder
        user: string
            predefined user name selected.
        Raises
        ------
        A folder must be selected.
        The selected folder must contain at least one .tif image.
        For statistical analysis multi (for mulitple
        experimental conditions) must also be True.
        """
        global imagefolder
        config.multi = self.multicb.isSelected()
        config.stats = self.statcb.isSelected()
        if (config.stats is True) and (config.multi is False):
            IJ.showMessage("Error: multiple experimental conditions are required for statistical analysis")
        else:
            # get a list of all the images in the user selected folder if .tif
            config.subfoldernames = list()
        # error if user has not selected a folder
        if imagefolder is None:
            IJ.showMessage("Error: Please select a folder first")
            imagefolder = IJ.getDirectory("Choose a Directory")
        else:
          for root, dirs, files in os.walk(imagefolder):
                config.subfoldernames.append(dirs)
                for name in files:
                        if name.endswith((".tif")):
                            config.listAllImages.append(os.path.join(root, name))
        # error if no .tif files in selected folder
        if config.listAllImages is []:
                IJ.showMessage("Error: no .tif files found in folder")
                imagefolder = IJ.getDirectory("Choose a Directory")
        else:
            # select subdirectory names within folder. This is for analysing
            # multiple experimental conditions where each subdirectory denotes
            # a separate experimental condition
            config.subfoldernames = config.subfoldernames[0]
            if config.multi is False:
                # sets subfoldernames to 1 if multiple experiment analysis is
                # not required (means can iterate over once in a for loop).
                config.subfoldernames = [1]
            config.imagecount = len(config.listAllImages)
            if config.newusercb is True:
                self.dispose()
                config.newuser = True
                if config.stats is False:
                    Dialog2()
                else:
                        DialogStats()
            else:
                     config.user = self.selectuser.getSelectedItem()
                     self.dispose()
                     if config.stats is False:
                         analysed()
                     else:
                            DialogStats()


class DialogStats(JFrame):
    def __init__(self):
        super(DialogStats, self).__init__()
        self.initUI()
        """ Defines which experimental condition each subfolder belongs to.
        For statistical analysis each experimental condition requires a
        minimum od three experimental repeats. This Dialog box allows the
        user to define the names of each experimental repeat (which will
        appear in the grpahs produced by R) and select which folder belongs
        to which experimental condition.
        Attributes
        ----------
        Rloc: textfield
            path to Rscript
        noConditions : textfield
           Number of experimental conditions
        Methods
        -------
        A dynamic dialog box is produced depending on the number of
        subfolders (experiments) and the number of experimental conditions
        defined by user. A matrix is dispayed where subfolder names are row
        names, column names are experimental conditions (defined by the
        user) and checkboxes allow the user to define which experiments
        belong to which experimental conditions. onOK creates a 2D list that
        defines which subfolders belong to which exerimental conditions -
        based on the checkboxes selected by the user.
        Raises
        ------
        Must be at least six folders i.e two experimetal conditions with
        three repeats each.
        """
    def initUI(self):
        global panel
        panel = JPanel()
        self.getContentPane().add(panel)
        panel.setBackground(Color.WHITE)
        panel.setLayout(None)
        self.setTitle("Define experimental conditions")
        self.setSize(config.width1, config.height1)
        Min2 = JTextField("Rscript location:")
        Min2.setBounds(20, 10, 85, 20)
        Min2.setEditable(False)
        panel.add(Min2)
        if "Windows" in OS:
            self.Rloc = JTextField("C:\\Program Files\\R\\R-3.5.1\\bin\\Rscript")
        elif "Mac" in OS:
            self.Rloc = JTextField("/Library/Frameworks/R.framework/Versions/3.3/Resources/Rscript")
        self.Rloc.setBounds(110, 10, 350, 20)
        self.Rloc.setEditable(True)
        panel.add(self.Rloc)
        Min1 = JTextField("No. experimental conditions (press enter)")
        Min1.setBounds(20, 40, 250, 20)
        Min1.setEditable(False)
        panel.add(Min1)
        self.noConditions = TextField("", actionPerformed=self.onClick)
        self.noConditions.setBounds(290, 41, 40, 20)
        panel.add(self.noConditions)
        self.setLocationRelativeTo(None)
        self.setLocation(int(IJ.getScreenSize().width * 0.01),
                           int(IJ.getScreenSize().height * 3/10))
        self.setVisible(True)

    def onClick(self, cb2):
        """ Array of texfields and checkboxes for each folder (experimental
         condition)
        The user enters the number fo experimental conditions and then
        presses OK on the keyboard.
        This displays a matrix of textfields and checkboxes for each
        folder. Row names are the name of each subfolder (experiment). The
        headings of the columns are empty texfields corresponding to the
        number of experimental conditions defined by the user.The user can
        enter the names of each experimental condition (which will appear
        on any graphs produced by R later). The matrix is made up of an
        array of checkboxes which allows the user to define which
        experimental condition each folder belongs to.
        Parameters
        ----------
        repeats: int
            number of experimental repeats defind by the user.
        subfoldernames : list
           list of all subfolders within main folder (each folder
           corresponds to an experimental condition)
        heigh1: int
            height on the dialog box.
        width1:int
            width of the dialog box.
        text: array
            array of textfields for the name of each subfolder
        accross: int
            position of text (array). Increments by 30 for each textfield
            required (repeats).
        check: checkbox
            array of checkboxes Where the number will be: number of
            experimental conditions * number of subfolders.
        down: int
            position of checkbox array going down. Increments for each
            subfolder
        accross2: int
            position of checkbox array going acrross. Increments for each
            experimental condition.
        names: array
            array of textfields for each experimental condition defined by
            user. User will enter the name of each experimental condition.
        OKbutton: button
            starts image analysis if a predefined user name has already
            been selected. Otherwise continues to create a new user name.
        resetbutton: button
            sets the dialogbox back to the start - before the number of
            experimental conditions was provided.
           Raises
        ------
        Must be at least six folders i.e two experimetal conditions with
        three repeats each. Must be at least two experimental conditions.
        """
        global  panel, check, repeats
        accross = 85
        text = [0] * len(config.subfoldernames)
        repeats = int(self.noConditions.getText())

        # need to be at least six subfolders (experiments and
        # two experimental conditions defined.
        if len(config.subfoldernames) < 6:
            IJ.showMessage("Error: must be at least six experiments (i.e 3 repeats of two conditions)")
        elif repeats < 2:
            IJ.showMessage("Error: must be at least two different experimental conditions")
        elif (len(config.subfoldernames) >= 6) and (repeats >= 2):
            repeats2 = len(config.subfoldernames) - 3
            repeats2 = repeats2 * 44
            config.height1 = config.height1 + repeats2
            self.setSize(config.width1, config.height1)

            # creates an array of texfields for the name of
            # each subfolder (experiment) and adds then to
            # the dialog box as a list.
            for i in range(0, len(config.subfoldernames)):
                text[i] = JTextField(config.subfoldernames[i])
                text[i].setBounds(20, accross, 100, 20)
                panel.add(text[i])
                accross = accross + 30

            if repeats > 3:
                repeats2 = repeats - 3
                repeats2 = repeats2 * 110
                config.width1 = config.width1 + repeats2
                self.setSize(config.width1, config.height1)

            check = [[0 for x in range(len(config.subfoldernames))] for y in range(repeats)]
            down = 85
            accross2 = 25
            config.names = [0] * repeats

            # adds an array of textfields for the number of experimental
            # conditions defined by the user as headings.
            for z in range(0, repeats):
                config.names[z] = JTextField()
                accross2 = accross2 + 105
                config.names[z].setBounds(accross2, 63, 100, 20)
                panel.add(config.names[z])
                down = 85

                # adds an array of checkboxes to make a matrix
                for x in range(0, len(config.subfoldernames)):
                    check[z][x] = JCheckBox()
                    check[z][x].setBounds(accross2, down, 40, 20)
                    panel.add(check[z][x])
                    down = down + 30
            panel.repaint()

            # Place buttons at bottom of the dialog box.
            OKbutton = JButton("OK", actionPerformed=self.onOK)
            OKbutton.setBackground(Color.BLACK)
            OKbutton.setBounds(80, down, 100, 30)
            panel.add(OKbutton)
            Resetbutton = JButton("Reset", actionPerformed=self.onReset)
            Resetbutton.setBackground(Color.BLACK)
            Resetbutton.setBounds(180, down, 100, 30)
            panel.add(Resetbutton)

    def onReset(self, cb2):
        # closes and reopens dialog box.
        self.dispose()
        DialogStats()

    def onOK(self, cb2):
        """
        Continuation of onClick. retrieves the names of each experimental
        condition and which subfolder (experiment) belongs to which
        experimental condition. creates a folder called statistical
        analysis and subfolders for each experimental condition. Retrives
        the location of Rscript, as defined by the user. This is required
        for running R via the command line later on.
        Parameters
        ----------
        subfoldernames : list
           list of all subfolders within main folder (each folder
           corresponds to an experimental condition).
        repeats2: int
            used to calculate the change in width depending on the number
            of experimental conditions defined.
        text: array
            array of textfields for the name of each subfolder
        same: int
            count to determine whether any subfolders (experiments) have
            been assigned more than one experimental condition.
        check: checkbox
            array of checkboxes Where the number will be: number of
            experimental conditions * number of subfolders.
        names: array
            array of textfields for each experimental condition defined by
            user. User will enter the name of each experimental condition.
        Returns (global in config.py)
        -------
        experiments: 2D list of strings
             list of all the subfolders (experiments) that are in each
             experimental condition.
        allimageNames: list of strings
            name of each experimental condition.
        allUniqueimageNames: list of strings
            same as allimageNames but is a list of unique names
            any duplicates have been removed.
        statsfolderPath: string
            file path to the create statsfolder.
        RscriptPath: string
            file path for R script (defined by user).
           Raises
        ------
        If any subfolders (experiments) have been assigned more than one
        experimental condition. If any of the experimental conditions have
        been assigened the same name.
        """

        config.experiments = [[0 for x in range(0)] for y in range(repeats)]
        same = 0

        # creates a 2D list (experiments) for each experimental conditions
        # with the names of each subfolder. as defined by the user (check).
        for i in range(0, repeats):
            for x in range(0, len(config.subfoldernames)):
                if check[i][x].isSelected() is True:
                    config.experiments[i].append(config.subfoldernames[x])
                    same = same + 1

        # if same is more than the number of subfolders then some of
        # the subfolders must have been assigned to multiple
        # experimental conditions.
        if same > len(config.subfoldernames):
            IJ.showMessage("Error: at least one experiment has been assigned two conditions")
        elif same != len(config.subfoldernames):
            IJ.showMessage("Error: all experiments must be assigned a condition")
        else:
            allimageNames = []

            # get the name of each experimental condition from names (allimageNames)
            for s in range(0, len(config.names)):
                allimageNames.append(config.names[s].getText())
            # remove any duplicate names
            allUniqueimageNames = set(allimageNames)

            # if allimageNames and allUniqueimageNames are not the same then some of the experimental
            # conditions must have the same name.
            if len(allUniqueimageNames) != len(allimageNames):
                IJ.showMessage("Error: all experimental conditions must have a unique name")
            # save file path to statistical analysis folder

            if "Windows" in OS:
                statsfolder = imagefolder+"\\statistical analysis"
                config.statsfolderpPath = imagefolder+"statistical analysis"
                config.statsfolderPath = statsfolderPath.replace("\\", "/")
            elif "Mac" in OS:
                statsfolder = imagefolder+"/statistical analysis"
                config.statsfolderPath = statsfolder

            # create folder called statistical analysis (if it does not
            # already exist).
            if not os.path.exists(statsfolder):
                    os.makedirs(statsfolder)

            # create subfolders for each experimental conditions,
            # within the statistical analysis folder.
            for f in range(0, len(config.names)):
                if config.names[f].getText() == "":
                    IJ.showMessage("Error: each experimental condition must be given a name")
                    break
                if "Windows" in OS:
                    if not os.path.exists(statsfolder+"\\"+config.names[f].getText()):
                        os.makedirs(statsfolder+"\\"+config.names[f].getText())
                elif "Mac" in OS:
                    if not os.path.exists(statsfolder+"/"+config.names[f].getText()):
                        os.makedirs(statsfolder+"/"+config.names[f].getText())

            self.dispose()
            config.RscriptPath = self.Rloc.getText()
            if "Windows" in OS:
                config.RscriptPath = '"'+RscriptPath +'"'
            if config.newuser is True:
                Dialog2()
            else:
                analysed()


class Dialog2(JFrame):
    def __init__(self):
        super(Dialog2, self).__init__()
        self.initUI()
        """ Enter new user name
        Attributes
        ----------
         Title: textfield
            to enter new user name
        OKbutton : button
           continues to next dialog box for entering user name settings.
           Raises
        ------
        If the user name already exists
        """

    def initUI(self):
        panel = JPanel()
        self.getContentPane().add(panel)
        panel.setBackground(Color.WHITE)
        panel.setLayout(None)
        self.setTitle("Enter user name")
        self.setSize(280, 150)
        
        self.Title = JTextArea("")
        self.Title.setBounds(15, 10, 250, 20)
        border = BorderFactory.createEtchedBorder()
        self.Title.setBorder(border)
        panel.add(self.Title)
        
        OKbutton = JButton("Enter", actionPerformed=self.onEnter)
        OKbutton.setBackground(Color.BLACK)
        OKbutton.setBounds(80, 50, 100, 30)
        panel.add(OKbutton)
        
        self.setLocationRelativeTo(None)
        self.setLocation(int(IJ.getScreenSize().width * 0.01),
                          int(IJ.getScreenSize().height * 3/10))
        self.setVisible(True)

    def onEnter(self, e):
        """ Enter new user name
        Parameters
        ----------
         Title: textfield
             to enter user name
        user : string
           new user name
        username: list of string
            list of all predefined user names
           Raises
        ------
        If the user name entered already exists. User is given the choice
        of either entering a new user name or overwriting the existing username.
        """
        config.user = self.Title.getText()
        config.user = config.user+".csv"
        
        # if the new user name entered already exists the user is asked
        # whether to overwrite the existing user name or choose a different
        # name
        if config.user in username:
            frame = JFrame()
            usernameExists = YesNoCancelDialog(frame, "Multi usernames defined", "Multiple usernames defined. Would you like to overwrite the settings?")
            if usernameExists.yesPressed() is True:
                Dialog3()
                self.dispose()               
        else:
             self.dispose()
             Dialog3()
# user selects which channels represent green and red in the images


class Dialog3(JFrame):
    def __init__(self):
        super(Dialog3, self).__init__()
        self.initUI()
        """ select channels for myelin and neurites
           Defines channels for myelin and neurites. Opens the first image in
           selected folder and displays the myelin channel only. For use by
           Dialod4.
           Raises
        ------
        Selected channels for neurites and myelin cannot be the same.
        """
    def initUI(self):
        panel = JPanel()
        self.getContentPane().add(panel)
        panel.setBackground(Color.WHITE)
        panel.setLayout(None)
        self.setTitle("Image settings")
        self.setSize(300, 200)

        Title2 = JTextArea("Neurite:")
        Title2.setBounds(15, 5, 70, 20)
        Title2.setEditable(False)
        background = Color.GRAY
        Title2.setBackground(background)
        panel.add(Title2)

        self.neurite = JComboBox(config.neurites)
        self.neurite.setBounds(15, 30, 250, 20)
        panel.add(self.neurite)

        Title3 = JTextArea("Myelin:")
        Title3.setBounds(15, 60, 80, 20)
        Title3.setEditable(False)
        background = Color.GRAY
        Title3.setBackground(background)
        panel.add(Title3)

        self.myelin = JComboBox(config.neurites)
        self.myelin.setBounds(15, 90, 250, 20)
        panel.add(self.myelin)

        OKbutton = JButton("Enter", actionPerformed=self.onEnter)
        OKbutton.setBackground(Color.BLACK)
        OKbutton.setBounds(80, 120, 100, 30)
        panel.add(OKbutton)

        self.setLocationRelativeTo(None)
        self.setLocation(int(IJ.getScreenSize().width * 0.01),
                             int(IJ.getScreenSize().height * 3/10))
        self.setVisible(True)

    def onEnter(self, e):
            global r, g
            r = self.neurite.getSelectedItem()
            r = int(config.neurites.index(r))
            g = self.myelin.getSelectedItem()
            g = int(config.neurites.index(g))
            if r == g:
                IJ.showMessage("Error: colours for myelin and neurites needs to be different")
            else:
                    self.dispose()
                    getimage()
                    green.show()
                    Dialog4()


class Dialog4(JFrame):
    def __init__(self):
        super(Dialog4, self).__init__()
        self.initUI()
    """ Graphical interface for defining myelin channel    image analysis
    settings
    Interactive interface where the user can change image analysis settings
    and visualise how these settings effect the image. The user can press
    next image at any time, which will open the next image in the selected
    folder and apply any analysis settings that have already been defined.
    Alternatively, the user can open a specific image and check "use
    selected image". The settings can be "Reset" back to defaul at any time.
    
    bug
    ---
    When image processing takes place a wait cursor is displayed. There is
    a lag between when the analysis or function has finished and when the
    image(s) is displayed. This means the wait cursor stops before the
    analysis has finished. This is especially pronounced when several
    images are being displayed.
    """
    def initUI(self):
        panel = JPanel()
        self.getContentPane().add(panel)
        panel.setBackground(Color.WHITE)
        panel.setLayout(None)

        Title3 = JTextArea("Background")
        Title3.setBounds(30, 0, 320, 20)
        Title3.setEditable(False)
        background = Color.GRAY
        Title3.setBackground(background);
        panel.add(Title3)

        backgroundlabel = JLabel()
        backgroundlabel.setBounds(30, 0, 320, 160)
        border = BorderFactory.createEtchedBorder()
        backgroundlabel.setBorder(border)
        panel.add(backgroundlabel)

        self.bCLAHE = JCheckBox("CLAHE?", False, actionPerformed=self.onCLAHE)
        self.bCLAHE.setFocusable(False)
        self.bCLAHE.setBounds(60, 20, 250, 20)
        panel.add(self.bCLAHE)

        self.rollingballcb = JCheckBox("Subtract background (rolling ball)?", 
                                       False, actionPerformed=self.onSubtractrollingball)
        self.rollingballcb.setFocusable(False)
        self.rollingballcb.setBounds(60, 40, 250, 20)
        panel.add(self.rollingballcb)

        self.neurireSubcb = JCheckBox("Subtract background (using neurites)?", 
                                      False, actionPerformed=self.onSubtractneurites)
        self.neurireSubcb.setFocusable(False)
        self.neurireSubcb.setBounds(60, 60, 250, 20)
        panel.add(self.neurireSubcb)

        Title4 = JTextArea("Remove back ground pixels")
        Title4.setBounds(30, 80, 320, 20)
        Title4.setEditable(False)
        background = Color.GRAY
        Title4.setBackground(background)
        panel.add(Title4)

        subpixels = JTextField("Subtract pixels using 'Math' - press enter")
        subpixels.setBounds(90, 110, 210, 20)
        border = BorderFactory.createLineBorder(Color.black)
        subpixels.setBorder(border)
        background = Color.GRAY
        subpixels.setBackground(background)
        panel.add(subpixels)

        self.setpixels2 = JTextField("0", actionPerformed=self.onSubtractpixels)
        self.setpixels2.setBounds(90, 130, 210, 20)
        border = BorderFactory.createLineBorder(Color.black)
        self.setpixels2.setBorder(border)
        panel.add(self.setpixels2)

        self.cellbodycb = JCheckBox("Remove cell bodies?", 
                                    False, actionPerformed=self.onRemovecellbodies)
        self.cellbodycb.setFocusable(False)
        self.cellbodycb.setBounds(120, 160, 170, 20)
        panel.add(self.cellbodycb)

        Title = JTextArea("Threshold method::")
        Title.setBounds(30, 180, 320, 20)
        Title.setEditable(False)
        background = Color.GRAY
        Title.setBackground(background)
        panel.add(Title)

        threshlabel = JLabel()
        threshlabel.setBounds(30, 180, 321, 140)
        border = BorderFactory.createEtchedBorder()
        threshlabel.setBorder(border)
        panel.add(threshlabel)

        autoThresh = ("Default", "Huang", "Intermodes", "IsoData", "Li", "MaxEntropy", 
                     "Mean", "MinError", "Minimum", "Moments", "Otsu", "Percentile", 
                     "RenyiEntropy", "Shanbhag", "Triangle", "Yen")
        self.autoT = JComboBox(autoThresh)
        self.autoT.setBounds(125, 205, 120, 20)
        self.autoT.setEnabled(False)
        panel.add(self.autoT)

        Min1 = JTextArea("Min:")
        Min1.setBounds(90, 220, 40, 20)
        Min1.setEditable(False)
        panel.add(Min1)

        self.tMin = JTextArea("200")
        self.tMin.setBounds(90, 240, 40, 20)
        border = BorderFactory.createLineBorder(Color.black)
        self.tMin.setBorder(border)
        self.tMin.setEditable(False)
        panel.add(self.tMin)

        Max1 = JTextArea("Max:")
        Max1.setBounds(240, 220, 40, 20)
        Max1.setEditable(False)
        panel.add(Max1)

        self.tMax = JTextArea("255")
        self.tMax.setBounds(240, 240, 40, 20)
        border = BorderFactory.createLineBorder(Color.black)
        self.tMax.setBorder(border)
        self.tMax.setEditable(False)
        panel.add(self.tMax)

        setThresholdbutton = JButton("Apply", actionPerformed=self.onSetThreshold)
        setThresholdbutton.setBackground(Color.BLACK)
        setThresholdbutton.setBounds(140, 280, 80, 30)
        panel.add(setThresholdbutton)

        threshlabel2 = JLabel()
        threshlabel2.setBounds(30, 330, 321, 80)
        border = BorderFactory.createEtchedBorder()
        threshlabel2.setBorder(border)
        panel.add(threshlabel2)

        Title3 = JTextField("Remove cell bodies")
        Title3.setBounds(120, 330, 150, 20)
        Title3.setEditable(False)
        background = Color.GRAY
        Title3.setBackground(background)
        panel.add(Title3)

        setCells2 = JTextField("Cell body radius - press enter")
        setCells2.setBounds(100, 355, 190, 20)
        border = BorderFactory.createLineBorder(Color.black)
        setCells2.setBorder(border)
        background = Color.GRAY
        setCells2.setBackground(background)
        setCells2.setEditable(False)
        panel.add(setCells2)

        self.setOutliers = JTextField("0", actionPerformed=self.onOutlier)
        self.setOutliers.setBounds(100, 375, 190, 20)
        border = BorderFactory.createLineBorder(Color.black)
        self.setOutliers.setBorder(border)
        self.setOutliers.setEditable(False)
        panel.add(self.setOutliers)

        threshlabel3 = JLabel()
        threshlabel3.setBounds(30, 440, 321, 65)
        border = BorderFactory.createEtchedBorder()
        threshlabel3.setBorder(border)
        panel.add(threshlabel3)

        self.frangicb = JCheckBox("Apply frangi analysis?", 
                                  False, actionPerformed=self.onFrangi)
        self.frangicb.setFocusable(False)
        self.frangicb.setBounds(120, 415, 170, 20)
        panel.add(self.frangicb)

        setCells3 = JTextField("Grey scale filter - press enter")
        setCells3.setBounds(97, 450, 200, 20)
        border = BorderFactory.createLineBorder(Color.black)
        setCells3.setBorder(border)
        background = Color.GRAY
        setCells3.setBackground(background)
        setCells3.setEditable(False)
        panel.add(setCells3)

        self.greyscale = JTextField("0", actionPerformed=self.onGreyscale)
        self.greyscale.setBounds(97, 470, 200, 20)
        border = BorderFactory.createLineBorder(Color.black)
        self.greyscale.setBorder(border)
        self.greyscale.setEditable(True)
        panel.add(self.greyscale)

        userimage = JCheckBox("Use selected image", False, actionPerformed=self.onUserimage)
        userimage.setFocusable(False)
        userimage.setBounds(180, 530, 170, 20)
        panel.add(userimage)

        Nextimagebutton = JButton("Next Image", actionPerformed=self.onNextimage)
        Nextimagebutton.setBackground(Color.BLACK)
        Nextimagebutton.setBounds(240, 560, 100, 30)
        panel.add(Nextimagebutton)

        Cancelbutton = JButton("Cancel", actionPerformed=self.onCancel)
        Cancelbutton.setBackground(Color.BLACK)
        Cancelbutton.setBounds(140, 560, 100, 30)
        panel.add(Cancelbutton)

        Nextdialogbutton = JButton("Next", actionPerformed=self.onNextdialog)
        Nextdialogbutton.setBounds(40, 560, 100, 30)
        Nextdialogbutton.setBackground(Color.BLACK)
        panel.add(Nextdialogbutton)

        Resetbutton = JButton("Reset", actionPerformed=self.onReset)
        Resetbutton.setBounds(70, 530, 100, 30)
        Resetbutton.setBackground(Color.BLACK)
        panel.add(Resetbutton)

        self.setTitle("Settings for myelin")
        self.setSize(395, 640)
        self.setLocationRelativeTo(None)
        self.setLocation(int(IJ.getScreenSize().width * 0.01),
                             int(IJ.getScreenSize().height * 3/10))
        self.setVisible(True)
        global c, d, f, m, myelinpanel
        c = 0
        d = 0
        f = False
        m = False
        myelinpanel = self

    def onCLAHE(self, cb1):
        """
        Applies CLAHE to image if checked. If unchecked closes image and
        reverts back to the original unaltered image (if other background
        settings have not been applied). For the below background
        subtraction methods (onSubtractrollingball() and
        onSubtractneurites()) CLAHE will always be applied to the image
        first. Consequently, if one of the bacground methods is applied
        before checking CLAHE, the image will be closed and a new image
        will be opened where CLAHE will be applied to the image and then
        the background subtracted. If CLAHE is unchecked and background
        subtraction has already been set, the image will be closed and
        the same image with only background subtraction will be displayed.
        Parameters
        ----------
        backgroundsubRolling : bool
           state of rolling ball background subtraction checkbox
           (rollingballcb)
        backgroundsubNeurite : bool
           state of neurite background subtraction checkbox (neurireSubcb)
        Returns (global in config.py)
        -------
        mCLAHE: bool
             state of CLAHE checkbox (bCLAHE)
        """
        self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
        mCLAHE = cb1.getSource()
        config.mCLAHE = mCLAHE.isSelected()
        if config.mCLAHE is True:
            # remove unwanted images so that the number of images open
            # does not pile up.
            basicfunctions.toOriginal()
            basicfunctions.green2()
            basicfunctions.CLAHE()
            if config.backgroundsubRolling is True:
                basicfunctions.rollingsubtract()
            elif config.backgroundsubNeurite is True:
                neuritesubtract()
        else:
            basicfunctions.closeimage()
            if (config.backgroundsubRolling is True) or (config.backgroundsubNeurite is True):
                basicfunctions.green2()
            if config.backgroundsubRolling is True:
                basicfunctions.rollingsubtract()
            elif config.backgroundsubNeurite is True:
                neuritesubtract()
        self.setCursor(Cursor.getDefaultCursor())

    def onSubtractrollingball(self, cb1):
        """ Rolling ball background subtraction
        Refer to onCLAHE for full description of background subtraction.
        Parameters
        ----------
        backgroundsubNeurite : bool
           state of neurite background subtraction checkbox (neurireSubcb)
        mCLAHE: bool
             state of CLAHE checkbox (bCLAHE)
        Returns (global in config.py)
        -------
        backgroundsubRolling: bool
             state of rolling ball background subtraction checkbox
             (rollingballcb)
        Raises
        ------
        Only one background subtraction method can be be selected at any
        one time (rolling ball or neurite background subtraction). The
        user must first deselect one before the other can be selected.
        """
        if config.backgroundsubNeurite is False:
            self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
            bgcbstate = cb1.getSource()
            config.backgroundsubRolling = bgcbstate.isSelected()
            if config.backgroundsubRolling is True:
                basicfunctions.ifOriginal()
                basicfunctions.rollingsubtract()
            elif config.backgroundsubRolling is False:
                 basicfunctions.closeimage()
                 if config.mCLAHE is True:
                     basicfunctions.green2()
                     basicfunctions.CLAHE()
            self.setCursor(Cursor.getDefaultCursor())
        else:
            IJ.showMessage("Error: only one background subtraction can be selected")
            self.bgcb.setSelected(False)

    def onSubtractneurites(self, cb1):
        """ neurite background subtraction
        Refer to onCLAHE for full description of background subtraction.
        Parameters
        ----------
         backgroundsubRolling : bool
           state of neurite background subtraction checkbox (neurireSubcb)
        mCLAHE: bool
             state of CLAHE checkbox (bCLAHE)
        Returns (global in config.py)
        -------
        backgroundsubNeurite: bool
             state of rolling ball background subtraction checkbox
             (rollingballcb)
        Raises
        ------
        same as onSubtractrollingball()
        """
        if config.backgroundsubRolling is False:
            self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
            bgcbstate2 = cb1.getSource()
            config.backgroundsubNeurite = bgcbstate2.isSelected()
            if config.backgroundsubNeurite is True:
                basicfunctions.ifOriginal()
                neuritesubtract()
            elif config.backgroundsubRolling is False:
                 basicfunctions.closeimage()
                 if config.mCLAHE is True:
                     basicfunctions.green2()
                     basicfunctions.CLAHE()
            self.setCursor(Cursor.getDefaultCursor())
        else:
            IJ.showMessage("Error: only one background subtraction can be selected")
            self.bgcb.setSelected(False)

    def onSubtractpixels(self, e):
         """ Math: pixel subtraction
         if performed for the first time the current image will be
         duplicated, displayed and pixel subtraction performed. If this is
         repeated the current image will  first be closed (stops number of
         displayed images mounting up).
         Parameters
         ----------
         m : bool
           marker for whether analysis has already been performed
         Returns (global in config.py)
         -------
         setpixles: string
             pixel subtraction value (has to be a string to run).
         """
         global m
         config.setpixels = self.setpixels2.getText()
         if m is True:
            basicfunctions.closeimage()
         basicfunctions.subpixels(config.setpixels)
         m = True

    def onRemovecellbodies(self, cb3):
        """ cell body selection
         closes any images from defining background subtraction to only the
         unprocessed original myelin channel image is displayed. Disables
         checkboxes for background subtraction enables checkboxes etc for
         selecting cell bodies. If deselected the opposite will be
         performed. Any previous settings for background subtraction will
         be performed.
        """
        config.cellbodycb = self.cellbodycb.isSelected()
        if self.cellbodycb.isSelected() is True:
            self.setOutliers.setEditable(True)
            self.setpixels2.setEditable(False)
            self.rollingballcb.setEnabled(False)
            self.neurireSubcb.setEnabled(False)
            self.bCLAHE.setEnabled(False)
            self.tMin.setEditable(True)
            self.tMax.setEditable(True)
            self.autoT.setEnabled(True)
            basicfunctions.closeimagebg()
            if config.setpixels != "0":
                basicfunctions.closeimage()
            getimage()
            green.show()
            
        else:
            self.setOutliers.setEditable(False)
            self.rollingballcb.setEnabled(True)
            self.neurireSubcb.setEnabled(True)
            self.bCLAHE.setEnabled(True)
            self.setpixels2.setEditable(True)
            self.tMin.setEditable(False)
            self.tMax.setEditable(False)
            basicfunctions.closeimage()
            getimage()
            green.show()
            applybackground()
            self.autoT.setEnabled(False)

    def onSetThreshold(self, e):
        """ Applies threshold
         Applies thresholding method selected by the user and crops the
         histogram according to user defined settings. First time this
         button is pressed the threshold will not be performed.This is
         because the user is meant to perform the thresholding/histogram
         cropping themselves using ImageJ - try and find the correct
         settings. The second the button is pressed thresholding will be
         performed - so the user can still change settings.
         Parameters
         ----------
         cellbodycb : bool
           checkbox to be selected before cell bodies are selected.
         Returns (global in config.py)
         -------
         c: integer
             counter for how many times button has been pressed by the user.
         Min: string
             value for cropping histogram
         Max: strong
             value for cropping histogram
         threshChoise: strong
             thresholding method selected by user
         Raises
         ------
         cellbodycb must be selected.
        """
        
        global d,c
        self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
        if config.cellbodycb is True:
            config.Min = int(self.tMin.getText())
            config.Max = int(self.tMax.getText())
            config.threshChoice = self.autoT.getSelectedItem()
            # perform threshold is button has been pressed more
            # than once.
            if c != 0:
                # if button has been prssed more than once close
                # current image (stops lots of images piling up).
                if c > 0:
                    basicfunctions.closeimage()
                getimage()
                ImageWindow.setNextLocation(int(IJ.getScreenSize().width * 1/3),
                                                int(IJ.getScreenSize().height * 1/14))
                green.show()
                IJ.setAutoThreshold(green, config.threshChoice+" dark")
                IJ.setRawThreshold(green, config.Min, config.Max, None)
                Prefs.blackBackground = True
                IJ.run(green, "Convert to Mask", "")
                basicfunctions.bgTitle2()
                threshResult = green.duplicate()
                d = 0
        else:
            IJ.showMessage("Error: first select checkbox for: Remove cell bodies?")
        c = c + 1
        self.setCursor(Cursor.getDefaultCursor())

    def onOutlier(self, e):
            """ Remove outliers
            Runs remove outliers to select cellbodies using user defined
            value.
             Parameters
             ----------
             cellbodycb : bool
                  checkbox to be selected before cell bodies are selected.
             Returns (global in config.py)
             -------
             d: integer
                 counter for how many times analysis has been performed.
             radius: string
                 value for removing outliers.
             Raises
             ------
             cellbodycb must be selected.
            """
            global d
            if config.cellbodycb is True:
                    sender = e.getSource()
                    value = sender.getText()
                    config.radius = str(value)
                    self.setOutliers.setText(config.radius)
                    # if remove outliers has been performed previously
                    # current image is closed (to stop images piling up).
                    if d > 0:
                        basicfunctions.closeimage()
                    threshResult = IJ.getImage()
                    threshResult = threshResult.duplicate()
                    ImageWindow.setNextLocation(int(IJ.getScreenSize().width * 1/3),
                                                    int(IJ.getScreenSize().height * 1/14))
                    IJ.run(threshResult, "Remove Outliers...", "radius="+config.radius+" threshold=50 which=Bright")
                    threshResult.show()
                    basicfunctions.bgTitle2()
                    d = d + 1
            else:
                    IJ.showMessage("Error: Please check the remove cell bodies checkbox first")

    def onFrangi(self, e):
        """ Frangi vesselness
            Performs frangi vesselness using the function frangifilter().
             Returns (global in config.py)
             -------
             d: integer
                 counter for how many times analysis has been performed.
             radius: string
                 value for removing outliers.
        """
        config.frangicb = self.frangicb.isSelected()
        if config.frangicb is True:
             frangifilter(self)
        else:
            basicfunctions.closeimage()

    def onGreyscale(self, e):
        """ grey scale morphology filter
         Returns (global in config.py)
         -------
         attrival2: string
             grey scale filter value ("Minimum").
         Raises
         ------
         Frangi vesselness must be performed first.
        """
        if config.frangicb is True:
            self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
            sender = e.getSource()
            attrival2 = sender.getText()
            config.greyscaleMinVal = str(attrival2)
            self.greyscale.setText(config.greyscaleMinVal)
            ImageWindow.setNextLocation(int(IJ.getScreenSize().width * 1/3),
                                                int(IJ.getScreenSize().height * 1/14))
            
            # if title of image does not contain vesselness then close
            basicfunctions.ifVesselness()
            IJ.run("Gray Scale Attribute Filtering", "operation=Opening attribute=[Box Diagonal] minimum="+config.greyscaleMinVal+" connectivity=4")
            g = IJ.getImage()
            g.setTitle("grey scale")
            self.setCursor(Cursor.getDefaultCursor())
        else:
            IJ.showMessage("Error: Please apply frangi analysis first")

    def onUserimage(self, e):
        """
        Allow user to open an image and select as current image so that it
        can used to optimise analysis settings. This must be a .tif
        composite of myelin and neurires channels. The image will be split
        and only the myelin channel displayed.
        """
        global userimagename
        sender = e.getSource()
        config.userimage2 = True
        userimagename = IJ.getImage()
        if sender.isSelected() is True:
            getimage()
            green.show()
        else:
            config.userimage2 = False

    def onCancel(self, e):
        basicfunctions.closeallimages()
        self.dispose()

    def onNextdialog(self, e):
        config.userimage2 = False
        self.dispose()
        basicfunctions.closeallimages()
        Dialog5()

    def onReset(self, e):
        """
        Reset all settings back to default.
        Open unprocessed myelin channel image.
           """
        global c, d, m
        basicfunctions.closeallimages()
        getimage()
        green.show()
        self.setOutliers.setEditable(False)
        self.cellbodycb.setSelected(False)
        self.rollingballcb.setEnabled(True)
        self.rollingballcb.setSelected(False)
        self.neurireSubcb.setEnabled(True)
        self.neurireSubcb.setSelected(False)
        self.bCLAHE.setEnabled(True)
        self.bCLAHE.setSelected(False)
        self.setpixels2.setEditable(True)
        self.tMin.setEditable(False)
        self.tMax.setEditable(False)
        self.frangicb.setSelected(False)
        self.autoT.setEnabled(True)
        self.setpixels2.setText("0")
        self.tMin.setText("200")
        self.tMax.setText("255")
        self.setOutliers.setText("0")
        self.greyscale.setText("0")
        config.mCLAHE = False
        config.backgroundsubRolling = False
        config.backgroundsubNeurite = False
        config.setpixels = "0"
        config.cellbodycb = False
        config.Min = "0"
        config.Max = "0"
        config.radius = "0"
        config.frangicb = False
        config.greyscaleMinVal = "0"
        c = 0
        d = 0
        m = False

    def onNextimage(self, e):
            """ Next image
            Dislays the next image in folder. Any settings that have been
            defined will be performed.
            """
            self.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))
            getNext()
            getimage()
            green2 = green.duplicate()
            green.show()
            if (config.cellbodycb is False) and (config.frangicb is False):
                ImageWindow.setNextLocation(int(IJ.getScreenSize().width * 1/3),
                                                int(IJ.getScreenSize().height * 1/14))
                green2.show()
                applybackground()
            if (config.cellbodycb is True) and (config.frangicb is False):
                removecellbodies()
            elif config.frangicb is True:
                if config.cellbodycb is False:
                    frangifilter(self)
                if config.cellbodycb is True:
                        removecellbodies()
                        frangifilter(self)
            self.setCursor(Cursor.getDefaultCursor())


class Dialog5(JFrame):
    def __init__(self):
        super(Dialog5, self).__init__()
        self.initUI()
        
    def initUI(self):
        """ Graphical interface for defining neurite channel analysis
        settings
         Provides choices for normalise local contrast (NLC) and despeckle.
         Also has a sparse neurites option which opens another dialog box.
        
        """
        
        panel = JPanel()
        self.getContentPane().add(panel)
        panel.setBackground(Color.WHITE)
        # show neuite channel and run NLC if sparse neurite (SN) settings
        # have not been defined (Dialog6).
        if config.SN is False:
              getimage()
              red.show()
              IJ.run(red, "Normalize Local Contrast", "block_radius_x=40 block_radius_y=40 standard_deviations="+config.contrast+" center stretch")
              IJ.run(red, "Auto Threshold", "method=default white")
              IJ.run(red, "Invert LUT", "")

        Title = JTextArea("Normalise local contrast:")
        Title.setBounds(30, 0, 320, 20)
        Title.setEditable(False)
        background = Color.GRAY
        Title.setBackground(background)
        panel.add(Title)

        border1 = JLabel()
        border1.setBounds(30, 20, 321, 150)
        border = BorderFactory.createEtchedBorder()
        border1.setBorder(border)
        panel.add(border1)

        sd = JTextArea("Standard deviation")
        sd.setBounds(125, 45, 160, 20)
        sd.setEditable(False)
        panel.add(sd)

        tMin = JTextField("0.5", actionPerformed=self.onEnter)
        tMin.setBounds(165, 70, 40, 20)
        border = BorderFactory.createLineBorder(Color.black)
        tMin.setBorder(border)
        if config.SN is True:
           tMin.setEditable(False)
        else:
           tMin.setEditable(True)
        panel.add(tMin)

        self.despecklecb = JCheckBox("Despeckle?", True, actionPerformed=self.onDespeckle)
        self.despecklecb.setFocusable(False)
        self.despecklecb.setBounds(140, 110, 110, 20)
        self.despecklecb.setSelected(False)        
        if config.SN is True:
            self.despecklecb.setEnabled(False)
            
        panel.add(self.despecklecb)
        startbutton = JButton("Sparse neurites", actionPerformed=self.onSN)
        startbutton.setBackground(Color.BLACK)
        startbutton.setBounds(130, 135, 120, 30)
        panel.add(startbutton)
        
        Nextimagebutton = JButton("Next Image", actionPerformed=self.onNextimage)
        Nextimagebutton.setBackground(Color.BLACK)
        Nextimagebutton.setBounds(240, 65, 100, 30)
        panel.add(Nextimagebutton)
        panel.setLayout(None)
        
        self.setTitle("Settings for dense neurites")
        self.setLocationRelativeTo(None)
        self.setLocation(int(IJ.getScreenSize().width * 0.01),
                             int(IJ.getScreenSize().height * 3/10))
        self.setVisible(True)
        startbutton = JButton("Start analysis", actionPerformed=self.onStartanalysis)
        startbutton.setBackground(Color.BLACK)
        startbutton.setBounds(130, 180, 120, 30)
        panel.add(startbutton)
        
        cancelbutton = JButton("Cancel", actionPerformed=self.onCancel)
        cancelbutton.setBackground(Color.BLACK)
        cancelbutton.setBounds(10, 180, 100, 30)
        panel.add(cancelbutton)

        userimage = JCheckBox("Use selected image", False, actionPerformed=self.onUserimage)
        userimage.setFocusable(False)
        userimage.setBounds(260, 185, 170, 20)
        panel.add(userimage)
        
        self.setSize(410, 250)

    def onEnter(self, e):
        """ Normalise local contrast
        Parameters
        ----------
        contrast: string
            value for normalise local contrast
        """
        sender = e.getSource()
        config.contrast = sender.getText()
        basicfunctions.closeimage()
        getimage()
        red.show()
        IJ.run(red, "Normalize Local Contrast", "block_radius_x=40 block_radius_y=40 standard_deviations="+config.contrast+" center stretch")
        IJ.run(red, "Auto Threshold", "method=default white")
        IJ.run(red, "Invert LUT", "")

    def onDespeckle(self, cb1):
        despecklecbstate = cb1.getSource()
        config.despeckle = despecklecbstate.isSelected()
        if config.despeckle is True:
                IJ.run("Despeckle", "")
        else:
                basicfunctions.closeimage()
                getimage()
                IJ.run(red, "Normalize Local Contrast", "block_radius_x=40 block_radius_y=40 standard_deviations="+config.contrast+" center stretch")
                IJ.run(red, "Auto Threshold", "method=default white")
                IJ.run(red, "Invert LUT", "")
                red.show()

    def onSN(self, setb):
        """ Open dialog for sparse neurite settings.
        """

        config.userimage2 = False
        self.dispose()
        basicfunctions.closeallimages()
        getimage()
        red.show()
        Dialog6()

    def onCancel(self, setb):
         self.dispose()
         basicfunctions.closeimage()

    def onNextimage(self, setb):
         """ Get next image in selected folder
          Open the next image in user selected image folder, display the
          red channel and run NLC.
          Parameters
          ----------
          constrast: string
              "standard deviations" for NLC.
        """
         getNext()
         getimage()
         red.show()
         IJ.run(red, "Normalize Local Contrast", "block_radius_x=40 block_radius_y=40 standard_deviations="+config.contrast+" center stretch")
         IJ.run(red, "Invert LUT", "")
         if config.despeckle is True:
             IJ.run(red, "Despeckle", "")

    def onStartanalysis(self, b):
        self.dispose()
        start_time = time.time()
        analysed()

    def onUserimage(self, e):
        """
        Allow user to open an image and select as current image so that it
        can used to optimise analysis settings. This must be a .tif
        composite of myelin and neurires channels. The image will be split
        and only the myelin channel displayed.
        """
        global userimagename
        sender = e.getSource()
        config.userimage2 = True
        userimagename = IJ.getImage()
        if sender.isSelected() is True:
            getimage()
            red.show()
        else:
            config.userimage2 = False

class Dialog6(JFrame):

    def __init__(self):
            super(Dialog6, self).__init__()
            self.initUI()

    def initUI(self):
            """ Graphical interface for defining sparse neurite analysis

            GUI to define background subtraction, enhancement using CLAHE
            and all ImageJ threshold methods. 
  
            """

            panel = JPanel()
            self.getContentPane().add(panel)
            panel.setBackground(Color.WHITE)
            self.setTitle("Settings sparse neurites")
            panel = JPanel()
            self.getContentPane().add(panel)
            
            panel.setBackground(Color.WHITE)
            panel.setLayout(None)
            
            Title3 = JTextArea("Background")
            Title3.setBounds(30, 0, 320, 20)
            Title3.setEditable(False)
            background = Color.GRAY
            Title3.setBackground(background)
            panel.add(Title3)
            
            backgroundlabel = JLabel()
            backgroundlabel.setBounds(30, 0, 320, 60)
            border = BorderFactory.createEtchedBorder()
            backgroundlabel.setBorder(border)
            panel.add(backgroundlabel)

            cellbodycb = JCheckBox("CLAHE?", False, actionPerformed=self.onCLAHE)
            cellbodycb.setFocusable(False)
            cellbodycb.setBounds(110, 20, 80, 20)
            panel.add(cellbodycb)
            
            bgcb = JCheckBox("Subtract background?", False, actionPerformed=self.onbg)
            bgcb.setFocusable(False)
            bgcb.setBounds(110, 40, 180, 20)
            panel.add(bgcb)
            
            Title = JTextArea("Threshold method:")
            Title.setBounds(30, 60, 320, 20)
            Title.setEditable(False)
            background = Color.GRAY
            Title.setBackground(background)
            panel.add(Title)
            
            test = JLabel()
            test.setBounds(30, 60, 321, 170)
            border = BorderFactory.createEtchedBorder()
            test.setBorder(border)
            panel.add(test)

            autoThresh = ("Default", "Huang", "Intermodes", "IsoData", "Li", "MaxEntropy", 
                          "Mean", "MinError", "Minimum", "Moments", "Otsu", "Percentile", 
                          "RenyiEntropy", "Shanbhag", "Triangle", "Yen")
            self.autoT2 = JComboBox(autoThresh)
            self.autoT2.setBounds(125, 90, 120, 20)
            panel.add(self.autoT2)
            
            panel.repaint()
            Min = JTextArea("Min:")
            Min.setBounds(110, 130, 40, 20)
            Min.setEditable(False)
            panel.add(Min)
            
            self.tMin = JTextArea("0")
            self.tMin.setBounds(110, 150, 40, 20)
            border = BorderFactory.createLineBorder(Color.black)
            self.tMin.setBorder(border)
            self.tMin.setEditable(True)
            panel.add(self.tMin)
            
            Max = JTextArea("Max:")
            Max.setBounds(210, 130, 40, 20)
            Max.setEditable(False)
            panel.add(Max)
            
            self.tMax = JTextArea("255")
            self.tMax.setBounds(210, 150, 40, 20)
            border = BorderFactory.createLineBorder(Color.black)
            self.tMax.setBorder(border)
            self.tMax.setEditable(True)
            panel.add(self.tMax)
            
            setbutton = JButton("Apply", actionPerformed=self.onSet)
            setbutton.setBackground(Color.BLACK)
            setbutton.setBounds(140, 190, 80, 30)
            panel.add(setbutton)

            userimage = JCheckBox("Use selected image", False, actionPerformed=self.onUserimage)
            userimage.setFocusable(False)
            userimage.setBounds(100, 240, 170, 20)
            panel.add(userimage)

            cancelbutton = JButton("Cancel", actionPerformed=self.onCancel)
            cancelbutton.setBackground(Color.BLACK)
            cancelbutton.setBounds(30, 270, 80, 30)
            panel.add(cancelbutton)
            
            cancelbutton = JButton("Next image", actionPerformed=self.onNext)
            cancelbutton.setBackground(Color.BLACK)
            cancelbutton.setBounds(250, 270, 100, 30)
            panel.add(cancelbutton)
            
            cancelbutton = JButton("Set for analysis", actionPerformed=self.onSetanalysis)
            cancelbutton.setBackground(Color.BLACK)
            cancelbutton.setBounds(115, 270, 130, 30)
            panel.add(cancelbutton)
            
            global c
            c = 0
            self.setSize(400, 330)
            self.setLocationRelativeTo(None)
            self.setLocation(int(IJ.getScreenSize().width * 0.01),
                                 int(IJ.getScreenSize().height * 2/10))
            self.setVisible(True)

    def onSetanalysis(self, cb1):
            if (config.Min2 == 0) and (config.Max2 == 0):
               IJ.showMessage("Error: please select threshold settings")            
            elif (config.Min2 == 0) and (config.Max2 == 255):
               IJ.showMessage("Error: please select threshold settings")
            else:
               config.userimage2 = False
               config.SN = True
               self.setVisible(False)
               Dialog5()

    def onCLAHE(self, cb1):
            """ CLAHE

            Run CLAHE if checked. If unchecked close image and run 
            background subtraction if selected.
            
            Parameters
            ----------
            cellbodycb : bool
                  checkbox to be selected before cell bodies are selected.
            Returns (global in config.py)
            -------
            mCLAHE2: bool
                 Perform CLAHE?
                     
            """
            
            CLAHEcbstate = cb1.getSource()
            config.mCLAHE2 = CLAHEcbstate.isSelected()
            if config.mCLAHE2 is True:
                IJ.run("Enhance Local Contrast (CLAHE)", "blocksize=127 histogram=256 maximum=3 mask=*None* fast_(less_accurate)")
            else:
                basicfunctions.closeimage()
                getimage()
                red.show()
                if config.Sbgcbstate is True:
                    IJ.run("Subtract Background...", "rolling=50")

    def onbg(self, cb1):
            """ rolling ball background subtraction. 

           
                     
            """
            
            bgcbstate2 = cb1.getSource()
            config.Sbgcbstate = bgcbstate2.isSelected()
            if config.Sbgcbstate is True:
                if w.getImageCount() == 0:
                    getimage()
                    red.show()
                    IJ.run("Subtract Background...", "rolling=50")
                else:
                    IJ.run("Subtract Background...", "rolling=50")
            else:
                basicfunctions.closeimage()
                getimage()
                red.show()
                if config.mCLAHE2 is True:
                    IJ.run("Enhance Local Contrast (CLAHE)", "blocksize=127 histogram=256 maximum=3 mask=*None* fast_(less_accurate)")

    def onCancel(self, e):
        """ Cancel and close dialog box. 
                   
        """

        config.userimage2 = False
        basicfunctions.closeallimages()
        self.dispose()
        config.SN = False
        Dialog5()

    def onSet(self, e):
            current = IJ.getImage()
            global c
            config.Min2 = int(self.tMin.getText())
            config.Max2 = int(self.tMax.getText())
            config.threshChoice2 = self.autoT2.getSelectedItem()
            if c != 0:
                basicfunctions.closeimage()
                getimage()
                red.show()
                if config.mCLAHE2 is True:
                    IJ.run("Enhance Local Contrast (CLAHE)", "blocksize=127 histogram=256 maximum=3 mask=*None* fast_(less_accurate)")
                if config.Sbgcbstate is True:
                    IJ.run("Subtract Background...", "rolling=50")
                IJ.setAutoThreshold(red, config.threshChoice2)
                IJ.run(red, "Invert LUT", "")
                IJ.setRawThreshold(red, config.Min2, config.Max2, None)
                IJ.run(red, "Convert to Mask", "")
            c = c + 1

    def onNext(self, cb1):
        basicfunctions.closeimage()
        getNext()
        getimage()
        red.show()
        if config.mCLAHE2 is True:
                IJ.run("Enhance Local Contrast (CLAHE)", "blocksize=127 histogram=256 maximum=3 mask=*None* fast_(less_accurate)")
        if config.Sbgcbstate is True:
            IJ.run("Subtract Background...", "rolling=50")
        if (config.Min2 != "0") or (config.Max2 != "0"):
                IJ.setAutoThreshold(red, config.threshChoice2)
                IJ.setRawThreshold(red, config.Min2, config.Max2, None)
                IJ.run("Convert to Mask", "")

    def onUserimage(self, e):
        """
        Allow user to open an image and select as current image so that it
        can used to optimise analysis settings. This must be a .tif
        composite of myelin and neurires channels. The image will be split
        and only the myelin channel displayed.
        """
        global userimagename
        sender = e.getSource()
        config.userimage2 = True
        userimagename = IJ.getImage()
        if sender.isSelected() is True:
            getimage()
            red.show()
        else:
            config.userimage2 = False
Dialog1()
