package fcs

import java.util.Properties;
import org.lsst.ccs.bootstrap.BootstrapResourceUtils;
import org.lsst.ccs.subsystems.fcs.*
import org.lsst.ccs.subsystems.fcs.testbench.*
import org.lsst.ccs.subsystems.fcs.common.*
import org.lsst.ccs.subsystems.fcs.simulation.*
import org.lsst.ccs.subsystems.fcs.drivers.*
import org.lsst.ccs.monitor.Channel
import org.lsst.ccs.monitor.Device
import org.lsst.ccs.description.groovy.CCSBuilder
import org.lsst.ccs.drivers.canopenjni.*
import org.lsst.ccs.drivers.canopenjni.rmi.*
import org.lsst.ccs.bootstrap.SubstitutionTokenUtils;

//************************************************************************//
// subsystem properties
// org.lsst.ccs.run.mode can be "simulation" or "hardware"
// org.lsst.ccs.fcs.instance.autochanger can be "PROTO", "AC1" or "AC2"
// org.lsst.ccs.fcs.instance.loader can be "PROTO", "LO1" or "LO2"
//************************************************************************//
Properties props = BootstrapResourceUtils.getBootstrapSystemProperties();



def runMode = props.getProperty("org.lsst.ccs.run.mode", "simulation");
def instanceAC = props.getProperty("org.lsst.ccs.fcs.instance.autochanger", "AC1");
def instanceCA = props.getProperty("org.lsst.ccs.fcs.instance.carousel", "FINAL");
def instanceLO = props.getProperty("org.lsst.ccs.fcs.instance.loader", "LO1");
boolean standaloneAutochanger = props.getProperty("org.lsst.ccs.fcs.instance.autochanger.standalone", "false").equals("true");
boolean standaloneCarousel = props.getProperty("org.lsst.ccs.fcs.instance.carousel.standalone", "false").equals("true");
boolean standaloneLoader = props.getProperty("org.lsst.ccs.fcs.instance.loader.standalone", "false").equals("true");

int standaloneCounter = 0;
if ( standaloneAutochanger ) standaloneCounter++;
if ( standaloneCarousel ) standaloneCounter++;
if ( standaloneLoader ) standaloneCounter++;

if ( standaloneCounter > 1 ) {
    throw new RuntimeException("Something went wrong with the standalone configuration: autochanger("+standaloneAutochanger+") carousel("+standaloneCarousel+") loader("+standaloneLoader+")");
}

boolean fullFcs = standaloneCounter == 0;

if ( fullFcs ) {
    System.out.println("Configuring groovy for full FCS");
} else if ( standaloneAutochanger ) {
    System.out.println("Configuring groovy for Autochanger standalone");    
} else if ( standaloneCarousel ) {
    System.out.println("Configuring groovy for Carousel standalone");    
} else if ( standaloneLoader ) {
    System.out.println("Configuring groovy for Loader standalone");    
}

//************************************************************************//

CCSBuilder builder = ["fcs"]

//********************************************************************************//
//Carousel variables
//********************************************************************************//

/* numOfAnalogInput on the CANopen device where we read the clamps sensors*/
def numOfAnalogInputFilterPresenceSensorXminus = [1, 2, 3, 4, 5] as int[]
def numOfAnalogInputLockSensorXminus = [6, 7, 8, 9, 10] as int[]
def numOfAnalogInputFilterPresenceSensorXplus = [11, 12, 13, 14, 15] as int[]
def numOfAnalogInputLockSensorXplus = [16, 17, 18, 19, 20] as int[]


//Carousel clamps controllers name
def clampXminusControllerName = "clampXminusController" //controller to unlock clamp on the side Xminus
def clampXplusControllerName =  "clampXplusController" //controller to unlock clamp on the side Xplus
//********************************************************************************//

//********************************************************************************//
//Autochanger variables
//********************************************************************************//
def acPlutoGatewayName = "acSensorsGateway" // to monitor the autochanger sensors
//************************************************************************//
//In FINAL products AC1 and AC2 on linear rails, 
//truckX+  is controlled by master controller
//and truckX- is controlled by slave controller.
//On prototype truckX+ is controlled by slave and X- by master.
//************************************************************************//
def truckXminusControllerName
def truckXplusControllerName
if ("AC1".equals(instanceAC) || "AC2".equals(instanceAC)) {
    truckXminusControllerName = "linearRailSlaveController";
    truckXplusControllerName = "linearRailMasterController";
} else {
    truckXminusControllerName = "linearRailMasterController";
    truckXplusControllerName = "linearRailSlaveController";
}
//********************************************************************************//

//********************************************************************************//
//Loader variables
//********************************************************************************//
def bridgeToLoaderName = "loaderTcpProxy" 
def loaderPlutoGatewayName = "loaderPlutoGateway" // to monitor the loader sensors
//********************************************************************************//

Class carouselClass = Class.forName("org.lsst.ccs.subsystems.fcs." + (runMode.equals("simulation") ? "simulation.Simu" : "") + "Carousel");
Class carouselSocketClass = Class.forName("org.lsst.ccs.subsystems.fcs." + (runMode.equals("simulation") ? "simulation.Simu" : "") + "CarouselSocket");
Class autochangerClass = Class.forName("org.lsst.ccs.subsystems.fcs." + (runMode.equals("simulation") ? "simulation.Simu" : "") + "Autochanger");

Class mainClass;
if (fullFcs) {
    mainClass = org.lsst.ccs.subsystems.fcs.FcsMain.class;
} else if (standaloneAutochanger) {
    mainClass = AutochangerMain.class;
} else if (standaloneCarousel) {
    mainClass = CarouselMain.class;
} else if (standaloneLoader) {
    mainClass = LoaderMain.class;
}

System.out.println("Building Main class: "+mainClass);

builder.
    main(mainClass)
    { //begin description of Main subs
    
    //-------------------------
    // BEGIN Filter Manager description
    if ( fullFcs || standaloneCarousel ) {
        filterManager(FilterManager) {
            //begin description of filter manager's children
            filterU (Filter)
            filterG (Filter)
            filterR (Filter)
            filterI (Filter)
            filterZ (Filter)
            filterY (Filter)
            filterID_46 (Filter)
            filterID_40 (Filter)
            filterID_30 (Filter)
            filterID_27 (Filter)
            filterID_5 (Filter)
            filterID_54 (Filter)
    
        }
    } else if ( standaloneAutochanger) {
        filterManager(FilterManager) {//begin description of filter manager's children
            filterU (Filter)
            filterG (Filter)
            filterR (Filter)
            filterI (Filter)
            filterZ (Filter)
            filterY (Filter)
            dummyFilter (Filter)
        }   
    }
    ////end description of filter manager's children
    // END Filter Manager description
    // ------------------------------
    
    //-------------------------
    if ( fullFcs || standaloneAutochanger || standaloneCarousel ) {
        tcpProxy (CanOpenProxy) 
        { 
            
            Class canInterfaceClass = runMode.equals("simulation") ? SimuCanOpenInterface.class : CanFestivalJNI.class;
            //canInterface(CanOpenRMIClient, registryHostName:"134.158.153.195", bindName:"canbus0") 
            //to launch fcs on the same HCU than canfestival
            canInterface(canInterfaceClass)
            
            if ( fullFcs || standaloneCarousel ) {
                Class hyttc580Class = runMode.equals("simulation") ? SimuTTC580.class : CanOpenTTC580.class;        
                // can open devices to read clamps sensors
                hyttc580 (hyttc580Class)
                
                Class carouselClampControllerClass = runMode.equals("simulation") ? SimuCarouselClampController.class : CanOpenEPOSCarouselClamp.class;
                "$clampXminusControllerName" (carouselClampControllerClass)
                "$clampXplusControllerName" (carouselClampControllerClass)
                
                Class carouselControllerClass = runMode.equals("simulation") ? SimuCarouselController.class : CanOpenEPOSCarousel.class;
                carouselController (carouselControllerClass)

                Class ai814Class = runMode.equals("simulation") ? SimuCanOpenADC.class : CanCBXAI814.class;
                // can open devices to read brakes sensors and temperatures
                ai814 (ai814Class)
                
                // can open devices to read temperatures in carousel motor and brakes
                pt100 (CanOpenPT100)
                
                if ( standaloneCarousel ) {
                    if ( "simulation".equals(runMode) ) {
                        //fake plutoGateway to simulate autochanger signals
                        fakePlutoGateway (SimuCarouselStandalonePlutoGateway)
                    }
                }
            }
            
            if ( fullFcs || standaloneAutochanger ) {
                
                //This is for the autochanger in the fcs
                Class autochangerPlutoGatewayClass = runMode.equals("simulation") ? (fullFcs ? SimuAutochangerPlutoGateway.class : SimuAutochangerStandalonePlutoGateway.class ) : CanOpenPlutoGateway.class;
                // can open devices
                //sensors gateway
                "$acPlutoGatewayName" (autochangerPlutoGatewayClass)
                
                Class strainClass = runMode.equals("simulation") ? SimuCanOpenStrainGauge.class : CanOpenStrainGauge.class;
                onlineStrainGauge (strainClass)
                
                Class linearControllerClass = runMode.equals("simulation") ? SimuAutochangerLinearRailController.class : CanOpenEPOSLinearRailTruck.class;           
                // can open motor controllers
                linearRailMasterController (linearControllerClass)
                linearRailSlaveController (linearControllerClass)     
                
                Class latchControllerClass = runMode.equals("simulation") ? SimuAutochangerLatchController.class : CanOpenEPOS.class;
                latchXminusController (latchControllerClass)
                latchXplusController (latchControllerClass)
                
                
                Class autochangerClampControllerClass = runMode.equals("simulation") ? SimuAutochangerOnlineClampController.class : CanOpenEPOSOnlineClamp.class;
                onlineClampXminusController (autochangerClampControllerClass)
                onlineClampXplusController (autochangerClampControllerClass)
                onlineClampYminusController (autochangerClampControllerClass)
                
                //Devices which are the same classes for hardware and for simulation
                brakeSystemGateway (CanOpenPlutoGateway)
                tempSensorsDevice1 (CanOpenSeneca4RTD)
                tempSensorsDevice2 (CanOpenSeneca4RTD)        

                Class proximitySensorsClass = runMode.equals("simulation") ? SimuCanCBXAI420.class : CanCBXAI420.class;
                proximitySensorsDevice (proximitySensorsClass)      
            }
            //---- DONE AUTOCHANGER
            
        }
    }
    
    //
    ////end description of bridgeToChanger's children
    //----------------------------------------------
    // END Bridge To CHANGER description
    //----------------------------------------------                
    //
    // tcp Proxy LOADER ONLY
    
    if ( fullFcs || standaloneLoader ) {
        Class canopenProxyClass = runMode.equals("simulation") ? SimuLoaderCanOpenProxy.class : LoaderCanOpenProxy.class;        
        "$bridgeToLoaderName"(canopenProxyClass) 
        {
            
            //real hardware
            if ( runMode.equals("hardware") && "PROTO".equals(instanceLO) ) {
                //loader CANbus is canbus1
                loaderCanInterface(CanOpenRMIClient, registryHostName:"134.158.155.194", bindName:"canbus1")
            } else if ( runMode.equals("hardware") && "LO1".equals(instanceLO)) { 
                //test in January 2020 the following line doesn't work because an init of loaderCanInterface init the cahnger canInterface.
                //            loaderCanInterface(CanFestivalJNI)
                loaderCanInterface(CanOpenRMIClient, registryHostName:"134.79.209.94", bindName:"canbus1")
            } else {            
                loaderCanInterface(SimuCanOpenInterface)
            }
            
            Class loaderPlutoGatewayClass = runMode.equals("simulation") ? SimuLoaderStandalonePlutoGateway.class : CanOpenPlutoGateway.class;
            "$loaderPlutoGatewayName" (loaderPlutoGatewayClass)
            
            
            Class loaderHooksControllerClass = runMode.equals("simulation") ? SimuLoaderClampController.class : CanOpenEPOS.class;
            hooksController (loaderHooksControllerClass) 
            
            Class loaderCarrierControllerClass = runMode.equals("simulation") ? SimuLoaderCarrierController.class : CanOpenEPOS.class;
            carrierController (loaderCarrierControllerClass)            
            
            
        }
    }
    //end description of bridge's childrens
    //----------------------------------------------
    // END Bridge To LOADER description
    //---------------------------------------------
    
    
    if ( fullFcs || standaloneAutochanger ) {
        // BEGIN Filter Identificator description
        filterIdentificator(FilterIdentificator)
        {//begin description of filter Identificator's children
            filterIDSensor0 (DigitalSensor)
            
            filterIDSensor1 (DigitalSensor)
            
            filterIDSensor2 (DigitalSensor)
            
            filterIDSensor3 (DigitalSensor)
            
            filterIDSensor4 (DigitalSensor)
            
            filterIDSensor5 (DigitalSensor)
        }//end description of filter identificator's children
        // END Filter Identificator description
    }
    
    /**********************************************************************/
    /*                BEGIN OF CAROUSEL DESCRIPTION                       */
    /**********************************************************************/

    //----------------------------
    // BEGIN Carousel description
    if ( fullFcs || standaloneCarousel ) {
        carousel(carouselClass)
        {//begin description of carousel's children
            /**********************************************************************/
            /*SOCKETi*/
            for (int i = 1; i<6;i++ ) {
            "socket${i}" ( carouselSocketClass,
                    id:i,
                    clampXminus:ref("clampXminus${i}"),
                    clampXplus:ref("clampXplus${i}"),
                    slaveModuleSensor:ref("slaveModuleSensor${i}")
                )
                {   
                "slaveModuleSensor${i}" (CarouselSensor)
                    //-------------------------
                    // BEGIN clampXminus description
                "clampXminus${i}" (CarouselClamp,
                        filterPresenceSensor:ref("filterPresenceXminus${i}"),
                        lockSensor:ref("lockSensorXminus${i}"),
                        //                    thermometer:ref("thermometerXminus${i}")
                    ) 
                    {
                    "filterPresenceXminus${i}" (CarouselClampSensor)
                        
                    "lockSensorXminus${i}" (CarouselClampSensor) 
                        
                        //                    "thermometerXminus${i}" (Thermometer)
                    }
                    //-------------------------
                    // END clampXminus description
                    
                    //-------------------------
                    // BEGIN clampXplus description
                "clampXplus${i}" (CarouselClamp,
                        filterPresenceSensor:ref("filterPresenceXplus${i}"),
                        lockSensor:ref("lockSensorXplus${i}"),
                        //                    thermometer:ref("thermometerXplus${i}")
                    )
                    {
                    "filterPresenceXplus${i}" (CarouselClampSensor)
                    "lockSensorXplus${i}" (CarouselClampSensor)
                        //                    "thermometerXplus${i}" (Thermometer)
                    }
                    //-------------------------
                    // END clampXplus description
                } // END carouselSocket /*SOCKETi*/ description
            } // END of loop of carouselSocket description.
            if ( standaloneCarousel ) {
                acAF3 (ComplementarySensors) {
                    acAF3s (DigitalSensor)
                    acAF3b (DigitalSensor)
                }            
            }
        }
    } else if ( standaloneAutochanger ) {        
        /**********************************************************************/
        /*                FAKE CAROUSEL DESCRIPTION                       */
        /**********************************************************************/
        //in the autochanger standalone subsystem the fake carousel is a switch which
        //simulates that carousel holds a filter at STANDBY 
        carousel(FakeFilterHolder, holdingFilterSensorName:"carouselHoldingFilterSensors") // CFC
        /**********************************************************************/
        /*                END of FAKE CAROUSEL DESCRIPTION                 */
        /**********************************************************************/        
    }
    //end description of carousel's children
    //END Carousel description
    // ------------------------    
    
    
    if ( fullFcs || standaloneAutochanger ) {
        // ------ Monitoring 
        seneca1(TempMonitorDevice, tempSensorsDevice:ref("tempSensorsDevice1"))
        seneca2(TempMonitorDevice, tempSensorsDevice:ref("tempSensorsDevice2"))
        
        // Channels read as a group with getADCValues
        tempLinearRailMotorXplus(Channel, devcName:"seneca1", hwChan:1, units:"\u00b0C", format:".1f", type:"C", subtype:"", checkLo:"flag", limitLo:-20.0, alarmLo:null, checkHi:"flag", limitHi:100.0, alarmHi:null)
        tempLinearRailMotorXminus(Channel, devcName:"seneca1", hwChan:2, units:"\u00b0C", format:".1f", type:"C", subtype:"", checkLo:"flag", limitLo:-20.0, alarmLo:null, checkHi:"flag", limitHi:100.0, alarmHi:null)
        tempClampMotorXplus(Channel, devcName:"seneca1", hwChan:3, units:"\u00b0C", format:".1f", type:"C", subtype:"", checkLo:"flag", limitLo:-20.0, alarmLo:null, checkHi:"flag", limitHi:100.0, alarmHi:null)
        tempClampMotorYminus(Channel, devcName:"seneca1", hwChan:4, units:"\u00b0C", format:".1f", type:"C", subtype:"", checkLo:"flag", limitLo:-20.0, alarmLo:null, checkHi:"flag", limitHi:100.0, alarmHi:null)
        
        tempClampMotorXminus(Channel, devcName:"seneca2", hwChan:1, units:"\u00b0C", format:".1f", type:"C", subtype:"", checkLo:"flag", limitLo:-20.0, alarmLo:null, checkHi:"flag", limitHi:100.0, alarmHi:null)
        tempFrontBox(Channel, devcName:"seneca2", hwChan:2, units:"\u00b0C", format:".1f", type:"C", subtype:"", checkLo:"flag", limitLo:-20.0, alarmLo:null, checkHi:"flag", limitHi:100.0, alarmHi:null)
        tempRearBox(Channel, devcName:"seneca2", hwChan:3, units:"\u00b0C", format:".1f", type:"C", subtype:"", checkLo:"flag", limitLo:-20.0, alarmLo:null, checkHi:"flag", limitHi:100.0, alarmHi:null)
        tempCellXminus(Channel, devcName:"seneca2", hwChan:4, units:"\u00b0C", format:".1f", type:"C", subtype:"", checkLo:"flag", limitLo:-20.0, alarmLo:null, checkHi:"flag", limitHi:100.0, alarmHi:null)
        
        // ***************************
        // * LOCAL PROTECTION SYSTEM *
        // ***************************
        
        //Is this for AUTOCHANGER only?
        //Carousel_CFC signal read on AC pluto Gateway sent by carousel.
        carouselHoldingFilterSensors(ComplementarySensors) {		
            carouselHoldingFilterSensor0(DigitalSensor)		
            carouselHoldingFilterSensor1(DigitalSensor)		
        }
        
        //Signals read on AC pluto gateway sent by loader
        // 
        loaderHoldingFilterSensors(ComplementarySensors) { //Loader_LRH (ex LFL)		
            loaderHoldingFilterSensor0(DigitalSensor)		
            loaderHoldingFilterSensor1(DigitalSensor)    		
        }
        
        loaderConnectedSensors(ComplementarySensors) {  // Loader_LPS
            loaderConnectedSensor(DigitalSensor)		
            loaderConnectedSensorC(DigitalSensor)		
        }//end description of autochanger loaderConnectedSensors children
        
        //Carousel_CS
        carouselStoppedAtStandbySensors(ComplementarySensors) { // Carousel_CS
            carouselStoppedAtStandby(DigitalSensor)		
            carouselStoppedAtStandbyC(DigitalSensor)
        }//end description of autochanger carouselStoppedAtStandbySensors children
        
        carousel_CF0Sensors(ComplementarySensors) { // Carousel_CF0
            carousel_CF0(DigitalSensor)		
            carousel_CF0_C(DigitalSensor)
        }//end description of autochanger carousel_CF0 children 
        
        carousel_CF1Sensors(ComplementarySensors) { // Carousel_CF1
            carousel_CF1(DigitalSensor)		
            carousel_CF1_C(DigitalSensor)
        }//end description of autochanger carousel_CF1 children 
        
        // Local Protection Module status
        lpmLinearRail1Status(DigitalSensor) 
        
        lpmLinearRail2Status(DigitalSensor)        
        
        lpmOnlineClampsStatus(DigitalSensor)
        
        lpmLatchesStatus(DigitalSensor)
        
        //loaderPresenceSensors is only on AC1 and AC2, not on PROTO
        loaderPresenceSensors (ComplementarySensors) { 
            presenceLoader (DigitalSensor)
            presenceLoader_C (DigitalSensor)
        } // end description loaderPresenceSensors
        
        //lockOutSensors is only on AC1 and AC2, not on PROTO
        lockOutSensors (ComplementarySensors) { 
            lockOut (DigitalSensor)	
            lockOut_C (DigitalSensor)
        } // end description lockOutSensors 
        
        //Signal emitted by autochanger OUT_AF0
        OUT_AF0_Sensors (ComplementarySensors) { 
            OUT_AF0 (DigitalSensor)		
            OUT_AF0_C (DigitalSensor)
        } // end description OUT_AF0      
        
        //Signal emitted by autochanger OUT_AF1
        OUT_AF1_Sensors (ComplementarySensors) { 
            OUT_AF1 (DigitalSensor)		
            OUT_AF1_C (DigitalSensor)
        } // end description OUT_AF1     
        
        //Signal emitted by autochanger OUT_AF3
        OUT_AF3_Sensors (ComplementarySensors) { 
            OUT_AF3 (DigitalSensor)		
            OUT_AF3_C (DigitalSensor)
        } // end description OUT_AF3    
        
        //Signal emitted by autochanger OUT_AP1
        OUT_AP1_Sensors (ComplementarySensors) { 
            OUT_AP1 (DigitalSensor)		
            OUT_AP1_C (DigitalSensor)
        } // end description OUT_AP1 
        
        //Signal emitted by autochanger OUT_AP2
        OUT_AP2_Sensors (ComplementarySensors) { 
            OUT_AP2 (DigitalSensor)		
            OUT_AP2_C (DigitalSensor)
        } // end description OUT_AP2
        
        //Signal emitted by autochanger OUT_AP3
        OUT_AP3_Sensors (ComplementarySensors) { 
            OUT_AP3 (DigitalSensor)		
            OUT_AP3_C (DigitalSensor)
        } // end description OUT_AP3  
    }
    //**************************************************************************//
    //**************************************************************************//
    // autochanger
    //**************************************************************************//
    //**************************************************************************//
    if ( standaloneCarousel ) {
        /**********************************************************************/
        /*                FAKE AUTOCHANGER DESCRIPTION                       */
        /**********************************************************************/
        //in the carousel standalone subsystem the fake autochanger is a switch which
        //simulate that autochanger holds a filter at STANDBY 
        
        autochanger(FakeFilterHolder, holdingFilterSensorName:"acAF3s", notHoldingFilterSensorName:"acAF3b")
    } else if ( standaloneLoader ) {  
        /**********************************************************************/
        /*                FAKE AUTOCHANGER DESCRIPTION                       */
        /**********************************************************************/
        //in the loader standalone subsystem the fake autochanger is a switch which
        //simulate that autochanger holds a filter at HANDOFF 
        
        /**********************************************************************/
        /*                END of FAKE AUTOCHANGER DESCRIPTION                 */
        /**********************************************************************/
        autochanger(FakeFilterHolder, holdingFilterSensorName:"acAF3", notHoldingFilterSensorName:"acAF0")
    } else {
        autochanger(autochangerClass, plutoGateway:ref("$acPlutoGatewayName")) {
            ////begin description of autochanger children
            
            //**************************************************************************//
            // autochanger trucks description
            //**************************************************************************//
            autochangerTrucks (AutochangerTwoTrucks, 
                truckXminus:ref("acTruckXminus"), truckXplus:ref("acTruckXplus"),
                linearRailMasterController:ref("linearRailMasterController"),
                linearRailSlaveController:ref("linearRailSlaveController")) {
                //begin description of autochanger trucks children
                acTruckXminus (AutochangerTruck, 
                    controller:ref("$truckXminusControllerName"),
                    handoffPositionSensors:ref("handoffPositionSensorsXminus"),
                    onlinePositionSensors:ref("onlinePositionSensorsXminus"),
                    standbyPositionSensors:ref("standbyPositionSensorsXminus"),
                )
                {//begin description of autochanger truckXminus children
                    handoffPositionSensorsXminus (ComplementarySensors) { 
                        handoffPositionSensorXminus (DigitalSensor)                        
                        handoffPositionSensorBXminus (DigitalSensor)
                    }
                    onlinePositionSensorsXminus (ComplementarySensors) { 
                        onlinePositionSensorXminus (DigitalSensor)                        
                        onlinePositionSensorBXminus (DigitalSensor)
                    }
                    standbyPositionSensorsXminus (ComplementarySensors) { 
                        standbyPositionSensorXminus (DigitalSensor)                        
                        standbyPositionSensorBXminus (DigitalSensor)
                    }
                }//end description of autochanger acTruckXminus children
                acTruckXplus (AutochangerTruck, 
                    controller:ref("$truckXplusControllerName"),
                    handoffPositionSensors:ref("handoffPositionSensorsXplus"),
                    onlinePositionSensors:ref("onlinePositionSensorsXplus"),
                    standbyPositionSensors:ref("standbyPositionSensorsXplus"),
                )
                {//begin description of autochanger truckXplus children
                    handoffPositionSensorsXplus (ComplementarySensors) { 
                        handoffPositionSensorXplus (DigitalSensor)                                    
                        handoffPositionSensorBXplus (DigitalSensor)
                    }
                    onlinePositionSensorsXplus (ComplementarySensors) { 
                        onlinePositionSensorXplus (DigitalSensor)
                        onlinePositionSensorBXplus (DigitalSensor)
                    }
                    standbyPositionSensorsXplus (ComplementarySensors) { 
                        standbyPositionSensorXplus(DigitalSensor)
                        standbyPositionSensorBXplus (DigitalSensor)
                    }
                }//end description of autochanger acTruckXplus children
                
            }//end description of autochanger trucks children            
            //**************************************************************************//
            // end of autochanger trucks description
            //**************************************************************************//
            
            //**************************************************************************//
            // autochanger latches description
            //**************************************************************************//
            latches (AutochangerTwoLatches, latchXminus:ref("latchXminus"), latchXplus:ref("latchXplus"))
            {//begin description of autochanger latches children
                //*************************************//
                // autochanger latchXminus description
                //*************************************//
                latchXminus (AutochangerLatch,
                    latchController:ref("latchXminusController"),
                    closeSensors:ref("closeSensorsLatchXminus"),
                    openSensors:ref("openSensorsLatchXminus"),
                    filterEngagedSensors:ref("filterEngagedSensorsLatchXminus"),
                )
                {//begin description of autochanger latchXminus children
                    closeSensorsLatchXminus (ComplementarySensors) { //begin description of autochanger lockSensorslatchXminus children
                        closeSensorLatchXminus (DigitalSensor)
                        closeSensorBLatchXminus (DigitalSensor)
                    }//end description of autochanger lockSensorslatchXminus children                
                    
                    openSensorsLatchXminus (ComplementarySensors) { //begin description of autochanger unlockSensorslatchXminus children
                        openSensorLatchXminus (DigitalSensor)
                        openSensorBLatchXminus (DigitalSensor)
                    }//end description of autochanger unlockSensorslatchXminus children
                    
                    filterEngagedSensorsLatchXminus (ComplementarySensors) { //begin description of autochanger filterEngagedSensorslatchXminus children
                        filterEngagedSensorLatchXminus (DigitalSensor)
                        filterEngagedSensorBLatchXminus (DigitalSensor)
                    }//end description of autochanger filterEngagedSensorslatchXminus children
                }//end description of autochanger latchXminus children
                //**********************************************//
                // end of autochanger latchXminus description   //
                //**********************************************//
                //*************************************//
                // autochanger latchXplus description
                //*************************************//
                latchXplus (AutochangerLatch,
                    latchController:ref("latchXplusController"),
                    closeSensors:ref("closeSensorsLatchXplus"),
                    openSensors:ref("openSensorsLatchXplus"),
                    filterEngagedSensors:ref("filterEngagedSensorsLatchXplus"),
                )
                {//begin description of autochanger latchXplus children
                    
                    closeSensorsLatchXplus (ComplementarySensors) { //begin description of autochanger lockSensorslatchXplus children
                        closeSensorLatchXplus (DigitalSensor)
                        closeSensorBLatchXplus (DigitalSensor)
                    }//end description of autochanger lockSensorslatchXplus children
                    openSensorsLatchXplus (ComplementarySensors) { //begin description of autochanger unlockSensorslatchXplus children
                        openSensorLatchXplus (DigitalSensor)
                        openSensorBLatchXplus (DigitalSensor)
                    }//end description of autochanger unlockSensorslatchXplus children
                    
                    filterEngagedSensorsLatchXplus (ComplementarySensors) { //begin description of autochanger filterEngagedSensorslatchXplus children
                        filterEngagedSensorLatchXplus (DigitalSensor)
                        filterEngagedSensorBLatchXplus (DigitalSensor)
                    }//end description of autochanger filterEngagedSensorslatchXplus children
                    
                }//end description of autochanger latchXplus children
                //**********************************************//
                // end of autochanger latchXplus description   //
                //**********************************************//
            }//end description of autochanger latches children
            //*****************************************************************************//
            // end of autochanger latches description
            //*****************************************************************************//
            
            //**************************************************************************//
            //**************************************************************************//
            // autochanger onlineClamps description
            //**************************************************************************//
            //**************************************************************************//
            onlineClamps (AutochangerThreeOnlineClamps, 
                onlineClampXminus:ref("onlineClampXminus"), 
                onlineClampXplus:ref("onlineClampXplus"), 
                onlineClampYminus:ref("onlineClampYminus")) 
            {//begin description of autochanger onlineClamps children
                
                onlineClampXminus(AutochangerOnlineClamp ,
                    controller:ref("onlineClampXminusController"),
                    closeSensors:ref("onlineClampXminusCloseSensors"),
                    openSensors:ref("onlineClampXminusOpenSensors"),
                )
                {//begin description of autochanger onlineClampXminus children
                    onlineClampXminusCloseSensors (ComplementarySensors) { //begin description of autochanger onlineClampXminusCloseSensors children
                        onlineClampXminusCloseSensor (DigitalSensor)
                        onlineClampXminusCloseSensorC (DigitalSensor)
                    }//end description of autochanger onlineClampXminusCloseSensors children
                    
                    onlineClampXminusOpenSensors (ComplementarySensors) { 
                        onlineClampXminusOpenSensor (DigitalSensor)
                        onlineClampXminusOpenSensorC (DigitalSensor)  
                    }
                }//end of  description of autochanger onlineClampXminus children
                
                onlineClampXplus(AutochangerOnlineClamp ,
                    controller:ref("onlineClampXplusController"),
                    closeSensors:ref("onlineClampXplusCloseSensors"),
                    openSensors:ref("onlineClampXplusOpenSensors"),
                )
                {//begin description of autochanger onlineClampXplus children
                    onlineClampXplusCloseSensors (ComplementarySensors) { 
                        onlineClampXplusCloseSensor (DigitalSensor)
                        onlineClampXplusCloseSensorC (DigitalSensor)
                    }                    
                    onlineClampXplusOpenSensors (ComplementarySensors) { 
                        onlineClampXplusOpenSensor (DigitalSensor)
                        onlineClampXplusOpenSensorC (DigitalSensor)
                    }
                }//end of  description of autochanger onlineClampXplus children
                
                onlineClampYminus(AutochangerOnlineClamp ,
                    controller:ref("onlineClampYminusController"),
                    closeSensors:ref("onlineClampYminusCloseSensors"),
                    openSensors:ref("onlineClampYminusOpenSensors"),
                )
                {//begin description of autochanger onlineClampYminus children
                    onlineClampYminusCloseSensors (ComplementarySensors) { 
                        onlineClampYminusCloseSensor (DigitalSensor)
                        onlineClampYminusCloseSensorC (DigitalSensor)
                    }
                    onlineClampYminusOpenSensors (ComplementarySensors) { 
                        onlineClampYminusOpenSensor (DigitalSensor)
                        onlineClampYminusOpenSensorC (DigitalSensor)
                    }
                }//end of  description of autochanger onlineClampYminus children
            }//end of  description of autochanger onlineClamps children
            //**************************************************************************//
            // end of autochanger onlineClamps description
            //**************************************************************************//
            inclinometerXminus (Inclinometer)
            inclinometerXplus (Inclinometer)
            
            
        }//end description of autochanger children
        //*****************************************************************************//
        //*****************************************************************************//
        // end of autochanger description
        //*****************************************************************************//
        //*****************************************************************************//
    }    
    
    if ( standaloneAutochanger ) {
        /**********************************************************************/
        /*                FAKE LOADER DESCRIPTION                       */
        /**********************************************************************/
        //in the autochanger standalone subsystem the fake loader is couple of complementary sensors
        //simulate that loader holds a filter at HANDOFF     
        loader(FakeFilterHolder, holdingFilterSensorName:"loaderHoldingFilterSensors")
        /**********************************************************************/
        /*                END of FAKE LOADER DESCRIPTION                 */
        /**********************************************************************/        
    } else if (fullFcs || standaloneLoader) {
        //begin description of loader
        loader (Loader)
        {//begin description of loader's children
            
            carrier(LoaderCarrier,
                handoffSensors:ref("loaderHandoffSensors"),
                storageSensors:ref("loaderStorageSensors"),
                engagedSensors:ref("loaderEngagedSensors")
            )
            {//begin description of loader carrier's children                
                
                if ( "PROTO".equals(instanceLO)) {
                    //for loader prototype engaged and handoff position sensors are not redondant
                    //ATTENTION J'AI RECOPIE CA pour le PROTO
                    loaderEngagedSensors (RedondantSensors) {//begin description of loader engagedSensors
                        loaderEngagedPositionSensor0 (DigitalSensor)                        
                        loaderEngagedPositionSensor1 (DigitalSensor)
                    }//end description of loader engagedSensors
                    
                    loaderHandoffSensors (RedondantSensors) {//begin description of loader handoffSensors
                        loaderHandoffPositionSensor0 (DigitalSensor)                        
                        loaderHandoffPositionSensor1 (DigitalSensor)
                    }//end description of loader handoffSensors   
                    
//                    //user_to_gateway n° 1
//                    loaderHandoffSensors (DigitalSensor)
//                    
//                    loaderEngagedSensors (DigitalSensor)
                    
                } else {                
                    loaderEngagedSensors (RedondantSensors) {//begin description of loader engagedSensors
                        loaderEngagedPositionSensor0 (DigitalSensor)                        
                        loaderEngagedPositionSensor1 (DigitalSensor)
                    }//end description of loader engagedSensors
                    
                    loaderHandoffSensors (RedondantSensors) {//begin description of loader handoffSensors
                        loaderHandoffPositionSensor0 (DigitalSensor)                        
                        loaderHandoffPositionSensor1 (DigitalSensor)
                    }//end description of loader handoffSensors                    
                }
                
                loaderStorageSensors (RedondantSensors) {//begin description of loader storageSensors
                    //user_to_gateway n° 1
                    loaderStoragePositionSensor0 (DigitalSensor)                    
                    loaderStoragePositionSensor1 (DigitalSensor)  
                }//end description of loader storageSensors
                
            }//end description of loader carrier's children
            
            clamp(LoaderClamp,
                hook1:ref("hook1"),hook2:ref("hook2"), hook3:ref("hook3"),hook4:ref("hook4"),
                forceSensor0:ref("forceSensor0"), forceSensor1:ref("forceSensor1"),
                clampedStatusSensor: ref("clampedStatusSensor"),
            )
            {//begin description of loader clamp's children
                for (int i = 1; i<5; i++) {
                    
            "hook${i}"(LoaderHook,
                        closeSensor:ref("loaderCloseSensor${i}"), openSensor:ref("loaderOpenSensor${i}"))
                    { //user_to_gateway n° 1
                    "loaderCloseSensor${i}" (DigitalSensor)
                        
                    "loaderOpenSensor${i}" (DigitalSensor)
                    }
                }
                
                forceSensor0(ForceSensor)
                
                forceSensor1(ForceSensor)
                
                // user_to_gateway n° 2
                unclampedStatusSensor (DigitalSensor)
                
                underClampedStatusSensor (DigitalSensor)
                
                clampedStatusSensor (DigitalSensor) 
                
                overClampedStatusSensor (DigitalSensor)
                
            }//end description of loader clamp's children
            
            
            loaderFilterPresenceSensors (RedondantSensors) { // user_to_gateway n° 1
                loaderFilterPresenceSensor0(DigitalSensor)                
                loaderFilterPresenceSensor1(DigitalSensor) 
            }
            
            loaderOnCameraSensors (RedondantSensors) { // user_to_gateway n° 1
                loaderOnCameraSensor0(DigitalSensor)                
                loaderOnCameraSensor1(DigitalSensor)
            }
            
            //key lock or permit signal
            keyLockSensors (ComplementarySensors) { 
                keyLock (DigitalSensor)
                keyLockb (DigitalSensor)
            }
            
            //engineering key
            keyEngSensors (ComplementarySensors) { 
                keyEng (DigitalSensor)
                keyEngb (DigitalSensor)
            }
            
            // output signals for Camera Protection System
            //LRH gateway 3, bits 4 & 5
            //LPS gateway 3, bits 6 & 7
            // LRH (Loader Holding Filter at HANDOFF)
            Loader_LRH (ComplementarySensors) { 
                LRH_0 (DigitalSensor)
                LRH_1 (DigitalSensor)
            }
            
            // LPS (Loader at STORAGE)
            Loader_LPS (ComplementarySensors) { 
                LPS_0 (DigitalSensor)
                LPS_1 (DigitalSensor)
            }
            
            loaderCarrierRelayStatus (DigitalSensor)
            
            loaderHooksRelayStatus (DigitalSensor)
            
            loaderChainPresenceSensor (DigitalSensor) 
            
            loaderDefaultStatus (DigitalSensor)
            
            loaderFilterGoodPositionStatus (DigitalSensor)
            
            //Signals comming from autochanger and read on loaderPlutoGateway//
            //AP2 user_to_gateway 3 input 0
            //AF0 user_to_gateway 3 input 1
            //AF1 user_to_gateway 3 input 2
            //AF3 user_to_gateway 3 input 3
            acAP2 (ComplementarySensors) { 
                acAP2s (DigitalSensor)
                acAP2b (DigitalSensor)
            }
            
            acAF0 (ComplementarySensors) { 
                acAF0s (DigitalSensor)
                acAF0b (DigitalSensor)
            } 
            
            acAF1 (ComplementarySensors) { 
                acAF1s (DigitalSensor)
                acAF1b (DigitalSensor)
            } 
            
            acAF3 (ComplementarySensors) { 
                acAF3s (DigitalSensor)
                acAF3b (DigitalSensor)
            } 
            //end of Signals comming from autochanger and read on loaderPLutoGateway// 
            
        }//end description of loader's children
    }
            
} // end description of main (FcsMain)
