/*
	Реализация спецификаций 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;

import java.io.*;
import java.util.*;
import malik.emulator.io.cloud.*;
import malik.emulator.io.vfs.*;

public class RecordStore extends Object
{
	public static final int AUTHMODE_PRIVATE = 0;
	public static final int AUTHMODE_ANY = 1;
	public static final int STATE_ERROR = -1;
	public static final int STATE_RESERV = 0;
	public static final int STATE_OPENED = 1;
	public static final int STATE_CLOSED = 2;
	private static int COUNT;
	private static RecordStore[] OPENED;
	private static final char RMS_HEX_PREFIX = '$';
	private static final int RMS_MAX_LENGTH = 32;
	private static final long RMS_SIGNATURE = 0x6d6964702d726d73L;
	private static final String RMS_DIRECTORY = "/rms/";
	private static final String RMS_EXTENSION = ".rms";
	private static final RecordFilter DEFAULT_FILTER;
	private static final RecordComparator DEFAULT_COMPARATOR;
	private static final Object LOCK;

	static
	{
		DefaultFilterAndComparator obj = new DefaultFilterAndComparator();
		DEFAULT_FILTER = obj;
		DEFAULT_COMPARATOR = obj;
		LOCK = obj;
	}

	public static void closeAllRecordStores()
	{
		int i;
		RecordStore store;
		synchronized(LOCK)
		{
			for(i = COUNT; i-- > 0; )
			{
				if((store = OPENED[i]) != null && store.openedCount != 0)
				{
					if(!store.saveData())
					{
						System.err.println("RecordStore.closeRecordStore: " +
								"не удалось сохранить данные.");
					}
					store.openedCount = 0;
					store.count = 0;
					store.records = null;
					store.listeners = null;
					System.out.println("RecordStore: внесены изменения в запись ".concat(
							store.recordStoreName));
				}
			}
		}
	}

	public static void deleteRecordStore(String recordStoreName)
			throws RecordStoreException, RecordStoreNotFoundException
	{
		int i;
		int error;
		checkName(recordStoreName);
		error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if((i = indexOfRecordStore(recordStoreName)) >= 0)
				{
					if(OPENED[i].openedCount != 0)
					{
						error = 1;
						break label0;
					}
					OPENED[i] = null;
				}
			}
		}
		if(error == 1)
		{
			throw new RecordStoreException("RecordStore.deleteRecordStore: " +
					"невозможно удалить открытое хранилище записей " + recordStoreName + ".");
		}
		try
		{
			CloudFileSystem.getInstance().deleteFile(RMS_DIRECTORY +
					toFileName(recordStoreName) + RMS_EXTENSION);
		}
		catch(IOException e)
		{
			throw new RecordStoreNotFoundException("RecordStore.deleteRecordStore: " +
					"хранилище записей " + recordStoreName + " не найдено.");
		}
	}

	public static int getState(String recordStoreName)
	{
		int i;
		RecordStore store;
		return recordStoreName == null ||
				(i = recordStoreName.length()) < 1 || i > RMS_MAX_LENGTH ? STATE_ERROR :
				((store = getRecordStore(recordStoreName)) == null ? STATE_RESERV :
				(store.openedCount != 0 ? STATE_OPENED : STATE_CLOSED));
	}

	public static String[] listRecordStores()
	{
		int i;
		int fnlen;
		int extlen = RMS_EXTENSION.length();
		String[] result;
		String name;
		Vector list = new Vector(COUNT);
		RecordStore store;
		FileEnumerator fe;
		for(i = COUNT; i-- > 0; )
		{
			if((store = OPENED[i]) != null)
			{
				list.addElement(store.recordStoreName);
			}
		}
		try
		{
			if((fe = CloudFileSystem.getInstance().findFirst(RMS_DIRECTORY)) != null)
			{
				try
				{
					do
					{
						if((!fe.isDirectory()) && (name = fe.getFileName()) != null &&
								name.regionMatches(true, fnlen = name.length() - extlen,
								RMS_EXTENSION, 0, extlen) && (!list.contains(name =
								toRecordStoreName(name.substring(0, fnlen)))))
						{
							list.addElement(name);
						}
					} while(fe.findNext());
				}
				finally
				{
					fe.close();
				}
			}
		}
		catch(IOException e)
		{
			e.printRealStackTrace();
		}
		list.copyInto(result = new String[list.size()]);
		return result;
	}

	public static RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary)
			throws RecordStoreException, RecordStoreNotFoundException, RecordStoreFullException
	{
		int i;
		int error;
		RecordStore result;
		checkName(recordStoreName);
		error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if((i = indexOfRecordStore(recordStoreName)) >= 0)
				{
					if((i = (result = OPENED[i]).openedCount) == 0 &&
							(!result.loadData()) && (!createIfNecessary))
					{
						error = 1;
						break label0;
					}
					result.openedCount = i + 1;
				} else
				{
					if((!(result = new RecordStore(recordStoreName)).loadData()) &&
							(!createIfNecessary))
					{
						error = 2;
						break label0;
					}
					register(result);
					result.openedCount = 1;
				}
			}
		}
		switch(error)
		{
		case 1:
			throw new RecordStoreException("RecordStore.openRecordStore: " +
					"не удалось загрузить данные.");
		case 2:
			throw new RecordStoreNotFoundException("RecordStore.openRecordStore: " +
					"не удалось найти хранилище записей " + recordStoreName + ".");
		}
		return result;
	}

	public static RecordStore openRecordStore(String recordStoreName,
			boolean createIfNecessary, int authmode, boolean writable)
			throws RecordStoreException, RecordStoreNotFoundException, RecordStoreFullException
	{
		return openRecordStore(recordStoreName, createIfNecessary);
	}

	public static RecordStore openRecordStore(String recordStoreName, String vendor, String suite)
			throws RecordStoreException, RecordStoreNotFoundException
	{
		return openRecordStore(recordStoreName, false);
	}

	static Object getMonitor()
	{
		return LOCK;
	}

	private static void checkName(String recordStoreName)
	{
		int len;
		if(recordStoreName == null || (len = recordStoreName.length()) < 1 || len > RMS_MAX_LENGTH)
		{
			throw new IllegalArgumentException("RecordStore: " +
					"недопустимое имя для хранилища записей.");
		}
	}

	private static void register(RecordStore store)
	{
		int i;
		if(OPENED == null)
		{
			OPENED = new RecordStore[2];
		}
		for(i = COUNT; i-- > 0; )
		{
			if(OPENED[i] == null)
			{
				OPENED[i] = store;
				return;
			}
		}
		if(COUNT == OPENED.length)
		{
			Array.copy(OPENED, 0, OPENED = new RecordStore[COUNT << 1], 0, COUNT);
		}
		OPENED[COUNT++] = store;
	}

	private static char getDigitRepresentation(int digit)
	{
		if(digit >= 0x00 && digit < 0x0a)
		{
			return (char) (digit + '0');
		}
		if(digit >= 0x0a && digit < 0x10)
		{
			return (char) (digit + ('A' - 0x0a));
		}
		throw new ArrayIndexOutOfBoundsException(digit);
	}

	private static int indexOfRecordStore(String recordStoreName)
	{
		int i;
		RecordStore store;
		for(i = COUNT; i-- > 0; )
		{
			if((store = OPENED[i]) != null && recordStoreName.equals(store.recordStoreName))
			{
				return i;
			}
		}
		return -1;
	}

	private static RecordStore getRecordStore(String recordStoreName)
	{
		int i;
		RecordStore store;
		for(i = COUNT; i-- > 0; )
		{
			if((store = OPENED[i]) != null && recordStoreName.equals(store.recordStoreName))
			{
				return store;
			}
		}
		return null;
	}

	private static String toFileName(String recordStoreName)
	{
		char c;
		int i;
		int len = recordStoreName.length();
		int length = 0;
		char[] result = new char[5 * RMS_MAX_LENGTH];
		for(i = 0; i < len; )
		{
			if(((c = recordStoreName.charAt(i++)) >= '0' && c <= '9') || (c >= 'a' && c <= 'z'))
			{
				result[length++] = c;
				continue;
			}
			result[length++] = RMS_HEX_PREFIX;
			result[length++] = getDigitRepresentation((c >> 0x0c) & 0x0f);
			result[length++] = getDigitRepresentation((c >> 0x08) & 0x0f);
			result[length++] = getDigitRepresentation((c >> 0x04) & 0x0f);
			result[length++] = getDigitRepresentation(c & 0x0f);
		}
		return new String(result, 0, length);
	}

	private static String toRecordStoreName(String fileName)
	{
		char c;
		char d;
		int i;
		int j;
		int len = fileName.length();
		int length = 0;
		char[] result = new char[RMS_MAX_LENGTH];
		for(i = 0; i < len && length < RMS_MAX_LENGTH; )
		{
			if((c = fileName.charAt(i++)) == RMS_HEX_PREFIX)
			{
				c = 0;
				j = 0;
				do
				{
					if(i >= len)
					{
						break;
					}
					if((d = fileName.charAt(i++)) >= '0' && d <= '9')
					{
						c = (char) ((((int) c) << 4) + (d - '0'));
						continue;
					}
					if(d >= 'A' && d <= 'F')
					{
						c = (char) ((((int) c) << 4) + (d - ('A' - 0x0a)));
						continue;
					}
					break;
				} while((++j) < 4);
			}
			result[length++] = c;
		}
		return new String(result, 0, length);
	}


	private int openedCount;
	private int nextID;
	private int version;
	private int count;
	private long lastModified;
	private Record[] records;
	private RecordListener[] listeners;
	private String recordStoreName;
	private String fileName;

	private RecordStore(String recordStoreName)
	{
		this.recordStoreName = recordStoreName;
		this.fileName = RMS_DIRECTORY + toFileName(recordStoreName) + RMS_EXTENSION;
	}

	public void addRecordListener(RecordListener listener)
	{
		int i;
		RecordListener[] listeners;
		if(listener == null)
		{
			return;
		}
		synchronized(LOCK)
		{
			if((listeners = this.listeners) == null)
			{
				listeners = this.listeners = new RecordListener[2];
			}
			if(indexOfListener(listener) < 0)
			{
				if((i = indexOfListener(null)) < 0)
				{
					Array.copy(listeners, 0, listeners = this.listeners =
							new RecordListener[(i = listeners.length) << 1], 0, i);
				}
				listeners[i] = listener;
			}
		}
	}

	public void removeRecordListener(RecordListener listener)
	{
		int i;
		RecordListener[] listeners;
		if(listener == null)
		{
			return;
		}
		synchronized(LOCK)
		{
			if((listeners = this.listeners) != null && (i = indexOfListener(listener)) >= 0)
			{
				listeners[i] = null;
			}
		}
	}

	public void closeRecordStore()
			throws RecordStoreException, RecordStoreNotOpenException
	{
		int i;
		int error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if((i = openedCount) == 0)
				{
					error = 1;
					break label0;
				}
				if((openedCount = i - 1) == 0)
				{
					if(!saveData())
					{
						error = 2;
						break label0;
					}
					count = 0;
					records = null;
					listeners = null;
					System.out.println("RecordStore: внесены изменения в запись ".concat(
							recordStoreName));
				}
			}
		}
		switch(error)
		{
		case 1:
			throw new RecordStoreNotOpenException("RecordStore.closeRecordStore: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		case 2:
			throw new RecordStoreException("RecordStore.closeRecordStore: " +
					"не удалось сохранить данные.");
		}
	}

	public void setMode(int authmode, boolean writable)
			throws RecordStoreException
	{
		if(authmode != AUTHMODE_ANY && authmode != AUTHMODE_PRIVATE)
		{
			throw new IllegalArgumentException("RecordStore.setMode: " +
					"недопустимое значение параметра authmode.");
		}
	}

	public void setRecord(int recordId, byte[] src, int offset, int length)
			throws RecordStoreException, RecordStoreFullException,
			RecordStoreNotOpenException, InvalidRecordIDException
	{
		int lim;
		int len;
		int index;
		int error;
		byte[] data;
		if(src != null && ((lim = offset + length) > (len = src.length) ||
				lim < offset || offset > len || offset < 0))
		{
			throw new ArrayIndexOutOfBoundsException("RecordStore.setRecord: " +
					"индекс выходит из диапазона.");
		}
		error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if(openedCount == 0)
				{
					error = 1;
					break label0;
				}
				if((index = indexOfRecord(recordId)) < 0)
				{
					error = 2;
					break label0;
				}
				if(src != null)
				{
					Array.copy(src, offset, data = new byte[length], 0, length);
				} else
				{
					data = new byte[0];
				}
				records[index].setData(data);
				version++;
				lastModified = System.currentTimeMillis();
			}
		}
		switch(error)
		{
		case 1:
			throw new RecordStoreNotOpenException("RecordStore.setRecord: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		case 2:
			throw new InvalidRecordIDException("RecordStore.setRecord: " +
					"несуществующий идентификатор записи: " + recordId + ".");
		}
		notifyListenersChanged(recordId);
	}

	public void deleteRecord(int recordId)
			throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
	{
		int i;
		int c;
		int index;
		int error;
		Record[] r;
		error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if(openedCount == 0)
				{
					error = 1;
					break label0;
				}
				if((index = indexOfRecord(recordId)) < 0)
				{
					error = 2;
					break label0;
				}
				r = records;
				if((i = (c = count - 1) - index) > 0)
				{
					Array.copy(r, index + 1, r, index, i);
				}
				r[count = c] = null;
				version++;
				lastModified = System.currentTimeMillis();
			}
		}
		switch(error)
		{
		case 1:
			throw new RecordStoreNotOpenException("RecordStore.deleteRecord: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		case 2:
			throw new InvalidRecordIDException("RecordStore.deleteRecord: " +
					"несуществующий идентификатор записи: " + recordId + ".");
		}
		notifyListenersDeleted(recordId);
	}

	public int addRecord(byte[] src, int offset, int length)
			throws RecordStoreException, RecordStoreNotOpenException, RecordStoreFullException
	{
		int c;
		int lim;
		int len;
		int error;
		int result;
		byte[] data;
		Record[] r;
		if(src != null && ((lim = offset + length) > (len = src.length) ||
				lim < offset || offset > len || offset < 0))
		{
			throw new ArrayIndexOutOfBoundsException("RecordStore.addRecord: " +
					"индекс выходит из диапазона.");
		}
		error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if(openedCount == 0)
				{
					error = 1;
					result = 0;
					break label0;
				}
				if((r = records) == null || r.length == 0)
				{
					r = records = new Record[1];
				}
				if((c = count) == r.length)
				{
					Array.copy(r, 0, r = records = new Record[c << 1], 0, c);
				}
				if(src != null)
				{
					Array.copy(src, offset, data = new byte[length], 0, length);
				} else
				{
					data = new byte[0];
				}
				r[c] = new Record(result = nextID++, data);
				count = c + 1;
				version++;
				lastModified = System.currentTimeMillis();
			}
		}
		if(error == 1)
		{
			throw new RecordStoreNotOpenException("RecordStore.addRecord: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		}
		notifyListenersAdded(result);
		return result;
	}

	public int getRecord(int recordId, byte[] dst, int offset)
			throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
	{
		int lim;
		int len;
		int index;
		int error;
		int length;
		byte[] data;
		if(dst == null)
		{
			throw new NullPointerException("RecordStore.getRecord: " +
					"параметр dst равен нулевой ссылке.");
		}
		error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if(openedCount == 0)
				{
					error = 1;
					length = 0;
					break label0;
				}
				if((index = indexOfRecord(recordId)) < 0)
				{
					error = 2;
					length = 0;
					break label0;
				}
				length = (data = records[index].getData()).length;
				if((lim = offset + length) > (len = dst.length) ||
						lim < offset || offset > len || offset < 0)
				{
					error = 3;
					break label0;
				}
				Array.copy(data, 0, dst, offset, length);
			}
		}
		switch(error)
		{
		case 1:
			throw new RecordStoreNotOpenException("RecordStore.getRecord: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		case 2:
			throw new InvalidRecordIDException("RecordStore.getRecord: " +
					"несуществующий идентификатор записи: " + recordId + ".");
		case 3:
			throw new ArrayIndexOutOfBoundsException("RecordStore.getRecord: " +
					"индекс выходит из диапазона.");
		}
		return length;
	}

	public int getRecordSize(int recordId)
			throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
	{
		int index;
		int error;
		int result;
		error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if(openedCount == 0)
				{
					error = 1;
					result = 0;
					break label0;
				}
				if((index = indexOfRecord(recordId)) < 0)
				{
					error = 2;
					result = 0;
					break label0;
				}
				result = records[index].getDataSize();
			}
		}
		switch(error)
		{
		case 1:
			throw new RecordStoreNotOpenException("RecordStore.getRecordSize: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		case 2:
			throw new InvalidRecordIDException("RecordStore.getRecordSize: " +
					"несуществующий идентификатор записи: " + recordId + ".");
		}
		return result;
	}

	public int getSizeAvailable()
			throws RecordStoreNotOpenException
	{
		if(openedCount == 0)
		{
			throw new RecordStoreNotOpenException("RecordStore.getSizeAvailable: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		}
		return (int) Runtime.getRuntime().freeMemory();
	}

	public int getSize()
			throws RecordStoreNotOpenException
	{
		int i;
		int error;
		int result;
		Record[] r;
		error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if(openedCount == 0)
				{
					error = 1;
					result = 0;
					break label0;
				}
				result = 0x20;
				for(r = records, i = count; i-- > 0; )
				{
					if(((result += r[i].getDataSize() + 0x08) & 0x03) != 0)
					{
						result = (result + 0x04) & (-0x04);
					}
				}
			}
		}
		if(error == 1)
		{
			throw new RecordStoreNotOpenException("RecordStore.getSize: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		}
		return result;
	}

	public int getVersion()
			throws RecordStoreNotOpenException
	{
		if(openedCount == 0)
		{
			throw new RecordStoreNotOpenException("RecordStore.getVersion: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		}
		return version;
	}

	public int getNumRecords()
			throws RecordStoreNotOpenException
	{
		if(openedCount == 0)
		{
			throw new RecordStoreNotOpenException("RecordStore.getNumRecords: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		}
		return count;
	}

	public int getNextRecordID()
			throws RecordStoreException, RecordStoreNotOpenException
	{
		if(openedCount == 0)
		{
			throw new RecordStoreNotOpenException("RecordStore.getNextRecordID: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		}
		return nextID;
	}

	public long getLastModified()
			throws RecordStoreNotOpenException
	{
		if(openedCount == 0)
		{
			throw new RecordStoreNotOpenException("RecordStore.getLastModified: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		}
		return lastModified;
	}

	public byte[] getRecord(int recordId)
			throws RecordStoreException, RecordStoreNotOpenException, InvalidRecordIDException
	{
		int index;
		int error;
		int length;
		byte[] data;
		byte[] result;
		error = 0;
		synchronized(LOCK)
		{
			label0:
			{
				if(openedCount == 0)
				{
					error = 1;
					result = null;
					break label0;
				}
				if((index = indexOfRecord(recordId)) < 0)
				{
					error = 2;
					result = null;
					break label0;
				}
				Array.copy(data = records[index].getData(), 0,
						result = new byte[length = data.length], 0, length);
			}
		}
		switch(error)
		{
		case 1:
			throw new RecordStoreNotOpenException("RecordStore.getRecord: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		case 2:
			throw new InvalidRecordIDException("RecordStore.getRecord: " +
					"несуществующий идентификатор записи: " + recordId + ".");
		}
		return result;
	}

	public String getName()
			throws RecordStoreNotOpenException
	{
		if(openedCount == 0)
		{
			throw new RecordStoreNotOpenException("RecordStore.getName: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		}
		return recordStoreName;
	}

	public RecordEnumeration enumerateRecords(RecordFilter filter,
			RecordComparator comparator, boolean autoRebuild)
			throws RecordStoreNotOpenException
	{
		if(openedCount == 0)
		{
			throw new RecordStoreNotOpenException("RecordStore.enumerateRecords: " +
					"хранилище записей " + recordStoreName + " не открыто.");
		}
		return new Enumerator(this, filter == null ? DEFAULT_FILTER : filter,
				comparator == null ? DEFAULT_COMPARATOR : comparator, autoRebuild);
	}

	boolean isRecordStoreOpened()
	{
		return openedCount != 0;
	}

	int getRecordsCount()
	{
		return count;
	}

	Record[] getRecords()
	{
		return records;
	}

	String getRecordStoreName()
	{
		return recordStoreName;
	}

	private void notifyListenersAdded(int recordId)
	{
		int i;
		RecordListener[] listeners;
		RecordListener listener;
		for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
		{
			if((listener = listeners[i]) != null)
			{
				try
				{
					listener.recordAdded(this, recordId);
				}
				catch(RuntimeException e)
				{
					e.printRealStackTrace();
				}
			}
		}
	}

	private void notifyListenersChanged(int recordId)
	{
		int i;
		RecordListener[] listeners;
		RecordListener listener;
		for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
		{
			if((listener = listeners[i]) != null)
			{
				try
				{
					listener.recordChanged(this, recordId);
				}
				catch(RuntimeException e)
				{
					e.printRealStackTrace();
				}
			}
		}
	}

	private void notifyListenersDeleted(int recordId)
	{
		int i;
		RecordListener[] listeners;
		RecordListener listener;
		for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
		{
			if((listener = listeners[i]) != null)
			{
				try
				{
					listener.recordDeleted(this, recordId);
				}
				catch(RuntimeException e)
				{
					e.printRealStackTrace();
				}
			}
		}
	}

	private boolean saveData()
	{
		boolean result;
		int i;
		int c;
		int length;
		byte[] data;
		Record[] r;
		Record rec;
		FileOutputStream file;
		DataOutputStream stream;
		if((file = new FileOutputStream(fileName)).hasOpenError())
		{
			return false;
		}
		try
		{
			try
			{
				(stream = new DataOutputStream(file)).writeLong(RMS_SIGNATURE);
				stream.writeInt(c = this.count);
				stream.writeInt(this.version);
				stream.writeLong(this.lastModified);
				stream.writeInt(this.nextID);
				stream.writeInt(0);
				for(r = this.records, i = 0; i < c; i++)
				{
					stream.writeInt((rec = r[i]).getRecordID());
					stream.writeInt(length = (data = rec.getData()).length);
					stream.write(data);
					switch(length & 0x03)
					{
					case 0x01:
						stream.writeByte(0);
						/* fall through */
					case 0x02:
						stream.writeByte(0);
						/* fall through */
					case 0x03:
						stream.writeByte(0);
						/* fall through */
					default:
						break;
					}
				}
			}
			finally
			{
				file.close();
			}
			result = true;
		}
		catch(IOException e)
		{
			e.printRealStackTrace();
			result = false;
		}
		return result;
	}

	private boolean loadData()
	{
		boolean result;
		int i;
		int c;
		int id;
		int length;
		byte[] data;
		Record[] r;
		FileInputStream file;
		DataInputStream stream;
		if((file = new FileInputStream(fileName)).hasOpenError())
		{
			this.nextID = 1;
			this.version = 1;
			this.count = 0;
			this.lastModified = System.currentTimeMillis();
			this.records = null;
			return false;
		}
		try
		{
			try
			{
				if((stream = new DataInputStream(file)).readLong() != RMS_SIGNATURE)
				{
					this.nextID = 1;
					this.version = 1;
					this.count = 0;
					this.lastModified = System.currentTimeMillis();
					this.records = null;
					result = false;
				} else
				{
					this.count = c = stream.readInt();
					this.version = stream.readInt();
					this.lastModified = stream.readLong();
					this.nextID = stream.readInt();
					this.records = r = new Record[c];
					for(stream.skipBytes(0x04), i = 0; i < c; i++)
					{
						id = stream.readInt();
						stream.read(data = new byte[length = stream.readInt()]);
						if((length &= 0x03) != 0)
						{
							stream.skipBytes(0x04 - length);
						}
						r[i] = new Record(id, data);
					}
					result = true;
				}
			}
			finally
			{
				file.close();
			}
		}
		catch(IOException e)
		{
			this.nextID = 1;
			this.version = 1;
			this.count = 0;
			this.lastModified = System.currentTimeMillis();
			this.records = null;
			e.printRealStackTrace();
			result = false;
		}
		return result;
	}

	private int indexOfRecord(int recordId)
	{
		int i;
		Record[] r;
		for(r = records, i = count; i-- > 0; )
		{
			if(r[i].getRecordID() == recordId)
			{
				return i;
			}
		}
		return -1;
	}

	private int indexOfListener(RecordListener listener)
	{
		int i;
		RecordListener[] listeners;
		for(i = (listeners = this.listeners).length; i-- > 0; )
		{
			if(listeners[i] == listener)
			{
				return i;
			}
		}
		return -1;
	}
}
