/*
* Copyright (C) 2015 Simon Vig Therkildsen
*
* 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 net.simonvt.cathode.database;
import android.database.Cursor;
import android.database.CursorIndexOutOfBoundsException;
import android.provider.BaseColumns;
import java.util.ArrayList;
import java.util.List;
/**
* A mutable cursor implementation backed by an {@link java.util.ArrayList} of {@code Object}s.
*/
public class SimpleCursor extends AbsSimpleCursor {
private final String[] columnNames;
private List<Object[]> data = new ArrayList<>();
private final int columnCount;
/**
* Constructs a new cursor with the given initial capacity.
*
* @param columnNames names of the columns, the ordering of which
* determines column ordering elsewhere in this cursor
*/
public SimpleCursor(String[] columnNames) {
this.columnNames = columnNames;
this.columnCount = columnNames.length;
}
/**
* Constructs a SimpleCursor from the data in source.
*/
public SimpleCursor(Cursor source) {
this.columnNames = source.getColumnNames();
this.columnCount = this.columnNames.length;
final int columnCount = source.getColumnCount();
while (source.moveToNext()) {
Object[] data = new Object[columnCount];
for (int i = 0; i < columnCount; i++) {
final int type = source.getType(i);
switch (type) {
case Cursor.FIELD_TYPE_BLOB:
data[i] = source.getBlob(i);
break;
case Cursor.FIELD_TYPE_FLOAT:
data[i] = source.getFloat(i);
break;
case Cursor.FIELD_TYPE_INTEGER:
data[i] = source.getLong(i);
break;
case Cursor.FIELD_TYPE_STRING:
data[i] = source.getString(i);
break;
}
}
add(data);
}
}
private Object get(int column) {
if (column < 0 || column >= columnCount) {
throw new CursorIndexOutOfBoundsException(
"Requested column: " + column + ", # of columns: " + columnCount);
}
if (pos < 0) {
throw new CursorIndexOutOfBoundsException("Before first row.");
}
if (pos >= data.size()) {
throw new CursorIndexOutOfBoundsException("After last row.");
}
return data.get(pos)[column];
}
/**
* Adds a new row to the end with the given column values. Not safe
* for concurrent use.
*
* @param columnValues in the same order as the the column names specified
* at cursor construction time
* @throws IllegalArgumentException if {@code columnValues.length !=
* columnNames.length}
*/
public void add(Object[] columnValues) {
if (columnValues.length != columnCount) {
throw new IllegalArgumentException(
"columnNames.length = " + columnCount + ", columnValues.length = " + columnValues.length);
}
data.add(columnValues);
}
public Object[] get() {
return data.get(pos);
}
/**
* Adds a new row to the end with the given column values. Not safe
* for concurrent use.
*
* @param columnValues in the same order as the the column names specified at cursor construction
* time
* @param position The position at which to insert columnValues
* @throws IllegalArgumentException if {@code columnValues.length != columnNames.length}
*/
public void add(Object[] columnValues, int position) {
if (columnValues.length != columnCount) {
throw new IllegalArgumentException(
"columnNames.length = " + columnCount + ", columnValues.length = " + columnValues.length);
}
data.add(position, columnValues);
}
/**
* Removes the item at the specified position.
*/
public void remove(int position) {
data.remove(position);
}
public void remove(long id) {
if (hasColumn(BaseColumns._ID)) {
final int idColumn = getColumnIndex(BaseColumns._ID);
for (int position = 0; position < getCount(); position++) {
Object[] values = data.get(position);
final long rowId = Long.valueOf(values[idColumn].toString());
if (id == rowId) {
data.remove(position);
break;
}
}
}
}
@Override public int getCount() {
return data.size();
}
@Override public String[] getColumnNames() {
return columnNames;
}
public boolean hasColumn(String column) {
for (String col : columnNames) {
if (column.equals(col)) {
return true;
}
}
return false;
}
@Override public String getString(int column) {
Object value = get(column);
if (value == null) return null;
return value.toString();
}
@Override public short getShort(int column) {
Object value = get(column);
if (value == null) return 0;
if (value instanceof Number) return ((Number) value).shortValue();
return Short.parseShort(value.toString());
}
@Override public int getInt(int column) {
Object value = get(column);
if (value == null) return 0;
if (value instanceof Number) return ((Number) value).intValue();
return Integer.parseInt(value.toString());
}
@Override public long getLong(int column) {
Object value = get(column);
if (value == null) return 0;
if (value instanceof Number) return ((Number) value).longValue();
return Long.parseLong(value.toString());
}
@Override public float getFloat(int column) {
Object value = get(column);
if (value == null) return 0.0f;
if (value instanceof Number) return ((Number) value).floatValue();
return Float.parseFloat(value.toString());
}
@Override public double getDouble(int column) {
Object value = get(column);
if (value == null) return 0.0d;
if (value instanceof Number) return ((Number) value).doubleValue();
return Double.parseDouble(value.toString());
}
@Override public byte[] getBlob(int column) {
Object value = get(column);
return (byte[]) value;
}
@Override public int getType(int column) {
return getTypeOfObject(get(column));
}
public static int getTypeOfObject(Object obj) {
if (obj == null) {
return FIELD_TYPE_NULL;
} else if (obj instanceof byte[]) {
return FIELD_TYPE_BLOB;
} else if (obj instanceof Float || obj instanceof Double) {
return FIELD_TYPE_FLOAT;
} else if (obj instanceof Long
|| obj instanceof Integer
|| obj instanceof Short
|| obj instanceof Byte) {
return FIELD_TYPE_INTEGER;
} else {
return FIELD_TYPE_STRING;
}
}
@Override public boolean isNull(int column) {
return get(column) == null;
}
}