/*
* 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.List;
import org.cruxframework.crux.core.client.datasource.DataSourceRecord.DataSourceRecordState;
import com.google.gwt.user.client.ui.HasValue;
/**
* @author Thiago da Rosa de Bustamante
*
*/
public abstract class RemotePagedDataSource<T> extends AbstractPagedDataSource<T>
implements MeasurableRemoteDataSource<T>
{
protected DataSourceOperations<T> editableOperations = new DataSourceOperations<T>(this);
protected RemoteDataSourceCallback fetchCallback = null;
private RemoteDataSourceConfiguration config;
@SuppressWarnings("unchecked")
public RemotePagedDataSource()
{
this.data = new DataSourceRecord[0];
}
/**
* @see org.cruxframework.crux.core.client.datasource.RemoteDataSource#cancelFetching()
*/
public void cancelFetching()
{
currentPage--;
updateCurrentRecord();
this.fetchCallback.cancelFetching();
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#clearChanges()
*/
public void clearChanges()
{
this.editableOperations.reset();
}
@Override
public void firstRecord()
{
if (currentPage != 1)
{
checkChanges();
}
super.firstRecord();
ensurePageLoaded(currentRecord);
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#getNewRecords()
*/
public DataSourceRecord<T>[] getNewRecords()
{
return editableOperations.getNewRecords();
}
@Override
public int getRecordCount()
{
if (!loaded)
{
throw new DataSourceExcpetion(messages.dataSourceNotLoaded());
}
return this.config.getRecordCount();
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#getRemovedRecords()
*/
public DataSourceRecord<T>[] getRemovedRecords()
{
return editableOperations.getRemovedRecords();
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#getSelectedRecords()
*/
public DataSourceRecord<T>[] getSelectedRecords()
{
return editableOperations.getSelectedRecords();
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#getUpdatedRecords()
*/
public DataSourceRecord<T>[] getUpdatedRecords()
{
return editableOperations.getUpdatedRecords();
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#insertRecord(int)
*/
public DataSourceRecord<T> insertRecord(int index)
{
return editableOperations.insertRecord(index);
}
@Override
public void lastRecord()
{
if (currentPage != getPageCount())
{
checkChanges();
}
super.lastRecord();
ensurePageLoaded(currentRecord);
}
@Override
public boolean nextPage()
{
checkChanges();
if (super.nextPage())
{
fetchCurrentPage();
return true;
}
return false;
}
@Override
public boolean previousPage()
{
checkChanges();
if (super.previousPage())
{
fetchCurrentPage();
return true;
}
return false;
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#removeRecord(int)
*/
public DataSourceRecord<T> removeRecord(int index)
{
return editableOperations.removeRecord(index);
}
@SuppressWarnings("unchecked")
@Override
public void reset()
{
if(data != null)
{
this.data = new DataSourceRecord[0];
}
currentRecord = -1;
currentPage = 0;
loaded = false;
this.config = null;
editableOperations.reset();
}
/**
* @see org.cruxframework.crux.core.client.datasource.RemoteDataSource#setCallback(org.cruxframework.crux.core.client.datasource.RemoteDataSourceCallback)
*/
public void setCallback(RemoteDataSourceCallback callback)
{
this.fetchCallback = callback;
}
@Override
public boolean setCurrentPage(int pageNumber)
{
if (this.currentPage != pageNumber)
{
checkChanges();
}
if (super.setCurrentPage(pageNumber))
{
fetchCurrentPage();
return true;
}
return false;
}
/**
* @see org.cruxframework.crux.core.client.datasource.RemoteDataSource#setLoadData(org.cruxframework.crux.core.client.datasource.RemoteDataSourceConfiguration)
*/
@SuppressWarnings("unchecked")
public void setLoadData(RemoteDataSourceConfiguration config)
{
this.config = config;
this.loaded = (this.config != null);
this.data = new DataSourceRecord[getRecordCount()];
this.setCurrentPage(1);
}
@Override
public void setPageSize(int pageSize)
{
super.setPageSize(pageSize);
if (this.loaded)
{
load();
}
}
@Override
public void sort(String columnName, boolean ascending)
{
sort(columnName, ascending, false);
}
@SuppressWarnings("unchecked")
public void sort(String columnName, boolean ascending, boolean caseSensitive)
{
ensurePageLoaded(currentRecord);
if (currentRecord > -1)
{
DataSourceRecord<T>[] pageData = new DataSourceRecord[pageSize];
int startPageRecord = getPageStartRecord();
int endPageRecord = getPageEndRecord();
int pageSize = endPageRecord - startPageRecord + 1;
for (int i = 0; i<pageSize; i++)
{
pageData[i] = data[i+startPageRecord];
}
sortArray(pageData, columnName, ascending, caseSensitive);
updateRecords(startPageRecord, endPageRecord, pageData);
}
}
/**
* @see org.cruxframework.crux.core.client.datasource.RemoteDataSource#update(R[])
*/
public void update(DataSourceRecord<T>[] records)
{
int startRecord = getPageStartRecord();
int endRecord = getPageEndRecord();
int updateRecordsCount = updateRecords(startRecord, endRecord, records);
if (this.fetchCallback != null)
{
if (updateRecordsCount > 0)
{
fetchCallback.execute(startRecord, startRecord+updateRecordsCount-1);
}
else
{
fetchCallback.execute(-1, -1);
}
}
}
public void updateData(T[] data)
{
}
public void updateData(List<T> data)
{
}
public void copyValueToWidget(HasValue<?> valueContainer, String key, DataSourceRecord<?> dataSourceRecord)
{
}
public void setValue(Object value, String columnKey, DataSourceRecord<?> dataSourceRecord)
{
}
public int getRecordIndex(T boundObject)
{
return editableOperations.getRecordIndex(boundObject);
}
public void selectRecord(int index, boolean selected)
{
editableOperations.selectRecord(index, selected);
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#updateState(org.cruxframework.crux.core.client.datasource.DataSourceRecord, org.cruxframework.crux.core.client.datasource.DataSourceRecord.DataSourceRecordState)
*/
public void updateState(DataSourceRecord<T> record, DataSourceRecordState previousState)
{
editableOperations.updateState(record, previousState);
}
protected void ensurePageLoaded(int recordNumber)
{
boolean loaded = isPageLoaded(getPageForRecord(recordNumber));
if (!loaded)
{
throw new DataSourceExcpetion(messages.dataSourceNotLoaded());
}
}
/**
*
*/
protected void fetchCurrentPage()
{
int pageEndRecord = (currentPage * pageSize) - 1;
if (!isPageLoaded(currentPage))
{
fetch(getPageStartRecord(), pageEndRecord);
}
else
{
fetchCallback.execute(getPageStartRecord(), pageEndRecord);
}
}
@Override
protected int getPageEndRecord()
{
int endPageRecord = super.getPageEndRecord();
return endPageRecord + editableOperations.getNewRecordsCount() - editableOperations.getRemovedRecordsCount();
}
protected int getPageForRecord(int recordNumber)
{
int pageSize = getPageSize();
return (recordNumber / pageSize) + (recordNumber%pageSize==0?0:1);
}
protected boolean isPageLoaded(int pageNumber)
{
int startPageRecord = getPageStartRecord();
return (data.length > 0 && data[startPageRecord]!= null);
}
/**
*
* @param startRecord
* @param endRecord
* @param records
* @return
*/
protected int updateRecords(int startRecord, int endRecord, DataSourceRecord<T>[] records)
{
if (records != null && endRecord < getRecordCount())
{
for (int i = startRecord, j = 0; i <= endRecord && j < records.length; i++, j++)
{
this.data[i] = records[j];
}
return records.length;
}
return 0;
}
private void checkChanges()
{
if (editableOperations.isDirty())
{
throw new DataSourceExcpetion(messages.remoteDataSourcePageDirty());
}
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#getBoundObject()
*/
public T getBoundObject()
{
return getBoundObject(getRecord());
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#getBoundObject(org.cruxframework.crux.core.client.datasource.DataSourceRecord)
*/
public T getBoundObject(DataSourceRecord<T> record)
{
return super.getBoundObject(record);
}
/**
* @see org.cruxframework.crux.core.client.datasource.DataSource#cloneDTO(org.cruxframework.crux.core.client.datasource.DataSourceRecord)
*/
public T cloneDTO(DataSourceRecord<?> record)
{
return null;
}
}