001package jmri.jmrix.can.cbus.eventtable;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005
006import javax.annotation.Nonnull;
007import javax.swing.JCheckBox;
008
009import jmri.NamedBean;
010import jmri.jmrix.AbstractMessage;
011import jmri.jmrix.can.CanMessage;
012import jmri.jmrix.can.CanReply;
013import jmri.jmrix.can.cbus.CbusConstants;
014import jmri.jmrix.can.cbus.CbusEvent;
015import jmri.jmrix.can.cbus.CbusEventInterface;
016import jmri.jmrix.can.cbus.CbusMessage;
017import jmri.util.ThreadingUtil;
018import jmri.util.swing.JmriJOptionPane;
019
020/**
021 *
022 * @author Steve Young (c) 2018, 2019
023 *
024 */
025public class CbusEventTableAction implements PropertyChangeListener {
026
027    private final CbusBasicEventTableModel _model;
028
029    public CbusEventTableAction( @Nonnull CbusBasicEventTableModel model) {
030        _model = model;
031        addRemoveListenersToNbManagers(true);
032    }
033
034    protected boolean sessionConfirmDeleteRow=true; // display confirm popup
035
036    private void linkHwaddtoEvent(NamedBean bean, boolean beanState, CanMessage m){
037        if (m==null){
038            return;
039        }
040        int en = CbusMessage.getEvent(m);
041        int nn = CbusMessage.getNodeNumber(m);
042        CbusTableEvent event = _model.provideEvent(nn,en);
043        event.appendOnOffBean(bean, beanState, CbusEvent.getEvState(m));
044        fireJmriCellsChanged(_model.getEventTableRow(nn, en));
045    }
046
047    private void fireJmriCellsChanged(int row){
048        ThreadingUtil.runOnGUIEventually( ()->{
049            _model.fireTableCellUpdated(row, CbusEventTableDataModel.STLR_ON_COLUMN);
050            _model.fireTableCellUpdated(row, CbusEventTableDataModel.STLR_OFF_COLUMN);
051        });
052    }
053
054    private void fireAllJmriCellsChanged(){
055        for (int i=0; i < _model.getRowCount(); i++) {
056            fireJmriCellsChanged(i);
057        }
058    }
059
060    /**
061     * Update all columns for JMRI Sensor, Turnout and light details
062     */
063    public void updatejmricols(){
064
065        // reset all columns
066        _model._mainArray.forEach((n) -> n.resetBeans() );
067        fireAllJmriCellsChanged();
068        for (Class<?> classType : classTypes) {
069            jmri.Manager<?> sm = (jmri.Manager<?>) _model._memo.get(classType);
070            sm.getNamedBeanSet().forEach((nb) -> {
071                if (nb instanceof CbusEventInterface) {
072                    linkHwaddtoEvent( nb, true, ((CbusEventInterface)nb).getBeanOnMessage());
073                    linkHwaddtoEvent( nb, false, ((CbusEventInterface)nb).getBeanOffMessage());
074                }
075            });
076        }
077    }
078
079    public void resetAllSessionTotals() {
080        _model.getEvents().forEach( ( ev) ->{
081            ev.resetSessionTotals();
082            updateStatColumnsinGui(_model.getEventTableRow(ev.getNn(), ev.getEn()));
083        });
084    }
085
086    private final Class<?>[] classTypes = new Class<?>[]{
087        jmri.TurnoutManager.class,jmri.SensorManager.class,jmri.LightManager.class};
088
089    protected final void addRemoveListenersToNbManagers(boolean add){
090        for (Class<?> classType : classTypes) {
091            if (add) {
092                ((jmri.Manager<?>) _model._memo.get(classType)).addPropertyChangeListener(this);
093            } else {
094                ((jmri.Manager<?>) _model._memo.get(classType)).removePropertyChangeListener(this);
095            }
096        }
097    }
098
099    /** {@inheritDoc} */
100    @Override
101    public void propertyChange(PropertyChangeEvent ev){
102        updatejmricols();
103    }
104
105    /**
106     * Delete Button Clicked
107     * See whether to display confirm popup
108     * @param row int row number
109     */
110    public void buttonDeleteClicked(int row) {
111        if (sessionConfirmDeleteRow) {
112            // confirm deletion with the user
113            ThreadingUtil.runOnGUI( ()-> {
114                JCheckBox checkbox = new JCheckBox(Bundle.getMessage("PopupSessionConfirmDel")); // NOI18N
115                String message = Bundle.getMessage("DelConfirmOne") + "\n"
116                + Bundle.getMessage("DelConfirmTwo"); // NOI18N
117                Object[] params = {message, checkbox};
118
119                if (JmriJOptionPane.OK_OPTION == JmriJOptionPane.showConfirmDialog(
120                        null, params, Bundle.getMessage("DelEvPopTitle"),  // NOI18N
121                        JmriJOptionPane.OK_CANCEL_OPTION,
122                    JmriJOptionPane.WARNING_MESSAGE)) {
123
124                        sessionConfirmDeleteRow=!checkbox.isSelected();
125                        removeRow(row);
126                }
127            });
128        } else {
129            // no need to show warning, just delete
130            removeRow(row);
131        }
132    }
133
134    /**
135     * Remove Row from table
136     * @param row int row number
137     */
138    protected void removeRow(int row) {
139        _model._mainArray.remove(row);
140        ThreadingUtil.runOnGUIEventually( ()-> _model.fireTableRowsDeleted(row,row));
141    }
142
143    protected void updateGuiCell( int row, int col){
144        ThreadingUtil.runOnGUIEventually(() -> _model.fireTableCellUpdated(row, col));
145    }
146
147    private void updateStatColumnsinGui( int row){
148        for (int i : CbusEventTableDataModel.canFrameCols) {
149            updateGuiCell(row,i);
150        }
151    }
152
153        /**
154     * If new event add to table, else update table.
155     * @param m Message to process
156     */
157    protected void parseMessage( AbstractMessage m) {
158        if (!CbusMessage.isEvent(m)) { // also checks for extended & rtr
159            return;
160        }
161        CbusTableEvent ev = _model.provideEvent(CbusMessage.getNodeNumber(m),CbusMessage.getEvent(m));
162        ev.setState(CbusTableEvent.getEvState(m)); // sets state, timestamp and on / off count
163        ev.setCanId(CbusMessage.getId(m));
164        ev.setDataFromFrame(m);
165        ev.bumpDirection( (m instanceof CanReply) ? CbusConstants.EVENT_DIR_IN : CbusConstants.EVENT_DIR_OUT);
166        updateStatColumnsinGui(_model.getEventTableRow(CbusMessage.getNodeNumber(m), CbusMessage.getEvent(m)));
167
168    }
169
170    public void dispose(){
171        addRemoveListenersToNbManagers(false);
172    }
173
174    // private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusEventTableAction.class);
175}