# Script to automatically Schedule trains
#
# Author: Bill Fitch, copyright 2020
# Part of the JMRI distribution

# Description:
# We scan the operations:trains table and get a list of the trains that need to be scheduled
# in SchedulerMaster init we set up a listener which triggers every minute
# in the appropriate minute in the listener we append the train to the trains_to_be_scheduled
# in SchedulerMaster handle we process trains_to_be_scheduled by running run_trains(trains_to_be_scheduled)
# run_trains sets up a thread which moves the train, and removed the train from the trains_to_be_scheduled list

from javax.swing import JFrame, JPanel, JButton, BoxLayout, Box, JComponent, BorderFactory, JLabel, JTextField
from java.awt import GridLayout
from java.awt import Color, Font
from java.awt import Dimension, FlowLayout
from java.beans import PropertyChangeEvent
from java.awt.event import FocusAdapter, ActionListener
from javax.swing import SwingWorker, SwingUtilities
import os
import copy
import jmri
import java
import time
from org.python.core.util import StringUtil
from threading import Thread
from collections import Counter

# from javax.swing import JFrame
# from java.awt.event import WindowAdapter
from java.util.concurrent import CountDownLatch


CreateSchedulerPanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/SchedulerPanel.py')
execfile(CreateSchedulerPanel)

CreateRoutesPanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/RoutesPanel.py')
execfile(CreateRoutesPanel)

CreateEditRoutePanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/EditRoutePanel.py')
execfile(CreateEditRoutePanel)

CreateEditRoutePanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/Timetable.py')
execfile(CreateEditRoutePanel)

try:
    basestring
except NameError:
    basestring = str

if "list" in globals() and type(globals()["list"]).__name__ != "type":
    # print(" Detected shadowed 'list' type: ", type(globals()["list"]))  # list is being used in JMRI. This enables us to use list in Jython
    del globals()["list"]

CreateEditRoutePanel = jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/DisplayMqttTimetable.py')
execfile(CreateEditRoutePanel)

trains_to_be_scheduled = []
run_train_dict = {}
scheduled = {}
RunTrain_instance = {}
tListener = None

class SchedulerMaster(jmri.jmrit.automat.AbstractAutomaton):

    def __init__(self):
        global scheduling_in_operation_gbl
        self.logLevel = 0
        self.frame = None
        self.f = None
        scheduling_in_operation_gbl = False
        self.od = OptionDialog()

    def exit(self):       # called explicitly when scheduler thread is killed to stop multiple frames being visible
        try:
            self.frame.setVisible(False)
            self.f.setVisible(False)
            if "timetable_frame_gbl" in globals():
                timetable_frame_gbl.setVisible(False)
        except:
            pass

    def setup(self):
        global schedule_trains_hourly
        global schedule_trains_glb
        global scheduling_in_operation_gbl
        # schedule trains initially
        # schedule_trains_glb = False
        scheduling_in_operation_gbl = "False"
        self.stop_schedule_trains_master()    #don't really need this.
        # print "scheduling_in_operation_gbl 6 start setup", scheduling_in_operation_gbl
        # self.ToggleSchedulingtrains_action(None)      # Toggle schedule_trains_glb
        # print "scheduling_in_operation_gbl 6a", scheduling_in_operation_gbl

        if 'schedule_trains_hourly' not in globals():
            schedule_trains_hourly = False

        #run before setting up Schedule Master
        if self.logLevel > 0: print "starting SchedulerMaster setup"

        self.scheduler_master_sensor = sensors.getSensor("startSchedulerSensor")
        self.scheduler_view_scheduled_trains = sensors.getSensor("viewScheduledSensor")
        self.scheduler_edit_routes = sensors.getSensor("editRoutesSensor")
        self.scheduler_show_clock_sensor = sensors.getSensor("showClockSensor")
        self.timetable_sensor = sensors.getSensor("timetableSensor")
        self.departure_time_sensor = sensors.getSensor("departureTimeSensor")
        self.help_sensor = sensors.getSensor("helpSensor")


        if self.logLevel > 0: print "finished SchedulerMaster setup"
        if self.logLevel > 0: print "returned from setup"
        # print "scheduling_in_operation_gbl 7 end setup", scheduling_in_operation_gbl
        return True

    def init(self):
        global run_local_timetable_gbl
        # print "scheduling_in_operation_gbl 7 - init", scheduling_in_operation_gbl
        if "run_timetable_gbl" not in globals():
            run_local_timetable_gbl = False
        self.train_scheduler_setup = False
        # print "scheduling_in_operation_gbl 7 - init end", scheduling_in_operation_gbl
        if self.logLevel > 0: print "returned from init"

    showing_clock = False
    showing_trains = False
    def handle(self):
        # print "start handle 0"
        global schedule_trains_hourly
        global schedule_trains_glb
        global run_local_timetable_gbl
        global station_name_list_gbl
        global station_name_list_mqtt_gbl
        global group_location_gbl
        global timetable_triggered_gbl
        if self.logLevel > 0: print "start handle"
        # print "start handle"
        # print "scheduling_in_operation_gbl 7 handle", scheduling_in_operation_gbl
        self.button_sensors_to_watch = [self.scheduler_master_sensor, self.scheduler_view_scheduled_trains, \
                                        self.scheduler_edit_routes, \
                                        self.scheduler_show_clock_sensor, self.timetable_sensor, \
                                        self.departure_time_sensor, self.help_sensor]
        button_sensors_to_watch_JavaList = java.util.Arrays.asList(self.button_sensors_to_watch)

        self.waitSensorState(button_sensors_to_watch_JavaList, ACTIVE)
        # print "Z"
        if self.departure_time_sensor.getKnownState() == ACTIVE:
            self.set_departure_trains()
            # print "ZZ"
            self.departure_time_sensor.setKnownState(INACTIVE)
        # print "Y"
        if self.timetable_sensor.getKnownState() == ACTIVE:
            title = ""
            # if "station_name_list_gbl" not in globals():
            #     station_name_list_gbl = ""
            # print "b"
            TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager)
            train_list = TrainManager.getTrainsByTimeList()
            my_scheduled_route_list = [train.getRoute() for train in train_list]
            if None in my_scheduled_route_list:
                OptionDialog().displayMessage("check scheduled routes are entered correctly\ncannot proceed with timetable")
            else:
                # print "my_scheduled_route_list", my_scheduled_route_list
                # print "c"
                RouteManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.routes.RouteManager)
                # print "d"
                station_list = []

                for route in my_scheduled_route_list:
                    route_locations_list = route.getLocationsBySequenceList()
                    # print "route", route.getName(), "route_locations_list", route_locations_list
                    station_list1 = [str(route_location.getName()) for route_location in route_locations_list \
                                     if ".py" not in route_location.getName()]
                    # print "e" , "station_list1", station_list1
                    for x in station_list1:
                        if x not in station_list:
                            station_list.append(x)
                    station_list.sort()
                # print "station_list", station_list

                repeat = True
                while repeat:
                    # get station_group list
                    platform_list = []
                    station_group_list = []
                    station_group_list.append("All Stations")
                    station_group_location_list = []
                    PlatformPanel = MyTableModel7()
                    for location_name in station_list:
                        LocationManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.locations.LocationManager)
                        location = LocationManager.getLocationByName(location_name)
                        platform = PlatformPanel.get_location_platform(location)
                        station_group = PlatformPanel.get_location_station_group(location)
                        if station_group.strip() is not None and station_group.strip() is not "":
                            if station_group.strip() not in station_group_list:
                                station_group_list.append(station_group.strip())
                                # print "type station_group", type(station_group.strip())
                            station_group_location_list.append([station_group.strip(), location_name])
                        station_group_location_list.append(["All Stations", location_name])

                    if self.logLevel > 0: print "station list", station_list
                    msg = "timetables can be shown locally on this computer or\n" + \
                          "on remote computers/tablets communicating by mqtt\n\n" + \
                          "scheduler needs to be on and clock running"
                    opt0 = "Cancel"
                    if run_local_timetable_gbl == True:
                        opt1 = "hide local timetable"
                    else:
                        opt1 = "show local timetable"
                    opt4 = "set platforms and station groups"
                    opt2 = "select station for local timetable"
                    opt3 = "mqtt timetables"
                    if 'timetable_triggered_gbl' not in globals():
                        reply = OptionDialog().customQuestionMessage4str(msg, title, opt0, opt4, opt2, opt3)
                    else:
                        reply = OptionDialog().customQuestionMessage5str(msg, title, opt0, opt1, opt4, opt2, opt3)
                    # print "reply", reply
                    if self.logLevel > 0: print "timetable_sensor active"
                    if reply == OptionDialog().CLOSED_OPTION or reply == opt0:
                        repeat = False
                    elif reply == opt1:
                        if run_local_timetable_gbl == True:
                            run_local_timetable_gbl = False
                        else:
                            run_local_timetable_gbl = True

                    elif reply == opt4:
                        gui7 = CreateAndShowGUI7()
                        # Create a latch that waits for CreateAndShowGUI7 frame to be closed
                        # In CreateAndShowGUI7 the latch is decremented whe  the frame is closed
                        global latch
                        latch = CountDownLatch(1)
                        # Wait until the frame is closed
                        latch.await()
                        reply = True

                    elif reply == opt2:
                        repeat1 = True
                        select_from_stations = True
                        while repeat1 == True:
                            if "station_name_list_gbl" not in globals():
                                station_name_list_gbl = ""
                            list_items_no_trains = self.get_scheduled_routes("no_train")
                            list_items_with_trains = self.get_scheduled_routes("with_train")
                            if select_from_stations:
                                title = "select station(s) for timetable - only stations on scheduled routes are shown"
                                options = ["Cancel", "Select from Station Groups", "Show Timetable"]
                                result = OptionDialog().MultipleListOptions(station_list, title, options, preferred_size = "default")
                            else:
                                title = "select station_group for timetable"
                                options = ["Cancel", "Select from Stations", "Show Timetable"]
                                result = OptionDialog().ListOptions(station_group_list, title, options, preferred_size = "default")
                            option = result[1]
                            if option == "Cancel" or self.od.CLOSED_OPTION == True:
                                run_local_timetable_gbl = False
                                self.timetable_sensor.setKnownState(INACTIVE)
                                repeat1 = False
                            elif option == "Show Timetable":
                                if select_from_stations:
                                    station_name_list_gbl = result[0]
                                    # get group_station_name
                                    if len(station_name_list_gbl) == 1:
                                        group_location_gbl = station_name_list_gbl[0]   # the first and only station  station1
                                    else:
                                        group_location_gbl = self.get_group_station_name(station_name_list_gbl)
                                else:
                                    group_location_gbl = result[0]
                                    # get station list
                                    station_name_list = []
                                    for l in station_group_location_list:
                                        if l[0] == group_location_gbl:
                                            station_name_list.append(l[1])
                                    station_name_list_gbl = station_name_list

                                run_local_timetable_gbl = True
                                self.ensure_conditions_for_timetable_to_show_are_met()
                                repeat1 = True
                            else:
                                if select_from_stations == True:
                                    select_from_stations = False
                                else:
                                    select_from_stations = True
                                repeat1 = True
                        repeat = True
                    elif reply == opt3:
                        repeat = True
                        while repeat:
                            title = "MQTT timetables"
                            msg = "timetables can be shown on remote computers/tablets communicating by mqtt\n\n" + \
                                  "scheduler needs to be on and clock running"
                            opt0 = "Cancel"
                            opt1 = "Generate mqtt timetable"
                            opt2 = "View/delete mqtt timetables"
                            opt3 = "Display mqtt timetables"

                            reply = OptionDialog().customQuestionMessage4str(msg, title, opt0, opt1, opt2, opt3)
                            if self.od.CLOSED_OPTION == True or reply == opt0:
                                repeat = False
                            elif reply == opt1:
                                select_from_stations = True
                                if "station_name_list_gbl" not in globals():
                                    station_name_list_gbl = ""
                                list_items_no_trains = self.get_scheduled_routes("no_train")
                                list_items_with_trains = self.get_scheduled_routes("with_train")
                                if select_from_stations:
                                    title = "select station(s) for timetable - only stations on scheduled routes are shown"
                                    options = ["Cancel", "Select from Station Groups", "Generate Timetable"]
                                    result = OptionDialog().MultipleListOptions(station_list, title, options, preferred_size = "default")
                                else:
                                    title = "select station_group for timetable"
                                    options = ["Cancel", "Select from Stations", "Generate Timetable"]
                                    result = OptionDialog().ListOptions(station_group_list, title, options, preferred_size = "default")
                                option = result[1]
                                if option == "Cancel" or self.od.CLOSED_OPTION == True:
                                    run_local_timetable_gbl = False
                                    self.timetable_sensor.setKnownState(INACTIVE)
                                    repeat = False
                                elif option == "Generate Timetable":
                                    if select_from_stations:
                                        station_name_list_mqtt_gbl = result[0]
                                        # get group_station_name
                                        if len(station_name_list_gbl) == 1:
                                            group_location_mqtt_gbl = station_name_list_gbl[0]   # the first and only station  station1
                                        else:
                                            group_location_mqtt_gbl = self.get_group_station_name(station_name_list_mqtt_gbl)
                                            print "group_location_mqtt_gbl", group_location_mqtt_gbl
                                    else:
                                        group_location_mqtt_gbl = result[0]
                                        # print "group_location_mqtt_gbl", group_location_mqtt_gbl
                                        # get station list
                                        station_name_list = []
                                        for l in station_group_location_list:
                                            if l[0] == group_location_mqtt_gbl:
                                                station_name_list.append(l[1])
                                        station_name_list_mqtt_gbl = station_name_list
                                        # print "station_name_list_mqtt_gbl", station_name_list_mqtt_gbl

                                    # get emblem
                                    title = "Display Train Operator Emblem?"
                                    emblem_list = ["GB (British Rail)", "Germany (DB)", "No Emblem"]
                                    options = ["Cancel", "Generate Timetable"]
                                    result = self.od.ListOptions(emblem_list, title, options, preferred_size = "default")
                                    # print "result", result
                                    train_operator_emblem = result[0]
                                    option1 = result[1]
                                    if option1 == "Cancel" or self.od.CLOSED_OPTION == True:
                                        # run_local_timetable_gbl = False
                                        self.timetable_sensor.setKnownState(INACTIVE)
                                    else:
                                        self.generate_node_red_code(station_name_list_mqtt_gbl, group_location_mqtt_gbl, train_operator_emblem)
                                        self.write_list2([train_operator_emblem])
                                    repeat = True
                                else:
                                    if select_from_stations == True:
                                        select_from_stations = False
                                    else:
                                        select_from_stations = True
                                    repeat = True
                            elif reply == opt2: # view/delete mqtt timetables

                                msg = "The generated timetables are saved in the following directory \n" +\
                                    "Delete any that are not required"
                                OptionDialog().displayMessage(msg)

                                self.view_delete_mqtt_timetables()
                                repeat = True

                            elif reply == opt3: # display mqtt timetables
                                msg = "Will attempt to display all generated timetables in default browser \n" +\
                                    "If Node Red is installed the timetables will be displayed \n" + \
                                    "If MQTT is set up in jmri and mosquitto is running the timetables will work \n" +\
                                    " when the scheduler is running"
                                OptionDialog().displayMessage(msg)

                                dmt = DisplayMqttTimetable()
                                repeat = True
                        repeat = True
                self.timetable_sensor.setKnownState(INACTIVE)

        if self.scheduler_master_sensor.getKnownState() == ACTIVE:   # pause processing if we turn the sensor off

            if self.logLevel > 0:  print("checking valid operations trains")
            if self.logLevel > 0: print "train_scheduler_setup",self.train_scheduler_setup

            # # check whether can/want to schedule trains every hour
            # schedule_trains_hourly = self.check_whether_schedule_trains_every_hour()

            # print "scheduling_in_operation_gbl 8", scheduling_in_operation_gbl
            self.set_default_scheduling_values()
            # print "scheduling_in_operation_gbl 70", scheduling_in_operation_gbl
            self.set_period_trains_will_run_frame()
            # print "scheduling_in_operation_gbl 71", scheduling_in_operation_gbl
            self.show_analog_clock()      # show the analog clock

            # set time to midnight
            if self.logLevel > 0: print "set minute time listener"

            global minute_time_listener_setup
            if "minute_time_listener_setup" not in globals():
                minute_time_listener_setup = False
            if minute_time_listener_setup == False:
                self.setup_minute_time_listener_to_schedule_trains()    # only do this first time setup
            self.train_scheduler_setup = True

            self.scheduler_master_sensor.setKnownState(INACTIVE)

        if self.scheduler_view_scheduled_trains.getKnownState() == ACTIVE:
            self.show_operations_trains()
            self.scheduler_view_scheduled_trains.setKnownState(INACTIVE)

        if self.scheduler_edit_routes.getKnownState() == ACTIVE:
            self.show_routes()
            self.scheduler_edit_routes.setKnownState(INACTIVE)

        if self.scheduler_show_clock_sensor.getKnownState() == ACTIVE:
            self.show_analog_clock()
            self.scheduler_show_clock_sensor.setKnownState(INACTIVE)

        if self.help_sensor.getKnownState() == ACTIVE:
            self.display_help()
            self.help_sensor.setKnownState(INACTIVE)
        self.waitMsec(500)
        if self.logLevel > 0: print "end handle"
        # print "scheduling_in_operation_gbl 7 handle end", scheduling_in_operation_gbl
        # print "F"
        return True

    def mqtt_timetable_directory(self):
        path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "mqtt_timetables"
        if not os.path.exists(path):
            os.makedirs(path)
        return path + java.io.File.separator

    def view_delete_mqtt_timetables(self):

        dir = self.mqtt_timetable_directory()
        j = JFileChooser(dir);
        j.setAcceptAllFileFilterUsed(False)
        filter = FileNameExtensionFilter("json files json", ["json"])
        j.addChoosableFileFilter(filter);

        j.setDialogTitle("Delete not wanted mqtt timetables");

        ret = j.showDialog(None, "Delete");
        if ret == JFileChooser.APPROVE_OPTION:
            file = j.getSelectedFile()
            if file == "" or file == None:
                return
            if file.exists():
                os.remove(file.getAbsolutePath())
                # print("File " + file.getName() + " has been deleted successfully.")
            else:
                print("The selected file does not exist.")
        else:
            print("File selection cancelled.")
            return

    def get_group_station_name(self, station_name_list_gbl):

        # print "station_name_list_gbl", station_name_list_gbl
        concatenated_names = " ".join(station_name_list_gbl)    # [station1,station2]
        print "concatenated_names", concatenated_names

        station_groups = []
        for station_name in station_name_list_gbl:
            LocationManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.locations.LocationManager)
            location = LocationManager.getLocationByName(station_name)
            station_group = MyTableModel7().get_location_station_group(location)
            print "station_name", station_name, "station_group", station_group.replace(" ", "*")
            if station_group != "" and station_group != " ":
                station_groups.append(station_group)
                # print "appending station_groups", station_groups
        counter = Counter(station_groups)
        print "counter", counter
        print "counter.most_common(1)", counter.most_common(1)
        most_common_item = " "
        if counter.most_common() != []:
            most_common_item = counter.most_common(1)[0][0]
            print "most_common_item", most_common_item

        if most_common_item != " ":
            group_location_gbl = most_common_item.strip()   # need an option to rename this
        else:
            group_location_gbl = concatenated_names
        print "group_location_gbl", group_location_gbl

        return group_location_gbl

    def ensure_conditions_for_timetable_to_show_are_met(self):
        global scheduling_in_operation_gbl
        global timebase
        global start_hour_gbl, end_hour_gbl
        if "timebase" not in globals():
            timebase = jmri.InstanceManager.getDefault(jmri.Timebase)

        if "start_hour_gbl" not in globals():
            start_hour_gbl = None
        if start_hour_gbl == None:     # check if Start Scheduler has been run
            sm = SchedulerMaster()     # if not set up everything which would have been run
            sm.set_default_scheduling_values()
            # sm.set_period_trains_will_run_frame()
            # sm.show_analog_clock()      # show the analog clock
            sm.setup_minute_time_listener_to_schedule_trains()
            sm.train_scheduler_setup = True

        if timebase.getRun() == False:
            # get the current time without using timebase
            date = jmri.implementation.DefaultClockControl().getTime()
            calendar = java.util.Calendar.getInstance()
            calendar.setTime(date)
            minute = calendar.get(calendar.MINUTE)

            # Manually create and trigger a PropertyChangeEvent
            # have to call it twice to get the timetable to display
            event = PropertyChangeEvent("TimeSource", "time",(minute - 2) % 60, (minute - 1) % 60)
            TimeListener().propertyChange(event)  # Directly call the listener's method
            event = PropertyChangeEvent("TimeSource", "time", (minute - 1) % 60, minute)
            TimeListener().propertyChange(event)
        else:
            # print "should be OK to show timetable"
            pass

    def generate_node_red_code(self, station_name_list, station_name, train_operator_emblem):
        node_red_template_path = \
            jmri.util.FileUtil.getExternalFilename('program:jython/DispatcherSystem/timetable_template/node_red_flow.json"')
        # read the file into a string
        #check if file is present
        if os.path.isfile(node_red_template_path):
            #open text file in read mode
            text_file = open(node_red_template_path, "r")

            #read whole file to a string
            data = text_file.read()

            #close file
            text_file.close()
            # create a unique reference for the websocketout node
            import uuid
            id = str(uuid.uuid1())
            # change the file to work with station_name
            # websocket names cannot have spaces in them
            # so where we need to replace spaces we have My_Station$ instead of MyStation
            new_data = (data.replace('My_Station$_ref', id) \
                .replace('My_Station$', station_name.replace(" ","-")) \
                .replace("My_Station_List", str(station_name_list)) \
                .replace("My_Station", station_name) \
                .replace("My_Emblem", train_operator_emblem))
            # 'My_Station$' for url without spaces
            # "My_Station" for title
            # "My_Station_List" for list of stations to include


            # store the modified file to a file in the user directory
            new_node_red_template_directory = jmri.util.FileUtil.getExternalFilename('preference:dispatcher/mqtt_timetables/')

            #create the folder if it does not exist
            if not os.path.exists(new_node_red_template_directory):
                os.makedirs(new_node_red_template_directory)

            file_path = new_node_red_template_directory + java.io.File.separator + station_name + ".json"

            f = open(file_path, "w")
            f.write(new_data)
            f.close()
        else:
            OptionDialog().displayMessage(file_path + "does not exist, reinstall latest JMRI")

        msg = "node red file for '" + station_name + "' is in " + file_path + "\n" + \
              "import the file into a node_red instance on computer on same network \n" + \
              "and edit as illustrated in the help, and open indicated web page on tablet/laptop \n" + \
              "e.g. http://localhost:1880/" + station_name.replace(" ", "-") + ", where localhost should be replaced by network address \n" + \
              "of computer hosting node_red instance\n\n" + \
              "Note any spaces in the station name have been replaced by hyphens in the web address\n\n" + \
              "ALSO ensure an MQTT Connection is set up in preferences, as detailed in help."
        OptionDialog().displayMessage(msg)

    def set_departure_trains(self):
        # allow running of scheduled routes to set journey times and wait times,
        # which allow durations and departure times to be set up
        # print "set departure trains"
        global wait_time_gbl
        global scheduled
        global scheduling_margin_gbl
        global set_departure_trains_gbl
        global CreateAndShowGUI5_glb

        set_departure_trains_gbl = True
        self.set_default_scheduling_values()
        msg = "Set Departure Times"
        opt1 = "set wait time in stations"
        opt2 = "run train on route to set journey times"
        opt3 = "set departure times manually"
        reply = OptionDialog().customQuestionMessage3str(msg, "", opt1, opt2, opt3)
        if reply == opt1:
            memory = memories.getMemory("IM:" + "DS_wait_time")
            # print "memory", type(memory)
            if memory is None or memory.getValue() == "":
                memory = memories.provideMemory("IM:" + "DS_wait_time")
                memory.setValue(3)

            title = "wait time at station"
            msg = "set wait time at all stations"
            default_value = str(memory.getValue())

            wait_time = OptionDialog().input(msg, title, default_value)
            # memory = memories.getMemory("IM:" + "DS_wait_time")
            if memory is not None:
                memory.setValue(wait_time)
            # print "wait_time", wait_time
            return
        elif reply == opt2:
            list_items_no_trains = self.get_scheduled_routes("no_train")
            # print "list_items_no_trains", list_items_no_trains
            list_items_with_trains = self.get_scheduled_routes("with_train")
            # print "list_items_with_trains", list_items_with_trains
            list_items_starting_from_occupied_blocks = self.get_routes_starting_from_occupied_blocks()
            # print "list_items_starting_from_occupied_blocks", list_items_starting_from_occupied_blocks
            show_trains_in_occupied_blocks = True
            repeat = True
            while repeat:
                if show_trains_in_occupied_blocks:
                    title = "Select Route to Record Journey Times: Showing routes from occupied blocks"
                    options = ["Cancel", "Run Route", "Show all scheduled routes"]
                    reply1 = OptionDialog().ListOptions(list_items_starting_from_occupied_blocks, title, options, preferred_size = "default")
                else:
                    title = "Select Route to Record Journey Times: Showing scheduled routes"
                    options = ["Cancel", "Run Route", "Show routes starting from occupied blocks"]
                    reply1 = OptionDialog().ListOptions(list_items_no_trains, title, options, preferred_size = "default")

                my_list = reply1[0]
                route_name = str(my_list)
                option = str(reply1[1])

                if OptionDialog().CLOSED_OPTION == True or option == "Cancel":
                    # print "cancelling"
                    return
                elif option == "Run Route":
                    # print "Run Route"
                    train_array = [trn for [rte, trn] in list_items_with_trains if str(rte) == route_name]
                    if len(train_array) == 0:
                        OptionDialog().displayMessage("Selected route is not on the scheduled list - try again")
                        return
                    else:
                        train = train_array[0]
                    set_departure_times = True
                    param_scheduled_start = "00:00"
                    journey_time_row_displayed = True
                    if "CreateAndShowGUI5_glb" in globals():
                        if CreateAndShowGUI5_glb != None:
                            CreateAndShowGUI5_glb.frame.dispose()
                    CreateAndShowGUI5_glb = CreateAndShowGUI5(None, route_name, param_scheduled_start, journey_time_row_displayed = journey_time_row_displayed)
                    title = "Run Train"
                    msg = "Last time to cancel"
                    opt1 = "Cancel"
                    opt2 = "Run Train"
                    reply = OptionDialog().customQuestionMessage2str(msg, title, opt1, opt2)
                    if reply == JOptionPane.CANCEL_OPTION or reply == opt1:
                        CreateAndShowGUI5_glb.frame.dispose()
                        return
                    OptionDialog().displayMessageNonModal("Run Train along route " + str(route_name) + " now","<html>Check train is in required station<br>Then click to run route")
                    # print "Ended non modal, wait for non modal"
                    self.waitForNonModal()
                    # print "finished wait for non modal"
                    if self.logLevel > 0: print "running train %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", train.getDescription(), train.getName()
                    # running_train = RunTrain(train, g.g_stopping, set_departure_times)
                    route = train.getRoute()
                    routeName = route.getName()
                    station_from, station_to = self.get_first_and_last_station(route)   # starting from beginning of route
                    if self.logLevel > 0: print "station_from", station_from, "station_to", station_to
                    start_block = blocks.getBlock(station_from)
                    if self.logLevel > 0:  "start_block",start_block, "station_to", station_to
                    train_name = start_block.getValue()
                    no_repetitions = 0
                    delay_val = 0
                    # print "%%%%%%%%%%%%%%train_name%%%%%%%%%%%%%%", train_name
                    if train_name is None:
                        OptionDialog().displayMessage("No train is in the start position \n\n(maybe it has not been set up so the system recognises it)\npress setup train - register the train -  and try again")
                        return
                    else:
                        # print "train_name is not none"
                        pass

                    if "stopping" in train.getDescription():
                        if self.logLevel > 0: print "A"
                        run_train = RunRoute(route, g.g_stopping, station_from, station_to, no_repetitions, train_name, \
                                             set_departure_times = True)
                        run_train.setName("running_route_" + routeName)
                        instanceList.append(run_train)
                        run_train.start()
                    else:
                        if self.logLevel > 0: print "B"
                        run_train = RunRoute(route, g.g_express, station_from, station_to, no_repetitions, train_name, \
                                             set_departure_times = True)
                        run_train.setName("running_route_" + routeName)
                        instanceList.append(run_train)
                        run_train.start()
                    repeat = False
                else:
                    if show_trains_in_occupied_blocks == True:
                        show_trains_in_occupied_blocks = False
                    else:
                        show_trains_in_occupied_blocks = True
                    repeat = True

            return

        elif reply == opt3:

            list_items_no_trains = self.get_scheduled_routes("no_train")
            # print "list_items_no_trains", list_items_no_trains
            list_items_with_trains = self.get_scheduled_routes("with_train")
            # print "list_items_with_trains", list_items_with_trains
            list_items_all_routes = self.get_all_routes()
            # print "list_items_all_routes", list_items_all_routes
            show_all_routes = True
            repeat = True
            while repeat:
                if show_all_routes:
                    title = "Select Route to Record Journey Times: Showing all routes"
                    options = ["Cancel", "Set Departure Times", "Show scheduled routes"]
                    reply1 = OptionDialog().ListOptions(list_items_all_routes, title, options, preferred_size = "default")
                else:
                    title = "Select Route to Record Journey Times: Showing scheduled routes"
                    options = ["Cancel", "Set Departure Times", "Show all routes"]
                    reply1 = OptionDialog().ListOptions(list_items_no_trains, title, options, preferred_size = "default")

                my_list = reply1[0]
                option = reply1[1]
                route_name = str(my_list)

                option = str(option)
                if OptionDialog().CLOSED_OPTION == True or option == "Cancel":
                    # print "cancelling"
                    return
                elif option == "Set Departure Times":
                    param_scheduled_start = "00:00"
                    journey_time_row_displayed = True
                    if "CreateAndShowGUI5_glb" not in globals():
                        CreateAndShowGUI5_glb = CreateAndShowGUI5(None, route_name, param_scheduled_start, journey_time_row_displayed = journey_time_row_displayed)
                    else:
                        CreateAndShowGUI5_glb.frame.dispose()
                        CreateAndShowGUI5_glb = CreateAndShowGUI5(None, route_name, param_scheduled_start, journey_time_row_displayed = journey_time_row_displayed)
                    repeat = False
                else:
                    if show_all_routes == True:
                        show_all_routes = False
                    else:
                        show_all_routes = True
                    repeat = True

            return

    def get_first_and_last_station(self, route):

        routelocationsSequenceNumber_list = [ [routelocation, routelocation.getSequenceNumber()] \
                                              for routelocation in route.getLocationsBySequenceList() \
                                              if ".py" not in routelocation.getName()]

        if self.logLevel > 0: print "routelocationsSequenceNumber_list", routelocationsSequenceNumber_list
        first_routelocation = [routelocation \
                               for [routelocation, sequenceNo] in routelocationsSequenceNumber_list \
                               ][0]
        last_routelocation = [routelocation \
                              for [routelocation, sequenceNo] in routelocationsSequenceNumber_list \
                              ][-1]

        if self.logLevel > 0: print  "routelocation", routelocation
        return [str(first_routelocation), str(last_routelocation)]  # row number starts from 0

    def waitForNonModal(self):

        Jdialog_closed = sensors.getSensor("Jdialog_closed")
        Jdialog_closed.setKnownState(INACTIVE)
        btn = [Jdialog_closed]
        btn_to_watch = java.util.Arrays.asList(btn)
        # print "waiting for button" , Jdialog_closed.getKnownState()
        self.waitSensorState(btn_to_watch, ACTIVE)

    def get_scheduled_routes(self, option):
        TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager)
        train_list = TrainManager.getTrainsByTimeList()
        if option == "with_train":
            my_list = [[train.getRoute().getName() if train is not None else "" , train] for train in train_list if train.getRoute() is not None]
        else:
            my_list = [train.getRoute().getName() if train is not None else "" for train in train_list if train.getRoute() is not None]
        return sorted(my_list)

    def get_routes_starting_from_occupied_blocks(self):
        RouteManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.routes.RouteManager)
        route_list = RouteManager.getRoutesByNameList()
        my_list = [route.getName() for route in route_list if blocks.getBlock(route.getLocationsBySequenceList()[0].getName()).getSensor().getState() == ACTIVE ]
        return sorted(my_list)

    def get_all_routes(self):
        RouteManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.routes.RouteManager)
        route_list = RouteManager.getRoutesByNameList()
        my_list = [route.getName() for route in route_list ]
        return sorted(my_list)

    def start_and_end_time_scheduling(self):
        if self.logLevel > 0: print "start_and_end_time_scheduling"
        TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager)
        train_list = TrainManager.getTrainsByTimeList()
        start_time_hour = 23
        end_time_hour = 0
        for train in train_list:
            train_hour = int(train.getDepartureTimeHour())
            if train_hour < start_time_hour:
                start_time_hour = train_hour
            else:
                pass
            if train_hour > end_time_hour:
                end_time_hour = train_hour
            else:
                pass
        # print "[start_time_hour, end_time_hour]", [start_time_hour, end_time_hour]
        if self.logLevel > 0: print "start_and_end_time_scheduling end"
        return [start_time_hour, end_time_hour]

    def set_period_trains_will_run_frame(self):
        global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \
            scheduling_margin_gbl, scheduling_in_operation_gbl
        if self.frame == None:
            # print "frame is None"
            self.frame = jmri.util.JmriJFrame('Schedule Trains');

            panel = JPanel()
            panel.setLayout(BoxLayout(panel, BoxLayout.Y_AXIS))
            self.frame.add(panel)

            row0 = JPanel()
            row0.setLayout(BoxLayout(row0, BoxLayout.X_AXIS))
            txt = JTextField(140)
            txt.setMaximumSize( txt.getPreferredSize() );
            txt.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(Color.red),
                txt.getBorder()));
            label_panel_location = JLabel()
            # btnpanelLocation = JButton("Set Panel Location", actionPerformed = btnpanelLocation_action)
            btnpanelLocation = JButton("Set Panel Location")
            row0.add(Box.createVerticalGlue())
            row0.add(Box.createRigidArea(Dimension(20, 0)))
            row0.add(btnpanelLocation)
            row0.add(Box.createRigidArea(Dimension(20, 0)))
            row0.add(label_panel_location)
            row0.add(Box.createRigidArea(Dimension(20, 0)))


            rowTitle_22 = JPanel()
            rowTitle_22.setLayout(BoxLayout(rowTitle_22, BoxLayout.X_AXIS))
            rowTitle_23 = JPanel()
            rowTitle_23.setLayout(BoxLayout(rowTitle_23, BoxLayout.X_AXIS))
            rowStage1Title_1 = JLabel("Sets Up System to run hourly trains ")
            rowStage1Title_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13));
            # get_start_filename()
            # get_backup_filename()
            # rowStage1Title_1 = JLabel("    Modifies: " + start_filename + "  Creates backup: " + backup_filename)
            # rowStage1Title_1.add(Box.createHorizontalGlue());
            # rowStage1Title_1.setAlignmentX(rowStage1Title_1.LEFT_ALIGNMENT)
            # rowStage1Title_2 = JLabel("Run Scheduled Trains")
            # rowStage1Title_3 = JLabel("    Read Help to see how system works")     #start_filename + "_icons"

            rowTitle_22.add(Box.createVerticalGlue())
            rowTitle_22.add(Box.createRigidArea(Dimension(20, 0)))
            rowTitle_22.add(rowStage1Title_1)
            # rowTitle_22.add(Box.createRigidArea(Dimension(20, 0)))
            # rowTitle_22.add(rowStage1Title_2)

            # rowTitle_22.add(Box.createVerticalGlue())
            # rowTitle_22.add(Box.createRigidArea(Dimension(20, 0)))
            # rowTitle_22.add(JLabel(""))
            # rowTitle_23.add(rowStage1Title_3)

            rowTitle_33 = JPanel()
            rowTitle_33.setLayout(BoxLayout(rowTitle_33, BoxLayout.X_AXIS))
            rowTitle_33.add(Box.createVerticalGlue())
            rowTitle_33.add(Box.createRigidArea(Dimension(30, 0)))
            rowTitle_33.add(rowStage1Title_1)

            # buttons

            rowStage1Button = JPanel()
            rowStage1Button.setLayout(BoxLayout(rowStage1Button, BoxLayout.X_AXIS))

            global rowrowStage4Button_4, rowAStage1Button_1,  rowBStage1Button_1, rowCStage1Button_1, rowDStage1Button_1, rowEStage1Button_1, rowFStage1Button_1
            rowAStage1Button = JPanel()
            rowAStage1Button.setLayout(BoxLayout(rowAStage1Button, BoxLayout.X_AXIS))

            rowBStage1Button = JPanel()
            rowBStage1Button.setLayout(BoxLayout(rowBStage1Button, BoxLayout.X_AXIS))

            rowCStage1Button = JPanel()
            rowCStage1Button.setLayout(BoxLayout(rowCStage1Button, BoxLayout.X_AXIS))

            rowDStage1Button = JPanel()
            rowDStage1Button.setLayout(BoxLayout(rowDStage1Button, BoxLayout.X_AXIS))

            rowEStage1Button = JPanel()
            rowEStage1Button.setLayout(BoxLayout(rowEStage1Button, BoxLayout.X_AXIS))

            rowFStage1Button = JPanel()
            rowFStage1Button.setLayout(BoxLayout(rowFStage1Button, BoxLayout.X_AXIS))

            rowrowStage1Button_1 = JLabel("Change parameters to run trains")
            rowrowStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13));
            rowrowStage1Button_1.add(Box.createHorizontalGlue());
            rowrowStage1Button_1.setAlignmentX(rowrowStage1Button_1.LEFT_ALIGNMENT)

            stringToDisplay = "start hour: " + str(start_hour_gbl)
            rowAStage1Button_1 = JLabel(stringToDisplay)
            rowAStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13));
            rowAStage1Button_1.add(Box.createHorizontalGlue());
            rowAStage1Button_1.setAlignmentX(rowAStage1Button_1.LEFT_ALIGNMENT)

            stringToDisplay = "end hour: " + str(end_hour_gbl)
            rowBStage1Button_1 = JLabel(stringToDisplay)
            rowBStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13));
            rowBStage1Button_1.add(Box.createHorizontalGlue());
            rowBStage1Button_1.setAlignmentX(rowBStage1Button_1.LEFT_ALIGNMENT)

            stringToDisplay = "fast clock (when scheduling trains): x " + str(fast_clock_rate)
            rowCStage1Button_1 = JLabel(stringToDisplay)
            rowCStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13));
            rowCStage1Button_1.add(Box.createHorizontalGlue());
            rowCStage1Button_1.setAlignmentX(rowCStage1Button_1.LEFT_ALIGNMENT)

            stringToDisplay = "fast clock (outside running times): x " + str(speed_not_operational_gbl)
            rowDStage1Button_1 = JLabel(stringToDisplay)
            rowDStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13));
            rowDStage1Button_1.add(Box.createHorizontalGlue());
            rowDStage1Button_1.setAlignmentX(rowDStage1Button_1.LEFT_ALIGNMENT)

            stringToDisplay = "scheduling margin: " + str(scheduling_margin_gbl) + " fast mins"
            rowEStage1Button_1 = JLabel(stringToDisplay)
            rowEStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13));
            rowEStage1Button_1.add(Box.createHorizontalGlue());
            rowEStage1Button_1.setAlignmentX(rowEStage1Button_1.LEFT_ALIGNMENT)

            stringToDisplay = "scheduling in operation: " + str(scheduling_in_operation_gbl)
            rowFStage1Button_1 = JLabel(stringToDisplay)
            rowFStage1Button_1.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13));
            rowFStage1Button_1.add(Box.createHorizontalGlue());
            rowFStage1Button_1.setAlignmentX(rowFStage1Button_1.LEFT_ALIGNMENT)

            rowStage1Button_1 = JButton("Initialisation", actionPerformed = self.setup_schedule_parameters_panel)

            stage1Button = rowStage1Button_1

            rowStage2Button = JPanel()
            rowStage2Button.setLayout(BoxLayout(rowStage2Button, BoxLayout.X_AXIS))
            rowrowStage2Button_2 = JLabel("Set Clock to Session Start")
            rowrowStage2Button_2.setFont(rowTitle_22.getFont().deriveFont(Font.BOLD, 13));

            rowrowStage2Button_2.add(Box.createHorizontalGlue());
            rowrowStage2Button_2.setAlignmentX(rowrowStage2Button_2.LEFT_ALIGNMENT)
            rowStage2Button_2 = JButton("Set Time  ", actionPerformed = self.SetTime_action)
            stage2Button = rowStage2Button_2

            rowStage3Button = JPanel()
            rowStage3Button.setLayout(BoxLayout(rowStage3Button, BoxLayout.X_AXIS))
            rowrowStage3Button_3 = JLabel("Stop/Start Scheduling Trains")
            rowrowStage3Button_3.setFont(rowTitle_33.getFont().deriveFont(Font.BOLD, 13));

            rowrowStage3Button_3.add(Box.createHorizontalGlue());
            rowrowStage3Button_3.setAlignmentX(rowrowStage3Button_3.LEFT_ALIGNMENT)
            rowStage3Button_3 = JButton("Schedule ", actionPerformed = self.ToggleSchedulingtrains_action)
            stage3Button = rowStage3Button_3

            rowStage4Button = JPanel()
            rowStage4Button.setLayout(BoxLayout(rowStage4Button, BoxLayout.X_AXIS))
            rowrowStage4Button_4 = JLabel("Stop/Start Clock")
            rowrowStage4Button_4.setFont(rowTitle_33.getFont().deriveFont(Font.BOLD, 13));

            rowrowStage4Button_4.add(Box.createHorizontalGlue());
            rowrowStage4Button_4.setAlignmentX(rowrowStage4Button_4.LEFT_ALIGNMENT)
            rowStage4Button_4 = JButton("Stop/Start", actionPerformed = self.StopStartClock_action)
            stage4Button = rowStage4Button_4

            rowStage5Button = JPanel()
            rowStage5Button.setLayout(BoxLayout(rowStage5Button, BoxLayout.X_AXIS))
            rowrowStage5Button_5 = JLabel("<html>Initialise time, start scheduler, start time<br>Stop scheduler, stop time</html>")
            rowrowStage5Button_5.setFont(rowTitle_33.getFont().deriveFont(Font.BOLD, 13));
    
            rowrowStage5Button_5.add(Box.createHorizontalGlue());
            rowrowStage5Button_5.setAlignmentX(rowrowStage5Button_5.LEFT_ALIGNMENT)
            rowStage5Button_5 = JButton("Initialise", actionPerformed = self.StopStartScheduler_action)
            stage5Button = rowStage5Button_5

            rowStage6Button = JPanel()
            rowStage6Button.setLayout(BoxLayout(rowStage6Button, BoxLayout.X_AXIS))
            rowrowStage6Button_6 = JLabel("<html>Start scheduler, start time<br>Stop scheduler, stop time</html>")
            rowrowStage6Button_6.setFont(rowTitle_33.getFont().deriveFont(Font.BOLD, 13));
    
            rowrowStage6Button_6.add(Box.createHorizontalGlue());
            rowrowStage6Button_6.setAlignmentX(rowrowStage6Button_6.LEFT_ALIGNMENT)
            rowStage6Button_6 = JButton("   Run   ", actionPerformed = self.Running_StopStartScheduler_action)
            stage6Button = rowStage6Button_6

            rowStage1Button.add(Box.createVerticalGlue())
            rowStage1Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage1Button.add(rowStage1Button_1)
            rowStage1Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage1Button.add(rowrowStage1Button_1)

            rowAStage1Button.add(Box.createVerticalGlue())
            rowAStage1Button.add(Box.createRigidArea(Dimension(120, 0)))
            rowAStage1Button.add(rowAStage1Button_1)

            rowBStage1Button.add(Box.createVerticalGlue())
            rowBStage1Button.add(Box.createRigidArea(Dimension(120, 0)))
            rowBStage1Button.add(rowBStage1Button_1)

            rowCStage1Button.add(Box.createVerticalGlue())
            rowCStage1Button.add(Box.createRigidArea(Dimension(120, 0)))
            rowCStage1Button.add(rowCStage1Button_1)

            rowDStage1Button.add(Box.createVerticalGlue())
            rowDStage1Button.add(Box.createRigidArea(Dimension(120, 0)))
            rowDStage1Button.add(rowDStage1Button_1)

            rowEStage1Button.add(Box.createVerticalGlue())
            rowEStage1Button.add(Box.createRigidArea(Dimension(120, 0)))
            rowEStage1Button.add(rowEStage1Button_1)

            rowFStage1Button.add(Box.createVerticalGlue())
            rowFStage1Button.add(Box.createRigidArea(Dimension(120, 0)))
            rowFStage1Button.add(rowFStage1Button_1)

            rowStage2Button.add(Box.createVerticalGlue())
            rowStage2Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage2Button.add(rowStage2Button_2)
            rowStage2Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage2Button.add(rowrowStage2Button_2)

            rowStage3Button.add(Box.createVerticalGlue())
            rowStage3Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage3Button.add(rowStage3Button_3)
            rowStage3Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage3Button.add(rowrowStage3Button_3)

            rowStage4Button.add(Box.createVerticalGlue())
            rowStage4Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage4Button.add(rowStage4Button_4)
            rowStage4Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage4Button.add(rowrowStage4Button_4)

            rowStage5Button.add(Box.createVerticalGlue())
            rowStage5Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage5Button.add(rowStage5Button_5)
            rowStage5Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage5Button.add(rowrowStage5Button_5)

            rowStage6Button.add(Box.createVerticalGlue())
            rowStage6Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage6Button.add(rowStage6Button_6)
            rowStage6Button.add(Box.createRigidArea(Dimension(20, 0)))
            rowStage6Button.add(rowrowStage6Button_6)

        #Title
            # panel.add(self.leftJustify(rowTitle_2))
            panel.add(self.leftJustify(rowTitle_22))
            panel.add(self._create_separator_row())

            #stage1
            panel.add(self.leftJustify(rowStage1Button))
            panel.add(self.leftJustify(rowAStage1Button))
            panel.add(self.leftJustify(rowBStage1Button))
            panel.add(self.leftJustify(rowCStage1Button))
            panel.add(self.leftJustify(rowDStage1Button))
            panel.add(self.leftJustify(rowEStage1Button))
            panel.add(self._create_separator_row())

            #stage2
            panel.add(self.leftJustify(rowStage2Button))
            # panel.add(self.leftJustify(rowStage2Separator))

            panel.add(self.leftJustify(rowStage3Button))
            panel.add(self.leftJustify(rowFStage1Button))

            panel.add(self.leftJustify(rowStage4Button))
            panel.add(self._create_separator_row())
            panel.add(self.leftJustify(rowStage5Button))
            panel.add(self._create_separator_row())
            panel.add(self.leftJustify(rowStage6Button))
            panel.add(self._create_separator_row())

        self.frame.pack()
        self.frame.setVisible(True)
        self.frame.setSize(450, 400)
        self.frame.setLocation(10,10)

    def _create_separator_row(self):
        """Creates and returns a new separator panel object."""
        separatorPanel = JPanel()
        separatorPanel.setLayout(BoxLayout(separatorPanel, BoxLayout.X_AXIS))
        separatorLabel = JLabel("*******************************************************************")
        separatorLabel.add(Box.createHorizontalGlue())
        separatorLabel.setAlignmentX(separatorLabel.LEFT_ALIGNMENT)

        separatorPanel.add(Box.createVerticalGlue())
        separatorPanel.add(Box.createRigidArea(Dimension(20, 0)))
        separatorPanel.add(separatorLabel)
        separatorPanel.add(Box.createRigidArea(Dimension(20, 0)))
        separatorPanel.add(JLabel("")) # Empty label for spacing

        return self.leftJustify(separatorPanel)

    def leftJustify(self, panel):
        b = Box.createHorizontalBox()
        b.add( panel )
        b.add( Box.createHorizontalGlue() )
        # (Note that you could throw a lot more components
        # and struts and glue in here.)
        return b

        # self.close_this_panel(event)
        #
        # self.run_trains()

    def close_this_panel(self, event):
        if self.logLevel > 0: print "closing panel"
        comp = event.getSource()
        win = SwingUtilities.getWindowAncestor(comp);
        win.dispose()

    def SetTime_action(self, event):
        global fast_clock_running_at_operational_speed
        global timebase

        # timebase needs to be running to set rate and time
        timebase.setRun(True)
        timebase.userSetRate(float(speed_not_operational_gbl))

        # set clock to beginning of session
        self.set_timebase_start_hour(int(start_hour_gbl)-1, 55)
        # self.set_timebase_start_hour(0, 0)

        # set timebase to stop
        timebase.setRun(False)
        if "rowrowStage4Button_4" in globals():
            if timebase.getRun():
                state = "Started"
            else:
                state = "Stopped"
            stringToDisplay = "Stop/Start Clock:  " + state
            rowrowStage4Button_4.setText(stringToDisplay) # Update the label

    def ToggleSchedulingtrains_action(self, event):
        global schedule_trains_glb
        global scheduling_in_operation_gbl
        global rowFStage1Button_1

        # schedule_trains_glb = False
        if self.logLevel > 0: print "ToggleSchedulingtrains_action", "scheduling_in_operation_gbl", scheduling_in_operation_gbl
        #stop Scheduler

        if 'scheduling_in_operation_gbl' not in globals():
            scheduling_in_operation_gbl = "True"
            # print "scheduling_in_operation_gbl 8", scheduling_in_operation_gbl
        if scheduling_in_operation_gbl == "False":
            self.start_schedule_trains_master()
            scheduling_in_operation_gbl = "True"
        else:
            self.stop_schedule_trains_master()
            scheduling_in_operation_gbl = "False"
        # print "scheduling_in_operation_gbl 0", scheduling_in_operation_gbl

        stringToDisplay = "scheduling in operation: " + str(scheduling_in_operation_gbl)

        if 'rowFStage1Button_1' in globals():
            rowFStage1Button_1.setText(stringToDisplay) # Update the label
        if self.logLevel > 0: print "ToggleSchedulingtrains_action end", "scheduling_in_operation_gbl", scheduling_in_operation_gbl

    def StopStartClock_action(self, event):
        self.swap_timebase_state_run_stop()

    def StopStartScheduler_action(self, event):
        if scheduling_in_operation_gbl == "False":   # start scheduler
            self.ToggleSchedulingtrains_action(event)
            # if timebase.getRun() == True:          # set time
            self.SetTime_action(event)          # sets time and sets timebase to stop
            # if timebase.getRun() == False:
            self.swap_timebase_state_run_stop() # start timebase
        else:
            # stop scheduler (was running)
            self.ToggleSchedulingtrains_action(event)
            # leave time at same time as before
            # stop timebase
            self.set_timebase_state_stop()

    def Running_StopStartScheduler_action(self, event):
        if scheduling_in_operation_gbl == "False":   # start scheduler
            self.ToggleSchedulingtrains_action(event)
            if timebase.getRun() == False:
                self.swap_timebase_state_run_stop() # start timebase
        else:
            # stop scheduler (was running)
            self.ToggleSchedulingtrains_action(event)
            # leave time at same time as before
            # stop timebase
            self.set_timebase_state_stop()

    def swap_timebase_state_run_stop(self):
        global timebase
        global tListener
        global fast_clock_rate
        global rowrowStage4Button_4
        if timebase.getRun() == True:
            timebase.removeMinuteChangeListener(tListener)
            timebase.setRun(False)
            # print "fast_clock_rate", fast_clock_rate
        else:
            timebase.setRun(True)
            if tListener is None:
                tListener = TimeListener()
            timebase.addMinuteChangeListener(tListener)
        if "rowrowStage4Button_4" in globals():
            if timebase.getRun():
                state = "Started"
            else:
                state = "Stopped"
            stringToDisplay = "Stop/Start Clock:  " + state
            rowrowStage4Button_4.setText(stringToDisplay) # Update the label
        else:
            # print '"rowrowStage4Button_4" not in globals()'
            pass

    def set_timebase_state_stop(self):
        global timebase
        global tListener
        global fast_clock_rate
        global rowrowStage4Button_4

        timebase.removeMinuteChangeListener(tListener)
        timebase.setRun(False)

        if "rowrowStage4Button_4" in globals():
            state = "Stopped"
            stringToDisplay = "Stop/Start Clock:  " + state
            rowrowStage4Button_4.setText(stringToDisplay) # Update the label
        else:
            # print '"rowrowStage4Button_4" not in globals()'
            pass

    def start_schedule_trains_master(self):

        global instanceList
        global rowFStage1Button_1

        # start scheduler
        if self.logLevel > 0: print "setup values for running"

        schedule_trains_master = ScheduleTrains()
        schedule_trains_master.setName('Schedule Trains Master')

        list_existing_schedule_trains = [iL.getName() for iL in instanceList if iL.getName() == 'Schedule Trains Master']
        # print "list_existing_schedule_trains", list_existing_schedule_trains

        if list_existing_schedule_trains == []:
            # print "appending instance list"
            instanceList.append(schedule_trains_master)
            if schedule_trains_master.setup():
                # print "setting name"
                schedule_trains_master.setName('Schedule Trains Master')
                schedule_trains_master.start()

        scheduling_in_operation_gbl = "False"
        # print "scheduling_in_operation_gbl 2", scheduling_in_operation_gbl
        stringToDisplay = "scheduling in operation: " + str(scheduling_in_operation_gbl)

        if 'rowFStage1Button_1' in globals():
            rowFStage1Button_1.setText(stringToDisplay) # Update the label
        if self.logLevel > 0: print "end setup values for running"

    def stop_schedule_trains_master(self):
        global instanceList
        #stop all threads even if there are duplications

        summary = jmri.jmrit.automat.AutomatSummary.instance()
        automatsList = java.util.concurrent.CopyOnWriteArrayList()
        schedule_trains_master = ScheduleTrains()

        for automat in summary.getAutomats():
            automatsList.add(automat)
        # print "automatsList", automatsList
        for automat in automatsList:
            # print "automat", automat
            if "ScheduleTrains" in str(automat): automat.stop()
            # print automat, "stopped"
        # print "automatsList2", automatsList
        # print "end stop_all_threads"

        instanceList = [iL for iL in instanceList if str(iL.getName()) != 'Schedule Trains Master']

    def set_default_scheduling_values(self):

        # self.show_analog_clock()      # show the analog clock

        # print "set_default_scheduling_hourly_values"

        global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \
            scheduling_margin_gbl, scheduling_in_operation_gbl
        # read parameters
        scheduling_in_operation_gbl1 = False   # change of logic do not set scheduling_in_operation_gbl here
        [start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \
         scheduling_margin_gbl, scheduling_in_operation_gbl1] = self.read_list()
        if self.logLevel > 0: print "read list" , [start_hour_gbl, end_hour_gbl, speed_not_operational_gbl]
        if start_hour_gbl == "":
            start_hour_gbl = "04"
            end_hour_gbl = "22"
            fast_clock_rate = "10"
            speed_not_operational_gbl = "100"
            scheduling_margin_gbl = "3"
            scheduling_in_operation_gbl = "False"
            # print "1scheduling_in_operation_gbl", scheduling_in_operation_gbl

        self.write_list([start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \
                         scheduling_margin_gbl, scheduling_in_operation_gbl])
        # print "fast_clock_rate in set_default_scheduling_values", fast_clock_rate

    def setup_schedule_parameters_panel(self, event):
        """Creates and displays a panel for setting the scheduler parameters."""
        # read parameters
        [self.start_hour, self.end_hour, fast_clock_rate, self.speed_not_operational, \
         self.scheduling_margin, self.scheduling_in_operation] = self.read_list()
        if self.logLevel > 0: print "read list" , [self.start_hour, self.end_hour, self.speed_not_operational]
        if self.start_hour == "":
            self.start_hour = "04"
            self.end_hour = "22"
            fast_clock_rate = "10"
            self.speed_not_operational = "100"
            self.scheduling_margin = "10"
            self.scheduling_in_operation = "False"

        # Create and set up the window.
        self.params_frame = JFrame("Set Schedule Parameters") #NOI18N
        self.params_frame.setPreferredSize(Dimension(550, 250))

        # Create and set up the panel using a simple grid layout.
        self.params_panel = JPanel(GridLayout(0, 2, 10, 5)) # hgap, vgap
        self.params_panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)) # top, left, bottom, right

        # Add the widgets to the panel.
        self.add_schedule_parameter_widgets()

        # Set the panel to be the content pane of the window.
        self.params_frame.setContentPane(self.params_panel)

        # Display the window.
        self.params_frame.pack()
        self.params_frame.setVisible(True)

    class FieldValidator(FocusAdapter, ActionListener):
        """
        A listener that validates a text field when focus is lost or Enter is pressed.
        If validation fails, it reverts the field to its previous value.
        """
        def __init__(self, validation_function, field):
            self.validation_function = validation_function
            self.field = field
            self.old_value = None

        def focusGained(self, event):
            """Store the current value when the field gains focus."""
            self.old_value = self.field.getText()

        def _validate_and_revert(self):
            """Helper method to run validation and revert on failure."""
            if not self.validation_function(self.field):
                # The validation function already shows the error message.
                # Now, revert the text field to the last known good value.
                self.field.setText(self.old_value)

        def focusLost(self, event):
            """Validate when focus is lost."""
            self._validate_and_revert()

        def actionPerformed(self, event):
            """Validate when Enter is pressed."""
            self._validate_and_revert()

    def add_schedule_parameter_widgets(self):
        """Adds labels, fields, and buttons to the parameters panel."""

        global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \
                     scheduling_margin_gbl, scheduling_in_operation_gbl

        # --- Create Widgets ---
        start_hour_label = JLabel("Start Hour (0-23):") #NOI18N
        self.start_hour_field = JTextField(4)

        end_hour_label = JLabel("End Hour (0-23):") #NOI18N
        self.end_hour_field = JTextField(4)

        fast_clock_label = JLabel("Fast Clock Rate (Running Period):") #NOI18N
        self.fast_clock_field = JTextField(4)

        fast_clock_off_label = JLabel("Fast Clock Rate (Non Running Period) (1-100):") #NOI18N
        self.fast_clock_off_field = JTextField(4)

        margin_label = JLabel("Scheduling Margin (Fast Mins, 0-20):") #NOI18N
        self.margin_field = JTextField(4)

        save_button = JButton("Save") #NOI18N
        cancel_button = JButton("Cancel") #NOI18N

        # --- Pre-fill fields with existing values ---
        # This assumes the values are stored as attributes of your class.
        # If they are globals, you would reference them directly.
        self.start_hour_field.setText(str(self.start_hour))
        self.end_hour_field.setText(str(self.end_hour))
        self.fast_clock_field.setText(str(fast_clock_rate))
        self.fast_clock_off_field.setText(str(self.speed_not_operational))
        self.margin_field.setText(str(self.scheduling_margin))

        # --- Add Listeners for real-time validation (on focus loss or Enter key) ---
        start_hour_validator = self.FieldValidator(self.validate_start_hour, self.start_hour_field)
        self.start_hour_field.addFocusListener(start_hour_validator)
        self.start_hour_field.addActionListener(start_hour_validator)

        end_hour_validator = self.FieldValidator(self.validate_end_hour, self.end_hour_field)
        self.end_hour_field.addFocusListener(end_hour_validator)
        self.end_hour_field.addActionListener(end_hour_validator)

        fast_clock_validator = self.FieldValidator(self.validate_fast_clock_rate, self.fast_clock_field)
        self.fast_clock_field.addFocusListener(fast_clock_validator)
        self.fast_clock_field.addActionListener(fast_clock_validator)

        fast_clock_off_validator = self.FieldValidator(self.validate_fast_clock_off_rate, self.fast_clock_off_field)
        self.fast_clock_off_field.addFocusListener(fast_clock_off_validator)
        self.fast_clock_off_field.addActionListener(fast_clock_off_validator)

        margin_validator = self.FieldValidator(self.validate_margin, self.margin_field)
        self.margin_field.addFocusListener(margin_validator)
        self.margin_field.addActionListener(margin_validator)

        # --- Add Action Listeners ---
        save_button.actionPerformed = self.save_schedule_parameters_action
        cancel_button.actionPerformed = self.cancel_schedule_parameters_action

        # --- Add Widgets to Panel in Order, wrapping fields to control size ---
        self.params_panel.add(start_hour_label)
        field_panel1 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0))
        field_panel1.add(self.start_hour_field)
        self.params_panel.add(field_panel1)

        self.params_panel.add(end_hour_label)
        field_panel2 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0))
        field_panel2.add(self.end_hour_field)
        self.params_panel.add(field_panel2)

        self.params_panel.add(fast_clock_label)
        field_panel3 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0))
        field_panel3.add(self.fast_clock_field)
        self.params_panel.add(field_panel3)

        self.params_panel.add(fast_clock_off_label)
        field_panel4 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0))
        field_panel4.add(self.fast_clock_off_field)
        self.params_panel.add(field_panel4)

        self.params_panel.add(margin_label)
        field_panel5 = JPanel(FlowLayout(FlowLayout.LEFT, 10, 0))
        field_panel5.add(self.margin_field)
        self.params_panel.add(field_panel5)

        # --- Add Buttons ---
        # Create a panel to hold both buttons, so they can be centered together.
        button_panel = JPanel(FlowLayout(FlowLayout.CENTER, 10, 5)) # hgap=10, vgap=5
        button_panel.add(save_button)
        button_panel.add(cancel_button)

        # Add an empty label to the first column of the last row to push the button panel to the right.
        self.params_panel.add(JLabel(""))
        self.params_panel.add(button_panel)


    def save_schedule_parameters_action(self, event):
        """Saves the parameters back to the class and closes the window."""

        global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \
            scheduling_margin_gbl, scheduling_in_operation_gbl

        # --- Run all validations one last time before saving ---
        if not self.validate_start_hour(self.start_hour_field): return
        if not self.validate_end_hour(self.end_hour_field): return
        if not self.validate_fast_clock_rate(self.fast_clock_field): return
        if not self.validate_fast_clock_off_rate(self.fast_clock_off_field): return
        if not self.validate_margin(self.margin_field): return

        # All validation passed, now save the values.
        self.start_hour = int(self.start_hour_field.getText())
        self.end_hour = int(self.end_hour_field.getText())
        fast_clock_rate = int(self.fast_clock_field.getText())
        self.speed_not_operational = int(self.fast_clock_off_field.getText())
        self.scheduling_margin = int(self.margin_field.getText())

        items = [str(item) for item in [self.start_hour,self.end_hour, fast_clock_rate, \
                                        self.speed_not_operational, \
                                        self.scheduling_margin, scheduling_in_operation_gbl]]
        if self.logLevel > 0: print "items to write", items
        self.write_list(items)

        # store in globals

        start_hour_gbl = self.start_hour
        end_hour_gbl = self.end_hour
        speed_not_operational_gbl = self.speed_not_operational
        scheduling_margin_gbl = self.scheduling_margin

        # update the jlabel texts

        stringToDisplay = "start hour: " + str(start_hour_gbl)
        rowAStage1Button_1.setText(stringToDisplay) # Update the label

        stringToDisplay = "end hour: " + str(end_hour_gbl)
        rowBStage1Button_1.setText(stringToDisplay) # Update the label

        stringToDisplay = "fast clock (when scheduling trains): x " + str(fast_clock_rate)
        rowCStage1Button_1.setText(stringToDisplay) # Update the label

        stringToDisplay = "fast clock (outside running times): x " + str(speed_not_operational_gbl)
        rowDStage1Button_1.setText(stringToDisplay) # Update the label

        stringToDisplay = "scheduling margin: " + str(scheduling_margin_gbl) + " fast mins"
        rowEStage1Button_1.setText(stringToDisplay) # Update the label

        print
        "Scheduler parameters saved."

        # Close the window after saving.
        self.params_frame.dispose()


    def cancel_schedule_parameters_action(self, event):
        """Closes the window without saving."""
        self.params_frame.dispose()

    # --- Validation Methods ---

    def validate_start_hour(self, field):
        """Validates the Start Hour field."""
        try:
            value = int(field.getText())
            if not (0 <= value <= 23):
                OptionDialog().displayMessage("Start Hour must be between 0 and 23.")
                return False
        except ValueError:
            OptionDialog().displayMessage("Start Hour must be a valid number.")
            return False
        return True

    def validate_end_hour(self, field):
        """Validates the End Hour field."""
        try:
            value = int(field.getText())
            if not (0 <= value <= 23):
                OptionDialog().displayMessage("End Hour must be between 0 and 23.")
                return False
        except ValueError:
            OptionDialog().displayMessage("End Hour must be a valid number.")
            return False
        return True

    def validate_fast_clock_rate(self, field):
        """Validates the Fast Clock Rate (Running) field."""
        try:
            value = int(field.getText())
            if value <= 0:
                OptionDialog().displayMessage("Fast Clock Rate (Running) must be a positive number.")
                return False
        except ValueError:
            OptionDialog().displayMessage("Fast Clock Rate (Running) must be a valid number.")
            return False
        return True

    def validate_fast_clock_off_rate(self, field):
        """Validates the Fast Clock Rate (Outside Hours) field."""
        try:
            value = int(field.getText())
            if not (1 <= value <= 100):
                OptionDialog().displayMessage("Fast Clock Rate (Outside Hours) must be between 1 and 100.")
                return False
        except ValueError:
            OptionDialog().displayMessage("Fast Clock Rate (Outside Hours) must be a valid number.")
            return False
        return True

    def validate_margin(self, field):
        """Validates the Scheduling Margin field."""
        try:
            value = int(field.getText())
            if not (0 <= value <= 20):
                OptionDialog().displayMessage("Scheduling Margin must be between 0 and 20.")
                return False
        except ValueError:
            OptionDialog().displayMessage("Scheduling Margin must be a valid number.")
            return False
        return True

    def directory(self):
        path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "hourlySchedule"
        if not os.path.exists(path):
            os.makedirs(path)
        return path + java.io.File.separator

    def write_list(self, a_list):
        # store list in binary file so 'wb' mode
        file = self.directory() + "hourlySchedule.txt"
        if self.logLevel > 0: print "hourlySchedule" , a_list
        if self.logLevel > 0: print "file" , file
        with open(file, 'wb') as fp:
            if self.logLevel > 0: print "a_list", a_list
            i = 0
            for items in a_list:
                if self.logLevel > 0: print "items", items
                fp.write('%s' %items)
                if i < 5 : fp.write(",")
                i+=1
                # for item in items:
                #     if self.logLevel > 0: print "item", item
                #     fp.write('%s' %item)
                #     if i < 3 : fp.write(",")
                #     i+=1
                # fp.write('\n')

    # Read list to memory
    def read_list(self):
        # for reading also binary mode is important
        file = self.directory() + "hourlySchedule.txt"
        n_list = []
        try:
            with open(file, 'rb') as fp:
                for line in fp:
                    # print "line", line
                    # x = line[:-1]
                    # print x
                    y = line.split(",")
                    if self.logLevel > 0: print "y" , y
                    n_list = y
            return n_list
        except:
            return ["", "", "", "", "", ""]

    def directory2(self):
        path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "train_operators_emblem"
        if not os.path.exists(path):
            os.makedirs(path)
        return path + java.io.File.separator

    def write_list2(self, a_list):
        # store list in binary file so 'wb' mode
        file = self.directory2() + "train_operator_emblem.txt"
        if self.logLevel > 0: print "train_operator_emblem" , a_list
        if self.logLevel > 0: print "file" , file
        with open(file, 'wb') as fp:
            if self.logLevel > 0: print "a_list", a_list
            i = 0
            for items in a_list:
                if self.logLevel > 0: print "items", items
                fp.write('%s' %items)
                if i < 5 : fp.write(",")
                i+=1


    # Read list to memory
    def read_list2(self):
        # for reading also binary mode is important
        file = self.directory2() + "train_operator_emblem.txt"
        n_list = []
        try:
            with open(file, 'rb') as fp:
                for line in fp:
                    # print "line", line
                    # x = line[:-1]
                    # print x
                    y = line.split(",")
                    if self.logLevel > 0: print "y" , y
                    n_list = y
            return n_list
        except:
            return ["", "", "", "", "", ""]

    def is_time_format(self, input):
        try:
            time.strptime(input, '%H:%M')
            return True
        except IndexError:
            if self.logLevel > 0: print "a"
        except ValueError:
            return False

    def setup_minute_time_listener_to_schedule_trains(self):
        global tListener
        global timebase
        global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, \
            scheduling_margin_gbl, scheduling_in_operation_gbl
        global schedule_trains_hourly
        global minute_time_listener_setup

        if self.logLevel > 0: print "Setting up Time Scheduler"
        timebase = jmri.InstanceManager.getDefault(jmri.Timebase)

        # set up timebase and start at midnight
        if self.logLevel > 0: print "******************************************set timebase hour"

        self.set_default_scheduling_values()

        self.set_timebase_start_hour(int(start_hour_gbl)-1, 45)
        self.set_timebase_start_hour(12, 0)
        #
        # attach a listener to the timebase.
        tListener = TimeListener()


        # to set the rate, the timebase needs to be running
        mystate = timebase.getRun()
        if timebase.getRun() == False:
            self.swap_timebase_state_run_stop()
        timebase.userSetRate(float(fast_clock_rate))
        desired_state = False
        if False != timebase.getRun():
            self.swap_timebase_state_run_stop()

        minute_time_listener_setup = True
        self.init = True

    def set_timebase_start_hour(self, hour, minute):
        from java.util import Date
        global timebase
        mystate = timebase.getRun()
        if mystate == False:
            self.swap_timebase_state_run_stop()
        timebase = jmri.InstanceManager.getDefault(jmri.Timebase)
        date = Date(2020,10,21)     #any date really
        date.setHours(hour)
        date.setMinutes(minute)
        timebase.userSetTime(date)   ## set to 00:00 21/10/2020 (want the time to be 00:00)
        if mystate != timebase.getRun():
            self.swap_timebase_state_run_stop()

    def train_scheduler(self):
        #reset fast clock
        self.reset_clock()

        #go through operations:trains and get the train starting now

    def reset_clock(self):
        pass

    f = None

    def display_help(self):
        ref = "html.scripthelp.DispatcherSystem.DispatcherSystem"
        jmri.util.HelpUtil.displayHelpRef(ref)

    def show_analog_clock(self):
        if self.f == None:
            self.f = jmri.jmrit.analogclock.AnalogClockFrame()
            self.f.setSize(300, 200)
            self.f.setLocationRelativeTo(None)
            if self.frame != None:
                self.f.setLocation(self.frame.getX() + self.frame.getWidth(), self.frame.getY());
        self.f.setVisible(True)

    def set_time_to_beginning_of_hourly_train_working(self):
        global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, scheduling_margin_gbl, scheduling_in_operation_gbl
        # start_hour_gbl is the start of hourly working
        start_hour = int(start_hour_gbl)
        if self.logLevel > 0: print "start_hour", start_hour
        self.set_timebase_start_hour(start_hour -1, 55)

    def show_routes(self):
        # a = jmri.jmrit.operations.routes.RoutesTableAction()
        # a.actionPerformed(None)
        CreateAndShowGUI6(self)

    def show_operations_trains(self):
        global CreateAndShowGUI4_frame
        # delete any previous frames
        if "CreateAndShowGUI4_frame" in globals():
            CreateAndShowGUI4_frame.setVisible(False)
        else:
            # print "not in globals"
            pass

        # show dispatcher system form
        CreateAndShowGUI4(self)

    def get_train_list(self):
        TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager)
        train_list = TrainManager.getTrainsByTimeList()
        return train_list

from java.util.concurrent import TimeUnit

class TimeListener(java.beans.PropertyChangeListener):
    # This is called every minute since it has been attached as timebase.addMinuteChangeListener(tListener)
    def __init__(self):
        # global timetable_gbl
        self.logLevel = 0
        if self.logLevel > 0: print "set up TimeListener"
        self.prev_time = 0
        if self.logLevel > 0: print "end TimeListener"

    def propertyChange(self, event):

        global fast_clock_running_at_operational_speed
        if 'fast_clock_running_at_at_operational_speed' not in globals():
            fast_clock_running_at_operational_speed = True
        global minutes_old2, minutes_old3
        global schedule_trains_hourly
        global timetable_gbl, run_local_timetable_gbl
        global fast_clock_rate
        global send_mqtt_messages_gbl

        if 'minutes_old3' not in globals():
            minutes_old3 = 0
        # print "a"
        minutes_old = int(event.getOldValue())
        # print "b"
        minutes = int(event.getNewValue())
        # print "c", minutes

        if self.logLevel > 0: print "property change", "minutes", minutes,

        if 'minutes_old2' not in globals():
            minutes_old2 = minutes_old

        if self.logLevel > 0: print "before: minutes_old3", minutes_old3

        if self.logLevel > 0: print "minutes_old", minutes_old, "minutes", minutes, "minutes_old2", minutes_old2, \
            "(minutes_old - minutes_old2)", (minutes_old - minutes_old2), \
            "(minutes_old - minutes_old2) % 60 == 1", (minutes_old - minutes_old2) % 60 == -1

        # if self.logLevel > 0: print "property change", event.newValue
        if (minutes_old - minutes_old2) % 60 != 0:
            # when we set the fast clock in the event timer it triggers a new event at the same time
            # we then get into a recursion. This ignores the second call at the same time
            if self.logLevel > 0: print "two events are triggered with the same minutes"
        else:
            if self.logLevel > 0: print "timeListener: normal Operation"
            if self.logLevel > 0: print "minutes_old", minutes_old, "minutes", minutes, "minutes_old2", minutes_old2, \
                "(minutes - minutes_old2) % 60 ", (minutes - minutes_old2) % 60
            # print "y", minutes, type(minutes), int(minutes)
            if int(minutes) % 10 == 0:               # only check every 10 minutes to prevent problens at non_operational_speeds
                # don't just check at 0 minutes in case train us started not on the hour
                if self.logLevel > 0: print "minutes", int(minutes), "int(minutes) % 10", int(minutes) % 10, "minutes", minutes
                # print "e"
                minutes_old2 = minutes
                # print "set fast clock rate"
                self.set_fast_clock_rate()      # sets global fast_clock_at_operational_speed
            self.process_operations_trains(event)    # scheduled trains

            send_mqtt_messages_gbl = True
            if 'send_mqtt_messages_gbl' not in globals():
                send_mqtt_messages_gbl = False
            if 'run_local_timetable_gbl' not in globals():
                run_local_timetable_gbl = False
            # print "send_mqtt_messages_gbl", send_mqtt_messages_gbl
            if run_local_timetable_gbl or send_mqtt_messages_gbl:
                # do not display more frequently than 5 secs
                # print "f1", fast_clock_rate
                fcr = int(str(fast_clock_rate))
                x = (5.0 / 60.0)
                # print "x", x, "fcr", fcr, "x*fcr", x * fcr
                no_fast_minutes = int(x * fcr)
                if no_fast_minutes == 0: no_fast_minutes = 1
                if minutes % no_fast_minutes == 0:
                    Trigger_Timetable(minutes)
            else:
                # print "HIDING TIMETABLE WINDOW"
                # print "run_timetable_gbl", run_timetable_gbl, "send_mqtt_messages_gbl", send_mqtt_messages_gbl
                if 'timetable_gbl' in globals():
                    # timetable_gbl = None
                    if timetable_gbl != None:
                        timetable_gbl.hideWindow()

        minutes_old2 = minutes    # use minutes_old2 to prevent recursion
        minutes_old3 = minutes_old
        if self.logLevel > 0: print "after: minutes_old3", minutes_old3
        if self.logLevel > 0: print "end property change" ; print ""

    def stop(self):
        tListener.cancel()

    def set_fast_clock_rate(self):
        # set the fast clock rate
        global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, scheduling_margin_gbl, scheduling_in_operation_gbl
        global schedule_trains_hourly
        global timebase
        global fast_clock_running_at_operational_speed

        # if self.logLevel > 0:  print "TimeListener: change",event.propertyName, "from", event.oldValue, "to", event.newValue

        if self.logLevel > 0: print "set_fast_clock_rate: 1"
        if self.speed_not_operational_gbl__is_defined():
            if self.logLevel > 0: print "set_fast_clock_rate: 2", speed_not_operational_gbl

            # if schedule_trains_hourly:
            if True:
                hour = int(timebase.getTime().getHours())
                minutes = int(timebase.getTime().getMinutes())
                rate = timebase.userGetRate()


                if self.logLevel > 0: print "set_fast_clock_rate:", "schedule_trains_hourly", schedule_trains_hourly
                fast_clock_during_non_operational_times = speed_not_operational_gbl
                if self.logLevel > 0: print "fast clock during non operational_times", fast_clock_during_non_operational_times
                if self.logLevel > 0: print "hour", hour, "start_hour_gbl", start_hour_gbl, "end_hour_gbl", end_hour_gbl, \
                    "fast_clock_rate", fast_clock_rate, "speed_not_operational_gbl", speed_not_operational_gbl, \
                    "hour >= start_hour_gbl and hour <= end_hour_gbl", hour >= int(start_hour_gbl) and hour <= int(end_hour_gbl)
                if hour >= int(start_hour_gbl) and hour <= int(end_hour_gbl):
                    # or hour == int(start_hour_gbl - 1) % 24 and minutes == 59:
                    if rate != fast_clock_rate:       # check to stop recursion error
                        timebase.userSetRate(float(fast_clock_rate))
                        fast_clock_running_at_operational_speed = True
                    if self.logLevel > 0: print "set_fast_clock_rate:", "fast_clock_rate slow", fast_clock_rate
                    pass
                else:
                    if self.logLevel > 0: print "fast_clock_during_non_operational_times", fast_clock_during_non_operational_times
                    fcr = fast_clock_during_non_operational_times
                    if fcr > 100 : fcr = 100  # set to maximum
                    if rate != fcr:
                        timebase.userSetRate(float(fcr))
                        fast_clock_running_at_operational_speed = False
                    if self.logLevel > 0: print "set_fast_clock_rate:", "fcr", fcr
        else:
            print "speed_not_operational_gbl__is_defined()", False

    def process_operations_trains(self, event ):
        global timebase
        global schedule_trains_hourly
        global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, scheduling_margin_gbl, scheduling_in_operation_gbl
        global scheduled
        global trains_to_be_scheduled
        if self.logLevel > 0: print " ******   in process_operations_trains"
        if self.logLevel > 0: print "A1"
        if 'schedule_trains_hourly' not in globals():
            schedule_trains_hourly = False
        if self.logLevel > 0: print "in process_operations_trains", "schedule_trains_hourly", schedule_trains_hourly

        hour = int(timebase.getTime().getHours())
        if self.logLevel > 1: print "type hour" , type(hour)
        minutes = event.newValue
        if self.logLevel > 1: print "type minutes", type(minutes)
        self.curr_time = minutes + hour * 60
        if self.logLevel > 1: print "curr_time", self.curr_time
        self.prev_time = self.curr_time -1
        if self.logLevel > 1: print "prev_time", self.prev_time

        # only schedule within stat_hour and end_hour
        if int(start_hour_gbl) <= hour <= int(end_hour_gbl):
            pass    # need to process trains
        else:
            if self.logLevel > 0: print "returning in process_operational_trains"
            return  # outside operational time

        if self.logLevel > 0: print "A2"
        if self.logLevel > 1: print "TimeListener: process_operations_trains"
        TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager)
        train_list = TrainManager.getTrainsByTimeList()
        train_list = [train for train in train_list if "skip" not in train.getComment()]  # exclude trains marked as 'don't schedule' in Scheduled trains table
        if self.logLevel > 0: print "train_list",train_list
        #if self.logLevel > 1: print "prev_time", self.prev_time, "curr_time", self.curr_time
        if self.logLevel > 0: print "a3"
        for train in train_list:
            if self.logLevel > 1: print "*******************"
            if self.logLevel > 1: print ("train list: departure time: ", str(train.getDepartureTime()), str(train.getName()))
            if self.logLevel > 1: print "prev_time", self.prev_time, "curr_time", self.curr_time, "train.getDepartTimeMinutes()", train.getDepartTimeMinutes()
        #get the train that is triggered in the current minute
        if event == None:
            if self.logLevel > 0: print "event is none , returning"
            return

        if self.logLevel > 0: print "A4"

        # schedule the train taking account of the repeat command
        # trains_to_start = []
        if self.logLevel > 0: print "train_list", train_list, "trains_to_be_scheduled", trains_to_be_scheduled
        for train in train_list:
            comment = train.getComment()
            repeat_command = self.find_between(comment, "[repeat-", "-repeat]")
            if self.logLevel > -1: print "train", train, "repeat_command", repeat_command
            max = int(minutes)
            min = (int(minutes) - 1)
            mid = int(train.getDepartTimeMinutes())

            if repeat_command == "Once":
                if max == 0:
                    min += 1; mid += 1; max += 1
                print "hour", hour, "minutes", minutes, "mid", mid, "min", min, "max", max, "train.getDepartTimeMinutes()", train.getDepartTimeMinutes()
                min1 = hour - 1
                mid1 = int(train.getDepartureTimeHour())
                max1 = hour
                if max1 == 0:      # ensure mid lies between min amd max (ensure we don't have 1 < 0 <= 0)
                    min1 += 1; mid1 += 1; max1 += 1
                print "min1", min1, "mid1", mid1, "max1", max1, "(min1) <  (mid1) <= (max1)", (min1) <  (mid1) <= (max1)
                if (min % 60 < (mid % 60) <= max % 60) and \
                        ((min1) <  (mid1) <= (max1)):
                    if train not in trains_to_be_scheduled:
                        trains_to_be_scheduled.append(train)
                        scheduled[train] = False
            elif repeat_command == "Repeat every 20 mins":
                if max % 20 == 0:
                    min += 1; mid += 1; max += 1      # ensure mid lies between min amd max (ensure we don't have 59 < 0 <= 0)
                if (min % 20 < (mid % 20) <= max % 20):
                    if train not in trains_to_be_scheduled:
                        trains_to_be_scheduled.append(train)
                        scheduled[train] = False
            elif repeat_command == "Repeat every 30 mins":
                if max % 30 == 0:
                    min += 1; mid += 1; max += 1
                if (min % 30 < (mid % 30) <= max % 30):
                    if train not in trains_to_be_scheduled:
                        trains_to_be_scheduled.append(train)
                        scheduled[train] = False
            elif repeat_command == "Repeat every Hour":
                if self.logLevel > 0: print "min", min, "max", max, "mid", mid
                if max == 0:
                    min += 1; mid += 1; max += 1
                    if self.logLevel > 0: print "min", min, "max", max, "mid", mid
                if (min < (mid % 60) <= max):
                    if train not in trains_to_be_scheduled:
                        trains_to_be_scheduled.append(train)
                        scheduled[train] = False
            elif repeat_command == "Repeat every 2 Hours":
                if max == 0:
                    min += 1; mid += 1; max += 1
                min1 = hour - 1
                mid1 = int(train.getDepartureTimeHour())
                max1 = hour
                if max1 % 2 == 0:      # ensure mid lies between min amd max (ensure we don't have 1 < 0 <= 0)
                    min1 += 1; mid1 += 1; max1 += 1
                if (min < (mid % 60) <= max) and \
                        ((min1 % 2) <  (mid1 % 2) <= (max1 % 2)):
                    if train not in trains_to_be_scheduled:
                        trains_to_be_scheduled.append(train)
                        scheduled[train] = False
            else:
                if self.logLevel > 0: print "incorrect repeat command", repeat_command
                # assume set to once
                if self.prev_time < int(train.getDepartTimeMinutes()) <= self.curr_time and \
                        "skip" not in train.getDescription():   # if skip in description of scheduled Train do not run the train
                    if train not in trains_to_be_scheduled:
                        trains_to_be_scheduled.append(train)
                        scheduled[train] = False
            if self.logLevel > 0: print "trains_to_be_scheduled", trains_to_be_scheduled

        if self.logLevel > 0: print "Time listener: trains_to_be_scheduled", trains_to_be_scheduled
        if self.logLevel > 0: print "scheduled", scheduled
        if self.logLevel > 0: print "trains_to_be_scheduled", trains_to_be_scheduled

    def speed_not_operational_gbl__is_defined(self):
        global start_hour_gbl, end_hour_gbl, fast_clock_rate, speed_not_operational_gbl, scheduling_margin_gbl, scheduling_in_operation_gbl
        try:
            speed_not_operational_gbl
        except NameError:
            if self.logLevel > 0: print("well, it WASN'T defined after all!")
            return False
        else:
            if self.logLevel > 0: print("sure, it was defined.")
            return True

    def find_between(self, s, first, last):
        try:
            start = s.index(first) + len(first)
            end = s.index(last, start)
            return s[start:end]
        except IndexError:
            if self.logLevel > 0: print "D"
        except ValueError:
            return ""

class Trigger_Timetable:
    def __init__(self, minutes):
        global timetable_triggered_gbl
        global print_count
        timetable_triggered_gbl = True
        if minutes == None: return
        self.run(minutes)

    def run(self, minutes):
        t1 = Thread(target=self.send_timetable_and_clock_via_mqtt, args=(minutes,))
        t1.start()
        t1.join()

    def send_timetable_and_clock_via_mqtt(self, minutes):
        global station_name_list_gbl, group_location_gbl, run_local_timetable_gbl
        global timetable_gbl
        self.logLevel = 0
        global timebase, print_count
        # print "****************start send_timetable_and_clock_via_mqtt"
        hour = int(timebase.getTime().getHours())
        time = str(hour).zfill(2) + ":" + str(minutes).zfill(2)
        file = self.directory2() + "train_operator_emblem.txt"
        event = ""

        event = self.read_list2()[0]
        try:
            self.send_clock_message(hour, minutes, event)
        except:
            if "print_count" not in globals(): print_count = 0
            if print_count < 1: print "clock message not sent"
            print_count += 1
        if "station_name_list_gbl" not in globals():
            station_name_list_gbl = ""
        if "group_location_gbl" not in globals():
            group_location_gbl = ""
        # get list of origins, destinations and times at intermediate stations
        timetable = self.get_timetable(hour, minutes)
        if 'group_location_gbl' != "" and 'station_name_list_gbl' != "":
            station_name = group_location_gbl
            station_names_list = station_name_list_gbl
        else:
            station_name = 'Not Set'
            station_names_list = ['Not Set']

        self.generate_local_timetable(station_name, station_names_list, time, timetable)

        if "run_local_timetable_gbl" not in globals():
            print "run_local_timetable_gbl not defined"
            return

        if run_local_timetable_gbl == None:
            print "run_local_timetable_gbl None"
            return

        if run_local_timetable_gbl:
            if "timetable_gbl" in globals():
                if timetable_gbl != None:
                    timetable_gbl.frame.setVisible(True)
        else:
            if "timetable_gbl" in globals():
                if timetable_gbl != None:
                    timetable_gbl.frame.setVisible(False)
        try:
            self.send_timetable_messages(timetable)
        except:
            pass

    def find_between(self, s, first, last):
        try:
            start = s.index(first) + len(first)
            end = s.index(last, start)
            return str(s[start:end])
        except ValueError:
            return ""
        except IndexError:
            print "index error find_between", "first", first, "last", last

    def get_timetable(self, hour, minutes1):

        global schedule_trains_hourly
        global start_hour_gbl, end_hour_gbl
        global fast_clock_rate
        self.curr_time = minutes1 + hour * 60
        timetable = []

        TrainManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.trains.TrainManager)
        train_list = TrainManager.getTrainsByTimeList()

        for train in train_list:
            if self.logLevel > 0: print "train", train, "train.getDescription()", train.getDescription()

            if train.getDescription() is not None and "skip" not in train.getDescription():
                if self.logLevel > 0: print "train", train, train.getDescription()
                comment = train.getComment()
                repeat = self.find_between(comment, "[repeat-", "-repeat]")
                departure_time_minutes = train.getDepartTimeMinutes() % 60
                departure_time_hour = train.getDepartureTimeHour()
                train_name = train.getName()

                if repeat == "Once":
                    minutes = [departure_time_minutes]
                elif repeat == "Repeat every 20 mins":
                    minutes = [minutes for minutes in range(0,59) if (minutes % 20) == (int(departure_time_minutes) % 20)]
                elif repeat == "Repeat every 30 mins":
                    minutes = [minutes for minutes in range(0,59) if (minutes % 30) == (int(departure_time_minutes) % 30)]
                elif repeat == "Repeat every Hour":
                    minutes = [departure_time_minutes]
                elif repeat == "Repeat every 2 Hours":
                    minutes = [departure_time_minutes]
                else:
                    minutes = [0]

                if repeat == "Once":
                    hours = [departure_time_hour]
                else:
                    if hour < int(end_hour_gbl):
                        start_hour = max(hour, int(start_hour_gbl))
                        end_hour = max(hour + 3, int(start_hour_gbl))
                    else:
                        start_hour = int(start_hour_gbl)
                        end_hour = int(start_hour_gbl) + 3
                    hours = [hour1 for hour1 in range(start_hour, end_hour)]
                    if repeat == "Repeat every 2 Hours": #update hours if 2 hourly
                        hours = [hour1 for hour1 in hours if (int(train.getDepartureTimeHour()) % 2 == hour1 % 2)]

                for train_mins in minutes:
                    for train_hour in hours:
                        depart_time = int(str(train_mins)) + int(str(train_hour)) * 60

                        train_route_start_time = str(train_hour).zfill(2) + ":" + str(train_mins).zfill(2)
                        if self.logLevel > 0: print "train", train, train.getDescription(), "train_route_start_time", train_route_start_time
                        train_route = train.getRoute()
                        if train_route is not None:
                            if self.logLevel > 0: print "train_route", train_route
                            locations = [location for location in train_route.getLocationsBySequenceList() \
                                         if ".py" not in location.getName()]
                            first_location = locations[0]
                            first_station = str(first_location.getName())
                            last_location = locations[-1]
                            last_station = str(last_location.getName())
                            comments = [location.getComment() for location in train_route.getLocationsBySequenceList() \
                                        if ".py" not in location.getName()]
                            journey_duration = 0
                            for comment in comments:
                                duration_sec = self.find_between(comment, "[duration_sec-", "-duration_sec]")
                                if self.logLevel > 0: print "duration_sec", duration_sec
                                if duration_sec != "":
                                    duration = ((float(duration_sec) * int(str(fast_clock_rate))) / 60.0)  # fast minutes
                                else:
                                    # print "setting duration 0"
                                    duration = 0
                                journey_duration += int(duration)

                            for i, route_location in enumerate(train_route.getLocationsBySequenceList()):
                                station_name = str(route_location.getName())
                                platform_name = str(MyTableModel7().get_location_platform(route_location.getLocation()))
                                if self.logLevel > 0: print "platform_name", platform_name
                                if platform_name == "":
                                    platform_name = station_name
                                if self.logLevel > 0: print "platform_name", platform_name
                                if self.logLevel > 2: print "****************************", station_name, "***************************"
                                if ".py" in station_name:   # exclude actions
                                    break
                                timetable_entry_names = ["train_name", "station_name", "station_departure_time", "last_station",
                                                         "last_station_arrival_time", "via"]
                                # remove items from start of via list, and the destination
                                locations1 = train_route.getLocationsBySequenceList()
                                locations = [str(loc) for loc in locations1]

                                via = locations[i+1:-1]
                                via = [location2 for location2 in via if ".py" not in location2]
                                if via == []:
                                    via = "-"
                                if i != 0 and last_station == station_name:
                                    via = ["Terminates Here"]
                                via = str(via).replace('[','').replace(']','').replace("'", "")

                                comment = route_location.getComment()
                                if i == 0:
                                    station_departure_time = train_route_start_time
                                    time_to_station = 0
                                else:
                                    duration_sec = self.find_between(comment, "[duration_sec-", "-duration_sec]")
                                    if str(duration_sec) == "":
                                        duration_sec = 0

                                    if self.logLevel > 2: print route_location, "duration_sec", duration_sec
                                    duration = float((float(duration_sec) * int(str(fast_clock_rate))) / 60.0)
                                    if self.logLevel > 2: print route_location, "duration", duration

                                    time_to_station = int(duration)
                                    if self.logLevel > 2: print "time_to_station", time_to_station

                                previous_departure_time = station_departure_time
                                if self.logLevel > 0:
                                    print train_name, "previous_departure_time", previous_departure_time
                                station_departure_time = self.add_times(station_departure_time, time_to_station)
                                if self.logLevel > 0: print train_name, route_location, "station_departure_time", station_departure_time

                                # if the wait_time and journey_time have been set we can set the arrival time
                                wait_time = self.find_between(comment, "[wait_time-", "-wait_time]")
                                journey_time = self.find_between(comment, "[journey_time-", "-journey_time]")
                                if journey_time == "":
                                    journey_time = "0"
                                # convert journey time to fast minutes
                                journey_time_fast_mins = ((float(str(journey_time)) * int(str(fast_clock_rate))) / 60.0)
                                if wait_time != "" and journey_time != "":
                                    if i == -1:
                                        station_arrival_time = station_departure_time
                                    else:
                                        if self.logLevel > 0: print train_name, route_location, "journey_time", journey_time
                                        station_arrival_time = self.add_times(previous_departure_time, journey_time_fast_mins)
                                else:
                                    if i == 0:
                                        station_arrival_time = ""
                                    else:
                                        station_arrival_time = station_departure_time

                                [h, m] = station_departure_time.split(":")
                                station_departure_time_in_mins = int(m) + int(h) * 60
                                # [h, m] = station_arrival_time.split(":")
                                # station_arrival_time_in_mins = int(m) + int(h) * 60

                                if i != 0 and last_station == station_name:
                                    station_departure_time = ""

                                # make sure we don't display trains that have a departure time > current time
                                # keep departures up for 1 fast minutes after the departure time
                                if self.curr_time - 1 < station_departure_time_in_mins:

                                    timetable_entry = [train_name, \
                                                       station_name , \
                                                       platform_name , \
                                                       station_arrival_time, \
                                                       station_departure_time, \
                                                       first_station, \
                                                       last_station, \
                                                       via]

                                    timetable.append(timetable_entry)
        #sort timetable by time
        timetable.sort(key = lambda row: max(row[3],row[4]))
        return timetable

    def generate_local_timetable(self, station_name, station_names_list, time, timetable):
        global timetable_gbl
        if "timetable_gbl" not in globals():
            timetable_gbl = Timetable(station_name)
            timetable_gbl.update_timetable(station_name, station_names_list, time, timetable)
        elif timetable_gbl == None:
            timetable_gbl = Timetable(station_name)
            timetable_gbl.update_timetable(station_name, station_names_list, time, timetable)
        else:
            # update the Timetable, Timetable class has already been initiated
            timetable_gbl.update_timetable(station_name, station_names_list, time, timetable)

    def send_timetable_messages(self,timetable):
        i = 0
        msg = "["
        for [train_name, \
             station_name , \
             platform , \
             station_arrival_time, \
             station_departure_time, \
             first_station, \
             last_station, \
             via] in timetable:
            msg += '{"type" : "' + "schedule" + '", ' + \
                   '"train_name" : "' + str(train_name) + '", ' + \
                   '"station_name" : "' + str(station_name) + '", ' + \
                   '"platform" : "' + str(platform) + '", ' + \
                   '"station_arrival_time" : "' + str(station_arrival_time) + '", ' + \
                   '"station_departure_time" : "' + str(station_departure_time) + '", ' + \
                   '"first_station" : "' + str(first_station) + '", ' + \
                   '"last_station" : "' + str(last_station) + '", ' + \
                   '"via" : "' + str(via) + '"},'
            i += 1
        msg = msg[:-1]
        msg += "]"
        self.send_mqtt_message(msg)

    def send_mqtt_message(self, msg):
        global print_count
        try:
            # Find the MqttAdapter
            mqttAdapter = jmri.InstanceManager.getDefault( jmri.jmrix.mqtt.MqttSystemConnectionMemo ).getMqttAdapter()
            # create content to send "/jmri/timetable message content"
            topic = "jmri/timetable"
            payload = msg
            mqttAdapter.publish(topic, payload)
        except:
            if "print_count" not in globals(): print_count = 0
            if print_count < 1: print "failure mqtt message"
            print_count += 1

    def send_clock_message(self, hour, minutes, event):

        msg = '[{"type" : "' + "clock" + '", ' + \
              '"time" : "' + str(hour).zfill(2) + ":" + str(minutes).zfill(2) + '",' \
                                                                                '"emblem" : "' + str(event) + '"}]'
        self.send_mqtt_message(msg)

    def add_times(self, station_departure_time, time_to_station):
        # add time_to_station to station_departure time
        # station_departure_time is in form hh:mm
        # print "time_to_station", time_to_station  , "should be mins"
        [hours, mins] = station_departure_time.split(":")
        # print "hours", hours, "mins", mins
        hour = int(hours) + int(time_to_station) // 60
        min = (int(mins) + int(time_to_station)) % 60
        # print "hour", hour, "min", min
        station_departure_time_new = str(hour).zfill(2) + ":" + str(min).zfill(2)
        # print "station_departure_time_new", station_departure_time_new
        return station_departure_time_new

    def directory2(self):
        # print "directory2"
        path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "train_operators_emblem"
        # print "path", path
        if not os.path.exists(path):
            os.makedirs(path)
        return path + java.io.File.separator

    def write_list2(self, a_list):
        # store list in binary file so 'wb' mode
        file = self.directory2() + "train_operator_emblem.txt"
        if self.logLevel > 0: print "train_operator_emblem" , a_list
        if self.logLevel > 0: print "file" , file
        with open(file, 'wb') as fp:
            if self.logLevel > 0: print "a_list", a_list
            i = 0
            for items in a_list:
                if self.logLevel > 0: print "items", items
                fp.write('%s' %items)
                if i < 5 : fp.write(",")
                i+=1

    # Read list to memory
    def read_list2(self):
        # for reading also binary mode is important
        file = self.directory2() + "train_operator_emblem.txt"
        # print "file", file
        n_list = []
        try:
            with open(file, 'rb') as fp:
                for line in fp:
                    # print "line", line
                    # x = line[:-1]
                    # print x
                    y = line.split(",")
                    if self.logLevel > 0: print "y" , y
                    n_list = y
            return n_list
        except:
            return ["", "", "", "", "", ""]

class RunRoute(jmri.jmrit.automat.AbstractAutomaton):

    def __init__(self, route, graph, station_from, station_to, no_repetitions, train_name, \
                 delay = 0, scheduling_train = False, set_departure_times = False, train = None):

        # print ("route" , route, "station_from", station_from, "station_to", station_to, \
        #                "no_repetitions", no_repetitions, "train_name", train_name, \
        #                "scheduling_train", scheduling_train)

        # station_from is set to the initial position of the train, not necessarily
        # the start position of the route
        # station_to is set only if returning to start position
        # in that case it is set to station_from
        # the route gives the stations on the route

        # note station_to and station_from are strings, while elements of route are locations
        self.logLevel = 0
        if self.logLevel > 0: print "loglevel", self.logLevel

        if self.logLevel > 0: print "in init RunRoute"
        if self.logLevel > 0: print route, station_from, station_to, no_repetitions, train_name, delay

        self.delay = delay
        self.scheduling_train = scheduling_train
        self.set_departure_times = set_departure_times
        if self.logLevel > 0: print "set_departure_times", set_departure_times
        self.route = route
        self.train = train   # only used if scheduling_train = True
        self.train_name = train_name

        if route is None or train_name is None:
            self.mycount = None
            self.no_repetitions = -1
            if self.logLevel > 0: print "RunRoute: route == ", route, " train_name == ", train_name
        else:
            if self.logLevel > 0: print "RunRoute: route =", route
            self.graph = graph
            self.station_from = station_from
            self.station_to = station_to
            self.no_repetitions = no_repetitions
            self.mycount = 0
            # self.train_name_in = train_name
            self.train_name = train_name        # null if train not in start block

            # set up station_list
            station_list_locations = self.route.getLocationsBySequenceList()
            #convert station_list to strings
            station_list = [location.getName() for location in station_list_locations]
            station_comment_list = [location.getComment()  for location in station_list_locations]
            self.initial_station_in_route = station_list[0]

            # prepend station_from if required
            self.prepended = False
            if self.logLevel > 0: print "station_list before", station_list, "self.station_from",self.station_from,"self.station_to",self.station_to,"station_list[0]",station_list[0]
            if self.station_from == None:                       #ensure route starts at station_from
                pass
            elif self.station_from != station_list[0]:
                try:
                    station_list.insert(0,self.station_from)
                    station_comment_list.insert(0, None)
                except:
                    if self.logLevel > 0: print "fred"
                self.prepended = True                           # we have to remove this initial station if we are repeating
            if self.logLevel > 0: print "station_list",station_list

            # append station_to if required
            if self.station_to == None:                         #ensure route ends at station_to
                pass
            elif self.station_to != station_list[-1]:
                station_list.append(self.station_to)
                try:
                    station_comment_list.append(None)
                except:
                    if self.logLevel > 0: print "jim"
            if self.logLevel > 0: print "station_list",station_list

            # if repeating append initial station in route
            if self.no_repetitions > 0:                             #ensure route end at start point if repeating
                if self.station_to != self.initial_station_in_route:
                    if station_list[-1] != self.initial_station_in_route:
                        station_list.append(self.initial_station_in_route)
                        station_comment_list.append(None)
            if self.logLevel > 0: print "station_list after", station_list

            self.station_list = station_list
            self.station_comment_list = station_comment_list

            if self.logLevel > 0: print "self.station_comment_list", self.station_comment_list

            # ignore the number of repetitions if station_to was not set to station_from
            if self.station_list[0] != self.station_list[-1]:
                self.no_repetitions = 0

    def handle(self):
        if self.route is not None and self.train_name is not None:
            if self.logLevel > 0: print "in handle", self.mycount
            if self.delay > 0 and self.mycount == 0:  # only delay on the first iteration
                self.waitMsec(self.delay)
            if int(self.mycount) <= int(self.no_repetitions):
                # print "repeating", "self.mycount", self.mycount, "self.no_repetitions", self.no_repetitions
                if self.logLevel > 0: print "station_list in handle", self.station_list, "in handle", self.mycount
                response = self.run_route(self.train_name)

                if self.logLevel > 0: print "prepended", self.prepended
                if self.mycount == 0 and self.prepended:
                    if self.logLevel > 0: print "station_list before pop", self.station_list
                    self.station_list.pop(0)
                    self.station_comment_list.pop(0)
                    if self.logLevel > 0: print "station_list after pop", self.station_list
                if self.logLevel > 0: print "returning true", "train_name", self.train_name, "mycount", self.mycount, "reps" , self.no_repetitions

                self.mycount += 1     # 0 first time round
                return True
            else:
                if self.logLevel > 0: print "returning false", "train_name", self.train_name, "mycount", self.mycount, "reps" , self.no_repetitions
                return False

    def run_route(self, train_to_move):
        global check_action_route_flag
        global fast_clock_rate
        if self.logLevel > 0: print "************************************run train******************"
        if self.logLevel > 0:  print "!     start run_route"

        station_from = None
        prev_station_index = 0
        for station_index, station in enumerate(self.station_list):
            # print "station_index", station_index, "station", station, "train_to_move", train_to_move
            if self.logLevel > 0: print "self.scheduling_train", self.scheduling_train

            # do action if one has been requested
            if self.station_is_action(station):  #if the station_name is a python_file
                action = station
                self.execute_action(action)     # execute the python file
            else:
                # print "running at station", "station_from", station_from
                station_to = station  # both now strings
                if station_from != None:    # first time round station_from is not set up
                    # find the accumulated durations
                    if self.scheduling_train or self.set_departure_times:
                        durations = [MyTableModel5().find_between(comment, "[duration_sec-", "-duration_sec]")
                                     for comment in self.station_comment_list]
                        # print "durations 4", durations
                        accumulated_durations = []
                        total = 0
                        for n in durations:
                            try:
                                total += int(n)
                            except:
                                pass
                            accumulated_durations.append(total)
                        if station_index != self.find_row_first_location(self.route):
                            previous_station_index = self.find_row_prev_location(station_index, self.route)
                            station_comment = self.station_comment_list[previous_station_index]  # do not use prev_station_index as it includes actions
                            accumulated_duration = accumulated_durations[previous_station_index]
                        else:
                            station_comment = None
                            accumulated_duration = 0

                        if self.logLevel > 0: print "station", station, "station_comment", station_comment, \
                            "station_index", station_index, "prev_station_index", prev_station_index
                        if self.logLevel > 0: print "accumulated_duration", accumulated_duration

                    if self.logLevel > 0:  print self.route.getName(), "!     moving from", station_from, "to", station_to

                    self.station_from_name = station_from
                    self.station_to_name = station_to
                    start_block = blocks.getBlock(station_from)

                    if self.logLevel > 0:  "start_block",start_block, "station_to", station_to
                    if self.logLevel > 0: print "calling move_between_stations","station_from",station_from,"station_to",station_to,"train_to_move",train_to_move
                    if self.set_departure_times:
                        # print "setting previous time"
                        previous_time = int(round(time.time()))  # in secs

                    if self.scheduling_train:

                        self.wait_for_scheduled_time(self.route, previous_station_index, accumulated_duration, train_to_move)
                        # done when we know the transit name
                        # print "__________________________Start__" + train_to_move + "___________________________________"
                        strpad = station_index * "  "
                        success = self.check_train_in_block_for_scheduling_margin_fast_minutes(start_block, train_to_move, strpad)
                        if success:
                            move_train = MoveTrain(station_from, station_to, train_to_move, self.graph, mode = "scheduling", route = self.route)
                            move_train.move_between_stations(station_from, station_to, train_to_move, self.graph, mode = "scheduling")
                            transit_name = move_train.transit_name
                            print "__________________________End____" + train_to_move + "__transit: " + transit_name
                        else:
                            print "failed to move train - no train in block - have waited for scheduling margin"
                            transit_name = move_train.transit_name
                            print "__________________________End____" + train_to_move + "__transit: " + transit_name
                    else:
                        success = self.check_train_in_block_allow_manual_repositioning(train_to_move, self.station_from_name)
                        if success:
                            move_train = MoveTrain(station_from, station_to, self.train_name, self.graph, route = self.route)
                            move_train.move_between_stations(station_from, station_to, self.train_name, self.graph)
                        move_train = None

                    # train has moved, if we are in departure_time_setting mode, store the journey time
                    if self.logLevel > 0: print "about to store departure times"
                    if self.set_departure_times:
                        if self.logLevel > 0: print "storing departure times"
                        current_time = int(round(time.time()))  # in secs
                        journey_time_in_secs = current_time - previous_time
                        print "previous_time", previous_time, "current_time", current_time
                        if self.logLevel > 0: print "before store", "journey_time_in_secs", journey_time_in_secs
                        self.store_journey_time(self.route, station_index, str(journey_time_in_secs))
                        if self.logLevel > 0: print "after store"

                    if self.logLevel > 0: print "finished move between stations station_from = ", station_from, " station_to = ", station_to
                    end_block = blocks.getBlock(station_to)  #do following in case the block sensor is a bit dodgy
                    end_block.setValue(self.train_name)

                check_action_route_flag = False     # This flag may have been set by the action appearing in the route
                # before this move. It has to be reset.
                # print "check_action_route_flag reset", check_action_route_flag
                station_from = station_to
                prev_station_index = station_index

        if self.scheduling_train:
            fast_minute = 1000*60/int(str(fast_clock_rate))
            self.waitMsec(fast_minute)
        else:
            self.waitMsec(4000)

        if self.logLevel > 0:  print "!     finished run_train"

    def find_row_first_location(self, route):
        # print "find_row_first_location"
        # get the row (sequenceNo) of the first location that is not an action (a python file  xx.py)
        routelocationsSequenceNumber_list = [ [routelocation, routelocation.getSequenceNumber()] \
                                              for routelocation in route.getLocationsBySequenceList() \
                                              if ".py" not in routelocation.getName()]

        # print "routelocationsSequenceNumber_list", routelocationsSequenceNumber_list
        current_val = [[routelocation, sequenceNo] \
                       for [routelocation, sequenceNo] in routelocationsSequenceNumber_list \
                       if 1 == sequenceNo][0]
        # print "current_val", current_val

        current_index = routelocationsSequenceNumber_list.index(current_val)
        # print "current_index", current_index
        # print "routelocations_list", routelocations_list, "index", index
        try:
            [routelocation, row] = routelocationsSequenceNumber_list[current_index]
            # row = routelocationsSequenceNumber_list[currentIndex + 1]
        except:
            row = None
        # print "row", row
        return row - 1    # row number starts from 0

    def find_row_prev_location(self, row, route):
        # get the row (sequenceNo) of the first location that is not an action (a python file  xx.py)
        routelocationsSequenceNumber_list = [ [routelocation, routelocation.getSequenceNumber()] \
                                              for routelocation in route.getLocationsBySequenceList() \
                                              if ".py" not in routelocation.getName()]
        current_val_list = [[routelocation, sequenceNo] \
                       for [routelocation, sequenceNo] in routelocationsSequenceNumber_list \
                       if row == sequenceNo-1]

        current_val = current_val_list[0]
        current_index = routelocationsSequenceNumber_list.index(current_val)
        [routelocation, row] = routelocationsSequenceNumber_list[current_index - 1]

        return row - 1     # row number starts from 1

    def check_train_in_block_for_scheduling_margin_fast_minutes(self, start_block, train_to_move, strpad = ""):
        global scheduling_margin_gbl
        global timebase
        # print "__________________________Start__" + train_to_move + "___________________________________"
        # timehm = str(timebase.getTime().getHours()) + ":" + str(timebase.getTime().getMinutes())
        timehm = "{:02d}:{:02d}".format(timebase.getTime().getHours(), timebase.getTime().getMinutes())
        print timehm, strpad, "check_train", train_to_move, "in_block", start_block.getUserName(), "for", scheduling_margin_gbl, "fast_minutes"
        global fast_clock_rate
        if self.logLevel > 0: print "check_train_in_block_for_scheduling_margin_fast_minutes"

        for j in range(int(scheduling_margin_gbl)):    # try to schedule train for scheduling_margin_gbl fast minutes
            train_in_block = self.blockOccupied(start_block)
            train_block_name = start_block.getValue()
            if train_in_block and (train_block_name == train_to_move):
                # print strpad + "--" + str(train_to_move) + " train in start block " + str(start_block.getUserName())
                return True
            else:
                print (strpad + "--" + str(train_to_move) + " not in start_block: " + str(start_block.getUserName()) \
                        + " time waited: " + str(j) + " fast minutes")
                fast_minute = 1000*60/int(str(fast_clock_rate))
                self.waitMsec(fast_minute)
        return False

    def check_train_in_block_allow_manual_repositioning(self, train_name, station_from_name):
        i = 0
        # print "train_name", train_name, "station_from_name", station_from_name
        while self.check_train_in_start_block(train_name, station_from_name) == False:
            if i > 2: # allow some time to recover
                title = ""
                msg = "Cannot run train, train not in start block\n" + \
                      train_name + " should be in block " + station_from_name + \
                      "\nmove it there manually and it might recover"
                opt1 = "have moved train, try again"
                opt2 = "cancel moving train"
                reply = OptionDialog().customQuestionMessage2str(msg, title, opt1, opt2)
                if reply == opt1:  # "have moved train, try again"
                    i = -1
                else:  # opt2
                    return False   # "cancel moving train"
            self.waitMsec(5000)
            i += 1
        # move_train = MoveTrain(station_from, station_to, train_to_move, self.graph, station_comment)
        # move_train.move_between_stations(station_from, station_to, train_to_move, self.graph)
        return True

    def store_journey_time(self, route, row, journey_time):
        global CreateAndShowGUI5_glb
        routeLocationList = route.getLocationsBySequenceList()
        routeLocation = routeLocationList[row]
        print "routeLocation", routeLocation, "row", row, "value", journey_time, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5"
        # OptionDialog().displayMessageNonModal("about to set_value_in_comment", "OK")
        self.set_value_in_comment(routeLocation, journey_time, "journey_time")
        wait_time = self.get_value_in_comment(routeLocation, "wait_time")
        duration_sec = int(journey_time) + int(wait_time)
        self.set_value_in_comment(routeLocation, duration_sec, "duration_sec")
        # OptionDialog().displayMessageNonModal("about to populate_action", "OK")
        CreateAndShowGUI5_glb.populate_action(None)
        # OptionDialog().displayMessageNonModal("about to update_journey_time_action", "OK")
        CreateAndShowGUI5_glb.update_journey_time_action(None)
        # OptionDialog().displayMessageNonModal("just did update_journey_time_action", "OK")
        # CreateAndShowGUI5_glb.update_duration_action(None)
        #

    def set_value_in_comment(self, routeLocation, value, duration_string):
        global CreateAndShowGUI5_glb

        comment = routeLocation.getComment()    #Null

        if comment == None:
            comment = ""

        delim_start = "[" + duration_string + "-"
        delim_end = "-" + duration_string + "]"

        comment = CreateAndShowGUI5_glb.insert_between(comment, delim_start, delim_end, value)
        routeLocation.setComment(comment)

    def get_value_in_comment(self, routeLocation, duration_string):

        delim_start = "[" + duration_string + "-"
        delim_end = "-" + duration_string + "]"

        comment = routeLocation.getComment()
        value = self.find_between(comment, "[" + duration_string + "-", "-" + duration_string + "]")

        return value

    def find_between(self, s, first, last):
        try:
            start = s.index(first) + len(first)
            end = s.index(last, start)
            return s[start:end]
        except ValueError:
            return ""

    def wait_for_scheduled_time(self, route, row, accumulated_durations, train_to_move):
        global fast_clock_rate
        global timebase
        global scheduling_margin_gbl
        if 'timebase' not in globals():
            timebase = jmri.InstanceManager.getDefault(jmri.Timebase)

        routeLocationList = route.getLocationsBySequenceList()
        routeLocation = routeLocationList[row]
        train_comment = self.train.getComment()
        if self.logLevel > 0: print "train_to_move", train_to_move, "routeLocation", routeLocation
        comment = routeLocation.getComment()
        # print "train_comment", train_comment, "comment", comment
        if self.logLevel > 0: print "x1"
        repeat_command = TimeListener().find_between(train_comment, "[repeat-", "-repeat]")
        if self.logLevel > 0: print "x3"
        current_minutes = int(timebase.getTime().getMinutes())
        if self.logLevel > 0: print "x2", "current_minutes", current_minutes

        # the departure time for the train is the first one in the hour
        # get what would be the current time if we were running the first train in the hour
        # so we can get the difference of the two and hence get the wait time
        # this is easier than getting the actual departure time minutes of the train
        if repeat_command == "Once":
            current_minutes_mod = current_minutes
            current_minutes_mod_array = [current_minutes_mod]
        elif repeat_command == "Repeat every 20 mins":
            current_minutes_mod = current_minutes % 20
            cmm20 = self.add_minutes(current_minutes_mod, 20)
            cmm40 = self.add_minutes(current_minutes_mod, 40)
            current_minutes_mod_array = [current_minutes_mod, cmm20, cmm40]
        elif repeat_command == "Repeat every 30 mins":
            current_minutes_mod = current_minutes % 30
            cmm30 = self.add_minutes(current_minutes_mod, 30)
            current_minutes_mod_array = [current_minutes_mod, cmm30]
        elif repeat_command == "Repeat every Hour":
            current_minutes_mod = current_minutes
            current_minutes_mod_array = [current_minutes_mod]
        elif repeat_command == "Repeat every 2 Hours":
            current_minutes_mod = current_minutes
            current_minutes_mod_array = [current_minutes_mod]
        else:
            print "error wrong repeat command"
            return
        if self.logLevel > 0: print "d", current_minutes, "current_minutes_mod", current_minutes_mod
        current_hour = int(str(timebase.getTime().getHours()))
        if self.logLevel > 0: print("a"), current_hour
        current_time = str(current_hour).zfill(2) + ":" + str(current_minutes_mod).zfill(2)
        if self.logLevel > 0: print "c", current_time
        train_start_time = self.train.getDepartureTime()
        if self.logLevel > 0: print "train_start_time", train_start_time, "accumulated_durations", accumulated_durations
        accumulated_durations_fast_mins = (accumulated_durations / 60.0) * int(str(fast_clock_rate)) # convert to fast min
        if self.logLevel > 0: print "accumulated_durations_fast_mins", accumulated_durations_fast_mins
        station_start_time = self.add_minutes_to_time(train_start_time, accumulated_durations_fast_mins)
        [station_start_hours, station_start_mins] = station_start_time.split(":")

        if self.logLevel > 0: print "station_start_time", station_start_time
        if self.logLevel > 0: print "current_time", current_time, "station_start_time", station_start_time

        #calculate minutes to wait
        minutes_to_wait_array = [self.subtract_minutes(station_start_mins, cm) for cm in current_minutes_mod_array]
        if self.logLevel > 0: print "minutes_to_wait_array", minutes_to_wait_array

        minutes_to_wait = min(minutes_to_wait_array)
        if self.logLevel > 0: print "minutes_to_wait", minutes_to_wait

        minutes_late = max([m-60 for m in minutes_to_wait_array]) # get the minutes late
        abs_minutes_late = abs(minutes_late)
        if self.logLevel > 0: print "minutes_late", minutes_late
        if self.logLevel > 0: print "minutes_late", abs_minutes_late

        index = minutes_to_wait_array.index(minutes_to_wait)
        if abs_minutes_late < int(scheduling_margin_gbl):
            if self.logLevel > 0: print "minutes_late2", minutes_late, "scheduling_margin_gbl", scheduling_margin_gbl
            fast_ms_to_wait = 0
        else:
            if self.logLevel > 0: print "minutes_to_wait", minutes_to_wait
            fast_ms_to_wait =  abs(minutes_to_wait) * 60 * 1000
            if self.logLevel > 0: print "waiting for ", current_minutes_mod_array[index]
        if self.logLevel > 0: print "v"
        ms_to_wait = fast_ms_to_wait / int(fast_clock_rate)
        if self.logLevel > 0: print "w"
        if self.logLevel > 0: print "waiting", "minutes_to_wait", minutes_to_wait
        if self.logLevel > 0: print "waiting", "ms_to_wait", ms_to_wait, "fast_secs_to_wait", fast_ms_to_wait/1000
        if self.logLevel > 0: print "time before wait", str(timebase.getTime())
        self.waitMsec(ms_to_wait)
        if self.logLevel > 0: print "time after wait", str(timebase.getTime())
        if self.logLevel > 0: print "waited till start time"

    def add_minutes(self, min1, min2):
        min = (int(min1) + int(min2) ) % 60
        return min

    def add_minutes_to_time(self, time, minutes):

        if self.logLevel > 0: print "z", time, minutes

        [day, time_hours, time_mins] = time.split(":")

        if self.logLevel > 0: print "add minutes to time"

        if self.logLevel > 0: print "time", time, "minutes", minutes

        # print "hours", hours, "mins", mins
        hour = int(str(time_hours)) + (int(time_mins) + int(minutes)) // 60
        if self.logLevel > 0: print "hour"
        min = (int(minutes) + int(time_mins) ) % 60
        if self.logLevel > 0: print "min", min
        if self.logLevel > 0: print "hour", hour, "min", min

        station_departure_time_new = str(hour).zfill(2) + ":" + str(min).zfill(2)
        if self.logLevel > 0: print "station_departure_time_new", station_departure_time_new

        return station_departure_time_new

    def subtract_times(self, current_time, station_time):
        if self.logLevel > 0: print "subtract times"
        [curr_hours, curr_mins] = current_time.split(":")
        # current_mins = int(curr_hours) * 60 + int(curr_mins)
        current_mins = int(curr_mins)
        if self.logLevel > 0: print "curr_hours", curr_hours, "curr_mins", curr_mins, "current_mins", current_mins

        [dep_hours, dep_mins] = station_time.split(":")
        # station_mins = int(dep_hours) * 60 + int(dep_mins)
        station_mins = int(dep_mins)
        if self.logLevel > 0: print "dep_hours", dep_hours, "dep_mins", dep_mins, "station_mins", station_mins
        # print "current_time", current_time, "mins", mins
        wait_time = station_mins - current_mins
        if self.logLevel > 0: print "wait_time", wait_time
        wait_time = wait_time % 60
        if self.logLevel > 0: print "wait_time", wait_time
        return wait_time

    def subtract_minutes(self, min1, min2):
        wait_time = int(min1) - int(min2)
        if self.logLevel > 0: print "wait_time", wait_time
        wait_time = wait_time % 60
        if self.logLevel > 0: print "wait_time", wait_time
        return wait_time

    def subtract_times_neg(self, current_time, station_time):
        if self.logLevel > 0: print "subtract times"
        [curr_hours, curr_mins] = current_time.split(":")
        # current_mins = int(curr_hours) * 60 + int(curr_mins)
        current_mins = int(curr_mins)
        if self.logLevel > 0: print "curr_hours", curr_hours, "curr_mins", curr_mins, "current_mins", current_mins

        [dep_hours, dep_mins] = station_time.split(":")
        # station_mins = int(dep_hours) * 60 + int(dep_mins)
        station_mins = int(dep_mins)
        if self.logLevel > 0: print "dep_hours", dep_hours, "dep_mins", dep_mins, "station_mins", station_mins
        # print "current_time", current_time, "mins", mins
        wait_time = station_mins - current_mins
        if self.logLevel > 0: print "wait_time", wait_time
        wait_time = wait_time % 60
        if self.logLevel > 0: print "wait_time", wait_time
        return wait_time - 60

    def get_next_item_in_list(self,elem, li ):
        if (li.index(elem))+1 != len(li):
            thiselem = elem
            nextelem = li[li.index(elem)+1]
            indexNextElem = li.index(elem)+1
            # print 'thiselem',thiselem
            # print 'nextel',nextelem
        else:
            thiselem = elem
            nextelem = elem
            indexNextElem = li.index(elem)
            # print 'thiselem',li[li.index(elem)]
            # print 'nextel',li[li.index(elem)]
        return [nextelem, indexNextElem]

    def check_train_in_start_block(self, train_to_move, blockName):
        block = blocks.getBlock(blockName)
        if self.blockOccupied(block):
            if block.getValue() == train_to_move:
                return True
            else:
                "blockName" , blockName, "not occupied by", "train_to_move", train_to_move
                blockName = [block for block in blocks.getNamedBeanSet() if block.getValue() == train_to_move]
                if blockName != []:
                    blockName = blockName[0]
                else:
                    blockName = "train not in any block"
                #print "train_to_move", train_to_move, "in" , blockName
                return False
        else:
            #print "train_to_move", train_to_move, "not in" , blockName
            blockName = [block for block in blocks.getNamedBeanSet() if block.getValue() == train_to_move]
            if blockName != []:
                blockName = blockName[0]
            else:
                blockName = "train not in any block"
            #print "train_to_move", train_to_move, "in" , blockName
            return False

    def blockOccupied(self, block):
        if block.getState() == ACTIVE:
            state = True
        else:
            state = False
        return state

    def station_is_action(self, station):
        if station[-3:] == ".py":
            return True
        else:
            return False

    def action_directory_in_DispatcherSystem(self):
        path = jmri.util.FileUtil.getScriptsPath() + "DispatcherSystem" + java.io.File.separator + "actions"
        if not os.path.exists(path):
            os.makedirs(path)
        return path + java.io.File.separator

    def action_directory(self):
        path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "actions"
        if not os.path.exists(path):
            os.makedirs(path)
        return path + java.io.File.separator

    def execute_action(self, action):
        # execute a python file in the dispatcher directory
        file = self.action_directory() + action
        if not os.path.isfile(file):
            file = self.action_directory_in_DispatcherSystem() + action
        if not os.path.isfile(file):
            self.displayMessage("action file " + action + " does not exist, it must have been deleted\n" + \
                                "should be in directories:\n" + \
                                self.action_directory_in_DispatcherSystem() + " or\n" + \
                                self.action_directory())
        if self.logLevel > 0: print self.route.getName()," executing file", file
        exec(open(file).read())     # execute the file

    def displayMessage(self, msg, title = ""):
        self.CLOSED_OPTION = False
        s = JOptionPane.showOptionDialog(None,
                                         msg,
                                         title,
                                         JOptionPane.YES_NO_OPTION,
                                         JOptionPane.PLAIN_MESSAGE,
                                         None,
                                         ["OK"],
                                         None)
        #JOptionPane.showMessageDialog(None, msg, 'Message', JOptionPane.WARNING_MESSAGE)
        if s == JOptionPane.CLOSED_OPTION:
            self.CLOSED_OPTION = True
            return
        return s

class ScheduleTrains(jmri.jmrit.automat.AbstractAutomaton):

    def setup(self):
        self.logLevel = 0
        return True

    def handle(self):
        # print "run trains"
        self.run_trains()    #schedule trains if schedule_trains_glb is set True external to this routine
        # continue scheduling trains
        # print "end run trains"
        return True

    def run_trains(self):

        global trains_to_be_scheduled
        global schedule_trains_glb
        global fast_clock_running_at_operational_speed
        global scheduled
        global timebase
        global fast_clock_rate
        if self.logLevel > 0 : print "************************************run trains******************"
        # schedule_trains_glb = True
        if True:
            if 'fast_clock_running_at_operational_speed' not in globals():
                fast_clock_running_at_operational_speed = True
            if self.logLevel > 0 : print "run trains started: loop: scheduled trains", trains_to_be_scheduled, \
                "fast_clock_running_at_operational_speed", fast_clock_running_at_operational_speed
            # print "scheduled", scheduled
            if fast_clock_running_at_operational_speed:
                for train in trains_to_be_scheduled:
                    # print "train", train, "type", type(train)
                    if train.getDescription() is not None:
                        # print "description", train.getDescription()
                        # print "scheduled[train]", scheduled[train]
                        if scheduled[train] == False:
                            if self.logLevel > 0: print "train",train,"scheduled[train]",scheduled[train]
                            route = train.getRoute()
                            if route is not None:
                                routeName = route.getName()
                                station_from, station_to = SchedulerMaster().get_first_and_last_station(route)   # starting from beginning of route
                                start_block = blocks.getBlock(station_from)
                                if self.logLevel > 0:  "start_block",start_block, "station_to", station_to
                                # train_block_name = start_block.getValue()
                                train_to_be_scheduled = train.getDescription()
                                # this is obsolete: now checked in check_train_in_block_for_scheduling_margin_fast_minutes in run_route in class RunRoute
                                # run_route_flag = self.check_train_ok_to_start(train, train_block_name)
                                no_repetitions = 0
                                if True:
                                    if "stopping" in train.getDescription():
                                        # print "running train %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", train
                                        run_train = RunRoute(route, g.g_stopping, station_from, station_to, no_repetitions, train_to_be_scheduled, \
                                                             scheduling_train = True, train = train)
                                        run_train.setName("running_route_" + routeName)
                                        instanceList.append(run_train)
                                        run_train.start()
                                    else:
                                        # print "running train %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%", train
                                        run_train = RunRoute(route, g.g_express, station_from, station_to, no_repetitions, train_to_be_scheduled, \
                                                             scheduling_train = True, train = train)
                                        run_train.setName("running_route_" + routeName)
                                        instanceList.append(run_train)
                                        run_train.start()
                                    scheduled[train] = True
                                    trains_to_be_scheduled.pop(trains_to_be_scheduled.index(train))
                                    if self.logLevel > 0: print "scheduled train ", train
                if self.logLevel > 0:  print "!!!!!!!!!!!!!!!!!!!!!run_trains finished"
                if self.logLevel > 0:  print "trains_to_be_scheduled ", trains_to_be_scheduled
                if 'timebase' in globals():
                    if self.logLevel > 0:  print "timebase.getRate()",timebase.getRate()


        msecs_in_half_fast_minute = int(500.0 / float(str(fast_clock_rate)) * 60.0)
        # noMsec = int(1000/timebase.getRate())
        self.waitMsec(msecs_in_half_fast_minute)  # twice every fast minute

    def check_train_ok_to_start(self, train, train_block_name):

        # check the scheduled train is in the starting block
        if train_block_name == train.getDescription():
            # print "returning true"
            return True
        else:
            # print "returning false", "train_block_name", train_block_name, "train.getDescription()", train.getDescription()
            return False
