/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016, 2019 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package javax.microedition.rms;
final class Enumerator extends Object
implements RecordListener, RecordEnumeration
{
private boolean destroyed;
private boolean nowCreated;
private boolean autoRebuild;
private int current;
private int count;
private Record[] records;
private RecordStore store;
private RecordFilter filter;
private RecordComparator comparator;
private Object lock;
Enumerator(RecordStore store, RecordFilter filter, RecordComparator comparator,
boolean autoRebuild)
{
this.destroyed = false;
this.nowCreated = true;
this.autoRebuild = autoRebuild;
this.store = store;
this.filter = filter;
this.comparator = comparator;
this.lock = new Object();
rebuild();
if(!autoRebuild)
{
return;
}
store.addRecordListener(this);
}
public void recordAdded(RecordStore store, int recordId)
{
if(store != this.store)
{
return;
}
rebuild();
}
public void recordDeleted(RecordStore store, int recordId)
{
if(store != this.store)
{
return;
}
rebuild();
}
public void recordChanged(RecordStore store, int recordId)
{
if(store != this.store)
{
return;
}
rebuild();
}
public void destroy()
{
synchronized(lock)
{
checkDestroyed();
store.removeRecordListener(this);
destroyed = true;
nowCreated = false;
autoRebuild = false;
current = 0;
count = 0;
records = null;
store = null;
filter = null;
comparator = null;
}
}
public void rebuild()
{
boolean opened;
int i;
int j;
int sourceCount;
int rebuildedCount;
Record[] source;
Record[] rebuilded;
Record r1;
Record r2;
RecordStore store;
RecordFilter filter;
RecordComparator comparator;
Object lock;
synchronized(lock = this.lock)
{
checkDestroyed();
store = this.store;
filter = this.filter;
comparator = this.comparator;
}
synchronized(RecordStore.getMonitor())
{
if(opened = store.isRecordStoreOpened())
{
sourceCount = store.getRecordsCount();
source = store.getRecords();
} else
{
sourceCount = 0;
source = null;
}
}
if(source == null || !opened)
{
return;
}
rebuildedCount = 0;
rebuilded = new Record[sourceCount];
try
{
for(i = 0; i < sourceCount; i++)
{
if((r1 = source[i]) != null && filter.matches(r1.getData()))
{
rebuilded[rebuildedCount++] = r1;
}
}
for(i = 0; i < rebuildedCount - 1; i++)
{
r1 = rebuilded[i];
for(j = i + 1; j < rebuildedCount; j++)
{
r2 = rebuilded[j];
if(comparator.compare(r2.getData(), r1.getData()) < 0)
{
rebuilded[i] = r2;
rebuilded[j] = r1;
r1 = r2;
}
}
}
}
catch(RuntimeException e)
{
e.printStackTrace();
return;
}
synchronized(lock)
{
checkDestroyed();
nowCreated = true;
count = rebuildedCount;
records = rebuilded;
}
}
public void reset()
{
synchronized(lock)
{
checkDestroyed();
nowCreated = true;
}
}
public void keepUpdated(boolean autoRebuild)
{
synchronized(lock)
{
checkDestroyed();
if(this.autoRebuild != autoRebuild)
{
if(this.autoRebuild = autoRebuild)
{
store.addRecordListener(this);
} else
{
store.removeRecordListener(this);
}
}
}
if(autoRebuild)
{
rebuild();
}
}
public boolean isKeptUpdated()
{
checkDestroyed();
return autoRebuild;
}
public boolean hasNextElement()
{
boolean result;
synchronized(lock)
{
checkDestroyed();
result = nowCreated ? count > 0 : current < count - 1;
}
return result;
}
public boolean hasPreviousElement()
{
boolean result;
synchronized(lock)
{
checkDestroyed();
result = nowCreated ? count > 0 : current > 0;
}
return result;
}
public int numRecords()
{
checkDestroyed();
return count;
}
public int nextRecordId()
throws InvalidRecordIDException
{
int result;
synchronized(lock)
{
checkDestroyed();
result = records[checkAvailableRecord(true)].getRecordID();
}
return result;
}
public int previousRecordId()
throws InvalidRecordIDException
{
int result;
synchronized(lock)
{
checkDestroyed();
result = records[checkAvailableRecord(false)].getRecordID();
}
return result;
}
public byte[] nextRecord()
throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
{
int length;
byte[] data;
byte[] result;
synchronized(lock)
{
checkDestroyed();
checkOpenedRecordStore();
Array.copy(data = records[checkAvailableRecord(true)].getData(), 0,
result = new byte[length = data.length], 0, length);
}
return result;
}
public byte[] previousRecord()
throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
{
int length;
byte[] data;
byte[] result;
synchronized(lock)
{
checkDestroyed();
checkOpenedRecordStore();
Array.copy(data = records[checkAvailableRecord(false)].getData(), 0,
result = new byte[length = data.length], 0, length);
}
return result;
}
private void checkDestroyed()
{
if(destroyed)
{
throw new IllegalStateException("RecordEnumeration: " +
"использование после вызова метода destroy().");
}
}
private void checkOpenedRecordStore()
throws RecordStoreNotOpenException
{
RecordStore store;
if(!(store = this.store).isRecordStoreOpened())
{
throw new RecordStoreNotOpenException("RecordEnumeration: " +
"хранилище записей " + store.getRecordStoreName() + " не открыто.");
}
}
private int checkAvailableRecord(boolean moveToNext)
throws InvalidRecordIDException
{
int cnt = count;
int curr;
int result;
if(nowCreated)
{
if(cnt == 0)
{
throw new InvalidRecordIDException("RecordEnumeration: " +
"в перечислении больше не осталось записей.");
}
nowCreated = false;
result = current = moveToNext ? 0 : cnt - 1;
} else
{
if((curr = current) == (moveToNext ? cnt - 1 : 0))
{
throw new InvalidRecordIDException("RecordEnumeration: " +
"в перечислении больше не осталось записей.");
}
result = current = moveToNext ? curr + 1 : curr - 1;
}
return result;
}
}