001package jmri.jmrix.can.cbus;
002
003import java.util.EnumSet;
004import javax.annotation.CheckForNull;
005import javax.annotation.Nonnull;
006import jmri.jmrix.AbstractMessage;
007import jmri.jmrix.can.CanFrame;
008
009/**
010 * ENUM to represent various CBUS OPC Filters.
011 * 
012 * @author Steve Young (C) 2020
013 */
014public enum CbusFilterType {
015    CFIN(Bundle.getMessage("Incoming"),null) {
016        @Override
017        public int action(AbstractMessage m, CbusFilter cf) {
018            if (m instanceof jmri.jmrix.can.CanReply) {
019                return super.action(m,cf);
020            }
021            return -1;
022        } },
023    CFOUT(Bundle.getMessage("Outgoing"),null) {
024        @Override
025        public int action(AbstractMessage m, CbusFilter cf) {
026            if (m instanceof jmri.jmrix.can.CanMessage) {
027                return super.action(m, cf);
028            }
029            return -1;
030        } },
031    CFEVENT(Bundle.getMessage("CbusEvents"),null),
032    CFEVENTMIN(Bundle.getMessage("MinEvent"),CFEVENT) {
033        @Override
034        public int action(AbstractMessage m, CbusFilter cf) {
035        if ( CbusMessage.getEvent(m) < cf.getEvMin()) {
036            return super.action(m,cf);
037        }
038        CbusFilter.incrementCount(ordinal(),cf);
039        return -1;
040    } },
041    CFEVENTMAX(Bundle.getMessage("MaxEvent"),CFEVENT) {
042        @Override
043        public int action(AbstractMessage m, CbusFilter cf) {
044            if ( CbusMessage.getEvent(m) > cf.getEvMax()){ 
045                return super.action(m,cf);
046            }
047            CbusFilter.incrementCount(ordinal(),cf);
048            return -1;
049        } },
050    CFON(Bundle.getMessage("CbusOnEvents"),CFEVENT),
051    CFOF(Bundle.getMessage("CbusOffEvents"),CFEVENT),
052    CFSHORT(Bundle.getMessage("ShortEvents"),CFEVENT),
053    CFLONG(Bundle.getMessage("LongEvents"),CFEVENT),
054    CFSTD(Bundle.getMessage("StandardEvents"),CFEVENT),
055    CFREQUEST(Bundle.getMessage("RequestEvents"),CFEVENT),
056    CFRESPONSE(Bundle.getMessage("ResponseEvents"),CFEVENT),
057    CFED0(Bundle.getMessage("EVD0"),CFEVENT),
058    CFED1(Bundle.getMessage("EVD1"),CFEVENT),
059    CFED2(Bundle.getMessage("EVD2"),CFEVENT),
060    CFED3(Bundle.getMessage("EVD3"),CFEVENT),
061
062    CFNODE(Bundle.getMessage("CbusNodes"),null) {
063        @Override
064        public int action(AbstractMessage m, CbusFilter cf) {
065            return CbusFilter.checknode(CbusMessage.getNodeNumber(m),cf);
066        } },
067    CFNODEMIN(Bundle.getMessage("MinNode"),CFNODE) {
068        @Override
069        public int action(AbstractMessage m, CbusFilter cf) {
070            if ( CbusMessage.getNodeNumber(m) < cf.getNdMin()){ 
071                return super.action(m, cf);
072            }
073            CbusFilter.incrementCount(ordinal(),cf);
074            return -1;
075        } },
076    CFNODEMAX(Bundle.getMessage("MaxNode"),CFNODE) {
077        @Override 
078        public int action(AbstractMessage m, CbusFilter cf) {
079            if ( CbusMessage.getNodeNumber(m) > cf.getNdMax()){ 
080                return super.action(m, cf);
081            }
082            CbusFilter.incrementCount(ordinal(),cf);
083            return -1;
084        } },
085    CFNODES(Bundle.getMessage("CbusNodes"),CFNODE) {
086        @Override 
087        public int action(AbstractMessage m, CbusFilter cf) {
088            return -1;
089        } },
090
091    CFDATA(Bundle.getMessage("OPC_DA"),null),
092    CFACDAT("ACDAT",CFDATA),
093    CFDDES("DDES + DDWS",CFDATA),
094    CFRQDAT("RQDAT",CFDATA),
095    CFARDAT("ARDAT",CFDATA),
096    CFDDRS("DDRS",CFDATA),
097    CFRQDDS("RQDDS",CFDATA),
098    CFCABDAT("CABDAT",CFDATA),
099
100    CFCS(Bundle.getMessage("CommandStation"),null),
101    CFCSAQRL(Bundle.getMessage("LocoCommands"),CFCS),
102    CFCSKA(Bundle.getMessage("KeepAlive"),CFCS),
103    CFCSDSPD(Bundle.getMessage("SpeedDirection"),CFCS),
104    CFCSFUNC(Bundle.getMessage("Functions"),CFCS),
105    CFCSPROG(Bundle.getMessage("Programming"),CFCS),
106    CFCSLC(Bundle.getMessage("LayoutCommands"),CFCS),
107    CFCSC(Bundle.getMessage("CommandStationControl"),CFCS),
108
109    CFNDCONFIG(Bundle.getMessage("NodeConfiguration"),null),
110    CFNDSETUP(Bundle.getMessage("GeneralNodeSetup"),CFNDCONFIG),
111    CFNDVAR(Bundle.getMessage("NodeVariables"),CFNDCONFIG),
112    CFNDEV(Bundle.getMessage("NodeEvents"),CFNDCONFIG),
113    CFNDNUM(Bundle.getMessage("NodeNumbers"),CFNDCONFIG),
114
115    CFMISC(Bundle.getMessage("Misc"),null),
116    CFEXTRTR("Extended / RTR",CFMISC){
117        @Override 
118        public int action(AbstractMessage m, CbusFilter cf) {
119        if (m instanceof CanFrame && ((CanFrame) m).extendedOrRtr() ) {
120            if ( cf.getActiveFilters().get(ordinal()) ){
121                return ordinal();
122            } else {
123                CbusFilter.incrementCount(ordinal(),cf);
124                return -2; // special return as unable to contiinue filtering if extended or rtr
125            }
126        }
127        return -1;
128        } },
129    CFNETWK(Bundle.getMessage("NetworkCommands"),CFMISC),
130    CFCLOCK(Bundle.getMessage("CBUS_FCLK"),CFMISC),
131    CFOTHER(Bundle.getMessage("Others"),CFMISC),
132    CFUNKNOWN(Bundle.getMessage("Unknown"),CFMISC);
133
134    /**
135     * Perform Filter check for a particular message.
136     * Can be overridden by specific filters.
137     * 
138     * @param m CanMessage or CanReply
139     * @param cf main CbusFilter instance
140     * @return Filter category which blocked, else -1 or -2 if passed 
141     */
142    public int action(AbstractMessage m, CbusFilter cf){
143        if ( cf.getActiveFilters().get(ordinal()) ){
144            return ordinal();
145        } else {
146            CbusFilter.incrementCount(ordinal(),cf);
147            return -1;
148        }
149    }
150
151    private final String _bundleString;
152    private final CbusFilterType _category;
153
154    /**
155     * Create new CbusFilterType.
156     */
157    CbusFilterType(String bundle, CbusFilterType category) {
158        this._bundleString=bundle;
159        this._category = category;
160    }
161
162    /**
163     * Get Filter Name
164     * @return Filter Name
165     */
166    public final String getName(){
167        return _bundleString;
168    }
169
170    /**
171     * Get Filter Category
172     * @return Filter Category, else null if Category Head
173     */
174    @CheckForNull
175    public final CbusFilterType getCategory() {
176        return _category;
177    }
178
179    /**
180     * Get an EnumSet of Category Heads
181     * @return set
182     */
183    public final static EnumSet<CbusFilterType> getCatHeads() {
184        EnumSet<CbusFilterType> catSet = EnumSet.noneOf(CbusFilterType.class);
185        catSet.add(CFEVENT);
186        catSet.add(CFNODE);
187        catSet.add(CFDATA);
188        catSet.add(CFCS);
189        catSet.add(CFNDCONFIG);
190        catSet.add(CFMISC);
191        return catSet;
192    }
193
194    /**
195     * Is the Filter a parent of a category?
196     * @return true if category parent
197     */
198    public final boolean isCategoryHead() {
199        return getCatHeads().contains(this);
200    }
201
202    /**
203     * Should the Filter always be displayed?
204     * @return true if category head or in / out filter.
205     */
206    public final boolean alwaysDisplay() {
207        EnumSet<CbusFilterType> alwaysDisplay = getCatHeads();
208        alwaysDisplay.add(CFIN);
209        alwaysDisplay.add(CFOUT);
210        return alwaysDisplay.contains(this);
211    }
212
213    /**
214     * Get if the Filter needs to display a number spinner
215     * @return true to display a spinner
216     */
217    public final boolean showSpinners() {
218        EnumSet<CbusFilterType> spinnerSet = EnumSet.noneOf(CbusFilterType.class);
219        spinnerSet.addAll(EnumSet.of(CFEVENTMIN,CFEVENTMAX,CFNODEMIN,CFNODEMAX));
220        return spinnerSet.contains(this);
221    }
222
223    /**
224     * Get All Filters for a particular OPC
225     * @param opc OPC to get Filter List for
226     * @return set of Filters to use for the OPC.
227     */
228    @Nonnull
229    public final static EnumSet<CbusFilterType> allFilters(int opc) {
230        EnumSet<CbusFilterType> mergedSet = EnumSet.noneOf(CbusFilterType.class);
231        mergedSet.addAll(EnumSet.of(CFIN,CFOUT,CFEXTRTR));
232        mergedSet.addAll(CbusOpCodes.getOpcFilters(opc));
233        if (mergedSet.contains(CbusFilterType.CFEVENT)){
234            mergedSet.addAll(EnumSet.of(CbusFilterType.CFEVENTMIN,CbusFilterType.CFEVENTMAX));
235        }
236        if (mergedSet.contains(CbusFilterType.CFNODE)){
237           mergedSet.addAll(EnumSet.of(CbusFilterType.CFNODEMIN,CbusFilterType.CFNODEMAX));
238        }
239        return mergedSet;
240    }
241
242    /**
243     * Get ToolTip Text for the Filter
244     * @return HMTL list of OPCs with description, may be null if no ToolTip
245     */
246    @CheckForNull
247    public final String getToolTip(){
248        StringBuilder t = new StringBuilder();
249        for ( int i=0 ; (i < 257) ; i++) {
250            if (CbusOpCodes.getOpcFilters(i).contains(this) 
251            && !CbusOpCodes.getOpcName(i).isEmpty()){
252                t.append(CbusOpCodes.getOpcName(i))
253                .append(" : ")
254                .append(Bundle.getMessage("CBUS_" + CbusOpCodes.getOpcName(i)))
255                .append(" : ")
256                .append(Bundle.getMessage("CTIP_" + CbusOpCodes.getOpcName(i)))
257                .append("<br>");
258            }
259        }
260        if (!t.toString().isEmpty()){
261            t.insert(0,"<html>");
262            t.append("<html>");
263            return t.toString();
264        }
265        return null;
266    }
267}