/* * Copyright (C) 2015 Actor LLC. <https://actor.im> */ package im.actor.runtime.js.storage; import com.google.gwt.storage.client.Storage; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import im.actor.runtime.Log; import im.actor.runtime.bser.DataInput; import im.actor.runtime.bser.DataOutput; import im.actor.runtime.storage.ListEngineRecord; import im.actor.runtime.storage.ListStorage; import static im.actor.runtime.crypto.Base64Utils.fromBase64; import static im.actor.runtime.crypto.Base64Utils.toBase64; public class JsListStorage implements ListStorage { private static final String TAG = "JsListStorage"; private final Storage storage; private final String prefix; private final ArrayList<Index> index = new ArrayList<Index>(); private final Comparator<Index> comparator = new Comparator<Index>() { @Override public int compare(Index o1, Index o2) { return -compare(o1.getSortKey(), o2.getSortKey()); } int compare(long x, long y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); } }; public JsListStorage(String prefix, Storage storage) { this.storage = storage; this.prefix = prefix; String indexData = storage.getItem("list_" + prefix + "_index"); if (indexData != null) { try { byte[] data = fromBase64(indexData); DataInput dataInput = new DataInput(data, 0, data.length); int count = dataInput.readInt(); for (int i = 0; i < count; i++) { long id = dataInput.readLong(); long order = dataInput.readLong(); index.add(new Index(id, order)); } } catch (Exception e) { Log.e(TAG, e); } } updateIndex(); } @Override public void updateOrAdd(ListEngineRecord record) { // Update Index for (Index i : index) { if (i.getId() == record.getKey()) { index.remove(i); break; } } index.add(new Index(record.getKey(), record.getOrder())); updateIndex(); // Save record storage.setItem(getId(record.getKey()), toBase64(record.getData())); } @Override public void updateOrAdd(List<ListEngineRecord> items) { // Update Index for (ListEngineRecord record : items) { for (Index i : index) { if (i.getId() == record.getKey()) { index.remove(i); break; } } index.add(new Index(record.getKey(), record.getOrder())); } updateIndex(); // Save records for (ListEngineRecord record : items) { storage.setItem(getId(record.getKey()), toBase64(record.getData())); } } @Override public void delete(long key) { for (Index i : index) { if (i.getId() == key) { index.remove(i); storage.removeItem(getId(key)); updateIndex(); break; } } } @Override public void delete(long[] keys) { for (long key : keys) { for (Index i : index) { if (i.getId() == key) { index.remove(i); storage.removeItem(getId(key)); updateIndex(); break; } } } } @Override public void clear() { for (Index i : index) { storage.removeItem(getId(i.getId())); } index.clear(); updateIndex(); } @Override public ListEngineRecord loadItem(long key) { Index indexValue = null; for (Index i : index) { if (i.getId() == key) { indexValue = i; break; } } if (indexValue == null) { return null; } String item = storage.getItem(getId(key)); if (item != null) { byte[] res = fromBase64(item); return new ListEngineRecord(key, indexValue.getSortKey(), null, res); } return null; } @Override public List<ListEngineRecord> loadAllItems() { // TODO: Implement return null; } @Override public boolean isEmpty() { return getCount() == 0; } @Override public int getCount() { return index.size(); } public Long getHeadId() { if (index.size() > 0) { return index.get(0).getId(); } else { return null; } } public long[] getOrderedIds() { long[] res = new long[index.size()]; for (int i = 0; i < res.length; i++) { res[i] = index.get(i).getId(); } return res; } public long[] getPrevIdsInclusive(long sortKey) { ArrayList<Long> res = new ArrayList<Long>(); for (Index i : index) { if (i.getSortKey() <= sortKey) { res.add(i.getId()); } } long[] res2 = new long[res.size()]; for (int i = 0; i < res2.length; i++) { res2[i] = res.get(i); } return res2; } public long[] getPrevIdsExclusive(long sortKey) { ArrayList<Long> res = new ArrayList<Long>(); for (Index i : index) { if (i.getSortKey() < sortKey) { res.add(i.getId()); } } long[] res2 = new long[res.size()]; for (int i = 0; i < res2.length; i++) { res2[i] = res.get(i); } return res2; } private String getId(long id) { return "list_" + prefix + "_" + id; } private void updateIndex() { Collections.sort(index, comparator); DataOutput dataOutput = new DataOutput(); dataOutput.writeInt(index.size()); for (Index i : index) { dataOutput.writeLong(i.getId()); dataOutput.writeLong(i.getSortKey()); } storage.setItem("list_" + prefix + "_index", toBase64(dataOutput.toByteArray())); } private class Index { private long id; private long sortKey; private Index(long id, long sortKey) { this.id = id; this.sortKey = sortKey; } public long getId() { return id; } public long getSortKey() { return sortKey; } } }