# This file is part PyTSEB, consisting of of high level pyTSEB scripting
# Copyright 2016 Hector Nieto and contributors listed in the README.md file.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys

import ipywidgets as widgets
from IPython.display import display

from pyTSEB.TSEBConfigFileInterface import TSEBConfigFileInterface


class TSEBIPythonInterface(TSEBConfigFileInterface):

    def __init__(self):

        TSEBConfigFileInterface.__init__(self)

        '''Initialize input variables  with default  values'''
        self.input_file = './Input/ExampleTableInput.txt'
        self.output_text_file = './Output/test.txt'
        self.output_image_file = './Output/test.tif'

        # MOdel to run
        self.model = 'TSEB_PT'
        # Site Description
        self.lat = 36.95
        self.lon = 2.33
        self.alt = 200
        self.stdlon = 15
        self.zu = 2.5
        self.zt = 3.5
        # Spectral Properties
        self.rho_vis_C = 0.07
        self.rho_nir_C = 0.32
        self.tau_vis_C = 0.08
        self.tau_nir_C = 0.33
        self.rho_vis_S = 0.15
        self.rho_nir_S = 0.25
        self.emis_C = 0.98
        self.emis_S = 0.95
        # Surface Properties
        self.max_PT = 1.26
        self.x_LAD = 1.0
        self.leaf_width = 0.1
        self.z0soil = 0.01
        self.landcover = 12
        # Resistance options
        self.res = 0
        self.KN_b = 0.012
        self.KN_c = 0.0025
        self.KN_C_dash = 90.0
        # RowCrop calculation
        self.row = False
        self.row_az = 90
        # Soil Heat Flux calculation
        self.G_form = 1
        self.Gconstant = 0
        self.Gratio = 0.35
        self.G_amp = 0.35
        self.G_phase = 3
        self.G_shape = 24
        # Default Vegetation variables
        self.f_c = 1.0
        self.f_g = 1.0
        self.w_c = 1.0
        # Output variables saved in images
        # self.fields=('H1','LE1','R_n1','G1')
        # Ancillary output variables
        #self.anc_fields=('H_C1','LE_C1','LE_partition','T_C1', 'T_S1','R_ns1','R_nl1', 'u_friction', 'L')
        # File Configuration variables

    def point_time_series_widget(self):
        '''Creates a jupyter notebook GUI for running TSEB for a point time series dataset'''

        # Load and save configuration buttons
        self.w_loadconfig = widgets.Button(
            description='Load Configuration File')
        self.w_saveconfig = widgets.Button(
            description='Save Configuration File')
        # Input and output ascii files
        self.w_input = widgets.Button(description='Select Input File')
        self.w_inputtxt = widgets.Text(
            description='Input File :',
            value=self.input_file,
            width=500)
        self.w_output = widgets.Button(description='Select Output File')
        self.w_outputtxt = widgets.Text(
            description='Output File :',
            value=self.output_text_file,
            width=500)
        # Run pyTSEB button
        self.w_runmodel = widgets.Button(
            description='Run pyTSEB',
            background_color='green')
        # Create TSEB options widgets
        self.select_model()
        self.define_site_description_time_series()
        self.spectral_properties_time_series()
        self.surface_properties_time_series()
        self.resistances_time_series()
        self.additional_options_point()
        # Model Selection and create tabs
        tabs = widgets.Tab(
            children=[
                self.w_model,
                self.site_page,
                self.spec_page,
                self.veg_page,
                self.res_page,
                self.opt_page])
        tabs.set_title(0, 'TSEB Model')
        tabs.set_title(1, 'Site Description')
        tabs.set_title(2, 'Spectral Properties')
        tabs.set_title(3, 'Canopy Description')
        tabs.set_title(4, 'Resistance Model')
        tabs.set_title(5, 'Additional Options')
        # Display widgets
        display(self.w_loadconfig)
        display(widgets.HBox([self.w_input, self.w_inputtxt]))
        display(widgets.HBox([self.w_output, self.w_outputtxt]))
        display(tabs)
        display(self.w_saveconfig)
        display(self.w_runmodel)
        # Handle interactions
        self.w_res.on_trait_change(self._on_res_change, 'value')
        self.w_row.on_trait_change(self._on_row_change, 'value')
        self.w_G_form.on_trait_change(self._on_G_change, 'value')
        self.w_input.on_click(
            lambda b: self._on_input_clicked(b, 'Input Text', self.w_inputtxt))
        self.w_output.on_click(self._on_output_clicked)
        self.w_loadconfig.on_click(self._on_loadconfig_clicked)
        self.w_saveconfig.on_click(self._on_saveconfig_clicked)
        self.w_runmodel.on_click(self._on_runmodel_clicked)

        self.is_image = False

    def local_image_widget(self):
        '''Creates a jupyter notebook GUI for running TSEB for an image'''

        # Load and save configuration buttons
        self.w_loadconfig = widgets.Button(
            description='Load Configuration File')
        self.w_saveconfig = widgets.Button(
            description='Save Configuration File')
        # Input and output images
        self.w_T_R1_But = widgets.Button(
            description='Browse Radiometric Surface Temperature Image')
        self.w_T_R1 = widgets.Text(description='(K):', value='0', width=500)
        self.w_T_R0_But = widgets.Button(
            description='Browse Sunrise Radiometric Surface Temperature Image')
        self.w_T_R0 = widgets.Text(description='(K):', value='0', width=500)
        self.w_T_R0_But.visible = False
        self.w_T_R0.visible = False
        self.w_VZA = widgets.Button(description='Browse VZA Image')
        self.w_VZAtxt = widgets.Text(description='VZA:', value='0', width=500)
        self.w_LAI = widgets.Button(description='Browse LAI Image')
        self.w_LAItxt = widgets.Text(description='LAI:', value='1', width=500)
        self.w_Hc = widgets.Button(description='Browse H canopy Image')
        self.w_Hctxt = widgets.Text(
            description='H canopy:', value='1', width=500)
        self.w_w_C = widgets.Button(
            description='Browse Canopy widht/height Image')
        self.w_w_Ctxt = widgets.Text(
            description='w_C canopy:', value=str(
                self.w_c), width=500)
        self.w_f_c = widgets.Button(description='Browse F cover Image')
        self.w_f_ctxt = widgets.Text(
            description='F cover:', value=str(
                self.f_c), width=500)
        self.w_f_g = widgets.Button(description='Browse F green Image')
        self.w_f_gtxt = widgets.Text(
            description='F green:', value=str(
                self.f_g), width=500)
        self.w_mask = widgets.Button(description='Browse Image Mask')
        self.w_masktxt = widgets.Text(
            description='Mask:', value='0', width=500)
        self.w_output = widgets.Button(description='Select Output File')
        self.w_outputtxt = widgets.Text(
            description='Output File :',
            value=self.output_image_file,
            width=500)
        # Run pyTSEB button
        self.w_runmodel = widgets.Button(
            description='Run pyTSEB',
            background_color='green')
        # Create TSEB options widgets
        self.select_model()
        self.define_site_description_image()
        self.meteorology()
        self.spectral_properties_image()
        self.surface_properties_image()
        self.resistances_image()
        self.additional_options_point()
        # Model Selection tabs
        tabs = widgets.Tab(
            children=[
                self.w_model,
                self.site_page,
                self.met_page,
                self.spec_page,
                self.veg_page,
                self.res_page,
                self.opt_page])
        tabs.set_title(0, 'TSEB Model')
        tabs.set_title(1, 'Site Description')
        tabs.set_title(2, 'Meteorology')
        tabs.set_title(3, 'Spectral Properties')
        tabs.set_title(4, 'Canopy Description')
        tabs.set_title(5, 'Resistance Model')
        tabs.set_title(6, 'Additional Options')
        # Display widgets
        display(self.w_loadconfig)
        display(widgets.VBox([widgets.HTML('Select Radiometric Temperature Image(s)'),
                              widgets.HBox([self.w_T_R1_But, self.w_T_R1]),
                              widgets.HBox([self.w_T_R0_But, self.w_T_R0]),
                              widgets.HTML('Select View Zenith Angle data or type a constant value'),
                              widgets.HBox([self.w_VZA, self.w_VZAtxt]),
                              widgets.HTML('Select LAI data or type a constant value'),
                              widgets.HBox([self.w_LAI, self.w_LAItxt]),
                              widgets.HTML('Select Canopy Height data or type a constant value'),
                              widgets.HBox([self.w_Hc, self.w_Hctxt]),
                              widgets.HTML('Select Fractional Cover data or type a constant value'),
                              widgets.HBox([self.w_f_c, self.w_f_ctxt]),
                              widgets.HTML('Select Canopy width/height ratio or type a constant value'),
                              widgets.HBox([self.w_w_C, self.w_w_Ctxt]),
                              widgets.HTML('Select Green Fraction data or type a constant value'),
                              widgets.HBox([self.w_f_g, self.w_f_gtxt]),
                              widgets.HTML('Select Image Mask or set 0 to process the whole image'),
                              widgets.HBox([self.w_mask, self.w_masktxt])], background_color='#EEE'))
        display(widgets.HBox([self.w_output, self.w_outputtxt]))
        display(tabs)
        display(self.w_saveconfig)
        display(self.w_runmodel)
        # Handle interactions
        self.w_T_R1_But.on_click(
            lambda b: self._on_input_clicked(b, 'Surface Radiometric Temperature', self.w_T_R1))
        self.w_T_R0_But.on_click(
            lambda b: self._on_input_clicked(b, 'Morning Surface Radiometric Temperature', self.w_T_R0))
        self.w_VZA.on_click(
            lambda b: self._on_input_clicked(b, 'View Zenith Angle', self.w_VZAtxt))
        self.w_LAI.on_click(
            lambda b: self._on_input_clicked(b, 'Leaf Area Index', self.w_LAItxt))
        self.w_f_c.on_click(
            lambda b: self._on_input_clicked(b, 'Fractional Cover', self.w_f_ctxt))
        self.w_f_g.on_click(
            lambda b: self._on_input_clicked(b, 'Green Fraction', self.w_f_gtxt))
        self.w_Hc.on_click(
            lambda b: self._on_input_clicked(b, 'Canopy Height', self.w_Hctxt))
        self.w_w_C.on_click(
            lambda b: self._on_input_clicked(b, 'Canopy Width/Height Ratio', self.w_w_Ctxt))
        self.w_mask.on_click(
            lambda b: self._on_input_clicked(b, 'Mask', self.w_masktxt))
        self.w_output.on_click(self._on_output_clicked)
        self.w_model.on_trait_change(self._on_model_change, 'value')
        self.w_loadconfig.on_click(self._on_loadconfig_clicked)
        self.w_saveconfig.on_click(self._on_saveconfig_clicked)
        self.w_res.on_trait_change(self._on_res_change, 'value')
        self.w_row.on_trait_change(self._on_row_change, 'value')
        self.w_G_form.on_trait_change(self._on_G_change, 'value')
        self.w_runmodel.on_click(self._on_runmodel_clicked)

        self.is_image = True

    def select_model(self):
        ''' Widget to select the TSEB model'''

        self.w_model = widgets.ToggleButtons(
            description='Select TSEB model to run:',
            options={
                'Priestley Taylor': 'TSEB_PT',
                'Dual-Time Difference': 'DTD',
                'Component Temperatures': 'TSEB_2T'},
            value=self.model)

    def define_site_description_time_series(self):
        '''Widgets for site description parameters'''

        self.w_lat = widgets.BoundedFloatText(
            value=self.lat, min=-90, max=90, description='Lat.', width=100)
        self.w_lon = widgets.BoundedFloatText(
            value=self.lon, min=-180, max=180, description='Lon.', width=100)
        self.w_alt = widgets.FloatText(
            value=self.alt, description='Alt.', width=100)
        self.w_stdlon = widgets.BoundedFloatText(
            value=self.stdlon, min=-180, max=180, description='Std. Lon.', width=100)
        self.w_z_u = widgets.BoundedFloatText(
            value=self.zu,
            min=0.001,
            description='Wind meas. height',
            width=100)
        self.w_z_T = widgets.BoundedFloatText(
            value=self.zt, min=0.001, description='T meas. height', width=100)
        self.site_page = widgets.VBox([widgets.HBox([self.w_lat,
                                                    self.w_lon,
                                                    self.w_alt,
                                                    self.w_stdlon]),
                                      widgets.HBox([self.w_z_u,
                                                    self.w_z_T])],
                                      background_color='#EEE')

    def define_site_description_image(self):
        '''Widgets for site description parameters'''

        self.w_latBut = widgets.Button(description='Browse Latitude Image')
        self.w_lat = widgets.Text(
            description='(Decimal degrees)', value='0', width=500)
        self.w_lonBut = widgets.Button(description='Browse Longitude Image')
        self.w_lon = widgets.Text(
            description='(Decimal degrees):', value='0', width=500)
        self.w_altBut = widgets.Button(description='Browse Altitude Image')
        self.w_alt = widgets.Text(
            description='(m):', value='0', width=500)
        self.w_stdlon_But = widgets.Button(description='Browse Standard Longitude Image')
        self.w_stdlon = widgets.Text(
            description='(Decimal degrees):', value='0', width=500)
        self.w_z_u_But = widgets.Button(description='Wind meas. height')
        self.w_z_u = widgets.Text(
            description='(m):', value=str(self.zu), width=500)
        self.w_z_T_But = widgets.Button(description='Air temp. meas. height')
        self.w_z_T = widgets.Text(
            description='(m):', value=str(self.zt), width=500)

        self.site_page = widgets.VBox([widgets.HTML('Select latitude image or type a constant value'),
                                      widgets.HBox([self.w_latBut, self.w_lat]),
                                      widgets.HTML('Select longitude image or type a constant value'),
                                      widgets.HBox([self.w_lonBut, self.w_lon]),
                                      widgets.HTML('Select altitude image or type a constant value'),
                                      widgets.HBox([self.w_altBut, self.w_alt]),
                                      widgets.HTML('Select standard longitude image or type a constant value'),
                                      widgets.HBox([self.w_stdlon_But, self.w_stdlon]),
                                      widgets.HTML('Select wind measurement height image or type a constant value'),
                                      widgets.HBox([self.w_z_u_But, self.w_z_u]),
                                      widgets.HTML('Select air temperature measurement height image or type a constant value'),
                                      widgets.HBox([self.w_z_T_But, self.w_z_T])])

        self.w_latBut.on_click(
            lambda b: self._on_input_clicked(b, 'Latitude', self.w_lat))
        self.w_lonBut.on_click(
            lambda b: self._on_input_clicked(b, 'Longitude', self.w_lon))
        self.w_altBut.on_click(
            lambda b: self._on_input_clicked(b, 'Altitude', self.w_alt))
        self.w_stdlon_But.on_click(
            lambda b: self._on_input_clicked(b, 'Standard Longitude', self.w_stdlon))
        self.w_z_u_But.on_click(
            lambda b: self._on_input_clicked(b, 'Wind Measurement Height', self.w_z_u))
        self.w_z_T_But.on_click(
            lambda b: self._on_input_clicked(b, 'Air Temperature Measurement Height', self.w_z_T))

    def spectral_properties_image(self):
        '''Widgets for site spectral properties'''

        self.w_rho_vis_C_But = widgets.Button(description='Leaf refl. PAR')
        self.w_rho_vis_C = widgets.Text(
            description=' ', value=str(self.rho_vis_C), width=500)
        self.w_tau_vis_C_But = widgets.Button(description='Leaf trans. PAR')
        self.w_tau_vis_C = widgets.Text(
            description=' ', value=str(self.tau_vis_C), width=500)
        self.w_rho_nir_C_But = widgets.Button(description='Leaf refl. NIR')
        self.w_rho_nir_C = widgets.Text(
            description=' ', value=str(self.rho_nir_C), width=500)
        self.w_tau_nir_C_But = widgets.Button(description='Leaf trans. NIR')
        self.w_tau_nir_C = widgets.Text(
            description=' ', value=str(self.tau_nir_C), width=500)

        self.w_rho_vis_S_But = widgets.Button(description='Soil refl. PAR')
        self.w_rho_vis_S = widgets.Text(
            description=' ', value=str(self.rho_vis_S), width=500)
        self.w_rho_nir_S_But = widgets.Button(description='Soil refl. NIR')
        self.w_rho_nir_S = widgets.Text(
            description=' ', value=str(self.rho_nir_S), width=500)
        self.w_emis_C_But = widgets.Button(description='Leaf emissivity')
        self.w_emis_C = widgets.Text(
            description=' ', value=str(self.emis_C), width=500)
        self.w_emis_S_But = widgets.Button(description='Soil emissivity')
        self.w_emis_S = widgets.Text(
            description=' ', value=str(self.emis_S), width=500)

        self.spec_page = widgets.VBox([widgets.HTML('Select leaf PAR reflectance image or type a constant value'),
                                      widgets.HBox([self.w_rho_vis_C_But, self.w_rho_vis_C]),
                                      widgets.HTML('Select leaf PAR transmitance image or type a constant value'),
                                      widgets.HBox([self.w_tau_vis_C_But, self.w_tau_vis_C]),
                                      widgets.HTML('Select leaf NIR reflectance image or type a constant value'),
                                      widgets.HBox([self.w_rho_nir_C_But, self.w_rho_nir_C]),
                                      widgets.HTML('Select leaf NIR transmitance image or type a constant value'),
                                      widgets.HBox([self.w_tau_nir_C_But, self.w_tau_nir_C]),
                                      widgets.HTML('Select soil PAR reflectance or image type a constant value'),
                                      widgets.HBox([self.w_rho_vis_S_But, self.w_rho_vis_S]),
                                      widgets.HTML('Select soil NIR reflectance or image type a constant value'),
                                      widgets.HBox([self.w_rho_nir_S_But, self.w_rho_nir_S]),
                                      widgets.HTML('Select leaf emissivity image or type a constant value'),
                                      widgets.HBox([self.w_emis_C_But, self.w_emis_C]),
                                      widgets.HTML('Select soil emissivity image or type a constant value'),
                                      widgets.HBox([self.w_emis_S_But, self.w_emis_S])])

        self.w_rho_vis_C_But.on_click(
            lambda b: self._on_input_clicked(b, 'Leaf PAR Reflectance', self.w_rho_vis_C))
        self.w_tau_vis_C_But.on_click(
            lambda b: self._on_input_clicked(b, 'Leaf PAR Transmitance', self.w_tau_vis_C))
        self.w_rho_nir_C_But.on_click(
            lambda b: self._on_input_clicked(b, 'Leaf NIR Reflectance', self.w_rho_nir_C))
        self.w_tau_nir_C_But.on_click(
            lambda b: self._on_input_clicked(b, 'Leaf NIR Transmitance', self.w_tau_nir_C))
        self.w_rho_vis_S_But.on_click(
            lambda b: self._on_input_clicked(b, 'Soil PAR Reflectance', self.w_rho_vis_S))
        self.w_rho_nir_S_But.on_click(
            lambda b: self._on_input_clicked(b, 'Soil NIR Reflectance', self.w_rho_nir_S))
        self.w_emis_C_But.on_click(
            lambda b: self._on_input_clicked(b, 'Leaf Emissivity', self.w_emis_C))
        self.w_emis_S_But.on_click(
            lambda b: self._on_input_clicked(b, 'Soil Emissivity', self.w_emis_S))

    def spectral_properties_time_series(self):
        '''Widgets for site spectral properties'''

        self.w_rho_vis_C = widgets.BoundedFloatText(
            value=self.rho_vis_C, min=0, max=1, description='Leaf refl. PAR', width=80)
        self.w_tau_vis_C = widgets.BoundedFloatText(
            value=self.tau_vis_C, min=0, max=1, description='Leaf trans. PAR', width=80)
        self.w_rho_nir_C = widgets.BoundedFloatText(
            value=self.rho_nir_C, min=0, max=1, description='Leaf refl. NIR', width=80)
        self.w_tau_nir_C = widgets.BoundedFloatText(
            value=self.tau_nir_C, min=0, max=1, description='Leaf trans. NIR', width=80)

        self.w_rho_vis_S = widgets.BoundedFloatText(
            value=self.rho_vis_S, min=0, max=1, description='Soil refl. PAR', width=80)
        self.w_rho_nir_S = widgets.BoundedFloatText(
            value=self.rho_nir_S, min=0, max=1, description='Soil refl. NIR', width=80)
        self.w_emis_C = widgets.BoundedFloatText(
            value=self.emis_C, min=0, max=1, description='Leaf emissivity', width=80)
        self.w_emis_S = widgets.BoundedFloatText(
            value=self.emis_S, min=0, max=1, description='Soil emissivity', width=80)
        self.spec_page = widgets.VBox([widgets.HBox([self.w_rho_vis_C, self.w_tau_vis_C, self.w_rho_nir_C, self.w_tau_nir_C]), widgets.HBox(
            [self.w_rho_vis_S, self.w_rho_nir_S, self.w_emis_C, self.w_emis_S])], background_color='#EEE')

    def meteorology(self):
        '''Widgets for meteorological forcing'''
        self.w_DOY_But = widgets.Button(
            description='Browse Date of Year Image')
        self.w_DOY = widgets.Text(description=' ', value='1', width=500)
        self.w_time_But = widgets.Button(
            description='Browse Dec Time Image')
        self.w_time = widgets.Text(description='(h):', value='12', width=500)
        self.w_T_A1_But = widgets.Button(
            description='Browse Air Temperature Image')
        self.w_T_A1 = widgets.Text(description='(K):', value='0', width=500)
        self.w_T_A0_But = widgets.Button(
            description='Browse Sunrise Air Temperature Image')
        self.w_T_A0 = widgets.Text(description='(K):', value='0', width=500)
        self.w_T_A0_But.visible = False
        self.w_T_A0.visible = False
        self.w_S_dnBut = widgets.Button(
            description='Browse Shortwave Irradiance Image')
        self.w_S_dn = widgets.Text(description='(W/m2):', value='0', width=500)
        self.w_uBut = widgets.Button(description='Browse Wind Speed Image')
        self.w_u = widgets.Text(description='(m/s):', value='0.01', width=500)
        self.w_eaBut = widgets.Button(
            description='Browse Vapour Pressure Image')
        self.w_ea = widgets.Text(description='(mb):', value='0', width=500)

        met_text = widgets.HTML(
            'OPTIONAL: Leave empy to use estimated values for the following cells')
        self.w_L_dnBut = widgets.Button(
            description='Browse Longwave Irradiance Image')
        self.w_L_dn = widgets.Text(description='(W/m2):', value='', width=500)
        self.w_pBut = widgets.Button(description='Browse Pressure Image')
        self.w_p = widgets.Text(description='(mb):', value='', width=500)

        self.met_page = widgets.VBox([widgets.HTML('Select Day of Year image or type a constant value'),
                                     widgets.HBox([self.w_DOY_But, self.w_DOY]),
                                     widgets.HTML('Select time (decimal) image or type a constant value'),
                                     widgets.HBox([self.w_time_But, self.w_time]),
                                     widgets.HTML('Select air temperature image(s) or type a constant value'),
                                     widgets.HBox([self.w_T_A1_But, self.w_T_A1]),
                                     widgets.HBox([self.w_T_A0_But, self.w_T_A0]),
                                     widgets.HTML('Select shortwave irradiance image or type a constant value'),
                                     widgets.HBox([self.w_S_dnBut, self.w_S_dn]),
                                     widgets.HTML('Select wind speed image or type a constant value'),
                                     widgets.HBox([self.w_uBut, self.w_u]),
                                     widgets.HTML('Select vapour pressure image or type a constant value'),
                                     widgets.HBox([self.w_eaBut, self.w_ea]),
                                     widgets.HTML('<br>'),
                                     met_text,
                                     widgets.HTML('Select longwave irradiance image or type a constant value'),
                                     widgets.HBox([self.w_L_dnBut, self.w_L_dn]),
                                     widgets.HTML('Select pressure image or type a constant value'),
                                     widgets.HBox([self.w_pBut, self.w_p])], background_color='#EEE')

        self.w_DOY_But.on_click(
            lambda b: self._on_input_clicked(b, 'Day of Year', self.w_DOY))
        self.w_time_But.on_click(
            lambda b: self._on_input_clicked(b, 'Decimal Time', self.w_time))
        self.w_T_A0_But.on_click(
            lambda b: self._on_input_clicked(b, 'Sunrise Air Temperature', self.w_T_A0))
        self.w_T_A1_But.on_click(
            lambda b: self._on_input_clicked(b, 'Air Temperature', self.w_T_A1))
        self.w_S_dnBut.on_click(
            lambda b: self._on_input_clicked(b, 'Shortwave Irradiance', self.w_S_dn))
        self.w_uBut.on_click(
            lambda b: self._on_input_clicked(b, 'Wind Speed', self.w_u))
        self.w_eaBut.on_click(
            lambda b: self._on_input_clicked(b, 'Vapour Pressure', self.w_ea))
        self.w_L_dnBut.on_click(
            lambda b: self._on_input_clicked(b, 'Longwave Irradiance', self.w_L_dn))
        self.w_pBut.on_click(
            lambda b: self._on_input_clicked(b, 'Pressure', self.w_p))

    def surface_properties_time_series(self):
        '''Widgets for canopy properties'''

        self.w_PT = widgets.BoundedFloatText(
            value=self.max_PT, min=0, description="Max. alphaPT", width=80)
        self.w_LAD = widgets.BoundedFloatText(
            value=self.x_LAD, min=0, description="LIDF param.", width=80)
        self.w_LAD.visible = False
        self.w_leafwidth = widgets.BoundedFloatText(
            value=self.leaf_width, min=0.001, description="Leaf width", width=80)
        self.w_zsoil = widgets.BoundedFloatText(
            value=self.z0soil, min=0, description="soil roughness", width=80)
        # Landcover classes and values come from IGBP Land Cover Type Classification
        self.w_lc = widgets.Dropdown(
            options={
                    'WATER': 0,
                    'CONIFER EVERGREEN': 1,
                    'BROADLEAVED EVERGREEN': 2,
                    'CONIFER DECIDUOUS': 3,
                    'BROADLEAVED DECIDUOUS': 4,
                    'FOREST MIXED': 5,
                    'SHRUB CLOSED': 6,
                    'SHRUB OPEN': 7,
                    'SAVANNA WOODY': 8,
                    'SAVANNA': 9,
                    'GRASS': 10,
                    'WETLAND': 11,
                    'CROP': 12,
                    'URBAN': 13,
                    'CROP MOSAIC': 14,
                    'SNOW': 15,
                    'BARREN': 16
                    },
            value=self.landcover,
            description="Land Cover Type",
            width=200)
        lcText = widgets.HTML(value='''Land cover information is used to estimate roughness. <BR>
                                    For shrubs, conifers and broadleaves we use the model of <BR>
                                    Schaudt & Dickinson (2000) Agricultural and Forest Meteorology. <BR>
                                    For crops and grasses we use a fixed ratio of canopy heigh''', width=100)

        self.calc_row_options()
        self.veg_page = widgets.VBox([widgets.HBox([self.w_PT, self.w_LAD, self.w_leafwidth]),
                                      widgets.HBox([self.w_zsoil, self.w_lc, lcText]),
                                      widgets.HBox([self.w_row, self.w_rowaz])],
                                     background_color='#EEE')

    def surface_properties_image(self):
        '''Widgets for canopy properties'''

        self.w_PT_But = widgets.Button(
            description='Browse Initial alphaPT Image')
        self.w_PT = widgets.Text(description=' ', value=str(self.max_PT), width=500)
        self.w_LAD_But = widgets.Button(
            description='Browse Leaf Angle Distribution Image')
        self.w_LAD = widgets.Text(description='(degrees)', value=str(self.x_LAD), width=500)
        self.w_leafwidth_But = widgets.Button(
            description='Browse Leaf Width Image')
        self.w_leafwidth = widgets.Text(description='(m)', value=str(self.leaf_width), width=500)
        self.w_zsoil_But = widgets.Button(
            description='Browse Soil Roughness Image')
        self.w_zsoil = widgets.Text(description='(m)', value=str(self.z0soil), width=500)
        self.w_lc_But = widgets.Button(
            description='Browse Land Cover Image')
        # Landcover classes and values come from IGBP Land Cover Type Classification
        self.w_lc = widgets.Dropdown(
            options={
                'CROP': 12,
                'GRASS': 10,
                'SHRUB': 6,
                'CONIFER': 1,
                'BROADLEAVED': 4},
            value=self.landcover,
            description=" ",
            width=300)
        lcText = widgets.HTML(value='''Land cover information is used to estimate roughness. <BR>
                                    For shrubs, conifers and broadleaves we use the model of <BR>
                                    Schaudt & Dickinson (2000) Agricultural and Forest Meteorology. <BR>
                                    For crops and grasses we use a fixed ratio of canopy height<BR>''', width=600)

        self.calc_row_options()
        self.veg_page = widgets.VBox([widgets.HTML('Select alphaPT image or type a constant value'),
                                      widgets.HBox([self.w_PT_But, self.w_PT]),
                                      widgets.HTML('Select leaf angle distribution image or type a constant value'),
                                      widgets.HBox([self.w_LAD_But, self.w_LAD]),
                                      widgets.HTML('Select leaf width image or type a constant value'),
                                      widgets.HBox([self.w_leafwidth_But, self.w_leafwidth]),
                                      widgets.HTML('Select soil roughness image or type a constant value'),
                                      widgets.HBox([self.w_zsoil_But, self.w_zsoil]),
                                      widgets.HTML('Select landcover image or type a constant value'),
                                      widgets.HBox([self.w_lc_But, self.w_lc]),
                                      lcText,
                                      widgets.HBox([self.w_row, self.w_rowaz])], background_color='#EEE')

        self.w_PT_But.on_click(
            lambda b: self._on_input_clicked(b, 'Initial alphaPT', self.w_PT))
        self.w_LAD_But.on_click(
            lambda b: self._on_input_clicked(b, 'Leaf Angle Distribution', self.w_LAD))
        self.w_leafwidth_But.on_click(
            lambda b: self._on_input_clicked(b, 'Leaf Width', self.w_leafwidth))
        self.w_zsoil_But.on_click(
            lambda b: self._on_input_clicked(b, 'Soil Roughness', self.w_zsoil))
        self.w_lc_But.on_click(
            lambda b: self._input_dropdown_clicked(b, 'Land Cover', self.w_lc))

    def calc_row_options(self):
        '''Widgets for canopy in rows'''

        self.w_row = widgets.Checkbox(
            description='Canopy in rows?', value=self.row)
        self.w_rowaz = widgets.BoundedFloatText(
            value=self.row_az,
            min=0,
            max=360,
            description='Row orientation',
            width=80)
        self.w_rowaz.visible = False

    def resistances_time_series(self):
        '''Widgets for resistance model selection'''

        self.w_res = widgets.ToggleButtons(
            description='Select TSEB model to run:',
            options={
                'Kustas & Norman 1999': 0,
                'Choudhury & Monteith 1988': 1,
                'McNaughton & Van der Hurk': 2},
            value=self.res,
            width=300)
        self.w_KN_b = widgets.BoundedFloatText(
            value=self.KN_b, min=0, description='KN99 b', width=80)
        self.w_KN_c = widgets.BoundedFloatText(
            value=self.KN_c, min=0, description='KN99 c', width=80)
        self.w_KN_C_dash = widgets.BoundedFloatText(
            value=self.KN_C_dash, min=0, max=9999, description="KN99 C'", width=80)
        self.KN_params_box = widgets.HBox([self.w_KN_b, self.w_KN_c, self.w_KN_C_dash])
        self.res_page = widgets.VBox([self.w_res, self.KN_params_box], background_color='#EEE')

    def resistances_image(self):
        '''Widgets for resistance model selection'''

        self.w_res = widgets.ToggleButtons(
            description='Select TSEB model to run:',
            options={
                'Kustas & Norman 1999': 0,
                'Choudhury & Monteith 1988': 1,
                'McNaughton & Van der Hurk': 2},
            value=self.res,
            width=300)

        self.w_PT_But = widgets.Button(
            description='Browse Initial alphaPT Image')
        self.w_PT = widgets.Text(description=' ', value=str(self.max_PT), width=500)

        self.w_KN_b_But = widgets.Button(description='Browse Resistance Parameter b Image')
        self.w_KN_b = widgets.Text(
            value=str(self.KN_b), description=' ', width=500)
        self.w_KN_c_But = widgets.Button(description=('Browse Resistance Parameter c image'))
        self.w_KN_c = widgets.Text(
            value=str(self.KN_c), description='(m s-1 K-1/3)', width=500)
        self.w_KN_C_dash_But = widgets.Button(description=("Browse Resistance Parameter C' Image"))
        self.w_KN_C_dash = widgets.Text(
            value=str(self.KN_C_dash), description="s1/2 m-1", width=500)
        self.KN_params_box = widgets.VBox([widgets.HTML('Select resistance parameter b image or type a constant value'),
                                           widgets.HBox([self.w_KN_b_But, self.w_KN_b]),
                                           widgets.HTML('Select resistance parameter c image or type a constant value'),
                                           widgets.HBox([self.w_KN_c_But, self.w_KN_c]),
                                           widgets.HTML('Select resistance parameter C\' image or type a constant value'),
                                           widgets.HBox([self.w_KN_C_dash_But, self.w_KN_C_dash])], background_color='#EEE')
        self.res_page = widgets.VBox([self.w_res, self.KN_params_box], background_color='#EEE')

        self.w_KN_b_But.on_click(
            lambda b: self._on_input_clicked(b, 'Resistance Parameter b', self.w_KN_b))
        self.w_KN_c_But.on_click(
            lambda b: self._on_input_clicked(b, 'Resistance Parameter c', self.w_KN_c))
        self.w_KN_C_dash_But.on_click(
            lambda b: self._on_input_clicked(b, 'Resistance Parameter C\'', self.w_KN_C_dash))

    def additional_options_point(self):
        '''Widgets for additional TSEB options'''

        self.calc_G_options()
        self.opt_page = widgets.VBox([
            self.w_G_form,
            self.w_Gratio,
            self.w_Gconstanttext,
            self.w_Gconstant,
            widgets.HBox([self.w_G_amp, self.w_G_phase, self.w_G_shape])], background_color='#EEE')

    def calc_G_options(self):
        '''Widgets for method for computing soil heat flux'''

        self.w_G_form = widgets.ToggleButtons(
            description='Select method for soil heat flux',
            options={
                'Ratio of soil net radiation': 1,
                'Constant or measured value': 0,
                'Time dependent (Santanelo & Friedl)': 2},
            value=self.G_form,
            width=300)
        self.w_Gratio = widgets.BoundedFloatText(
            value=self.Gratio, min=0, max=1, description='G ratio (G/Rn)', width=80)
        self.w_Gconstant = widgets.FloatText(
            value=self.Gconstant, description='Value (W m-2)', width=80)
        self.w_Gconstant.visible = False
        self.w_Gconstanttext = widgets.HTML(
            value="Set G value (W m-2), ignored if G is present in the input file")
        self.w_Gconstanttext.visible = False
        self.w_Gconstant.visible = False
        self.w_G_amp = widgets.BoundedFloatText(
            value=self.G_amp, min=0, max=1, description='Amplitude (G/Rn)', width=80)
        self.w_G_amp.visible = False
        self.w_G_phase = widgets.BoundedFloatText(
            value=self.G_phase, min=-24, max=24, description='Time Phase (h)', width=80)
        self.w_G_phase.visible = False
        self.w_G_shape = widgets.BoundedFloatText(
            value=self.G_shape, min=0, max=24, description='Time shape (h)', width=80)
        self.w_G_shape.visible = False

    def get_data_TSEB_widgets(self, is_image):
        '''Parses the parameters in the GUI to TSEB variables for running TSEB'''

        self.params['model'] = self.w_model.value

        self.params['lat'] = self.w_lat.value
        self.params['lon'] = self.w_lon.value
        self.params['alt'] = self.w_alt.value
        self.params['stdlon'] = self.w_stdlon.value
        self.params['z_u'] = self.w_z_u.value
        self.params['z_T'] = self.w_z_T.value

        self.params['emis_C'] = self.w_emis_C.value
        self.params['emis_S'] = self.w_emis_S.value
        self.params['rho_vis_C'] = self.w_rho_vis_C.value
        self.params['tau_vis_C'] = self.w_tau_vis_C.value
        self.params['rho_nir_C'] = self.w_rho_nir_C.value
        self.params['tau_nir_C'] = self.w_tau_nir_C.value
        self.params['rho_vis_S'] = self.w_rho_vis_S.value
        self.params['rho_nir_S'] = self.w_rho_nir_S.value

        self.params['alpha_PT'] = self.w_PT.value
        self.params['x_LAD'] = self.w_LAD.value
        self.params['leaf_width'] = self.w_leafwidth.value
        self.params['z0_soil'] = self.w_zsoil.value
        self.params['landcover'] = self.w_lc.value

        self.params['resistance_form'] = self.w_res.value
        self.params['KN_b'] = self.w_KN_b.value
        self.params['KN_c'] = self.w_KN_c.value
        self.params['KN_C_dash'] = self.w_KN_C_dash.value

        if self.w_row.value == 0:
            self.params['calc_row'] = [0, 0]
        else:
            self.params['calc_row'] = [1, self.w_rowaz.value]

        if self.w_G_form.value == 0:
            self.params['G_form'] = [[0], self.w_Gconstant.value]
        elif self.w_G_form.value == 1:
            self.params['G_form'] = [[1], self.w_Gratio.value]
        elif self.w_G_form.value == 2:
            self.params['G_form'] = [[2, self.w_G_amp.value,
                                     self.w_G_phase.value, self.w_G_shape.value], 12.0]

        self.params['output_file'] = self.w_outputtxt.value
        self.outputFile = self.params['output_file']

        if is_image:
            # Get all the input parameters
            self.params['T_R1'] = self.w_T_R1.value
            self.params['VZA'] = self.w_VZAtxt.value
            self.params['LAI'] = self.w_LAItxt.value
            self.params['h_C'] = self.w_Hctxt.value
            self.params['f_c'] = self.w_f_ctxt.value
            self.params['f_g'] = self.w_f_gtxt.value
            self.params['w_C'] = self.w_w_Ctxt.value
            self.params['input_mask'] = self.w_masktxt.value

            self.params['DOY'] = self.w_DOY.value
            self.params['time'] = self.w_time.value
            self.params['T_A1'] = self.w_T_A1.value
            self.params['S_dn'] = self.w_S_dn.value
            self.params['u'] = self.w_u.value
            self.params['ea'] = self.w_ea.value
            self.params['L_dn'] = self.w_L_dn.value
            self.params['p'] = self.w_p.value

            if self.params['model'] == 'DTD':
                self.params['T_R0'] = self.w_T_R0.value
                self.params['T_A0'] = self.w_T_A0.value
        else:
            self.params['input_file'] = self.w_inputtxt.value
            self.params['f_c'] = self.f_c
            self.params['f_g'] = self.f_g
            self.params['w_C'] = self.w_c

        self.params['water_stress'] = False

        self.ready = True

    def _on_model_change(self, name, value):
        '''Behaviour when TSEB model is changed'''

        if value == 'DTD':
            self.w_T_R0_But.visible = True
            self.w_T_R0.visible = True
            self.w_T_A0_But.visible = True
            self.w_T_A0.visible = True
        else:
            self.w_T_R0_But.visible = False
            self.w_T_R0.visible = False
            self.w_T_A0_But.visible = False
            self.w_T_A0.visible = False

    def _on_row_change(self, name, value):
        '''Behaviour when selecting a canopy in row'''

        if value == 0:
            self.w_rowaz.visible = False
        else:
            self.w_rowaz.visible = True

    def _on_res_change(self, name, value):
        '''Behaviour when changing the resistance model'''

        if value == 0:
            self.KN_params_box.visible = True
        else:
            self.KN_params_box.visible = False

    def _on_G_change(self, name, value):
        '''Behaviour when changing the soil heat flux model'''

        if value == 0:
            self.w_Gratio.visible = False
            self.w_Gconstant.visible = True
            self.w_Gconstanttext.visible = True
            self.w_G_amp.visible = False
            self.w_G_phase.visible = False
            self.w_G_shape.visible = False
        elif value == 1:
            self.w_Gratio.visible = True
            self.w_Gconstant.visible = False
            self.w_Gconstanttext.visible = False
            self.w_G_amp.visible = False
            self.w_G_phase.visible = False
            self.w_G_shape.visible = False
        elif value == 2:
            self.w_Gratio.visible = False
            self.w_Gconstant.visible = False
            self.w_Gconstanttext.visible = False
            self.w_G_amp.visible = True
            self.w_G_phase.visible = True
            self.w_G_shape.visible = True

    def _on_loadconfig_clicked(self, b):
        '''Reads a configuration file and parses its data into the GUI'''

        input_file = self._get_input_filename(
            title='Select Input Configuration File')
        if not input_file:
            return
        config_data = self.parse_input_config(input_file, is_image=self.is_image)
        # Update the widget fields
        self.w_model.value = config_data['model']
        self.w_lat.value = config_data['lat']
        self.w_lon.value = config_data['lon']
        self.w_alt.value = config_data['alt']
        self.w_stdlon.value = config_data['stdlon']
        self.w_z_u.value = config_data['z_u']
        self.w_z_T.value = config_data['z_T']
        self.w_emis_C.value = config_data['emis_C']
        self.w_emis_S.value = config_data['emis_S']
        self.w_rho_vis_C.value = config_data['rho_vis_C']
        self.w_tau_vis_C.value = config_data['tau_vis_C']
        self.w_rho_nir_C.value = config_data['rho_nir_C']
        self.w_tau_nir_C.value = config_data['tau_nir_C']
        self.w_rho_vis_S.value = config_data['rho_vis_S']
        self.w_rho_nir_S.value = config_data['rho_nir_S']
        self.w_PT.value = config_data['alpha_PT']
        self.w_LAD.value = config_data['x_LAD']
        self.w_leafwidth.value = config_data['leaf_width']
        self.w_zsoil.value = config_data['z0_soil']
        if config_data['landcover'].isdigit():
            config_data['landcover'] = int(config_data['landcover'])
        if config_data['landcover'] not in self.w_lc.options.values():
                options = self.w_lc.options.copy()
                options.update({config_data['landcover']: config_data['landcover']})
                self.w_lc.options = options
        self.w_lc.value = config_data['landcover']
        self.w_G_form.value = int(config_data['G_form'])
        self.w_Gconstant.value = config_data['G_constant']
        self.w_Gratio.value = config_data['G_ratio']
        self.w_G_amp.value = config_data['G_amp']
        self.w_G_phase.value = config_data['G_phase']
        self.w_G_shape.value = config_data['G_shape']
        self.w_outputtxt.value = config_data['output_file']
        self.w_res.value = int(config_data['resistance_form'])
        self.w_KN_b.value = config_data['KN_b']
        self.w_KN_c.value = config_data['KN_c']
        self.w_KN_C_dash.value = config_data['KN_C_dash']

        if self.is_image:
            self.w_T_R1.value = str(config_data['T_R1']).strip('"')
            self.w_T_R0.value = str(config_data['T_R0']).strip('"')
            self.w_VZAtxt.value = str(config_data['VZA']).strip('"')
            self.w_LAItxt.value = str(config_data['LAI']).strip('"')
            self.w_Hctxt.value = str(config_data['h_C']).strip('"')
            self.w_f_ctxt.value = str(config_data['f_c']).strip('"')
            self.w_f_gtxt.value = str(config_data['f_g']).strip('"')
            self.w_w_Ctxt.value = str(config_data['w_C']).strip('"')
            self.w_masktxt.value = str(config_data['input_mask']).strip('"')
            self.w_DOY.value = config_data['DOY']
            self.w_time.value = config_data['time']
            self.w_T_A1.value = config_data['T_A1']
            self.w_S_dn.value = config_data['S_dn']
            self.w_u.value = config_data['u']
            self.w_ea.value = config_data['ea']
            self.w_L_dn.value = str(config_data['L_dn']).strip('"')
            self.w_p.value = str(config_data['p']).strip('"')
            self.w_T_A0.value = config_data['T_A0']
        else:
            self.w_inputtxt.value = str(config_data['input_file']).strip('"')

    def _on_saveconfig_clicked(self, b):
        '''Opens a configuration file and writes the parameters in the GUI into the file'''

        output_file = self._get_output_filename(
            title='Select Output Configuration File')
        if not output_file:
            return
        try:
            fid = open(output_file, 'w')
        except IOError:
            print('Could not write ' + output_file)
            return
        fid.write('# Input files\n')
        if self.is_image:
            fid.write('T_R1=' + str(self.w_T_R1.value) + '\n')
            fid.write('T_R0=' + str(self.w_T_R0.value) + '\n')
            fid.write('VZA=' + str(self.w_VZAtxt.value) + '\n')
            fid.write('LAI=' + str(self.w_LAItxt.value) + '\n')
            fid.write('f_c=' + str(self.w_f_ctxt.value) + '\n')
            fid.write('h_C=' + str(self.w_Hctxt.value) + '\n')
            fid.write('f_g=' + str(self.w_f_gtxt.value) + '\n')
            fid.write('w_C=' + str(self.w_w_Ctxt.value) + '\n')
            fid.write('input_mask=' + str(self.w_masktxt.value) + '\n')

            fid.write('\n# Output file\n')
            fid.write('output_file=' + str(self.w_outputtxt.value) + '\n')

            fid.write('\n# Meteorological data\n')
            fid.write('DOY=' + str(self.w_DOY.value) + '\n')
            fid.write('time=' + str(self.w_time.value) + '\n')
            fid.write('T_A1=' + str(self.w_T_A1.value) + '\n')
            fid.write('S_dn=' + str(self.w_S_dn.value) + '\n')
            fid.write('u=' + str(self.w_u.value) + '\n')
            fid.write('ea=' + str(self.w_ea.value) + '\n')
            fid.write('p=' + str(self.w_p.value) + '\n')
            fid.write('L_dn=' + str(self.w_L_dn.value) + '\n')
            fid.write('T_A0=' + str(self.w_T_A0.value) + '\n')

        else:
            fid.write('input_file=' + str(self.w_inputtxt.value) + '\n')
            fid.write('\n# Output file\n')
            fid.write('output_file=' + str(self.w_outputtxt.value) + '\n')

        # Write the commom fields
        fid.write('\n# Model Selection\n')
        fid.write('model=' + str(self.w_model.value) + '\n')

        fid.write('\n# Site Description\n')
        fid.write('lat=' + str(self.w_lat.value) + '\n')
        fid.write('lon=' + str(self.w_lon.value) + '\n')
        fid.write('alt=' + str(self.w_alt.value) + '\n')
        fid.write('stdlon=' + str(self.w_stdlon.value) + '\n')
        fid.write('z_u=' + str(self.w_z_u.value) + '\n')
        fid.write('z_T=' + str(self.w_z_T.value) + '\n')

        fid.write('\n# Spectral Properties\n')
        fid.write('emis_C=' + str(self.w_emis_C.value) + '\n')
        fid.write('emis_S=' + str(self.w_emis_S.value) + '\n')
        fid.write('rho_vis_C=' + str(self.w_rho_vis_C.value) + '\n')
        fid.write('rho_nir_C=' + str(self.w_rho_nir_C.value) + '\n')
        fid.write('tau_vis_C=' + str(self.w_tau_vis_C.value) + '\n')
        fid.write('tau_nir_C=' + str(self.w_tau_nir_C.value) + '\n')
        fid.write('tau_nir_C=' + str(self.w_tau_nir_C.value) + '\n')
        fid.write('rho_vis_S=' + str(self.w_rho_vis_S.value) + '\n')
        fid.write('rho_nir_S=' + str(self.w_rho_nir_S.value) + '\n')

        fid.write('\n# Surface Properties\n')
        fid.write('alpha_PT=' + str(self.w_PT.value) + '\n')
        fid.write('x_LAD=' + str(self.w_LAD.value) + '\n')
        fid.write('leaf_width=' + str(self.w_leafwidth.value) + '\n')
        fid.write('z0_soil=' + str(self.w_zsoil.value) + '\n')
        fid.write('landcover=' + str(self.w_lc.value) + '\n')

        fid.write('\n# Additional Options\n')
        fid.write('resistance_form=' + str(self.w_res.value) + '\n')
        fid.write('KN_b=' + str(self.w_KN_b.value) + '\n')
        fid.write('KN_c=' + str(self.w_KN_c.value) + '\n')
        fid.write('KN_C_dash=' + str(self.w_KN_C_dash.value) + '\n')
        fid.write('calc_row=' + str(int(self.w_row.value)) + '\n')
        fid.write('row_az=' + str(self.w_rowaz.value) + '\n')
        fid.write('G_form=' + str(self.w_G_form.value) + '\n')
        fid.write('G_constant=' + str(self.w_Gconstant.value) + '\n')
        fid.write('G_ratio=' + str(self.w_Gratio.value) + '\n')
        fid.write('G_amp=' + str(self.w_G_amp.value) + '\n')
        fid.write('G_phase=' + str(self.w_G_phase.value) + '\n')
        fid.write('G_shape=' + str(self.w_G_shape.value) + '\n')
        fid.flush()
        fid.close()
        del fid
        print('Saved Configuration File')

    def _on_input_clicked(self, b, name, value_widget):
        value_widget.value = self._get_input_filename("Select "+name+" Image")

    def _input_dropdown_clicked(self, b, name, value_widget):
        filename = self._get_input_filename("Select "+name+" Image")
        options = value_widget.options.copy()
        options.update({filename: filename})
        value_widget.options = options
        value_widget.value = filename

    def _get_input_filename(self, title='Select Input File'):
        root, askopenfilename, _ = self._setup_tkinter()
        # show an "Open" dialog box and return the path to the selected file
        input_file = askopenfilename(parent=root, title=title)
        root.destroy()  # Destroy the GUI
        return input_file

    def _on_output_clicked(self, b):
        '''Behaviour when clicking the output file button'''
        self.w_outputtxt.value = self._get_output_filename()

    def _get_output_filename(self, title='Select Output File'):
        root, _, asksaveasfilename = self._setup_tkinter()
        # show an "Open" dialog box and return the path to the selected file
        output_file = asksaveasfilename(title=title)
        root.destroy()  # Destroy the GUI
        return output_file

    def _setup_tkinter(self):
        '''Creates a Tkinter input file dialog'''

        # Import Tkinter GUI widgets
        if sys.version_info.major == 2:
            from tkFileDialog import askopenfilename, asksaveasfilename
            import Tkinter as tk
        else:
            from tkinter.filedialog import askopenfilename, asksaveasfilename
            import tkinter as tk

        # Code below is to make sure the file dialog appears above the
        # terminal/browser
        # Based on
        # http://stackoverflow.com/questions/3375227/how-to-give-tkinter-file-dialog-focus

        # Make a top-level instance and hide since it is ugly and big.
        root = tk.Tk()
        root.withdraw()

        # Make it almost invisible - no decorations, 0 size, top left corner.
        root.overrideredirect(True)
        root.geometry('0x0+0+0')

        # Show window again and lift it to top so it can get focus,
        # otherwise dialogs will end up behind the terminal.
        root.deiconify()
        root.lift()
        root.focus_force()

        return root, askopenfilename, asksaveasfilename

    def _on_runmodel_clicked(self, b):
        # Change the colour of the button to know it is running
        self.w_runmodel.background_color = 'yellow'
        # Get the data from the widgets
        self.get_data_TSEB_widgets(is_image=self.is_image)
        # run TSEB
        self.run(is_image=self.is_image)
        # Change the colour of the button to know it has finished
        self.w_runmodel.background_color = 'green'