001package jmri.jmrix.can.cbus.node;
002
003import java.util.Arrays;
004import java.util.Objects;
005import jmri.util.StringUtil;
006
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010/**
011 * Class to represent an event stored on a node.
012 * <p>
013 * Custom Equals method
014 *
015 * @author Steve Young Copyright (C) 2019
016 */
017public class CbusNodeEvent extends CbusBasicNodeEvent implements Comparable<CbusNodeEvent> {
018    
019    private int[] _evVarArr;
020    
021    /**
022     * Set the value of the event variable array by index
023     *
024     * @param memo CAN System Connection
025     * @param nn Event node Number
026     * @param en Event event or device number
027     * @param thisnode Host node number
028     * @param index number assigned by node, -1 if unknown
029     * @param maxEvVar Maximum event variables for the event
030     */
031    public CbusNodeEvent( jmri.jmrix.can.CanSystemConnectionMemo memo, int nn, int en, int thisnode, int index, int maxEvVar){
032        super(memo,nn,en,thisnode,index);
033        _evVarArr = new int[Math.max(maxEvVar, 0)];
034        java.util.Arrays.fill(_evVarArr,-1);
035    }
036    
037    protected CbusNodeEvent( int nn, int en, int thisnode, String eventString ){
038        super(null,nn,en,thisnode,-1);
039        _evVarArr = StringUtil.intBytesWithTotalFromNonSpacedHexString(eventString,false);
040        setTempFcuNodeName(null);
041    }
042    
043    protected CbusNodeEvent( CbusNodeEvent existing ) {
044        super(null,existing.getNn(),existing.getEn(),existing.getParentNn(),existing.getIndex());
045        setEvArr( Arrays.copyOf(
046            existing.getEvVarArray(),
047            existing.getEvVarArray().length) );
048        setTempFcuNodeName ( existing.getTempFcuNodeName());
049        
050    }
051
052    /**
053     * Set the value of the event variable array by index
054     *
055     * @param index event variable index, minimum 1
056     * @param value min 0 max 255
057     */
058    public void setEvVar(int index, int value) {
059        if ( index < 1 ) {
060            log.error("Event Index needs to be more than 0");
061            return;
062        }
063        if ( _evVarArr == null || index > _evVarArr.length ) {
064            log.error("Event Variable Index {} out of range, {} has {} Event Variables",
065                index, this, getNumEvVars() );
066            return;
067        }
068        if (value > 255 ) {
069            log.error("Event Variable value needs to be less than 255 (oxff)");
070            return;
071        }
072        _evVarArr[(index-1)]=value;
073        notifyModel();
074
075    }
076    
077    /**
078     * Set the value of the event variable array by existing array
079     *
080     * @param newArray event variable array, 1st value index 0 should be 1st event value, NOT total
081     */    
082    public final void setEvArr( int[] newArray ){
083        _evVarArr = newArray;
084        notifyModel();
085    }
086    
087    /**
088     * Returns the value of an event variable
089     *
090     * @param index of the variable, no array offset needed, 1 is 1
091     * @return the decimal event indexed variable value, -1 if unknown or index out of range
092     */
093    public int getEvVar(int index) {
094        if ( _evVarArr == null || index < 1 || index > _evVarArr.length ) {
095            log.error("Event Variable Index {} out of range, {} has {} Event Variables",
096                index, this, getNumEvVars() );
097            return -1;
098        }
099        return _evVarArr[(index-1)];
100    }
101    
102    public int[] getEvVarArray() {
103        return _evVarArr;
104    }
105    
106    /**
107     * Returns all event variables as a single string
108     * <p>
109     * eg. /"1, 13, 1, 0, 0/"
110     *
111     * @return the decimal string for of the array, unknown values are blanked
112     */    
113    public String getEvVarString(){
114        StringBuilder n = new StringBuilder();
115        // n.append("[ ");
116        for(int i = 0; i< _evVarArr.length; i++){
117            if ( _evVarArr[i] > -1 ) {
118                n.append( _evVarArr[i] );
119            }
120            else {
121                n.append( " " );
122            }
123            if ( i != ( _evVarArr.length-1 ) ) {
124                n.append( ", " );
125            }
126        }
127        // n.append(" ]");
128        return n.toString();
129    }
130    
131    /**
132     * Returns all event variables as a single hex string
133     * <p>
134     * eg. returns 0104D6A0
135     *
136     * @return the hex string for of the array
137     */ 
138    public String getHexEvVarString() {
139        if (getEvVarArray() != null) {
140            return StringUtil.hexStringFromInts(getEvVarArray()).replaceAll("\\s", "");
141        }
142        return "";
143    }
144
145    /**
146     * Returns the number of unknown event variables
147     *
148     * @return the decimal outstanding total
149     */    
150    public int getOutstandingVars() {
151        if ( getEvVarArray() == null ){
152            return 0;
153        }
154        int count = 0;
155        for (int val : getEvVarArray()){
156            if (val == -1) {
157                count ++;
158            }
159        }
160        return count;
161    }
162    
163    /**
164     * Returns the index of the next unknown event variable
165     * @return the decimal index value else 0 if all known
166     */     
167    public int getNextOutstanding() {
168        for (int i = 0; i < _evVarArr.length; i++) {
169            if ( _evVarArr[i] == -1) {
170                return i+1;
171            }
172        }
173        return 0;
174    }
175
176    /**
177     * Get the number of event variables
178     * by Array Length
179     * 
180     * @return number of event variables
181     */      
182    public int getNumEvVars() {
183        if ( _evVarArr == null ) {
184            return 0;
185        }
186        return _evVarArr.length;
187    }
188    
189    /**
190     * Sets unknown event variables to 0
191     * 
192     */
193    protected void allOutstandingEvVarsNotNeeded(){
194        for (int i = 0; i < _evVarArr.length; i++) {
195            if ( _evVarArr[i] == -1) {
196                _evVarArr[i] = 0;
197            }
198        }
199    }
200    
201    /** 
202     * {@inheritDoc} 
203     * <p>
204     * Custom method to compare Node Num, Ev Num, Parent Node Num, Event Variables
205     */
206    @Override
207    public boolean equals(Object o) {
208        if (!(o instanceof CbusNodeEvent)) {
209            return false;
210        }
211        CbusNodeEvent t = (CbusNodeEvent) o;
212        if ( this.getEn()!=t.getEn() || this.getNn()!=t.getNn() ) {
213            return false;
214        }
215        if ( this.getParentNn()!=t.getParentNn() ) {
216            return false;
217        }
218        return this.getHexEvVarString().equals(t.getHexEvVarString());
219    }
220    
221    /** {@inheritDoc} */
222    @Override
223    public int hashCode() {
224        return Objects.hash(getEn(), getNn(), getParentNn(), getHexEvVarString());
225    }
226    
227    /** 
228     * {@inheritDoc} 
229     * Compares to the Node / Event numbers of the Event
230     */
231    @Override
232    public int compareTo(CbusNodeEvent o) {
233        return Integer.compare(this.listOrder(),o.listOrder());
234    }
235    
236    private int listOrder(){
237        return (getNn()*65535+getEn())+100+(Objects.hash(getHexEvVarString())%100);
238    }
239    
240    private static final Logger log = LoggerFactory.getLogger(CbusNodeEvent.class);
241
242}