# -*- coding: utf-8 -*-
"""
Created on Wed Aug 10 14:27:00 2016

@author: Stuart
"""
import Tkinter as tk
import tkFileDialog
import ttk
import tkMessageBox

import os.path
import re

import pandas as pd

import base_dialog
import validation

from grid_box import GridBox
from grid_box import DialogGridBox

from ..configuration.base_configuration import RelationshipFilter
from ..configuration.base_configuration import Filter
from ..configuration.dataset_configuration import Exclusion
from ..configuration.dataset_configuration import CalibrationSector
from ..configuration.dataset_configuration import ShearMeasurement
from ..configuration.dataset_configuration import DatasetConfiguration
from ..configuration.preferences_configuration import Preferences

from ..core.dataset import getSeparatorValue
from ..core.dataset import getDecimalValue

from ..exceptions.handling import ExceptionHandler
from ..core.status import Status

columnSeparator = "|"

def encodeRelationshipFilterValuesAsText(relationshipFilter):
        text = ""
        for clause in relationshipFilter.clauses:
            text += encodeFilterValuesAsText(clause.column,clause.value, clause.filterType, clause.inclusive, "" )
            text += " #" + relationshipFilter.conjunction + "# "
        return text[:-5]

def encodeFilterValuesAsText(column, value, filterType, inclusive, active):
    return "{column}{sep}{value}{sep}{FilterType}{sep}{inclusive}{sep}{active}".format(column = column, sep = columnSeparator,value = value, FilterType = filterType, inclusive =inclusive, active = active)

def extractRelationshipFilterFromText(text):
    try:
        clauses = []
        for i, subFilt in enumerate(text.split(base_dialog.filterSeparator)):
            if i%2 == 0:
                items = subFilt.split(base_dialog.columnSeparator)
                column = items[0].strip()
                value = float(items[1].strip())
                filterType = items[2].strip()
                inclusive = base_dialog.getBoolFromText(items[3].strip())
                clauses.append(Filter(True,column,filterType,inclusive,value))
            else:
                if len(subFilt.strip()) > 1:
                        conjunction = subFilt.strip()
        return RelationshipFilter(True,conjunction,clauses)

    except ExceptionHandler.ExceptionType as ex:
        ExceptionHandler.add(ex, "Cannot parse values from filter text")


class FilterDialog(base_dialog.BaseDialog):

    def __init__(self, master, parent_dialog, item = None):

        self.parent_dialog = parent_dialog
        self.isNew = (item == None)

        if self.isNew:
            self.item = Filter()
        else:
            self.item = item

        base_dialog.BaseDialog.__init__(self, master)

    def ShowColumnPicker(self, parentDialog, pick, selectedColumn):
        return self.parent_dialog.ShowColumnPicker(parentDialog, pick, selectedColumn)

    def body(self, master):

        self.prepareColumns(master)     
                
        self.addTitleRow(master, "Filter Settings:")
        
        self.column = self.addPickerEntry(master, "Column:", validation.ValidateNotBlank(master), self.item.column)
        self.value = self.addEntry(master, "Value:", validation.ValidateFloat(master), self.item.value)
        self.filterType = self.addOption(master, "Filter Type:", ["Below", "Above", "AboveOrBelow"], self.item.filterType)

        if self.item.inclusive:
            self.inclusive = self.addCheckBox(master, "Inclusive:", 1)
        else:
            self.inclusive = self.addCheckBox(master, "Inclusive:", 0)
            
        if self.item.active:
            self.active = self.addCheckBox(master, "Active:", 1)
        else:
            self.active = self.addCheckBox(master, "Active:", 0)
            
        #dummy label to indent controls
        tk.Label(master, text=" " * 5).grid(row = (self.row-1), sticky=tk.W, column=self.titleColumn)                

    def apply(self):

        if int(self.active.get()) == 1:
            self.item.active = True
        else:
            self.item.active = False

        if int(self.inclusive.get()) == 1:
            self.item.inclusive = True
        else:
            self.item.inclusive = False
                
        self.item.column = self.column.get()
        self.item.value = float(self.value.get())
        self.item.filterType = self.filterType.get()

        if self.isNew:
            Status.add("Filter created")
        else:
            Status.add("Filter updated")

class ExclusionDialog(base_dialog.BaseDialog):

    def __init__(self, master, parent_dialog, item = None):

        self.isNew = (item == None)

        if self.isNew:
            self.item = Exclusion()
        else:
            self.item = item
        
        base_dialog.BaseDialog.__init__(self, master)
                    
    def body(self, master):

        self.prepareColumns(master)     

        #dummy label to force width
        tk.Label(master, text=" " * 275).grid(row = self.row, sticky=tk.W, column=self.titleColumn, columnspan = 8)
        self.row += 1
        
                
        self.addTitleRow(master, "Exclusion Settings:")
        
        self.startDate = self.addDatePickerEntry(master, "Start Date:", validation.ValidateNotBlank(master), self.item.startDate)
        self.endDate = self.addDatePickerEntry(master, "End Date:", validation.ValidateNotBlank(master), self.item.endDate)

        if self.item.active:
            self.active = self.addCheckBox(master, "Active:", 1)
        else:
            self.active = self.addCheckBox(master, "Active:", 0)

        #dummy label to indent controls
        tk.Label(master, text=" " * 5).grid(row = (self.row-1), sticky=tk.W, column=self.titleColumn)                

    def apply(self):

        if int(self.active.get()) == 1:
            self.item.active = True
        else:
            self.item.active = False

        self.item.startDate = pd.to_datetime(self.startDate.get().strip(), dayfirst =True)
        self.item.endDate = pd.to_datetime(self.endDate.get().strip(), dayfirst =True)

        if self.isNew:
            Status.add("Exclusion created")
        else:
            Status.add("Exclusion updated")
                        
class CalibrationDirectionDialog(base_dialog.BaseDialog):

    def __init__(self, master, parent_dialog, item):

        self.isNew = (item == None)
        
        if self.isNew:
            self.item = CalibrationSector()
        else:
            self.item = item

        base_dialog.BaseDialog.__init__(self, master)
                    
    def body(self, master):

        self.prepareColumns(master)     
                
        self.addTitleRow(master, "Calibration Direction Settings:")
        
        self.direction = self.addEntry(master, "Direction:", validation.ValidateFloat(master), self.item.direction)
        self.slope = self.addEntry(master, "Slope:", validation.ValidateFloat(master), self.item.slope)
        self.offset = self.addEntry(master, "Offset:", validation.ValidateFloat(master), self.item.offset)

        if self.item.active:
            self.active = self.addCheckBox(master, "Active:", 1)
        else:
            self.active = self.addCheckBox(master, "Active:", 0)

        #dummy label to indent controls
        tk.Label(master, text=" " * 5).grid(row = (self.row-1), sticky=tk.W, column=self.titleColumn)                

    def apply(self):

        if int(self.active.get()) == 1:
            self.item.active = True
        else:
            self.item.active = False
                
        self.item.direction = float(self.direction.get())
        self.item.slope = float(self.slope.get().strip())
        self.item.offset = float(self.offset.get().strip())

        if self.isNew:
            Status.add("Calibration direction created")
        else:
            Status.add("Calibration direction updated")

class ShearDialogBase(base_dialog.BaseDialog):

    def __init__(self, master, parent_dialog, item):

        self.parent_dialog = parent_dialog
        self.isNew = (item == None)
        
        if self.isNew:
            self.item = ShearMeasurement()
        else:
            self.item = item

        base_dialog.BaseDialog.__init__(self, master)

    def ShowColumnPicker(self, parentDialog, pick, selectedColumn):
        return self.parent_dialog.ShowColumnPicker(parentDialog, pick, selectedColumn) 

    def parse_height(self):
        
        wind_speed_text = self.windSpeed.get()

        if len(wind_speed_text) > 0:

            numbers = re.findall(r"[-+]?\d*\.\d+|[-+]?\d+", wind_speed_text)
            print numbers

            if len(numbers) > 0:

                try:
                    self.height.set("{0}".format(float(numbers[0])))
                except:
                    Status.add("Cannot parse height")

class ShearMeasurementDialog(ShearDialogBase):
    
    def __init__(self, master, parent_dialog, item):
        ShearDialogBase.__init__(self, master, parent_dialog, item)               
        
    def body(self, master):

        self.prepareColumns(master)                       
                
        self.addTitleRow(master, "Shear measurement:")
        
        self.height = self.addEntry(master, "Height:", validation.ValidatePositiveFloat(master), self.item.height)                
        self.windSpeed = self.addPickerEntry(master, "Wind Speed:", validation.ValidateNotBlank(master), self.item.wind_speed_column, width = 60)
        
        #dummy label to indent controls
        tk.Label(master, text=" " * 5).grid(row = (self.row-1), sticky=tk.W, column=self.titleColumn)                

    def apply(self):
                    
        self.item.height = float(self.height.get())
        self.item.wind_speed_column = self.windSpeed.get().strip()

        if self.isNew:
            Status.add("Shear measurement created")
        else:
            Status.add("Shear measurement updated")

class REWSProfileLevelDialog(ShearDialogBase):

    def __init__(self, master, parent_dialog, item):
        ShearDialogBase.__init__(self, master, parent_dialog, item)  

    def body(self, master):

        self.prepareColumns(master)
        self.addTitleRow(master, "REWS Level Settings:")

        self.height = self.addEntry(master, "Height:", validation.ValidatePositiveFloat(master), self.item.height)

        parse_button = tk.Button(master, text="Parse", command = self.parse_height, width=3, height=1)
        parse_button.grid(row=(self.row-1), sticky=tk.N, column=self.inputColumn, padx = 160)

        self.windSpeed = self.addPickerEntry(master, "Wind Speed:", validation.ValidateNotBlank(master), self.item.wind_speed_column, width = 60)
        self.windDirection = self.addPickerEntry(master, "Wind Direction:", None, self.item.wind_direction_column, width = 60)
        self.upflow = self.addPickerEntry(master, "Upflow:", None, self.item.upflow_column, width = 60)

        #dummy label to indent controls
        tk.Label(master, text=" " * 5).grid(row = (self.row-1), sticky=tk.W, column=self.titleColumn)

    def apply(self):
                    
        self.item.height = float(self.height.get())
        self.item.wind_speed_column = self.windSpeed.get().strip()
        self.item.wind_direction_column = self.windDirection.get().strip()
        self.item.upflow_column = self.upflow.get().strip()

        if self.isNew:
            Status.add("Rotor level created")
        else:
            Status.add("Rotor level updated")

class ExclusionsGridBox(DialogGridBox):

    def get_headers(self):
        return ["StartDate", "EndDate", "Active"]   

    def get_item_values(self, item):

        values_dict = {}

        if item.startDate is None:
            values_dict["StartDate"] = ""
        else:
            values_dict["StartDate"] = base_dialog.convertDateToText(item.startDate)

        if item.endDate is None:
            values_dict["EndDate"] = ""
        else:
            values_dict["EndDate"] = base_dialog.convertDateToText(item.endDate)
    
        values_dict["Active"] = item.active

        return values_dict

    def new_dialog(self, master, parent_dialog, item):
        return ExclusionDialog(master, self.parent_dialog, item)   

class FiltersGridBox(DialogGridBox):

    def get_headers(self):
        return ["Column","Value","FilterType","Inclusive","Active"]

    def get_item_values(self, item):

        values_dict = {}

        values_dict["Column"] = item.column
        values_dict["Value"] = item.value
        values_dict["FilterType"] = item.filterType
        values_dict["Inclusive"] = item.inclusive
        values_dict["Active"] = item.active

        return values_dict

    def new_dialog(self, master, parent_dialog, item):
        return FilterDialog(master, self.parent_dialog, item)  

class CalibrationSectorsGridBox(DialogGridBox):

    def get_headers(self):
        return ["Direction","Slope","Offset","Active"]

    def get_item_values(self, item):

        values_dict = {}

        values_dict["Direction"] = item.direction
        values_dict["Slope"] = item.slope
        values_dict["Offset"] = item.offset
        values_dict["Active"] = item.active

        return values_dict

    def new_dialog(self, master, parent_dialog, item):
        return CalibrationDirectionDialog(master, self.parent_dialog, item)  

class ShearGridBox(DialogGridBox):

    def get_headers(self):
        return ["Height","WindSpeed"]

    def get_item_values(self, item):

        values_dict = {}

        values_dict["Height"] = item.height
        values_dict["WindSpeed"] = item.wind_speed_column

        return values_dict

    def new_dialog(self, master, parent_dialog, item):
        return ShearMeasurementDialog(master, self.parent_dialog, item) 

class REWSGridBox(DialogGridBox):

    def get_headers(self):
        return ["Height","WindSpeed", "WindDirection"]

    def get_item_values(self, item):

        values_dict = {}

        values_dict["Height"] = item.height
        values_dict["WindSpeed"] = item.wind_speed_column
        values_dict["WindDirection"] = item.wind_direction_column

        return values_dict

    def new_dialog(self, master, parent_dialog, item):
        return REWSProfileLevelDialog(master, self.parent_dialog, item) 

class DatasetConfigurationDialog(base_dialog.BaseConfigurationDialog):

    def getInitialFileName(self):
        return "Dataset"

    def addFilePath(self, master, path):
        pass

    def file_path_update(self, *args):
        self.config.input_time_series.set_base(self.filePath.get())

    def time_series_path_update(self, *args):
        self.config.input_time_series.absolute_path = self.inputTimeSeriesPath.get()

    def add_general(self, master, path):

        self.filePath = self.addFileSaveAsEntry(master, "Configuration XML File Path:", validation.ValidateDatasetFilePath(master), path)
        self.filePath.variable.trace("w", self.file_path_update)

        self.name = self.addEntry(master, "Dataset Name:", validation.ValidateNotBlank(master), self.config.name)
              
        self.inputTimeSeriesPath = self.addFileOpenEntry(master, "Input Time Series Path:", validation.ValidateTimeSeriesFilePath(master), self.config.input_time_series.absolute_path, self.filePath)
        self.inputTimeSeriesPath.variable.trace("w", self.time_series_path_update)
                        
        self.separator = self.addOption(master, "Separator:", ["TAB", "COMMA", "SPACE", "SEMI-COLON"], self.config.separator)
        self.separator.trace("w", self.columnSeparatorChange)
        
        self.decimal = self.addOption(master, "Decimal Mark:", ["FULL STOP", "COMMA"], self.config.decimal)
        self.decimal.trace("w", self.decimalChange)
        
        self.headerRows = self.addEntry(master, "Header Rows:", validation.ValidateNonNegativeInteger(master), self.config.headerRows)

        self.startDate = self.addDatePickerEntry(master, "Start Date:", None, self.config.startDate)
        self.endDate = self.addDatePickerEntry(master, "End Date:", None, self.config.endDate)
        
        self.hubWindSpeedMode = self.addOption(master, "Hub Wind Speed Mode:", ["None", "Calculated", "Specified"], self.config.hubWindSpeedMode)
        self.hubWindSpeedMode.trace("w", self.hubWindSpeedModeChange)

        self.calibrationMethod = self.addOption(master, "Calibration Method:", ["None", "Specified", "LeastSquares"], self.config.calibrationMethod)
        self.calibrationMethod.trace("w", self.calibrationMethodChange)
        
        self.densityMode = self.addOption(master, "Density Mode:", ["None", "Calculated", "Specified"], self.config.densityMode)
        self.densityMode.trace("w", self.densityMethodChange)

    def add_measurements(self, master):

        self.timeStepInSeconds = self.addEntry(master, "Time Step In Seconds:", validation.ValidatePositiveInteger(master), self.config.timeStepInSeconds)
        self.badData = self.addEntry(master, "Bad Data Value:", validation.ValidateFloat(master), self.config.badData)

        self.dateFormat = self.addEntry(master, "Date Format:", validation.ValidateNotBlank(master), self.config.dateFormat, width = 60)
        pickDateFormatButton = tk.Button(master, text=".", command = base_dialog.DateFormatPicker(self, self.dateFormat, ['%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%S', '%d-%m-%y %H:%M', '%y-%m-%d %H:%M', '%d/%m/%Y %H:%M', '%d/%m/%Y %H:%M:%S', '%d/%m/%y %H:%M', '%y/%m/%d %H:%M']), width=5, height=1)
        pickDateFormatButton.grid(row=(self.row-1), sticky=tk.E+tk.N, column=self.buttonColumn)              

        self.timeStamp = self.addPickerEntry(master, "Time Stamp:", validation.ValidateNotBlank(master), self.config.timeStamp, width = 60) 
        self.turbineLocationWindSpeed = self.addPickerEntry(master, "Turbine Location Wind Speed:", None, self.config.turbineLocationWindSpeed, width = 60) #Should this be with reference wind speed?
        self.hubWindSpeed = self.addPickerEntry(master, "Hub Wind Speed:", None, self.config.hubWindSpeed, width = 60)
        self.hubTurbulence = self.addPickerEntry(master, "Hub Turbulence:", None, self.config.hubTurbulence, width = 60)
        self.temperature = self.addPickerEntry(master, "Temperature:", None, self.config.temperature, width = 60)
        self.pressure = self.addPickerEntry(master, "Pressure:", None, self.config.pressure, width = 60)
        self.density = self.addPickerEntry(master, "Density:", None, self.config.density, width = 60)
        self.inflowAngle = self.addPickerEntry(master, "Inflow Angle:", None, self.config.inflowAngle, width = 60)
        self.inflowAngle.setTip('Not required')
    
    def add_power(self, master):

        self.power = self.addPickerEntry(master, "Power:", None, self.config.power, width = 60)
        self.powerMin = self.addPickerEntry(master, "Power Min:", None, self.config.powerMin, width = 60)
        self.powerMax = self.addPickerEntry(master, "Power Max:", None, self.config.powerMax, width = 60)
        self.powerSD = self.addPickerEntry(master, "Power Std Dev:", None, self.config.powerSD, width = 60)
    
    def add_reference(self, master):
        
        self.referenceWindSpeed = self.addPickerEntry(master, "Reference Wind Speed:", None, self.config.referenceWindSpeed, width = 60)
        self.referenceWindSpeedStdDev = self.addPickerEntry(master, "Reference Wind Speed Std Dev:", None, self.config.referenceWindSpeedStdDev, width = 60)
        self.referenceWindDirection = self.addPickerEntry(master, "Reference Wind Direction:", None, self.config.referenceWindDirection, width = 60)
        self.referenceWindDirectionOffset = self.addEntry(master, "Reference Wind Direction Offset:", validation.ValidateFloat(master), self.config.referenceWindDirectionOffset)

    def add_reference_shear(self, master):
        
        self.shearCalibrationMethod = self.addOption(master, "Shear Calibration Method:", ["None", "LeastSquares"], self.config.shearCalibrationMethod)
        self.row += 1   

        label = tk.Label(master, text="Reference Shear Heights (Power Law):")
        label.grid(row=self.row, sticky=tk.W, column=self.titleColumn, columnspan = 2)
        self.row += 1   
       
        self.referenceShearGridBox = ShearGridBox(master, self, self.row, self.inputColumn)
        self.referenceShearGridBox.add_items(self.config.referenceShearMeasurements)

        self.copyToREWSButton = tk.Button(master, text="Copy To REWS", command = self.copyToREWSShearProfileLevels, width=12, height=1)
        self.copyToREWSButton.grid(row=self.row, sticky=tk.E+tk.N, column=self.buttonColumn)     


    def add_turbine_shear(self, master):
        
        label = tk.Label(master, text="Turbine Shear Heights (Power Law):")
        label.grid(row=self.row, sticky=tk.W, column=self.titleColumn, columnspan = 2)
        self.row += 1   
                    
        self.turbineShearGridBox = ShearGridBox(master, self, self.row, self.inputColumn)
        self.turbineShearGridBox.add_items(self.config.turbineShearMeasurements)
        
    def add_rews(self, master):
                    
        self.addTitleRow(master, "REWS Settings:")
        self.rewsDefined = self.addCheckBox(master, "REWS Active", self.config.rewsDefined)
        self.numberOfRotorLevels = self.addEntry(master, "REWS Number of Rotor Levels:", validation.ValidateNonNegativeInteger(master), self.config.numberOfRotorLevels)
        self.rotorMode = self.addOption(master, "REWS Rotor Mode:", ["EvenlySpacedLevels", "ProfileLevels"], self.config.rotorMode)
        self.hubMode = self.addOption(master, "Hub Mode:", ["Interpolated", "PiecewiseExponent"], self.config.hubMode)                

        label = tk.Label(master, text="REWS Profile Levels:")
        label.grid(row=self.row, sticky=tk.W, column=self.titleColumn, columnspan = 2)
        self.row += 1
        
        self.rewsGridBox = REWSGridBox(master, self, self.row, self.inputColumn)
        self.rewsGridBox.add_items(self.config.rewsProfileLevels)

        self.copyToShearButton = tk.Button(master, text="Copy To Shear", command = self.copyToShearREWSProfileLevels, width=12, height=1)
        self.copyToShearButton.grid(row=self.row, sticky=tk.E+tk.N, column=self.buttonColumn)           
        
    def add_specified_calibration(self, master):

        label = tk.Label(master, text="Calibration Sectors:")
        label.grid(row=self.row, sticky=tk.W, column=self.titleColumn, columnspan = 2)
        self.row += 1                

        self.calibrationSectorsGridBox = CalibrationSectorsGridBox(master, self, self.row, self.inputColumn)
        self.calibrationSectorsGridBox.add_items(self.config.calibrationSectors)
         
    def add_calculated_calibration(self, master):

        self.calibrationStartDate = self.addDatePickerEntry(master, "Calibration Start Date:", None, self.config.calibrationStartDate)                
        self.calibrationEndDate = self.addDatePickerEntry(master, "Calibration End Date:", None, self.config.calibrationEndDate)
        self.siteCalibrationNumberOfSectors = self.addEntry(master, "Number of Sectors:", None, self.config.siteCalibrationNumberOfSectors)
        self.siteCalibrationCenterOfFirstSector = self.addEntry(master, "Center of First Sector:", None, self.config.siteCalibrationCenterOfFirstSector)

        label = tk.Label(master, text="Calibration Filters:")
        label.grid(row=self.row, sticky=tk.W, column=self.titleColumn, columnspan = 2)
        self.row += 1     

        self.calibrationFiltersGridBox = FiltersGridBox(master, self, self.row, self.inputColumn)
        self.calibrationFiltersGridBox.add_items(self.config.calibrationFilters)

    def add_exclusions(self, master):

        #Exclusions
        label = tk.Label(master, text="Exclusions:")
        label.grid(row=self.row, sticky=tk.W, column=self.titleColumn, columnspan = 2)
        self.row += 1     
        
        self.exclusionsGridBox = ExclusionsGridBox(master, self, self.row, self.inputColumn)   
        self.exclusionsGridBox.add_items(self.config.exclusions)
    
    def add_filters(self, master):

        #Filters             
        label = tk.Label(master, text="Filters:")
        label.grid(row=self.row, sticky=tk.W, column=self.titleColumn, columnspan = 2)
        self.row += 1     
        
        self.filtersGridBox = FiltersGridBox(master, self, self.row, self.inputColumn)
        self.filtersGridBox.add_items(self.config.filters)

    def add_meta_data(self, master):  
        
        self.data_type = self.addOption(master, "Data Type:", ["Mast", "LiDAR", "SoDAR", "Mast & LiDAR", "Mast & SoDAR", "Spinner"], self.config.data_type)                
        self.outline_site_classification = self.addOption(master, "Outline Site Classification:", ["Flat", "Complex", "Offshore"], self.config.outline_site_classification)                
        self.outline_forestry_classification = self.addOption(master, "Outline Forestry Classification:", ["Forested", "Non-Forested"], self.config.outline_forestry_classification)                
        
        #IEC Site Classification [• As described by Annex B of IEC 61400-12-1 (2006)]
        self.iec_terrain_classification = self.addEntry(master, "IEC Terrain Classification:", None, self.config.iec_terrain_classification)

        self.latitude = self.addEntry(master, "Latitude:", validation.ValidateOptionalFloat(master), self.config.latitude)
        self.longitude = self.addEntry(master, "Longitude:", validation.ValidateOptionalFloat(master), self.config.longitude)
        self.continent = self.addOption(master, "Continent:", ["Europe", "North America", "Asia", "South America", "Africa", "Antarctica"], self.config.continent) 
        self.country = self.addOption(master, "Country:", self.get_countries(), self.config.country) 

        self.elevation_above_sea_level = self.addEntry(master, "Elevation Above Sea Level:", validation.ValidateOptionalFloat(master), self.config.elevation_above_sea_level)
        self.measurement_compliance = self.addOption(master, "Measurement Compliance:", ["IEC 61400-12-1 (2006) Compliant", "None", "Unknown"], self.config.measurement_compliance)                
        self.anemometry_type = self.addOption(master, "Anemometry Type:", ["Sonic", "Cups", "Spinner", "Not Applicable"], self.config.anemometry_type)                
        self.anemometry_heating = self.addOption(master, "Anemometry Heating:", ["Heated", "Unheated", "Unknown", "Not Applicable"], self.config.anemometry_heating)
        self.turbulence_measurement_type = self.addOption(master, "Turbulence Measurement Type", ["LiDAR", "SoDAR", "Cups", "Sonic"], self.config.turbulence_measurement_type)               
        self.power_measurement_type = self.addOption(master, "Power Measurement Type:", ["Transducer", "SCADA", "Unknown"], self.config.power_measurement_type)                
        self.turbine_control_type = self.addOption(master, "Turbine Control Type:", ["Pitch", "Stall", "Active Stall"], self.config.turbine_control_type)    
        self.turbine_technology_vintage = self.addEntry(master, "Turbine Technology Vintage:", validation.ValidateOptionalPositiveInteger(master), self.config.turbine_technology_vintage)                  

        self.time_zone = self.addOption(master, "Time Zone:", ["Local", "UTC"], self.config.time_zone)                

    def get_countries(self):
        return ["Åland Islands","Albania","Algeria","American Samoa","Andorra","Angola","Anguilla","Antarctica","Antigua and Barbuda","Argentina","Armenia","Aruba","Australia","Austria","Azerbaijan","Bahamas","Bahrain","Bangladesh","Barbados","Belarus","Belgium","Belize","Benin","Bermuda","Bhutan","Bolivia","Bosnia and Herzegovina","Botswana","Bouvet Island","Brazil","British Indian Ocean Territory","Brunei Darussalam","Bulgaria","Burkina Faso","Burundi","Cambodia","Cameroon","Canada","Cape Verde","Caribbean Netherlands ","Cayman Islands","Central African Republic","Chad","Chile","China","Christmas Island","Cocos (Keeling) Islands","Colombia","Comoros","Congo","Congo, Democratic Republic of","Cook Islands","Costa Rica","Côte d'Ivoire","Croatia","Cuba","Curaçao","Cyprus","Czech Republic","Denmark","Djibouti","Dominica","Dominican Republic","Ecuador","Egypt","El Salvador","English Name","Equatorial Guinea","Eritrea","Estonia","Ethiopia","Falkland Islands","Faroe Islands","Fiji","Finland","France","French Guiana","French Polynesia","French Southern Territories","Gabon","Gambia","Georgia","Germany","Ghana","Gibraltar","Greece","Greenland","Grenada","Guadeloupe","Guam","Guatemala","Guernsey","Guinea","Guinea-Bissau","Guyana","Haiti","Heard and McDonald Islands","Honduras","Hong Kong","Hungary","Iceland","India","Indonesia","Iran","Iraq","Ireland","Isle of Man","Israel","Italy","Jamaica","Japan","Jersey","Jordan","Kazakhstan","Kenya","Kiribati","Kuwait","Kyrgyzstan","Lao People's Democratic Republic","Latvia","Lebanon","Lesotho","Liberia","Libya","Liechtenstein","Lithuania","Luxembourg","Macau","Macedonia","Madagascar","Malawi","Malaysia","Maldives","Mali","Malta","Marshall Islands","Martinique","Mauritania","Mauritius","Mayotte","Mexico","Micronesia, Federated States of","Moldova","Monaco","Mongolia","Montenegro","Montserrat","Morocco","Mozambique","Myanmar","Namibia","Nauru","Nepal","New Caledonia","New Zealand","Nicaragua","Niger","Nigeria","Niue","Norfolk Island","North Korea","Northern Mariana Islands","Norway","Oman","Pakistan","Palau","Palestine, State of","Panama","Papua New Guinea","Paraguay","Peru","Philippines","Pitcairn","Poland","Portugal","Puerto Rico","Qatar","Réunion","Romania","Russian Federation","Rwanda","Saint Barthélemy","Saint Helena","Saint Kitts and Nevis","Saint Lucia","Saint Vincent and the Grenadines","Saint-Martin (France)","Samoa","San Marino","Sao Tome and Principe","Saudi Arabia","Senegal","Serbia","Seychelles","Sierra Leone","Singapore","Sint Maarten (Dutch part)","Slovakia","Slovenia","Solomon Islands","Somalia","South Africa","South Georgia and the South Sandwich Islands","South Korea","South Sudan","Spain","Sri Lanka","St. Pierre and Miquelon","Sudan","Suriname","Svalbard and Jan Mayen Islands","Swaziland","Sweden","Switzerland","Syria","Taiwan","Tajikistan","Tanzania","Thailand","The Netherlands","Timor-Leste","Togo","Tokelau","Tonga","Trinidad and Tobago","Tunisia","Turkey","Turkmenistan","Turks and Caicos Islands","Tuvalu","Uganda","Ukraine","United Arab Emirates","United Kingdom","United States","United States Minor Outlying Islands","Uruguay","Uzbekistan","Vanuatu","Vatican","Venezuela","Vietnam","Virgin Islands (British)","Virgin Islands (U.S.)","Wallis and Futuna Islands","Western Sahara","Yemen","Zambia","Zimbabwe"]

    def add_turbine(self, master):
        
        self.cutInWindSpeed = self.addEntry(master, "Cut In Wind Speed:", validation.ValidatePositiveFloat(master), self.config.cutInWindSpeed)
        self.cutOutWindSpeed = self.addEntry(master, "Cut Out Wind Speed:", validation.ValidatePositiveFloat(master), self.config.cutOutWindSpeed)
        self.ratedPower = self.addEntry(master, "Rated Power:", validation.ValidatePositiveFloat(master), self.config.ratedPower)
        self.hubHeight = self.addEntry(master, "Hub Height:", validation.ValidatePositiveFloat(master), self.config.hubHeight)
        self.diameter = self.addEntry(master, "Diameter:", validation.ValidatePositiveFloat(master), self.config.diameter)
        self.rotor_tilt = self.addEntry(master, "Tilt:", validation.ValidateOptionalFloat(master), self.config.rotor_tilt)

    def add_advanced(self, master):
        
        self.addTitleRow(master, "Density Pre-Correction:")

        label = tk.Label(master, text="Note: your are unlikely to need to complete the following settings.")
        label.grid(row=self.row, sticky=tk.W, column=self.titleColumn, columnspan = 2)
        self.row += 1 

        label = tk.Label(master, text="If your time series data file has already been corrected/normalised to a reference density please use the settings below.")
        label.grid(row=self.row, sticky=tk.W, column=self.titleColumn, columnspan = 2)
        self.row += 1   

        self.density_pre_correction_active = self.addCheckBox(master, "Density Pre-Correction Active:", self.config.density_pre_correction_active) 

        self.density_pre_correction_wind_speed = self.addPickerEntry(master, "Density Pre-Correction Wind Speed:", None, self.config.density_pre_correction_wind_speed) 

        self.density_pre_correction_reference_density = self.addEntry(master,
                                                                     "Density Pre-Connection Reference Density:",
                                                                     validation.ValidateOptionalFloat(master),
                                                                     self.config.density_pre_correction_reference_density)                

    def addFormElements(self, master, path):

        self.availableColumnsFile = None
        self.columnsFileHeaderRows = None
        self.availableColumns = []

        self.shearWindSpeedHeights = []
        self.shearWindSpeeds = []

        nb = ttk.Notebook(master, height=400)
        nb.pressed_index = None
        
        general_tab = tk.Frame(nb)
        turbines_tab = tk.Frame(nb)
        measurements_tab = tk.Frame(nb)
        power_tab = tk.Frame(nb)
        reference_tab = tk.Frame(nb)
        reference_shear_tab = tk.Frame(nb)
        turbine_shear_tab = tk.Frame(nb)
        rews_tab = tk.Frame(nb)
        calculated_calibration_tab = tk.Frame(nb)
        specified_calibration_tab = tk.Frame(nb)
        exclusions_tab = tk.Frame(nb)
        filters_tab = tk.Frame(nb)
        meta_data_tab = tk.Frame(nb)
        advanced_tab = tk.Frame(nb)

        nb.add(general_tab, text='General', padding=3)
        nb.add(turbines_tab, text='Turbine', padding=3)
        nb.add(measurements_tab, text='Measurements', padding=3)
        nb.add(power_tab, text='Power', padding=3)
        nb.add(reference_tab, text='Reference', padding=3)
        nb.add(reference_shear_tab, text='Reference Shear', padding=3)
        nb.add(turbine_shear_tab, text='Turbine Shear', padding=3)
        nb.add(rews_tab, text='REWS', padding=3)
        nb.add(calculated_calibration_tab, text='Calibration (Calculated)', padding=3)
        nb.add(specified_calibration_tab, text='Calibration (Specified)', padding=3)
        nb.add(exclusions_tab, text='Exclusions', padding=3)
        nb.add(filters_tab, text='Filters', padding=3)
        nb.add(meta_data_tab, text='Meta Data', padding=3)
        nb.add(advanced_tab, text='Advanced', padding=3)

        nb.grid(row=self.row, sticky=tk.E+tk.W+tk.N+tk.S, column=self.titleColumn, columnspan=8)
        master.grid_rowconfigure(self.row, weight=1)
        self.row += 1
        
        self.add_general(general_tab, path)
        self.add_turbine(turbines_tab)
        self.add_measurements(measurements_tab)
        self.add_power(power_tab)  
        self.add_reference(reference_tab)
        self.add_reference_shear(reference_shear_tab) 
        self.add_turbine_shear(turbine_shear_tab) 
        self.add_rews(rews_tab)                          
        self.add_calculated_calibration(calculated_calibration_tab)
        self.add_specified_calibration(specified_calibration_tab)
        self.add_exclusions(exclusions_tab)
        self.add_filters(filters_tab)
        self.add_meta_data(meta_data_tab)
        self.add_advanced(advanced_tab)

        self.calibrationMethodChange()
        self.densityMethodChange()

    def densityMethodChange(self, *args):
            
        if self.densityMode.get() == "Specified":
            densityModeSpecifiedComment = "Not required when density mode is set to specified"
            self.temperature.setTip(densityModeSpecifiedComment)
            self.pressure.setTip(densityModeSpecifiedComment)
            self.density.clearTip()
        elif self.densityMode.get() == "Calculated":
            densityModeCalculatedComment = "Not required when density mode is set to calculate"
            self.temperature.clearTip()
            self.pressure.clearTip()
            self.density.setTip(densityModeCalculatedComment)
        elif self.densityMode.get() == "None":
            densityModeNoneComment = "Not required when density mode is set to none"
            self.temperature.setTip(densityModeNoneComment)
            self.pressure.setTip(densityModeNoneComment)
            self.density.setTip(densityModeNoneComment)
        else:
            raise Exception("Unknown density methods: %s" % self.densityMode.get())

    def columnSeparatorChange(self, *args):
        Status.add('reading separator', verbosity=2)          
        sep = getSeparatorValue(self.separator.get())
        self.read_dataset()
        return sep
        
    def decimalChange(self, *args):
        Status.add('reading decimal', verbosity=2)
        decimal = getDecimalValue(self.decimal.get())
        self.read_dataset()
        return decimal
        
    def hubWindSpeedModeChange(self, *args):
            
        self.calibrationMethodChange()
            
    def calibrationMethodChange(self, *args):

        if self.hubWindSpeedMode.get() == "Calculated":

            hubWindSpeedModeCalculatedComment = "Not required for calculated hub wind speed mode"
            specifiedCalibrationMethodComment = "Not required for Specified Calibration Method"
            leastSquaresCalibrationMethodComment = "Not required for Least Squares Calibration Method"

            self.hubWindSpeed.setTip(hubWindSpeedModeCalculatedComment)
            self.hubTurbulence.setTip(hubWindSpeedModeCalculatedComment)

            self.siteCalibrationNumberOfSectors.clearTip()
            self.siteCalibrationCenterOfFirstSector.clearTip()
            self.referenceWindSpeed.clearTip()
            self.referenceWindSpeedStdDev.clearTip()
            self.referenceWindDirection.clearTip()
            self.referenceWindDirectionOffset.clearTip()
                    
            if self.calibrationMethod.get() in ("LeastSquares", "York"):
                self.turbineLocationWindSpeed.clearTip()
                self.calibrationStartDate.clearTip()
                self.calibrationEndDate.clearTip()
                self.calibrationSectorsGridBox.setTip(leastSquaresCalibrationMethodComment)
                self.calibrationFiltersGridBox.clearTip()
                    
            elif self.calibrationMethod.get() == "Specified":
                self.turbineLocationWindSpeed.setTipNotRequired()
                self.calibrationStartDate.setTipNotRequired()
                self.calibrationEndDate.setTipNotRequired()
                self.calibrationSectorsGridBox.clearTip()
                self.calibrationFiltersGridBox.setTip(specifiedCalibrationMethodComment)
            else:
                if len(self.calibrationMethod.get()) > 0:
                    raise Exception("Unknown calibration method: %s" % self.calibrationMethod.get())
 
        elif self.hubWindSpeedMode.get() == "Specified":

            hubWindSpeedModeSpecifiedComment = "Not required for specified hub wind speed mode"
            
            self.hubWindSpeed.clearTip()
            self.hubTurbulence.clearTip()

            self.turbineLocationWindSpeed.setTip(hubWindSpeedModeSpecifiedComment)
            self.calibrationStartDate.setTip(hubWindSpeedModeSpecifiedComment)
            self.calibrationEndDate.setTip(hubWindSpeedModeSpecifiedComment)
            self.siteCalibrationNumberOfSectors.setTip(hubWindSpeedModeSpecifiedComment)
            self.siteCalibrationCenterOfFirstSector.setTip(hubWindSpeedModeSpecifiedComment)
            self.referenceWindSpeed.setTip(hubWindSpeedModeSpecifiedComment)
            self.referenceWindSpeedStdDev.setTip(hubWindSpeedModeSpecifiedComment)
            self.referenceWindDirection.setTip(hubWindSpeedModeSpecifiedComment)
            self.referenceWindDirectionOffset.setTip(hubWindSpeedModeSpecifiedComment)

        elif self.hubWindSpeedMode.get() == "None":

            hubWindSpeedModeNoneComment = "Not required when hub wind speed mode is set to none"
            
            self.hubWindSpeed.setTip(hubWindSpeedModeNoneComment)
            self.hubTurbulence.setTip(hubWindSpeedModeNoneComment)
            self.turbineLocationWindSpeed.setTip(hubWindSpeedModeNoneComment)
            self.calibrationStartDate.setTip(hubWindSpeedModeNoneComment)
            self.calibrationEndDate.setTip(hubWindSpeedModeNoneComment)
            self.siteCalibrationNumberOfSectors.setTip(hubWindSpeedModeNoneComment)
            self.siteCalibrationCenterOfFirstSector.setTip(hubWindSpeedModeNoneComment)
            self.referenceWindSpeed.setTip(hubWindSpeedModeNoneComment)
            self.referenceWindSpeedStdDev.setTip(hubWindSpeedModeNoneComment)
            self.referenceWindDirection.setTip(hubWindSpeedModeNoneComment)
            self.referenceWindDirectionOffset.setTip(hubWindSpeedModeNoneComment)

        else:
            raise Exception("Unknown hub wind speed mode: %s" % self.hubWindSpeedMode.get())
                
    def copyToREWSShearProfileLevels(self):            
        
        self.rewsGridBox.remove_all()

        for item in self.referenceShearGridBox.get_items():
            self.rewsGridBox.add_item(ShearMeasurement(item.height, item.wind_speed_column))
        
    def copyToShearREWSProfileLevels(self):            
        
        self.referenceShearGridBox.remove_all()

        for item in self.rewsGridBox.get_items():
            self.referenceShearGridBox.add_item(ShearMeasurement(item.height, item.wind_speed_column))
            
    def getHeaderRows(self):

        headerRowsText = self.headerRows.get()
        
        if len(headerRowsText) > 0:
            return int(headerRowsText)
        else:
            return 0

    def ShowColumnPicker(self, parentDialog, pick, selectedColumn):
            
        if self.config.input_time_series.absolute_path == None:

            tkMessageBox.showwarning(
                    "InputTimeSeriesPath Not Set",
                    "You must set the InputTimeSeriesPath before using the ColumnPicker"
                    )

            return

        inputTimeSeriesPath = self.config.input_time_series.absolute_path
        headerRows = self.getHeaderRows()
                        
        if self.columnsFileHeaderRows != headerRows or self.availableColumnsFile != inputTimeSeriesPath:

                                        
            try:
                self.read_dataset()                              
            except ExceptionHandler.ExceptionType as e:
                tkMessageBox.showwarning(
                "Column header error",
                "It was not possible to read column headers using the provided inputs.\rPlease check and amend 'Input Time Series Path' and/or 'Header Rows'.\r"
                )

                ExceptionHandler.add(e, "ERROR reading columns from {0}".format(inputTimeSeriesPath))

            self.columnsFileHeaderRows = headerRows
            self.availableColumnsFile = inputTimeSeriesPath

        try:                                
            base_dialog.ColumnPickerDialog(parentDialog, pick, self.availableColumns, selectedColumn)
        except ExceptionHandler.ExceptionType as e:
            ExceptionHandler.add(e, "Error picking column")
    
    def read_dataset(self):
         Status.add('reading dataSet', verbosity=2)
         inputTimeSeriesPath = self.config.input_time_series.absolute_path
         headerRows = self.getHeaderRows()    
         dataFrame = pd.read_csv(inputTimeSeriesPath, sep = getSeparatorValue(self.separator.get()), skiprows = headerRows, decimal = getDecimalValue(self.decimal.get()))               
         self.availableColumns = []
         for col in dataFrame:
            self.availableColumns.append(col)
                    
    def setConfigValues(self):

        self.config.name = self.name.get()                
        self.config.startDate = base_dialog.getDateFromEntry(self.startDate)
        self.config.endDate = base_dialog.getDateFromEntry(self.endDate)
        self.config.hubWindSpeedMode = self.hubWindSpeedMode.get()
        self.config.calibrationMethod = self.calibrationMethod.get()
        self.config.densityMode = self.densityMode.get()

        self.config.input_time_series.absolute_path = self.inputTimeSeriesPath.get()
        self.config.timeStepInSeconds = int(self.timeStepInSeconds.get())
        self.config.badData = float(self.badData.get())
        self.config.dateFormat = self.dateFormat.get()
        self.config.separator = self.separator.get()
        self.config.decimal = self.decimal.get()
        self.config.headerRows = self.getHeaderRows()
        self.config.timeStamp = self.timeStamp.get()

        self.config.power = self.power.get()
        self.config.powerMin = self.powerMin.get()
        self.config.powerMax = self.powerMax.get()
        self.config.powerSD = self.powerSD.get()
        self.config.referenceWindSpeed = self.referenceWindSpeed.get()
        self.config.referenceWindSpeedStdDev = self.referenceWindSpeedStdDev.get()
        self.config.referenceWindDirection = self.referenceWindDirection.get()
        self.config.referenceWindDirectionOffset = base_dialog.floatSafe(self.referenceWindDirectionOffset.get())
        self.config.turbineLocationWindSpeed = self.turbineLocationWindSpeed.get()
        self.config.inflowAngle = self.inflowAngle.get()
        
        self.config.temperature = self.temperature.get()
        self.config.pressure = self.pressure.get()
        self.config.density = self.density.get()
        
        self.config.hubWindSpeed = self.hubWindSpeed.get()
        self.config.hubTurbulence = self.hubTurbulence.get()

        #REWS
        self.config.rewsDefined = bool(self.rewsDefined.get())
        self.config.numberOfRotorLevels = base_dialog.intSafe(self.numberOfRotorLevels.get())
        self.config.rotorMode = self.rotorMode.get()
        self.config.hubMode = self.hubMode.get()

        self.config.rewsProfileLevels = self.rewsGridBox.get_items()

        #shear masurements
        self.config.referenceShearMeasurements = self.referenceShearGridBox.get_items()
        self.config.turbineShearMeasurements = self.turbineShearGridBox.get_items()
        self.config.shearCalibrationMethod = self.shearCalibrationMethod.get()

        #calibrations
        self.config.calibrationStartDate = base_dialog.getDateFromEntry(self.calibrationStartDate)
        self.config.calibrationEndDate = base_dialog.getDateFromEntry(self.calibrationEndDate)
        self.config.siteCalibrationNumberOfSectors = base_dialog.intSafe(self.siteCalibrationNumberOfSectors.get())
        self.config.siteCalibrationCenterOfFirstSector = base_dialog.intSafe(self.siteCalibrationCenterOfFirstSector.get()) 
        
        #calbirations
        self.config.calibrationSectors = self.calibrationSectorsGridBox.get_items()
        
        #calibration filters                
        self.config.calibrationFilters = self.calibrationFiltersGridBox.get_items()

        #exclusions
        self.config.exclusions = self.exclusionsGridBox.get_items()

        #filters
        self.config.filters = self.filtersGridBox.get_items()

        #turbines                
        self.config.cutInWindSpeed = float(self.cutInWindSpeed.get())
        self.config.cutOutWindSpeed = float(self.cutOutWindSpeed.get())
        self.config.ratedPower = float(self.ratedPower.get())
        self.config.hubHeight = float(self.hubHeight.get())
        self.config.diameter = float(self.diameter.get())
        if len(self.rotor_tilt.get()) > 0:
            self.config.rotor_tilt = float(self.rotor_tilt.get())
        else:
            self.config.rotor_tilt = None

        #meta data

        self.config.data_type = self.data_type.get()
        self.config.outline_site_classification = self.outline_site_classification.get()
        self.config.outline_forestry_classification = self.outline_forestry_classification.get() 
        
        self.config.iec_terrain_classification = self.iec_terrain_classification.get()

        if len(self.latitude.get()) > 0:
            self.config.latitude = float(self.latitude.get())
        else:
            self.config.latitude = None

        if len(self.longitude.get()) > 0:
            self.config.longitude = float(self.longitude.get())
        else:
            self.config.longitude = None

        self.config.continent = self.continent.get()
        self.config.country = self.country.get()

        if len(self.elevation_above_sea_level.get()) > 0:
            self.config.elevation_above_sea_level = float(self.elevation_above_sea_level.get())
        else:
            self.config.elevation_above_sea_level = None

        self.config.measurement_compliance = self.measurement_compliance.get()
        self.config.anemometry_type = self.anemometry_type.get()
        self.config.anemometry_heating = self.anemometry_heating.get()
        self.config.turbulence_measurement_type = self.turbulence_measurement_type.get()    
        self.config.power_measurement_type = self.power_measurement_type.get()      
        self.config.turbine_control_type = self.turbine_control_type.get()

        if len(self.turbine_technology_vintage.get()) > 0:
            self.config.turbine_technology_vintage = int(self.turbine_technology_vintage.get())
        else:
            self.config.turbine_technology_vintage = None

        self.config.time_zone = self.time_zone.get()           

        #advanced
        
        self.config.density_pre_correction_active = bool(self.density_pre_correction_active.get())

        self.config.density_pre_correction_wind_speed = self.density_pre_correction_wind_speed.get()

        if len(self.density_pre_correction_reference_density.get()) > 0:
            self.config.density_pre_correction_reference_density = float(self.density_pre_correction_reference_density.get())
        else:
            self.config.density_pre_correction_reference_density = None

class DatasetGridBox(GridBox):

    def __init__(self, master, parent_dialog, row, column, datasets_file_manager):

        self.parent_dialog = parent_dialog

        headers = ["Dataset", "Exists"]

        GridBox.__init__(self, master, headers, row, column)

        self.pop_menu.add_command(label="Add Existing", command=self.add)
        self.pop_menu_add.add_command(label="Add Existing", command=self.add)

        self.datasets_file_manager = datasets_file_manager
        self.add_items(self.datasets_file_manager)
        
    def size(self):
        return self.item_count()

    def get(self, index):
        return self.get_items()[index].display_path

    def get_item_values(self, item):

        values_dict = {}

        values_dict["Dataset"] = item.display_path
        values_dict["Exists"] = os.path.isfile(item.absolute_path)

        return values_dict

    def get_header_scale(self):
        return 10

    def new(self):

        try:
            config = DatasetConfiguration()
            DatasetConfigurationDialog(self.master, self.add_from_file_path, config)                                         
        except ExceptionHandler.ExceptionType as e:
            ExceptionHandler.add(e, "ERROR creating dataset config")

    def add(self):

        preferences = Preferences.get()
        file_name = tkFileDialog.askopenfilename(parent=self.master, initialdir=preferences.dataset_last_opened_dir(), defaultextension=".xml")
        if len(file_name) > 0: self.add_from_file_path(file_name)

    def add_from_file_path(self, path):

        try:    
            preferences = Preferences.get()
            preferences.datasetLastOpened = path
            preferences.save()
        except ExceptionHandler.ExceptionType as e:
            ExceptionHandler.add(e, "Cannot save preferences")
        
        dataset = self.datasets_file_manager.append_absolute(path)

        self.add_item(dataset)

        self.parent_dialog.validate_datasets.validate()   

    def edit_item(self, item):                   

        try:
                
            datasetConfig = DatasetConfiguration(item.absolute_path)
            DatasetConfigurationDialog(self.master, None, datasetConfig, None)  
                                
        except ExceptionHandler.ExceptionType as e:

            ExceptionHandler.add(e, "ERROR editing")

    def remove(self):
        selected = self.get_selected()
        self.datasets_file_manager.remove(selected)
        GridBox.remove(self)
        self.parent_dialog.validate_datasets.validate()