001package jmri.jmrit.logixng.implementation;
002
003import java.io.File;
004import java.io.BufferedWriter;
005import java.io.FileNotFoundException;
006import java.io.OutputStreamWriter;
007import java.io.FileOutputStream;
008import java.io.PrintWriter;
009import java.nio.charset.StandardCharsets;
010import java.util.HashMap;
011import java.util.Map;
012import javax.annotation.CheckForNull;
013import javax.annotation.Nonnull;
014import jmri.jmrit.logixng.AnonymousTable;
015
016/**
017 * Default implementation for anonymous tables
018 */
019public class DefaultAnonymousTable implements AnonymousTable {
020
021    private final int _numRows;
022    private final int _numColumns;
023    private final Object[][] _data;
024    private final Map<String,Integer> rowNames = new HashMap<>();
025    private final Map<String,Integer> columnNames = new HashMap<>();
026
027    public DefaultAnonymousTable(int numRows, int numColumns) {
028        _numRows = numRows;
029        _numColumns = numColumns;
030        _data = new Object[numRows+1][numColumns+1];
031        setupTable();
032    }
033
034    /**
035     * Create a new anonymous table with an existing array of cells.
036     * Row 0 has the column names and column 0 has the row names.
037     * @param data the data in the table. Note that this data is not copied to
038     * an new array but used by the table as is.
039     */
040    public DefaultAnonymousTable(@Nonnull Object[][] data) {
041        // Row 0 has column names
042        _numRows = data.length-1;
043        // Column 0 has row names
044        _numColumns = data[0].length-1;
045        _data = data;
046
047        for (int row=0; row < _data.length; row++) {
048            if (_numColumns+1 != _data[row].length) {
049                throw new IllegalArgumentException("All rows in table must have same number of columns");
050            }
051        }
052
053        setupTable();
054/*
055        int i[][] = new int[15][];
056        i[5] = new int[3];
057        i[7] = new int[10];
058        i[5][2] = 3;
059//        i[5][8] = 4;
060        i[7][2] = 5;
061        i[7][8] = 6;
062//        i[2][2] = 7;
063//        i[2][8] = 8;
064
065        i = new int[15][20];
066//        i[5] = new int[3];
067        i[7] = new int[10];
068        i[5][2] = 3;
069        i[5][8] = 4;
070        i[7][2] = 5;
071        i[7][8] = 6;
072        i[2][2] = 7;
073        i[2][8] = 8;
074*/
075    }
076
077    private void setupTable() {
078        for (int i=0; i <= _numRows; i++) {
079            Object cell = _data[i][0];
080            if (cell != null && cell instanceof String) {
081                rowNames.put(cell.toString(), i);
082            }
083        }
084
085        for (int i=0; i <= _numColumns; i++) {
086            Object cell = _data[0][i];
087            if (cell != null && cell instanceof String) {
088                columnNames.put(cell.toString(), i);
089            }
090        }
091    }
092
093    /**
094     * {@inheritDoc}
095     */
096    @Override
097    public void storeTableAsCSV() throws FileNotFoundException {
098        throw new UnsupportedOperationException("Not supported");
099    }
100
101    /**
102     * {@inheritDoc}
103     */
104    @Override
105    public void storeTableAsCSV(@Nonnull File file)
106            throws FileNotFoundException {
107        storeTableAsCSV(file, null, null);
108    }
109
110    /**
111     * {@inheritDoc}
112     */
113    @Override
114    public void storeTableAsCSV(@Nonnull File file, boolean storeSystemUserName)
115            throws FileNotFoundException {
116        storeTableAsCSV(file, null, null);
117    }
118
119    /**
120     * {@inheritDoc}
121     */
122    @Override
123    public void storeTableAsCSV(
124            @Nonnull File file,
125            @CheckForNull String systemName, @CheckForNull String userName)
126            throws FileNotFoundException {
127
128        storeTableAsCSV(file, systemName, userName, true);
129    }
130
131    /**
132     * {@inheritDoc}
133     */
134    @Override
135    public void storeTableAsCSV(
136            @Nonnull File file,
137            @CheckForNull String systemName, @CheckForNull String userName,
138            boolean storeSystemUserName)
139            throws FileNotFoundException {
140
141        try (PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)))) {
142            if (storeSystemUserName) {
143                writer.format("%s\t%s%n", systemName, userName);
144            }
145            for (int row=0; row <= _numRows; row++) {
146                for (int column=0; column <= _numColumns; column++) {
147                    if (column > 0) writer.print("\t");
148//                    System.out.format("%d, %d: %s%n", row, column, _data[row][column].toString());
149                    if (_data[row][column] != null) writer.print(_data[row][column].toString());
150                }
151                writer.println();
152            }
153        }
154    }
155
156    /**
157     * {@inheritDoc}
158     */
159    @Override
160    public Object getCell(int row, int column) {
161        return _data[row][column];
162    }
163
164    /**
165     * {@inheritDoc}
166     */
167    @Override
168    public void setCell(Object value, int row, int column) {
169        _data[row][column] = value;
170    }
171
172    /**
173     * {@inheritDoc}
174     */
175    @Override
176    public int numRows() {
177        return _numRows;
178    }
179
180    /**
181     * {@inheritDoc}
182     */
183    @Override
184    public int numColumns() {
185        return _numColumns;
186    }
187
188    /**
189     * {@inheritDoc}
190     */
191    @Override
192    public int getRowNumber(String rowName) {
193        Integer rowNumber = rowNames.get(rowName);
194        if (rowNumber == null) {
195            try {
196                int row = Integer.parseInt(rowName);
197                if (row >= 0 && row <= _numRows) return row;
198            } catch (NumberFormatException e) {
199                // Do nothing
200            }
201        } else {
202            return rowNumber;
203        }
204        // If here, the row is not found
205        throw new RowNotFoundException(rowName);
206    }
207
208    /**
209     * {@inheritDoc}
210     */
211    @Override
212    public int getColumnNumber(String columnName) {
213        Integer columnNumber = columnNames.get(columnName);
214        if (columnNumber == null) {
215            try {
216                int column = Integer.parseInt(columnName);
217                if (column >= 0 && column <= _numColumns) return column;
218            } catch (NumberFormatException e) {
219                // Do nothing
220            }
221        } else {
222            return columnNumber;
223        }
224        // If here, the column is not found
225        throw new ColumnNotFoundException(columnName);
226    }
227
228    @Override
229    public void insertColumn(int col) {
230        throw new UnsupportedOperationException("Not supported");
231    }
232
233    @Override
234    public void deleteColumn(int col) {
235        throw new UnsupportedOperationException("Not supported");
236    }
237
238    @Override
239    public void insertRow(int row) {
240        throw new UnsupportedOperationException("Not supported");
241    }
242
243    @Override
244    public void deleteRow(int row) {
245        throw new UnsupportedOperationException("Not supported");
246    }
247
248}