#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Scoary - Microbial Pan-GWAS GUI
By Ola Brynildsrud
Norwegian Institute of Public Health
olbb@fhi.no
"""

import sys, os
import threading

try:
    import Tkinter
except ImportError:
    #Python 3 issues
    try:
        import tkinter as Tkinter
    except:
        sys.exit("Need to have Tkinter / tkinter installed")
    
try:
    import tkFileDialog
except ImportError:
    # Python 3 issues
    try:
        from tkinter import filedialog
        tkFileDialog = filedialog
    except:
        sys.exit("Could not find tkFileDialog / filedialog")

try:
    import ttk
except ImportError:
    # Python 3 issues
    try:
        from tkinter import ttk as ttk
    except:
        sys.exit("Could not find ttk / tkinter.ttk")
    
try:
    ttk
    Tkinter
except NameError:
    sys.exit("Need the following installed: Tkinter, tkFileDialog, ttk")
    
try:
    import os
except ImportError:
    sys.exit("Need to be able to import os")
    
try:
    import argparse
except ImportError:
    sys.exit("Need to be able to import argparse")
    
try:
    import scoary.methods as sm
    import scoary
except ImportError:
    sys.exit("Could not find the main Scoary executable") 

from pkg_resources import resource_string, resource_filename

class ScoaryGUI(Tkinter.Tk):
    """
    Create the main GUI window
    """
    def __init__(self,parent):
        Tkinter.Tk.__init__(self,parent)
        self.parent = parent

        self.Scoary_parameters = {"GPA": None,"Trait":None,"Tree":None,
                                  "Restrict":None, "Writetree": False,
                                  "Delimiter":",", "Startcol": "15",
                                  "Maxhits":None, "Notime":False,
                                  "Outdir":None, "Permutations":0,
                                  "No_pairwise":False, "Collapse":False,
                                  "Cutoffs": {"I": [1,0.05], 
                                              "B": [0,1.0], 
                                              "BH": [0,1.0], 
                                              "PW": [0,1.0], 
                                              "EPW": [1,0.05], 
                                              "P":[0,1.0]},                                
                                }
        self.initialize_menu()
        
        self.toppart = Tkinter.Frame(self,height="350",width="800")
        self.bottompart = Tkinter.Frame(self,height="50",width="800")
        self.toppart.pack(side='top',expand=False)
        self.bottompart.pack(side='bottom',expand=True,fill='both')
        
        self.nwpart = Tkinter.Frame(self.toppart,
                                    height="350",
                                    width="250")
        self.nepart = Tkinter.LabelFrame(self.toppart,
                                         height="350",
                                         width="550",
                                         text="Control panel")
        self.nwpart.pack(side='left',expand=False)
        self.nepart.pack(side='right',expand=True)
        
        # Add further frames to top or bottom
        
        self.logocanvas = Tkinter.Canvas(self.nwpart,
                                         height="250",
                                         width="250",
                                         relief="ridge",
                                         bd=0,
                                         highlightthickness=0)
        self.logocanvas.pack(side='top',expand=False)
        
        self.citationframe = Tkinter.Frame(self.nwpart,
                                           height="100",
                                           width="250")
        self.citationframe.pack(side='bottom',expand=False,fill='none')
        
        self.initialize_controlboard()
        self.initialize_logo()
        self.initialize_citation()
        self.initialize_statusframe()
        
        ######## MENUS ########
        
    def initialize_menu(self):
        """
        Initialize the menu at the top
        """
        self.menubar = Tkinter.Menu(self,relief="flat")
        filemenu = Tkinter.Menu(self.menubar,tearoff=0)
        filemenu.add_command(label="About",command=self.AboutScoary)
        filemenu.add_separator()
        filemenu.add_command(label="Quit",command=self.quit)
        self.filemenu = filemenu
        self.menubar.add_cascade(label="File",menu=self.filemenu)
        
        optsmenu = Tkinter.Menu(self.menubar,tearoff=0)
        optsmenu.add_command(label="Clear", command=self.ClearAll)
        optsmenu.add_command(label="Test example",
                             command=self.TestExample)
        self.optsmenu = optsmenu
        self.menubar.add_cascade(label="Options",menu=self.optsmenu)
        
        self.config(menu=self.menubar)        
        
    def initialize_citation(self):
        """
        Initialize the citation frame - below the logo
        """
        myfontstyle = ("Arial",8)
        self.citation = Tkinter.Label(self.citationframe,
                                      text=self.citationtext(),
                                      anchor='center',
                                      justify='center',
                                      font=myfontstyle)
        self.citation.pack(expand=True)
        
    def initialize_statusframe(self):
        """
        Initialize the frame and statusbar occupying the bottom
        """
        frame = self.bottompart
        
        frame.pb = ttk.Progressbar(frame,
                                   orient='horizontal',
                                   mode='determinate',
                                   maximum=100)
        frame.pb.pack(fill='both',expand=True,side='top')

        frame.lab = Tkinter.Label(frame,text=u"Awaiting input options")
        frame.lab.pack(in_=frame.pb,expand=True)
        #sys.stdout = StdoutToLabel(frame.lab, progressbar=frame.pb)
        sys.stdout = StdoutToLabel(frame.lab,
                                   progressbar=frame.pb,
                                   width=frame.cget('width'))
    
    def initialize_controlboard(self):
        """
        Initialize the controlboard - where all the settings are set.
        """
        board = self.nepart
        
        self.GPAentryVariable = Tkinter.StringVar()
        board.GPAentry = \
            Tkinter.Entry(board, 
            textvariable = self.GPAentryVariable,
            width=60)
        board.GPAentry.grid(column=0,row=0,sticky='W',columnspan=2)
        self.GPAentryVariable.set("Path to gene presence absence file")
        
        self.TraitsentryVariable = Tkinter.StringVar()
        board.Traitsentry = \
            Tkinter.Entry(board, 
            textvariable=self.TraitsentryVariable,
            width=60)
        board.Traitsentry.grid(column=0,row=1,sticky='W',columnspan=2)
        self.TraitsentryVariable.set("Path to traits/phenotype file")
        
        self.TreeentryVariable = Tkinter.StringVar()
        board.Treeentry = \
            Tkinter.Entry(board, 
            textvariable=self.TreeentryVariable,
            width=60)
        board.Treeentry.grid(column=0,row=2,sticky='W',columnspan=2)
        self.TreeentryVariable.set(
            "(Optional) Path to custom tree file")
        
        self.RestrictVariable = Tkinter.StringVar()
        board.Restrictentry = \
            Tkinter.Entry(board, 
            textvariable=self.RestrictVariable,
            width=60)
        board.Restrictentry.grid(column=0,row=3,sticky='W',columnspan=2)
        self.RestrictVariable.set(
            "(Optional) Path to file naming isolates to include")
        
        self.Outputdir = Tkinter.StringVar()
        board.Outputentry = \
            Tkinter.Entry(board, 
            textvariable=self.Outputdir,
            width=60)
        board.Outputentry.grid(column=0,row=4,sticky='W',columnspan=2)
        self.Outputdir.set("(Optional) Output directory")

        browsebuttonGPA = \
            Tkinter.Button(board, 
            text=u"Browse...", 
            command=self.BrowseButtonClickGPA)
        browsebuttonGPA.grid(column=2,row=0,sticky='e')
        
        browsebuttonTraits = \
            Tkinter.Button(board,
            text=u"Browse...", 
            command=self.BrowseButtonClickTraits)
        browsebuttonTraits.grid(column=2,row=1,sticky='e')
        
        browsebuttonTreeFile = \
            Tkinter.Button(board,
            text=u"Browse...", 
            command=self.BrowseButtonClickTreeFile)
        browsebuttonTreeFile.grid(column=2,row=2,sticky='e')
        
        browsebuttonRestrict = \
            Tkinter.Button(board,
            text=u"Browse...",
            command=self.BrowseButtonClickRestrict)
        browsebuttonRestrict.grid(column=2,row=3,sticky='e')
        
        browsebuttonOutput = \
            Tkinter.Button(board,
            text=u"Browse...",
            command=self.BrowseButtonClickOutput)
        browsebuttonOutput.grid(column=2,row=4,sticky='e')
        
        # Initialize frame for cutoffs
        board.pframe = Tkinter.LabelFrame(board,
                                          text="Cut-offs",
                                          relief='ridge')
        board.pframe.grid(column=0,row=5,sticky='w')
        self.initialize_pvalueframe()
        
        # Initialize frame for misc options
        board.miscframe = Tkinter.LabelFrame(board,
                                             text="Misc options",
                                             relief='ridge')
        board.miscframe.grid(column=1,row=5,sticky='e',columnspan=2)
        self.initialize_miscopts()
        
        ## Create extra space
        
        board.emptyspace = Tkinter.Frame(board)
        board.emptyspace.grid(column=0,row=6,columnspan=3,pady=(20,20))
        
        masterbuttonfont = ("Courier", 16)
        
        RunButton = Tkinter.Button(board.emptyspace,
            text=u"Run analysis",
            font=masterbuttonfont,
            command=self.RunAnalysis,
            padx=15,pady=10)
        RunButton.grid(column=2,row=0)
        
        QuitButton = Tkinter.Button(board.emptyspace,
            text=u"Quit",
            font=masterbuttonfont,
            command=self.quit,padx=15,pady=10)
        QuitButton.grid(column=1,row=0)
        
        HelpButton = Tkinter.Button(board.emptyspace,
                                    text=u"Help",
                                    font=masterbuttonfont,
                                    command=self.HelpButton,
                                    padx=15,pady=10)
        HelpButton.grid(column=0,row=0)
        
    def initialize_miscopts(self):
        """
        Initialize the miscellaneous options
        """
        board = self.nepart
        miscframe = board.miscframe
        
        # Max hits
        self.mhtext = Tkinter.StringVar()
        miscframe.mhlab = Tkinter.Label(miscframe,
                                        textvariable=self.mhtext)
        miscframe.mhlab.grid(column=0,row=0,sticky='w')
        self.mhtext.set("Max hits")
        
        self.maxhitsvar = Tkinter.StringVar()
        miscframe.maxhitsentry = \
            Tkinter.Entry(miscframe,
            textvariable=self.maxhitsvar,
            width=8)
        miscframe.maxhitsentry.grid(column=1,row=0)
        self.maxhitsvar.set("")
        
        # Delimiter
        self.delimtext = Tkinter.StringVar()
        miscframe.delim = \
            Tkinter.Label(miscframe,
            textvariable=self.delimtext)
        miscframe.delim.grid(column=0,row=1,sticky='w')
        self.delimtext.set("Delimiter")
        
        self.delimvar = Tkinter.StringVar()
        miscframe.delimentry = \
            Tkinter.Entry(miscframe,
            textvariable=self.delimvar,
            width=8)
        miscframe.delimentry.grid(column=1,row=1)
        self.delimvar.set(",")
        
        # Starting column
        self.sctext = Tkinter.StringVar()
        miscframe.sclab = \
            Tkinter.Label(miscframe,
            textvariable=self.sctext)
        miscframe.sclab.grid(row=2,column=0,sticky='w')
        self.sctext.set("Startcol GPA file")
        
        self.scvar = Tkinter.StringVar()
        miscframe.sc = Tkinter.Entry(miscframe,textvariable=self.scvar,width=8)
        miscframe.sc.grid(row=2,column=1)
        self.scvar.set("15")
        
        # Permutations
        self.permtext = Tkinter.StringVar()
        miscframe.permlab = \
            Tkinter.Label(miscframe,
            textvariable=self.permtext)
        miscframe.permlab.grid(row=3,column=0,sticky='w')
        self.permtext.set("Permutations")
        
        self.permvar = Tkinter.StringVar()
        miscframe.perm = \
            Tkinter.Entry(miscframe,
            textvariable=self.permvar,
            width=8)
        miscframe.perm.grid(row=3,column=1)
        self.permvar.set("0")
        
        # No timestamp
        self.notimevar = Tkinter.IntVar()
        miscframe.notime = \
            Tkinter.Checkbutton(miscframe,
            text=u"No timestamp",
            onvalue=1,
            offvalue=0,
            variable=self.notimevar)
        miscframe.notime.grid(row=5,column=0,sticky='w')
        
        # Write tree
        self.writetreevar = Tkinter.IntVar()
        miscframe.writetree = \
            Tkinter.Checkbutton(miscframe,
            text=u"Write tree",
            onvalue=1,
            offvalue=0,
            variable=self.writetreevar)
        miscframe.writetree.grid(row=6,column=0,sticky='w')

        # No_pairwise
        self.nopairwisevar = Tkinter.IntVar()
        miscframe.nopairwise = \
            Tkinter.Checkbutton(miscframe,
            text=u"No pairwise",
            onvalue=1,
            offvalue=0,
            variable=self.nopairwisevar)
        miscframe.nopairwise.grid(row=7,column=0,sticky='w')

        # Collapse
        self.collapsevar = Tkinter.IntVar()
        miscframe.collapse = \
            Tkinter.Checkbutton(miscframe,
            text=u"Collapse corr",
            onvalue=1,
            offvalue=0,
            variable=self.collapsevar)
        miscframe.collapse.grid(row=8,column=0,sticky='w')
        
    def initialize_pvalueframe(self):
        """
        Initialize the filtration controlboard
        """
        board = self.nepart
        pframe = board.pframe
        
        # Add p-value checkboxes
        
        self.naivetext = Tkinter.StringVar()
        self.pVar = Tkinter.IntVar()
        self.pVar.set(1)
        self.pBVar = Tkinter.IntVar()
        self.pBHVar = Tkinter.IntVar()
        self.pstext = Tkinter.StringVar()
        self.pPWVar = Tkinter.IntVar()
        self.pEPWVar = Tkinter.IntVar()
        self.pEPWVar.set(1)
        self.pPermVar = Tkinter.IntVar()
        
        pframe.naivelab = \
            Tkinter.Label(pframe,
            textvariable=self.naivetext)
        self.naivetext.set(u"Pop structure-naive filters")
        pframe.pNcheck = \
            Tkinter.Checkbutton(pframe,
            text=u"Naive (Fisher's)",
            onvalue=1,
            offvalue=0,
            variable=self.pVar)
        pframe.pBcheck = \
            Tkinter.Checkbutton(pframe,
            text=u"Bonferroni",
            onvalue=1,
            offvalue=0,
            variable=self.pBVar)
        pframe.pBHcheck = \
            Tkinter.Checkbutton(
            pframe,
            text=u"Benjamini-Hochberg",
            onvalue=1,
            offvalue=0,
            variable=self.pBHVar)
        pframe.pslab = \
            Tkinter.Label(pframe,
            textvariable=self.pstext)
        self.pstext.set(u"Pop structure-aware filters")
        pframe.pPWcheck = \
            Tkinter.Checkbutton(pframe,
            text=u"Pairwise comparison (Best)",
            onvalue=1,
            offvalue=0,
            variable=self.pPWVar)
        pframe.pEPWcheck = \
            Tkinter.Checkbutton(pframe,
            text=u"Pairwise comparison (Entire)",
            onvalue=1,
            offvalue=0,
            variable=self.pEPWVar)
        pframe.pPermcheck = \
            Tkinter.Checkbutton(pframe,
            text=u"Empirical p-value (Permutation)",
            onvalue=1,
            offvalue=0,
            variable=self.pPermVar)
        
        pframe.naivelab.grid(column=0,row=0,sticky='w')
        pframe.pNcheck.grid(column=0,row=1,sticky='w')
        pframe.pBcheck.grid(column=0,row=2,sticky='w')
        pframe.pBHcheck.grid(column=0,row=3,sticky='w')
        pframe.pslab.grid(column=0,row=4,sticky='w')
        pframe.pPWcheck.grid(column=0,row=5,sticky='w')
        pframe.pEPWcheck.grid(column=0,row=6,sticky='w')
        pframe.pPermcheck.grid(column=0,row=7,sticky='w')
        
        # Add p-value entry cells
        
        self.pNaive = Tkinter.StringVar()
        self.pBonf = Tkinter.StringVar()
        self.pBH = Tkinter.StringVar()
        self.pPW = Tkinter.StringVar()
        self.pEPW = Tkinter.StringVar()
        self.pPerm = Tkinter.StringVar()
        
        pframe.pNaiveEntry = Tkinter.Entry(pframe,
                                           textvariable=self.pNaive,
                                           width=8)
        pframe.pBonfEntry = Tkinter.Entry(pframe,
                                          textvariable=self.pBonf,
                                          width=8)
        pframe.pBHEntry = Tkinter.Entry(pframe,
                                        textvariable=self.pBH,
                                        width=8)
        pframe.pPWEntry = Tkinter.Entry(pframe,
                                        textvariable=self.pPW,
                                        width=8)
        pframe.pEPWEntry = Tkinter.Entry(pframe,
                                         textvariable=self.pEPW,
                                         width=8)
        pframe.pPermEntry = Tkinter.Entry(pframe,
                                          textvariable=self.pPerm,
                                          width=8)
        
        pframe.pNaiveEntry.grid(column=1,row=1,sticky='w')
        pframe.pBonfEntry.grid(column=1,row=2,sticky='w')
        pframe.pBHEntry.grid(column=1,row=3,sticky='w')
        pframe.pPWEntry.grid(column=1,row=5,sticky='w')
        pframe.pEPWEntry.grid(column=1,row=6,sticky='w')
        pframe.pPermEntry.grid(column=1,row=7,sticky='w')
        
        self.pNaive.set("0.05")
        self.pBonf.set("1.0")
        self.pBH.set("1.0")
        self.pPW.set("1.0")
        self.pEPW.set("0.05")
        self.pPerm.set("1.0")
        
        ######## EVENTS ########
        
    def AboutScoary(self):
        """
        Placeholder button. Planned short information about the method
        """
        topwin = Tkinter.Toplevel(self)
        button = \
            Tkinter.Button(topwin,
            text=str("https://github.com/AdmiralenOla/Scoary"))
        button.pack()
        
    def BrowseButtonClickGPA(self):
        """
        Browse button for gene presence absence field
        """
        myfile = \
            tkFileDialog.askopenfilename(
            filetypes=[('comma-separated values', '.csv'),
                       ('all files','.*')])
        self.GPAentryVariable.set(myfile)
        
    def BrowseButtonClickTraits(self):
        """
        Browse button for traits field
        """
        myfile = \
            tkFileDialog.askopenfilename(
            filetypes=[('comma-separated values', '.csv'),
                       ('all files','.*')])
        self.TraitsentryVariable.set(myfile)
        
    def BrowseButtonClickTreeFile(self):
        """
        Browse button for tree field
        """
        myfile = \
            tkFileDialog.askopenfilename(
            filetypes=[('newick tree files', '.nwk'),
                       ('all files','.*')])
        self.TreeentryVariable.set(myfile)
        
    def BrowseButtonClickRestrict(self):
        """
        Browse button for isolate restriction field
        """
        myfile = \
            tkFileDialog.askopenfilename(
            filetypes=[('comma-separated values','.csv'),
                       ('all files','.*')])
        self.RestrictVariable.set(myfile)            
        
    def BrowseButtonClickOutput(self):
        """
        Browse button for choosing output dir
        """
        mydir = tkFileDialog.askdirectory(mustexist=True)
        self.Outputdir.set(mydir)
    
    def HelpButton(self):
        """
        Placeholder button. Redirects to website
        """
        print("Visit https://github.com/AdmiralenOla/Scoary for help")
        
    def ClearAll(self):
        """
        Sets all variables to defaults
        """
        self.GPAentryVariable.set("Path to gene presence absence file")
        self.TraitsentryVariable.set("Path to traits/phenotype file")
        self.TreeentryVariable.set("(Optional) Path to custom tree "
                                   "file")
        self.RestrictVariable.set("(Optional) Path to file naming "
                                  "isolates to include")
        self.Outputdir.set("")
        self.maxhitsvar.set("")
        self.delimvar.set(",")
        self.scvar.set("15")
        self.notimevar.set(0)
        self.writetreevar.set(0)
        self.permvar.set("0")
        self.pVar.set(1)
        self.pBVar.set(0)
        self.pBHVar.set(0)
        self.pPWVar.set(0)
        self.pEPWVar.set(1)
        self.pNaive.set("0.05")
        self.pBonf.set("1.0")
        self.pBH.set("1.0")
        self.pPW.set("1.0")
        self.pEPW.set("0.05")
        self.pPerm.set("1.0")
        self.nopairwisevar.set(0)
        
    def TestExample(self):
        """
        Sets all variables corresponding to --test in the methods script
        """
        self.GPAentryVariable.set(
            str(os.path.join(resource_filename(__name__, 'exampledata'),
                             'Gene_presence_absence.csv')))
        self.TraitsentryVariable.set(
            str(os.path.join(resource_filename(__name__, 'exampledata'),
                             'Tetracycline_resistance.csv')))
        self.TreeentryVariable.set("")
        self.RestrictVariable.set("")
        self.Outputdir.set("./")
        self.maxhitsvar.set("")
        self.delimvar.set(",")
        self.scvar.set("15")
        self.notimevar.set(0)
        self.writetreevar.set(0)
        self.permvar.set("0")
        self.pVar.set(1)
        self.pBVar.set(0)
        self.pBHVar.set(0)
        self.pPWVar.set(0)
        self.pEPWVar.set(1)
        self.pNaive.set("0.05")
        self.pBonf.set("1.0")
        self.pBH.set("1.0")
        self.pPW.set("1.0")
        self.pEPW.set("0.05")
        self.pPerm.set("1.0")
        self.nopairwisevar.set(0)
        
        ######## RUNNING THE ANALYSIS ########
        
    def RunAnalysis(self):
        """
        Upon click "Run analysis" - Reads all the set parameters and 
        calls run method
        """
        self.Scoary_parameters["GPA"] = self.GPAentryVariable.get()
        self.Scoary_parameters["Traits"] = \
            self.TraitsentryVariable.get()
        self.Scoary_parameters["Tree"] = self.TreeentryVariable.get()
        self.Scoary_parameters["Outdir"] = self.Outputdir.get()
        self.Scoary_parameters["Restrict"] = self.RestrictVariable.get()
        self.Scoary_parameters["Writetree"] = self.writetreevar.get()
        self.Scoary_parameters["Delimiter"] = self.delimvar.get()
        self.Scoary_parameters["Startcol"] = self.scvar.get()
        self.Scoary_parameters["Maxhits"] = self.maxhitsvar.get()
        self.Scoary_parameters["Notime"] = self.notimevar.get()
        self.Scoary_parameters["Permutations"] = self.permvar.get()
        self.Scoary_parameters["No_pairwise"] = self.nopairwisevar.get()
        self.Scoary_parameters["Collapse"] = self.collapsevar.get()
        self.Scoary_parameters["Cutoffs"]["I"][0] = self.pVar.get()
        self.Scoary_parameters["Cutoffs"]["I"][1] = self.pNaive.get()
        self.Scoary_parameters["Cutoffs"]["B"][0] = self.pBVar.get()
        self.Scoary_parameters["Cutoffs"]["B"][1] = self.pBonf.get()
        self.Scoary_parameters["Cutoffs"]["BH"][0] = self.pBHVar.get()
        self.Scoary_parameters["Cutoffs"]["BH"][1] = self.pBH.get()
        self.Scoary_parameters["Cutoffs"]["PW"][0] = self.pPWVar.get()
        self.Scoary_parameters["Cutoffs"]["PW"][1] = self.pPW.get()
        self.Scoary_parameters["Cutoffs"]["EPW"][0] = self.pEPWVar.get()
        self.Scoary_parameters["Cutoffs"]["EPW"][1] = self.pEPW.get()
        self.Scoary_parameters["Cutoffs"]["P"][0] = self.pPermVar.get()
        self.Scoary_parameters["Cutoffs"]["P"][1] = self.pPerm.get()
        
        self.PrepareScoaryCMDline()
        
    def PrepareScoaryCMDline(self):
        """
        Prepares arguments to correspond with argparse namespace and 
        runs. Listens to sys.stdout and updates statusbar.
        """
        citation=False
        RunScoary = True
        correction = []
        p_value_cutoff = []
        for m in self.Scoary_parameters["Cutoffs"]:
            if self.Scoary_parameters["Cutoffs"][m][0] == 1:
                correction.append(m)
                try:
                    p_value_cutoff.append(
                        float(self.Scoary_parameters["Cutoffs"][m][1]))
                except ValueError:
                    print("Please enter real numbers in the p value "
                          "fields")
                    RunScoary = False
                    break
                    
        delimiter = self.Scoary_parameters["Delimiter"]
        genes = (self.Scoary_parameters["GPA"] if 
                 self.Scoary_parameters["GPA"] not in 
                 ["","Path to gene presence absence file"] else None)
        try:
            max_hits = (int(self.Scoary_parameters["Maxhits"]) if 
                        self.Scoary_parameters["Maxhits"] not in [""]
                        else None)
        except ValueError:
            print("Please enter a real number (or nothing) in the max "
                  "hits field")
            max_hits = None
            RunScoary = False
        try:    
            permutations = (abs(int(
                            self.Scoary_parameters["Permutations"])) if 
                            self.Scoary_parameters["Permutations"] 
                            not in [""]
                            else 0)
        except ValueError:
            print("Please enter a real number (or nothing) in the max "
                  "hits field")
            permutations = 0
            RunScoary = False
        newicktree = (self.Scoary_parameters["Tree"] if 
                      self.Scoary_parameters["Tree"] not in 
                      ["", "(Optional) Path to custom tree file"] 
                      else None)
        no_time = (True if self.Scoary_parameters["Notime"] == 1 
                   else False)
        outdir = (self.Scoary_parameters["Outdir"] if 
                  self.Scoary_parameters["Outdir"] not in 
                  ["","(Optional) Output directory"]
                  else "./")
        restrict_to = (self.Scoary_parameters["Restrict"] if 
                       self.Scoary_parameters["Restrict"] not in 
                       ["","(Optional) Path to file naming isolates to "
                       "include"] 
                       else None)
        start_col = self.Scoary_parameters["Startcol"]
        test = False
        threads = 1
        traits = (self.Scoary_parameters["Traits"] if 
                  self.Scoary_parameters["Traits"] not in 
                  ["","Path to traits/phenotype file"] 
                  else None)
        upgma_tree = (True if self.Scoary_parameters["Writetree"] == 1 
                      else False)
        write_reduced=False
        collapse= (True if self.Scoary_parameters["Collapse"] == 1
                   else False)
        no_pairwise = (True if self.Scoary_parameters["No_pairwise"] == 1
                       else False)
               
        myargs = argparse.Namespace(citation=citation,
                                    correction=correction,
                                    p_value_cutoff=p_value_cutoff,
                                    delimiter=delimiter,
                                    genes=genes,
                                    grabcols=[],
                                    max_hits=max_hits,
                                    newicktree=newicktree,
                                    no_time=no_time,
                                    restrict_to=restrict_to,
                                    outdir=outdir,
                                    permute=permutations,
                                    start_col=start_col,
                                    test=test,
                                    threads=threads,
                                    traits=traits,
                                    upgma_tree=upgma_tree,
                                    write_reduced=write_reduced,
                                    collapse=collapse,
                                    no_pairwise=no_pairwise)
        
        if RunScoary:
            try:
                
                sm.main(args=myargs,
                        cutoffs=dict(
                            list(zip(correction, p_value_cutoff))),
                        statusbar=sys.stdout)

            except SystemExit as SE:
                # Set status bar color to red?
                if str(SE) == "0":
                    print("Analysis complete!")
                else:
                    print("Fatal error: %s" % str(SE))
        
        # Listen to stdout and update statusbar
        
    ######## MISC METHODS ########
        
    def initialize_logo(self):
        """
        Initialize logo
        """
        photo=Tkinter.PhotoImage(data=self.Photobase64())
        self.logocanvas.img = photo
        self.logocanvas.create_image(0,0,anchor='nw',image=photo)
        
    def citationtext(self):
        """
        Returns citation info
        """
        text = "SCOARY version %s \n\n" \
        "Please cite as: \n" \
        "Brynildsrud O, Bohlin J, Scheffer L, \n" \
        "Eldholm V. Rapid scoring of genes in \n" \
        "microbial pan-genome-wide association \n" \
        "studies with Scoary. Genome Biol. \n" \
        "2016;17:238" % scoary.__version__
        return text
        
    def Photobase64(self):
        """
        base64 encoding of the logo
        """
        photo= """
        R0lGODlh+gD6AOf/AAABAAEEAAMGAgcJBQoMCAwPCw8RDhIUERYYFhkbGRwdGx8g
        HiIkISYoJSstKjsrLkArL0gqJ00pI0QsJzEyMEQtLT8wMkYvL0IxLkUwM0svMDQ2
        M0IyNE0wMUQzMEMzNUoyMjY4NUQ1N0Y1MkI3ODk7OEc3OUk5PEU7PD4/PU07OUU9
        QkE/Q04+QD9DRUFDQERETVBBSEtDSE1DQ0dFSEZHRVRDRlZDQUFJUUlLSD1PWVRK
        SjhRWkxOSzRVY1xMUEdSXj5VZFBST0BWYFNVUjRcbl9VWFZYVWJVUT9ebEtdaDZj
        dVtdWkBjd2lcVyNsh2hcXSxrgV9hXjlsg2VnZDV0inFmZzF3kmpsaXZpZyl8lh5/
        nit9nm5wbSeEo3hzcjiCnXN1ch6JroBzcnZ4dYF2di+KqRaQuoB4cnh6dyeOs4d5
        dBiUuASaw3x+e4CBf4mBeyyXwACj0wCh8YyFgIWHhJCEhBugygCm8ACo8QCp8h6l
        zhGo2ACr7h+i7QCr9IuNigCu4wCw3gqt8I6QjRyr2wCy9BCu8QC16ZqSjJKUkQC2
        8Q2z6QC2+Bew8wC59AC67wC6/Be166GWip6XkQC895eZlgC9/iC18qSclSa49QjB
        9qKdnJ2fnBDA+yi78aWgny2+9KKkoTLA9qWnpKynpamrqEfD9Kyuq7OtqjvJ+EvG
        97iysbK0sE7M9lvK9be5tl/N+bu9umDS9768wMS8tWzQ9sDCv8bBwHvT+3rW94XW
        +MbIxM/HwHza+4fY+snLyM7KzIjd95Hb+M3PzJXf/J3e/NfSytjS0dPV0ZHl+aXg
        +drWx57j+tXX1Kjj/N3a0dnb2Kjn+bLo+7nn++Te2t7h3ePi2bvu+8Ps+uPl4ubm
        3Mbv/c3t/u7o5+jq5svy+uzr4tTx++3s4+zu6/Pt7Nj0/+7w7d7z//Hw5t32++T1
        /PL08Pjz8ff27ej5//T38/D4/+z6+/P4++77/PX6/fj69/r8+ff9//n+///9+/z+
        +//9////9v7//P///yH+C1Njb2FyeSBsb2dvACH5BAEKAP8ALAAAAAD6APoAAAj+
        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
        """
        return photo
        
class StdoutToLabel(Tkinter.Label):
    """
    The special widget that listens to sys.stdout and updates its
    label accordingly. This widget also owns the progressbar it is
    placed on and updates it every time sys.stdout is called.
    Use stop() to stop retrieving from sys.stdout.
    Credit: http://stackoverflow.com/questions/2914603/
    """

    def __init__(self, widget, progressbar=None, width='default'):
        Tkinter.Label.__init__(self)
        self.defstdout = sys.stdout
        self.widget = widget
        self.progressbar = progressbar
        
        if width == 'default':
            try:
                self.width = widget.cget('width')
            except:
                self.width = None
        else:
            self.width = width

    def flush(self):
        """
        Frame sys.stdout's flush method.
        """
        self.defstdout.flush()

    def write(self, string, end=None):
        """
        Frame sys.stdout's write method. Puts input
        strings in the widget.
        """
        self.defstdout.write(string)
        if string == "\n":
            pass
        elif (len(string) > 100 and
        self.width is not None and 
        self.width > 0):
            if ("Fatal error" in string):
                self.widget.config(text=
                "Fatal error: See log file for details")
            else:
                self.widget.config(text="See log file for details")
        elif string is not None:

            last_char = string[-1]

            if last_char != '\n' and string.startswith('\r'):
                number = string.lstrip("\r").rstrip("%")
                number = number.split(".")[0]
                number = int(number)
                self.progressbar["value"] = number                
                
            elif last_char != '\n':
                self.widget.config(text=string)

            elif last_char == '\n' and string.startswith('\r'):
                number = string.lstrip("\r").rstrip("%")
                number = number.split(".")[0]
                number = int(number)
                self.progressbar["value"] = number
                
            else:
                self.widget.config(text=string[:-1])
                
        self.update()
        self.progressbar.update()

    def start(self):
        """
        Starts retrieving.
        """
        sys.stdout = self

    def stop(self):
        """
        Stops retrieving.
        """
        sys.stdout = self.defstdout

    @property
    def errors(self):
        return self.defstdout.errors

    @property
    def encoding(self):
        return self.defstdout.encoding
        
def main():
    root = ScoaryGUI(None)
    root.title("Scoary")
    root.geometry("800x400")
    root.resizable(0,0)
    root.mainloop()
    
if __name__ == "__main__":
    pass
