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(@Nonnull File file)
098            throws FileNotFoundException {
099        storeTableAsCSV(file, null, null);
100    }
101
102    /**
103     * {@inheritDoc}
104     */
105    @Override
106    public void storeTableAsCSV(
107            @Nonnull File file,
108            @CheckForNull String systemName, @CheckForNull String userName)
109            throws FileNotFoundException {
110        
111        try (PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)))) {
112            writer.format("%s\t%s%n", systemName, userName);
113            for (int row=0; row <= _numRows; row++) {
114                for (int column=0; column <= _numColumns; column++) {
115                    if (column > 0) writer.print("\t");
116//                    System.out.format("%d, %d: %s%n", row, column, _data[row][column].toString());
117                    if (_data[row][column] != null) writer.print(_data[row][column].toString());
118                }
119                writer.println();
120            }
121        }
122    }
123    
124    /**
125     * {@inheritDoc}
126     */
127    @Override
128    public Object getCell(int row, int column) {
129        return _data[row][column];
130    }
131
132    /**
133     * {@inheritDoc}
134     */
135    @Override
136    public void setCell(Object value, int row, int column) {
137        _data[row][column] = value;
138    }
139
140    /**
141     * {@inheritDoc}
142     */
143    @Override
144    public int numRows() {
145        return _numRows;
146    }
147
148    /**
149     * {@inheritDoc}
150     */
151    @Override
152    public int numColumns() {
153        return _numColumns;
154    }
155    
156    /**
157     * {@inheritDoc}
158     */
159    @Override
160    public int getRowNumber(String rowName) {
161        Integer rowNumber = rowNames.get(rowName);
162        if (rowNumber == null) {
163            try {
164                int row = Integer.parseInt(rowName);
165                if (row >= 0 && row <= _numRows) return row;
166            } catch (NumberFormatException e) {
167                // Do nothing
168            }
169        } else {
170            return rowNumber;
171        }
172        // If here, the row is not found
173        throw new RowNotFoundException(rowName);
174    }
175
176    /**
177     * {@inheritDoc}
178     */
179    @Override
180    public int getColumnNumber(String columnName) {
181        Integer columnNumber = columnNames.get(columnName);
182        if (columnNumber == null) {
183            try {
184                int column = Integer.parseInt(columnName);
185                if (column >= 0 && column <= _numColumns) return column;
186            } catch (NumberFormatException e) {
187                // Do nothing
188            }
189        } else {
190            return columnNumber;
191        }
192        // If here, the column is not found
193        throw new ColumnNotFoundException(columnName);
194    }
195
196    @Override
197    public void insertColumn(int col) {
198        throw new UnsupportedOperationException("Not supported");
199    }
200
201    @Override
202    public void deleteColumn(int col) {
203        throw new UnsupportedOperationException("Not supported");
204    }
205
206    @Override
207    public void insertRow(int row) {
208        throw new UnsupportedOperationException("Not supported");
209    }
210
211    @Override
212    public void deleteRow(int row) {
213        throw new UnsupportedOperationException("Not supported");
214    }
215
216}