# AnyRailExportAddtions.py - SteveT - 05/09/2023
# Intended to be run ONCE after opening a file generated by the AnyRail export
# The AnyRail export outputs a background .jpg, and a set of internal Block objects
# for all AnyRail "Sections" which have been assigned a "Name".
# This script does some cleanup of the generated Block and Turnout definitions, creates Sensors
# and assigns them to the corresponding Blocks
# Both Sensors and Turnouts are created to match your default hardware Connection.
# Requirements:
#   AnyRail "Section" names must contain a unique Block number, this number is used to generate 
#     the JMRI Block and Sensor systemNames.
#   AnyRail Turnouts must have "Label" names entered with a unique Turnout number.
#   If desired, you can include a unique "User Name" after the unique number, such as "186 Yard Track 1"
#     The number will be used for the SystemName, and the trailing text for the UserName
# Pre-export suggestions: set AnyRail Zoom to 1:6, disable "Show Visible track"  
# Thanks to Cliff Anderson's AnyRailBuildSensorList.py and Bill Fitch's CreateSignalLogicAndSections.py
#   for some of the code and much of the inspiration
# TODO: handle underscore in AR SectionName
# TODO: "rename" the Block systemName to match (Block "move" currently causes NPE in JMRI) 

import jmri
import java
import org.slf4j.LoggerFactory
import re
from java.awt import Color

connectionPrefix = turnouts.getSystemPrefix() # get  the "Connection Prefix" in use for the default JMRI connection
log = org.slf4j.LoggerFactory.getLogger("jmri.jmrit.jython.exec.script.AnyRailExportAdditions")

log.info( "AnyRailExportAdditions.py Tweaking LayoutEditor appearance" )
panels = jmri.InstanceManager.getDefault(jmri.jmrit.display.EditorManager)
layoutPanels = panels.getList(jmri.jmrit.display.layoutEditor.LayoutEditor)
if (len(layoutPanels) != 1) :
    log.error('Error finding single LayoutEditor panel.')
    exit

layoutEditor = layoutPanels[0]
log.debug("tweaking some display values for panel '{}'".format(layoutEditor.getLayoutName()))
ltdo = layoutEditor.getLayoutTrackDrawingOptions()    
ltdo.setMainRailWidth(2) 
ltdo.setMainBlockLineWidth(3)
layoutEditor.setTurnoutDrawUnselectedLeg(False)
layoutEditor.setTurnoutCircleSize(3)
layoutEditor.setTurnoutCircleColor(Color.LIGHT_GRAY)
layoutEditor.setTurnoutCircleThrownColor(Color.LIGHT_GRAY)
layoutEditor.redrawPanel()

log.info( "AnyRailExportAdditions.py Create and Assign Sensors to blocks" )
blocksCreated = 0 #count successes
blocksSkipped = 0 # and failures

blocksSet = list(blocks.getNamedBeanSet()) # use a copy for the loop
for blockBean in blocksSet :

#     if (blocksCreated > -1) : continue #debugging, comment out before committing
    
    blockSystemName = str ( blockBean )
    block = blocks.getBlock(blockSystemName)
    anyRailUserName = block.getUserName()
    if (anyRailUserName == None) :
         log.warn('AnyRail SectionName "{}" is empty for block {}, skipped.'.format(blockSystemName, anyRailUserName))
         blocksSkipped += 1
         continue

    # remove cruft added around entered value, e.g. B_15_LS223 South Staging Lead_Pass through -> LS223 South Staging Lead
    result = re.search("B_\d+_(.+)_", anyRailUserName)
    if (result == None) :
         log.warn("Unexpected syntax '{}', skipping.".format(anyRailUserName))
         blocksSkipped += 1
         continue
    userName = result.group(1)

    # extract the block number from this username, e.g. LS223 South Staging Lead -> 223
    result = re.search("(\d+)", userName)
    if (result == None) :
         log.warn('BlockNumber not found in "{}", skipping.'.format(userName))
         blocksSkipped += 1
         continue
    blockNumber = result.group(1)
    blockName = "B" + blockNumber # block Name will be Bnnn

    result = blocks.getByUserName(blockName) # prevent duplicates in username and systemname
    if (result != None) :
         log.warn('Block "{}" already exists, skipping.'.format(blockName))
         blocksSkipped += 1
         continue
    
    result = re.search("[\d]+[\s]*(\D+.*)*", userName) # whatever follows the first number is userName
    if (result != None) :
        userName = result.group(1)   

    log.debug('Processing blockSystemName={}, anyRailUserName={}, blockName={}, userName={}'.format(blockSystemName, anyRailUserName, blockName, userName))
    
    block.setUserName(userName if userName else blockName)
    
    sensorName = connectionPrefix + "S" + blockNumber
    check = sensors.getBySystemName(sensorName) # insure no duplicate systemnames
    if (check) :
        log.warn("Sensor systemName '{}' is duplicate, skipping".format(sensorName))
        continue   
    newSensor = sensors.newSensor(sensorName, None) # create the hardware sensor using systemName
    if (userName) :
        newSensor.setUserName(userName)
    
    newSensor.setUseDefaultTimerSettings(True) # not sure why this isn't the default   
    
    block.setSensor(sensorName) #set the Sensor for the block

    log.debug("Created Sensor={} and assigned it to Block {} (renamed from {})".format(sensorName, blockName, anyRailUserName))   
    blocksCreated += 1

log.info("Created and assigned {} Sensors to Blocks, skipped {} invalid Blocks".format(blocksCreated, blocksSkipped))
log.info("AnyRailExportAdditions.py Converting Internal Turnouts to Hardware")

turnoutsCreated = 0 #count successes
turnoutsSkipped = 0 # and failures

turnoutsSet = list(turnouts.getNamedBeanSet()) # use a copy for the loop
for turnoutBean in turnoutsSet :

    # if (turnoutsCreated > 5) : continue

    # get the Turnout systemName entered as AnyRail Label, and get reference to that turnout
    oldSystemName = str ( turnoutBean )
    oldTurnout = turnouts.getTurnout(oldSystemName)
    anyRailUserName = oldTurnout.getUserName() # AnyRail stores entered name as userName
    if (anyRailUserName == None) :
         log.warn('Turnout "{}" has no userName, skipping.'.format(oldSystemName))
         turnoutsSkipped += 1
         continue
    result = re.search("(\d+)", anyRailUserName) # get the first number sequence
    if (result == None) :
         log.warn('Turnout Number not found in "{}", skipping.'.format(anyRailUserName))
         turnoutsSkipped += 1
         continue
    turnoutNumber = result.group(1)   

    oldTurnout.setUserName(None) # clear old username to avoid duplicates
    
    newSystemName =  connectionPrefix + "T" + turnoutNumber # systemName is xTnnn
    checkTurnout = turnouts.getTurnout(newSystemName) # insure systemname is not already used
    if (checkTurnout) :
        log.warn("Turnout systemName '{}' would be duplicate, not replaced".format(newSystemName))
        continue   

    newUserName = None
    result = re.search("[\d]+[\s]*(\D+.*)*", anyRailUserName) # whatever follows the first number is new userName
    if (result != None) :
        newUserName = result.group(1)   
        checkTurnout = turnouts.getByUserName(newUserName)
        if (checkTurnout) :
            log.warn("Turnout '{}' would duplicate userName '{}', clearing".format(newSystemName, newUserName))
            newUserName = None   
    
    log.debug("Replacing Turnout {} with {} {}".format(oldSystemName, newSystemName, '('+newUserName+')' if newUserName else ''))

    newTurnout = turnouts.provideTurnout(newSystemName) # create new hardware turnout
    newTurnout.setUserName(anyRailUserName)      # move the old username to new turnout  
    beans.moveBean(oldTurnout, newTurnout, anyRailUserName) # move references from old to new   
    beans.updateBeanFromUserToSystem(newTurnout) # move refs to sysname, so we can change userName
    newTurnout.setUserName(newUserName)          # set new userName, can be None
    turnouts.deleteBean(oldTurnout, 'DoDelete')  # delete old turnout           

    turnoutsCreated += 1

log.info('Replaced {} Turnouts, skipped {} Turnouts'.format(turnoutsCreated, turnoutsSkipped))
