/*
* Copyright (C) 2015 Actor LLC. <https://actor.im>
*/
package im.actor.runtime.generic.mvvm.alg;
import java.util.ArrayList;
import im.actor.runtime.generic.mvvm.AppleListUpdate;
import im.actor.runtime.generic.mvvm.ChangeDescription;
// Disabling Bounds checks for speeding up calculations
/*-[
#define J2OBJC_DISABLE_ARRAY_BOUND_CHECKS 1
]-*/
public final class ChangeBuilder {
private static <T> ArrayList<ChangeDescription<T>> optimize(ArrayList<ChangeDescription<T>> modifications) {
ArrayList<ChangeDescription<T>> res = new ArrayList<ChangeDescription<T>>();
ChangeDescription<T> desc = null;
for (ChangeDescription<T> d : modifications) {
if (d.getOperationType() == ChangeDescription.OperationType.ADD) {
if (desc != null) {
if (desc.getOperationType() == ChangeDescription.OperationType.ADD) {
if (desc.getIndex() + desc.getLength() == d.getIndex()) {
desc = ChangeDescription.mergeAdd(desc, d);
} else {
res.add(desc);
desc = null;
}
} else {
res.add(desc);
desc = null;
}
}
} else {
if (desc != null) {
res.add(desc);
desc = null;
}
}
if (desc == null) {
desc = d;
// res.add(d);
}
}
if (desc != null) {
res.add(desc);
}
return res;
}
public static <T> ArrayList<ChangeDescription<T>> processAndroidModifications(
ArrayList<ChangeDescription<T>> modifications, ArrayList<T> initialList) {
modifications = optimize(modifications);
return modifications;
}
public static <T> AppleListUpdate processAppleModifications(
ArrayList<ChangeDescription<T>> modifications, ArrayList<T> initialList, boolean isLoadMore) {
modifications = optimize(modifications);
ArrayList<State<T>> states = new ArrayList<State<T>>();
ArrayList<State<T>> current = new ArrayList<State<T>>();
for (int i = 0; i < initialList.size(); i++) {
State<T> state = new State<T>();
state.startingIndex = i;
states.add(state);
current.add(state);
}
for (ChangeDescription<T> m : modifications) {
if (m.getOperationType() == ChangeDescription.OperationType.REMOVE) {
for (int i = 0; i < m.getLength(); i++) {
State<T> state = current.remove(m.getIndex());
state.wasDeleted = true;
}
} else if (m.getOperationType() == ChangeDescription.OperationType.ADD) {
int index = m.getIndex();
for (T itm : m.getItems()) {
State<T> state = new State<T>();
state.wasAdded = true;
state.item = itm;
current.add(index++, state);
}
} else if (m.getOperationType() == ChangeDescription.OperationType.MOVE) {
State<T> state = current.remove(m.getIndex());
current.add(m.getDestIndex(), state);
if (!state.wasAdded) {
state.wasMoved = true;
}
} else if (m.getOperationType() == ChangeDescription.OperationType.UPDATE) {
int index = m.getIndex();
for (T itm : m.getItems()) {
State<T> state = current.get(index++);
state.item = itm;
if (!state.wasAdded) {
state.wasUpdated = true;
}
}
}
}
ArrayList<Integer> removed = new ArrayList<Integer>();
ArrayList<Move> moved = new ArrayList<Move>();
ArrayList<Integer> added = new ArrayList<Integer>();
ArrayList<Integer> updated = new ArrayList<Integer>();
// Building deletions
for (int i = 0; i < states.size(); i++) {
State<T> s = states.get(i);
if (s.wasDeleted) {
removed.add(s.startingIndex);
}
}
// Building add/update/move
for (int i = 0; i < current.size(); i++) {
State<T> s = current.get(i);
if (s.wasMoved && s.startingIndex != i) {
moved.add(new Move(s.startingIndex, i));
}
if (s.wasUpdated) {
updated.add(i);
}
if (s.wasAdded) {
added.add(i);
}
}
return new AppleListUpdate(removed, added, moved, updated, isLoadMore);
}
private ChangeBuilder() {
}
private static class State<T> {
private boolean wasDeleted;
private int startingIndex = -1;
private boolean wasUpdated;
private boolean wasMoved;
private boolean wasAdded;
private T item;
}
}