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 (value > 255 ) {
064            log.error("Event Variable value needs to be less than 255 (oxff)");
065            return;
066        }
067        _evVarArr[(index-1)]=value;
068        notifyModel();
069        
070    }
071    
072    /**
073     * Set the value of the event variable array by existing array
074     *
075     * @param newArray event variable array, 1st value index 0 should be 1st event value, NOT total
076     */    
077    public final void setEvArr( int[] newArray ){
078        _evVarArr = newArray;
079        notifyModel();
080    }
081    
082    /**
083     * Returns the value of an event variable
084     *
085     * @param index of the variable, no array offset needed, 1 is 1
086     * @return the decimal event indexed variable value
087     */
088    public int getEvVar(int index) {
089        return _evVarArr[(index-1)];
090    }
091    
092    public int[] getEvVarArray() {
093        return _evVarArr;
094    }
095    
096    /**
097     * Returns all event variables as a single string
098     * <p>
099     * eg. /"1, 13, 1, 0, 0/"
100     *
101     * @return the decimal string for of the array, unknown values are blanked
102     */    
103    public String getEvVarString(){
104        StringBuilder n = new StringBuilder();
105        // n.append("[ ");
106        for(int i = 0; i< _evVarArr.length; i++){
107            if ( _evVarArr[i] > -1 ) {
108                n.append( _evVarArr[i] );
109            }
110            else {
111                n.append( " " );
112            }
113            if ( i != ( _evVarArr.length-1 ) ) {
114                n.append( ", " );
115            }
116        }
117        // n.append(" ]");
118        return n.toString();
119    }
120    
121    /**
122     * Returns all event variables as a single hex string
123     * <p>
124     * eg. returns 0104D6A0
125     *
126     * @return the hex string for of the array
127     */ 
128    public String getHexEvVarString() {
129        if (getEvVarArray() != null) {
130            return StringUtil.hexStringFromInts(getEvVarArray()).replaceAll("\\s", "");
131        }
132        return "";
133    }
134
135    /**
136     * Returns the number of unknown event variables
137     *
138     * @return the decimal outstanding total
139     */    
140    public int getOutstandingVars() {
141        if ( getEvVarArray() == null ){
142            return 0;
143        }
144        int count = 0;
145        for (int val : getEvVarArray()){
146            if (val == -1) {
147                count ++;
148            }
149        }
150        return count;
151    }
152    
153    /**
154     * Returns the index of the next unknown event variable
155     * @return the decimal index value else 0 if all known
156     */     
157    public int getNextOutstanding() {
158        for (int i = 0; i < _evVarArr.length; i++) {
159            if ( _evVarArr[i] == -1) {
160                return i+1;
161            }
162        }
163        return 0;
164    }
165
166    /**
167     * Get the number of event variables
168     * by Array Length
169     * 
170     * @return number of event variables
171     */      
172    public int getNumEvVars() {
173        return _evVarArr.length;
174    }
175    
176    /**
177     * Sets unknown event variables to 0
178     * 
179     */
180    protected void allOutstandingEvVarsNotNeeded(){
181        for (int i = 0; i < _evVarArr.length; i++) {
182            if ( _evVarArr[i] == -1) {
183                _evVarArr[i] = 0;
184            }
185        }
186    }
187    
188    /** 
189     * {@inheritDoc} 
190     * <p>
191     * Custom method to compare Node Num, Ev Num, Parent Node Num, Event Variables
192     */
193    @Override
194    public boolean equals(Object o) {
195        if (!(o instanceof CbusNodeEvent)) {
196            return false;
197        }
198        CbusNodeEvent t = (CbusNodeEvent) o;
199        if ( this.getEn()!=t.getEn() || this.getNn()!=t.getNn() ) {
200            return false;
201        }
202        if ( this.getParentNn()!=t.getParentNn() ) {
203            return false;
204        }
205        return this.getHexEvVarString().equals(t.getHexEvVarString());
206    }
207    
208    /** {@inheritDoc} */
209    @Override
210    public int hashCode() {
211        return Objects.hash(getEn(), getNn(), getParentNn(), getHexEvVarString());
212    }
213    
214    /** 
215     * {@inheritDoc} 
216     * Compares to the Node / Event numbers of the Event
217     */
218    @Override
219    public int compareTo(CbusNodeEvent o) {
220        return Integer.compare(this.listOrder(),o.listOrder());
221    }
222    
223    private int listOrder(){
224        return (getNn()*65535+getEn())+100+(Objects.hash(getHexEvVarString())%100);
225    }
226    
227    private static final Logger log = LoggerFactory.getLogger(CbusNodeEvent.class);
228
229}