/*
* Copyright 2011 cruxframework.org.
*
* 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 org.cruxframework.crux.core.client.datasource;
import java.util.Arrays;
import java.util.Comparator;
import org.cruxframework.crux.core.client.ClientMessages;
import org.cruxframework.crux.core.client.Legacy;
import org.cruxframework.crux.core.client.utils.StringUtils;
import com.google.gwt.core.client.GWT;
/**
* @author Thiago da Rosa de Bustamante
*
*/
abstract class AbstractScrollableDataSource<E> implements MeasurableDataSource<E>
{
protected ColumnDefinitions<E> definitions = new ColumnDefinitions<E>();
protected DataSourceRecord<E>[] data;
protected int currentRecord = -1;
protected boolean loaded = false;
protected ClientMessages messages = GWT.create(ClientMessages.class);
public ColumnDefinitions<E> getColumnDefinitions()
{
return definitions;
}
public void setColumnDefinitions(ColumnDefinitions<E> columnDefinitions)
{
this.definitions = columnDefinitions;
}
public Object getValue(String columnName)
{
if (currentRecord > -1)
{
DataSourceRecord<E> dataSourceRow = data[currentRecord];
return getValue(columnName, dataSourceRow);
}
return null;
}
public boolean hasNextRecord()
{
ensureLoaded();
return (data != null && currentRecord < data.length -1);
}
public void nextRecord()
{
if (hasNextRecord())
{
currentRecord++;
}
}
public void reset()
{
if(data != null)
{
data = null;
}
currentRecord = -1;
loaded = false;
}
@Deprecated
public DataSourceRecord<E> getRecord(int index)
{
ensureLoaded();
if (currentRecord > -1)
{
return data != null ? data[index] : null;
}
else
{
return null;
}
}
public DataSourceRecord<E> getRecord()
{
ensureLoaded();
if (currentRecord > -1)
{
return data != null ? data[currentRecord] : null;
}
else
{
return null;
}
}
public boolean hasPreviousRecord()
{
ensureLoaded();
return (data != null && currentRecord > 0 && data.length > 0);
}
public void previousRecord()
{
if (hasPreviousRecord())
{
currentRecord--;
}
}
@Override
public void sort(final String columnName, boolean ascending)
{
sort(columnName, ascending, false);
}
@Override
public void sort(final String columnName, boolean ascending, boolean caseSensitive)
{
ensureLoaded();
if (data != null)
{
sortArray(data,columnName, ascending, caseSensitive);
}
}
protected void sortArray(DataSourceRecord<E>[] array, final String columnName, final boolean ascending, final boolean caseSensitive)
{
final String columnName1;
String columnName2 = null;
if(columnName.indexOf('#') > -1)
{
String[] columnsName = columnName.split("#");
columnName1 = columnsName[0];
columnName2 = columnsName[1];
}else
{
columnName1 = columnName;
}
if (!definitions.getColumn(columnName1).isSortable())
{
throw new DataSourceExcpetion(messages.dataSourceErrorColumnNotComparable(columnName));
}
//optimization: infer column type only once
if(array == null || array[0] == null)
{
return;
}
final boolean isStringColumn = getValue(columnName1, array[0]) instanceof String;
final String finalColumnName2 = columnName2;
final boolean isStringColumn2 = getValue(columnName2,array[0]) instanceof String;
Arrays.sort(array, new Comparator<DataSourceRecord<E>>(){
public int compare(DataSourceRecord<E> o1, DataSourceRecord<E> o2)
{
if (ascending)
{
if (o1==null) return (o2==null?0:-1);
if (o2==null) return 1;
}
else
{
if (o1==null) return (o2==null?0:1);
if (o2==null) return -1;
}
Object value1 = getValue(columnName1, o1);
Object value2 = getValue(columnName1, o2);
if (ascending)
{
if (value1==null) return (value2==null?0:-1);
if (value2==null) return 1;
}
else
{
if (value1==null) return (value2==null?0:1);
if (value2==null) return -1;
}
int ret1 = compareNonNullValuesByType(value1,value2,ascending,caseSensitive, isStringColumn);
if(ret1 != 0)
{
return ret1;
}else if(finalColumnName2 != null)
{
Object value1col2 = getValue(finalColumnName2, o1);
Object value2col2 = getValue(finalColumnName2, o2);
if (ascending)
{
if (value1col2==null) return (value2col2==null?0:-1);
if (value2col2==null) return 1;
}
else
{
if (value1col2==null) return (value2col2==null?0:1);
if (value2col2==null) return -1;
}
return compareNonNullValuesByType(value1col2,value2col2,ascending,caseSensitive, value1col2 instanceof String);
}else
{
return ret1;
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private int compareNonNullValuesByType(Object value1, Object value2, boolean ascending, boolean caseSensitive, boolean isStringColumns)
{
if(isStringColumns)
{
if (ascending)
{
return StringUtils.localeCompare((String)value1, (String)value2, caseSensitive);
} else
{
return StringUtils.localeCompare((String)value2, (String)value1, caseSensitive);
}
}
if (ascending)
{
return ((Comparable)value1).compareTo(value2);
}
else
{
return ((Comparable)value2).compareTo(value1);
}
}
});
firstRecord();
}
public int getRecordCount()
{
return (data!=null?data.length:0);
}
public void firstRecord()
{
currentRecord = -1;
nextRecord();
}
public void lastRecord()
{
ensureLoaded();
currentRecord = getRecordCount()-1;
}
protected void ensureLoaded()
{
if (!loaded)
{
throw new DataSourceExcpetion(messages.dataSourceNotLoaded());
}
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#getValue(java.lang.String, org.cruxframework.crux.core.client.datasource.DataSourceRecord)
*/
@SuppressWarnings("unchecked")
public Object getValue(String columnName, DataSourceRecord<?> dataSourceRecord)
{
ColumnDefinition<?, E> column = definitions.getColumn(columnName);
if (column != null)
{
return dataSourceRecord != null ? column.getValue((E) dataSourceRecord.getRecordObject()) : null;
}
return null;
}
/**
* @return
* @deprecated Use getBoundObject instead
*/
@Deprecated
@Legacy
public E getBindedObject()
{
return getBindedObject(getRecord());
}
/**
* @param record
* @return
* @deprecated Use getBoundObject instead
*/
@Deprecated
@Legacy
public E getBindedObject(DataSourceRecord<E> record)
{
return getBoundObject(record);
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#getBoundObject()
*/
public E getBoundObject()
{
return getBoundObject(getRecord());
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#getBoundObject(org.cruxframework.crux.core.client.datasource.DataSourceRecord)
*/
public E getBoundObject(DataSourceRecord<E> record)
{
return null;
}
}