001package jmri.jmrix.can.cbus.node;
002
003import javax.annotation.Nonnull;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007/**
008 * Class to get Node Statistics.
009 *
010 * @author Steve Young Copyright (C) 2019
011 */
012public class CbusNodeStats {
013
014    private final CbusBasicNodeWithManagers _node;
015    
016    /**
017     * Create a new CbusNodeStats
018     *
019     * @param node Node to provide stats for
020     */
021    public CbusNodeStats ( CbusBasicNodeWithManagers node ){
022        _node = node;
023    }
024    
025    /**
026     * Node Type Name, if available. 
027     * @return If Node Parameters 1 and 3 are set eg. "CANPAN", else potentially a NAME OPC return, else empty string.
028     *
029     */
030    @Nonnull
031    public String getNodeTypeName() {
032        if (!CbusNodeConstants.getModuleType(_node.getNodeParamManager().getParameter(1),_node.getNodeParamManager().getParameter(3)).isEmpty() ){
033            return CbusNodeConstants.getModuleType(_node.getNodeParamManager().getParameter(1),_node.getNodeParamManager().getParameter(3));
034        }
035        else if ( _node instanceof CbusNode ){
036            return ((CbusNode)_node).getNodeNameFromName();
037        }
038        else {
039            return "";
040        }
041    }
042    
043    /**
044     * Get Node Number and name
045     * @return string eg "1234 UserName", no trailing space.
046     */
047    @Nonnull
048    public String getNodeNumberName() {
049        if ( !_node.getUserName().isEmpty() ){
050            return "" + _node.getNodeNumber() + " " + _node.getUserName();
051        }
052        else if ( !getNodeTypeName().isEmpty() ){
053            return "" + _node.getNodeNumber() + " " + getNodeTypeName();
054        }
055        else {
056            return String.valueOf(_node.getNodeNumber());
057        }
058    }
059    
060    /**
061     * Get the total number of bytes to store in a backup file
062     *
063     * @return total number, else 0 if still waiting for a total number of events
064     */
065    public int totalNodeFileBytes(){
066        return Math.max(0,_node.getNodeParamManager().getParameter(0)) + 
067            Math.max(0,_node.getNodeNvManager().getNV(0)) + 
068            Math.max(0,_node.getNodeParamManager().getParameter(5) * _node.getNodeEventManager().getTotalNodeEvents());
069    }
070
071    /**
072     * Get the total bytes to transfer all data currently on module
073     *
074     * @return total number, else -1 if still waiting for a total number of events
075     */
076    public int totalNodeBytes() {
077        if ( ( _node.getNodeParamManager().getParameter(0) < 0 ) 
078            || ( _node.getNodeParamManager().getParameter(6) < 0 ) 
079            || ( _node.getNodeParamManager().getParameter(5) < 0 )
080            || ( _node.getNodeEventManager().getTotalNodeEvents() < 0 ) ){
081                return -1;
082            }
083        return _node.getNodeParamManager().getParameter(0) + /* Total Parameters */
084            _node.getNodeParamManager().getParameter(6) + /* Total NV's */
085            ( _node.getNodeParamManager().getParameter(5) * _node.getNodeEventManager().getTotalNodeEvents() ) + /* Ev Variables for All Events */
086            ( _node.getNodeEventManager().getTotalNodeEvents()  ); /* Events from index return */
087    }
088    
089    /**
090     * Get the number of data bytes outstanding to fetch from a node
091     *
092     * @return total number, else -1 if still waiting for a total number of events
093     */
094    public int totalRemainingNodeBytes(){
095        if ( ( _node.getNodeParamManager().getOutstandingParams() < 0 ) 
096            || ( _node.getNodeNvManager().getOutstandingNvCount() < 0 ) 
097            || ( _node.getNodeEventManager().getOutstandingEvVars() < 0 )
098            || ( _node.getNodeEventManager().getOutstandingIndexNodeEvents() < 0 ) ){
099            return -1;
100        }
101        
102        return _node.getNodeParamManager().getOutstandingParams() + /* Total Parameters */
103        _node.getNodeNvManager().getOutstandingNvCount() + /* Total NV's */
104        _node.getNodeEventManager().getOutstandingEvVars() + 
105        ( _node.getNodeEventManager().getOutstandingIndexNodeEvents() ); /* Events from index return */
106        
107    }
108    
109    /**
110     * Get the amount of Node data known to JMRI
111     * in terms of percentage of total data fetch done so far.
112     *
113     * @return float min 0 max 1
114     */
115    public float floatPercentageRemaining(){
116        float soFar = ( 1.0f * ( totalNodeBytes() - totalRemainingNodeBytes() ) ) / ( totalNodeBytes() );
117        if ( soFar > 0 && soFar < 1.000001 ) {
118            return soFar;
119        }
120        return 0.0f;
121    }
122    
123    /**
124     * Check if node has finished loading all available data
125     * 
126     * The first time that all data is loaded, saves new backup.
127     *
128     */
129    protected void checkNodeFinishedLoad(){
130        if ((!_node.getNodeBackupManager().getBackupStarted()) && totalRemainingNodeBytes() == 0) {
131            if (!_node.getNodeBackupManager().doStore(true,hasLoadErrors()) ) {
132                log.error("Unable to save Finished Load to Node Backup File");
133            }
134            _node.notifyPropertyChangeListener("BACKUPS", null, null);
135        }
136        // reset value if node comes online after being offline
137        if (_node.getNodeBackupManager().getBackupStarted() && totalRemainingNodeBytes()>0) {
138            _node.getNodeBackupManager().setBackupStarted(false);
139        }
140    }
141    
142    // 8 timers, 8 errors ?
143    public boolean hasLoadErrors() {
144        return _node.getNodeTimerManager().numEvTimeoutCount + _node.getNodeTimerManager().paramRequestTimeoutCount + _node.getNodeTimerManager().allEvTimeoutCount > 0;
145    }
146    
147    private static final Logger log = LoggerFactory.getLogger(CbusNodeStats.class);
148    
149}