/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.inputmethod.keyboard.layout.expected;
import java.util.Arrays;
/**
* This class builds a keyboard that is a two dimensional array of elements E
.
*
* A keyboard consists of an array of rows, and a row consists of an array of elements. Each row
* may have different number of elements. A element of a keyboard can be specified by a row number
* and a column number, both numbers starts from 1.
*
* @param the type of a keyboard element. A keyboard element must be an immutable object.
*/
abstract class AbstractKeyboardBuilder {
// A building array of rows.
private E[][] mRows;
// Returns an instance of default element.
abstract E defaultElement();
// Returns an E
array instance of the size
.
abstract E[] newArray(final int size);
// Returns an E[]
array instance of the size
.
abstract E[][] newArrayOfArray(final int size);
/**
* Construct an empty builder.
*/
AbstractKeyboardBuilder() {
mRows = newArrayOfArray(0);
}
/**
* Construct a builder from template keyboard. This builder has the same dimensions and
* elements of rows.
* @param rows the template keyboard rows. The elements of the rows
will be
* shared with this builder. Therefore a element must be an immutable object.
*/
AbstractKeyboardBuilder(final E[][] rows) {
mRows = newArrayOfArray(rows.length);
for (int rowIndex = 0; rowIndex < rows.length; rowIndex++) {
final E[] row = rows[rowIndex];
mRows[rowIndex] = Arrays.copyOf(row, row.length);
}
}
/**
* Return current constructing keyboard.
* @return the array of the array of the element being constructed.
*/
E[][] build() {
return mRows;
}
/**
* Return the number of rows.
* @return the number of rows being constructed.
*/
int getRowCount() {
return mRows.length;
}
/**
* Get the current contents of the specified row.
* @param row the row number to get the contents.
* @return the array of elements at row number row
.
* @throws RuntimeException if row
is illegal.
*/
E[] getRowAt(final int row) {
final int rowIndex = row - 1;
if (rowIndex < 0 || rowIndex >= mRows.length) {
throw new RuntimeException("Illegal row number: " + row);
}
return mRows[rowIndex];
}
/**
* Set an array of elements to the specified row.
* @param row the row number to set elements
.
* @param elements the array of elements to set at row number row
.
* @throws RuntimeException if row
is illegal.
*/
void setRowAt(final int row, final E[] elements) {
final int rowIndex = row - 1;
if (rowIndex < 0) {
throw new RuntimeException("Illegal row number: " + row);
}
final E[][] newRows = (rowIndex < mRows.length) ? mRows
: Arrays.copyOf(mRows, rowIndex + 1);
newRows[rowIndex] = elements;
mRows = newRows;
}
/**
* Set or insert an element at specified position.
* @param row the row number to set or insert the element
.
* @param column the column number to set or insert the element
.
* @param element the element to set or insert at row,column
.
* @param insert if true, the element
is inserted at row,column
.
* Otherwise the element
replace the element at row,column
.
* @throws RuntimeException if row
or column
is illegal.
*/
void setElementAt(final int row, final int column, final E element, final boolean insert) {
final E[] elements = getRowAt(row);
final int columnIndex = column - 1;
if (columnIndex < 0) {
throw new RuntimeException("Illegal column number: " + column);
}
if (insert) {
if (columnIndex >= elements.length + 1) {
throw new RuntimeException("Illegal column number: " + column);
}
final E[] newElements = Arrays.copyOf(elements, elements.length + 1);
// Shift the remaining elements.
System.arraycopy(newElements, columnIndex, newElements, columnIndex + 1,
elements.length - columnIndex);
// Insert the element at row,column
.
newElements[columnIndex] = element;
// Replace the current row with one.
setRowAt(row, newElements);
return;
}
final E[] newElements = (columnIndex < elements.length) ? elements
: Arrays.copyOf(elements, columnIndex + 1);
newElements[columnIndex] = element;
setRowAt(row, newElements);
}
}