<commit_before>/*
 * Copyright (C) 2015 Actor LLC. <https://actor.im>
 */

package im.actor.model.js.angular;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;

import java.util.ArrayList;

import im.actor.model.droidkit.bser.BserObject;
import im.actor.model.droidkit.engine.ListEngineItem;
import im.actor.model.js.JsMessenger;
import im.actor.model.js.entity.JsEntityConverter;
import im.actor.model.js.providers.storage.JsListEngine;
import im.actor.model.js.providers.storage.JsListEngineCallback;

/**
 * Created by ex3ndr on 27.03.15.
 */
public class AngularList<T extends JavaScriptObject, V extends BserObject & ListEngineItem> implements JsListEngineCallback<V> {

    private final JsMessenger messenger;
    private final JsListEngine<V> listEngine;
    private final boolean isInverted;
    private final JsEntityConverter<V, T> entityConverter;

    private ArrayList<AngularListCallback<T>> callbacks = new ArrayList<AngularListCallback<T>>();

    private ArrayList<V> values;
    private JsArray<T> jsValues;

    public AngularList(JsListEngine<V> listEngine, boolean isInverted, JsEntityConverter<V, T> entityConverter, JsMessenger messenger) {
        this.messenger = messenger;
        this.listEngine = listEngine;
        this.entityConverter = entityConverter;
        this.isInverted = isInverted;

        this.values = new ArrayList<V>();
        this.jsValues = JavaScriptObject.createArray().cast();

        long[] rids = listEngine.getOrderedIds();
        for (long rid : rids) {
            V item = listEngine.getValue(rid);
            if (isInverted) {
                insert(jsValues, 0, entityConverter.convert(item, messenger));
                values.add(0, item);
            } else {
                values.add(item);
                jsValues.push(entityConverter.convert(item, messenger));
            }
        }
        listEngine.addListener(this);
    }

    public void subscribe(AngularListCallback<T> callback) {
        if (!callbacks.contains(callback)) {
            callbacks.add(callback);
        }
        callback.onCollectionChanged(jsValues);
    }

    public void unsubscribe(AngularListCallback<T> callback) {
        callbacks.remove(callback);
    }

    public void forceReconvert() {
        clear(jsValues);

        for (int i = 0; i < values.size(); i++) {
            jsValues.push(entityConverter.convert(values.get(i), messenger));
        }

        notifySubscribers();
    }

    public ArrayList<V> getRawItems() {
        return values;
    }

    @Override
    public void onItemAddedOrUpdated(V item) {
        try {
            long id = item.getEngineId();
            long sortKey = item.getEngineSort();
            for (int i = 0; i < values.size(); i++) {
                if (values.get(i).getEngineId() == id) {
                    values.remove(i);
                    remove(jsValues, i);
                    break;
                }
            }

            if (isInverted) {
                for (int i = values.size() - 1; i >= 0; i--) {
                    if (values.get(i).getEngineSort() > sortKey) {
                        values.add(i, item);
                        insert(jsValues, i, entityConverter.convert(item, messenger));
                        return;
                    }
                }
            } else {
                for (int i = 0; i < values.size(); i++) {
                    if (values.get(i).getEngineSort() < sortKey) {
                        values.add(i, item);
                        insert(jsValues, i, entityConverter.convert(item, messenger));
                        return;
                    }
                }
            }

            values.add(item);
            jsValues.push(entityConverter.convert(item, messenger));
        } finally {
            notifySubscribers();
        }
    }

    @Override
    public void onItemRemoved(long id) {
        for (int i = 0; i < values.size(); i++) {
            if (values.get(i).getEngineId() == id) {
                values.remove(i);
                remove(jsValues, i);
                break;
            }
        }

        notifySubscribers();
    }

    @Override
    public void onClear() {
        values.clear();
        clear(jsValues);<commit_msg>fix(js): Fixed angular list sorting<commit_after>/*
 * Copyright (C) 2015 Actor LLC. <https://actor.im>
 */

package im.actor.model.js.angular;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;

import java.util.ArrayList;

import im.actor.model.droidkit.bser.BserObject;
import im.actor.model.droidkit.engine.ListEngineItem;
import im.actor.model.js.JsMessenger;
import im.actor.model.js.entity.JsEntityConverter;
import im.actor.model.js.providers.storage.JsListEngine;
import im.actor.model.js.providers.storage.JsListEngineCallback;

/**
 * Created by ex3ndr on 27.03.15.
 */
public class AngularList<T extends JavaScriptObject, V extends BserObject & ListEngineItem> implements JsListEngineCallback<V> {

    private final JsMessenger messenger;
    private final JsListEngine<V> listEngine;
    private final boolean isInverted;
    private final JsEntityConverter<V, T> entityConverter;

    private ArrayList<AngularListCallback<T>> callbacks = new ArrayList<AngularListCallback<T>>();

    private ArrayList<V> values;
    private JsArray<T> jsValues;

    public AngularList(JsListEngine<V> listEngine, boolean isInverted, JsEntityConverter<V, T> entityConverter, JsMessenger messenger) {
        this.messenger = messenger;
        this.listEngine = listEngine;
        this.entityConverter = entityConverter;
        this.isInverted = isInverted;

        this.values = new ArrayList<V>();
        this.jsValues = JavaScriptObject.createArray().cast();

        long[] rids = listEngine.getOrderedIds();
        for (long rid : rids) {
            V item = listEngine.getValue(rid);
            if (isInverted) {
                insert(jsValues, 0, entityConverter.convert(item, messenger));
                values.add(0, item);
            } else {
                values.add(item);
                jsValues.push(entityConverter.convert(item, messenger));
            }
        }
        listEngine.addListener(this);
    }

    public void subscribe(AngularListCallback<T> callback) {
        if (!callbacks.contains(callback)) {
            callbacks.add(callback);
        }
        callback.onCollectionChanged(jsValues);
    }

    public void unsubscribe(AngularListCallback<T> callback) {
        callbacks.remove(callback);
    }

    public void forceReconvert() {
        clear(jsValues);

        for (int i = 0; i < values.size(); i++) {
            jsValues.push(entityConverter.convert(values.get(i), messenger));
        }

        notifySubscribers();
    }

    public ArrayList<V> getRawItems() {
        return values;
    }

    @Override
    public void onItemAddedOrUpdated(V item) {
        try {
            long id = item.getEngineId();
            long sortKey = item.getEngineSort();
            for (int i = 0; i < values.size(); i++) {
                if (values.get(i).getEngineId() == id) {
                    long oldSort = values.get(i).getEngineSort();
                    long newSort = item.getEngineSort();
                    values.remove(i);
                    remove(jsValues, i);
                    break;
                }
            }

            if (isInverted) {
                for (int i = values.size() - 1; i >= 0; i--) {
                    if (values.get(i).getEngineSort() < sortKey) {
                        values.add(i + 1, item);
                        insert(jsValues, i + 1, entityConverter.convert(item, messenger));
                        return;
                    }
                }

                values.add(item);
                jsValues.push(entityConverter.convert(item, messenger));
            } else {
                for (int i = 0; i < values.size(); i++) {
                    if (values.get(i).getEngineSort() < sortKey) {
                        values.add(i, item);
                        insert(jsValues, i, entityConverter.convert(item, messenger));
                        return;
                    }
                }

                values.add(0, item);
                insert(jsValues, 0, entityConverter.convert(item, messenger));
            }

        } finally {
            notifySubscribers();
        }
    }

    @Override
    public void onItemRemoved(long id) {
        for (int i = 0; i < values.size(); i++) {
            if (values.get(i).getEngineId() == id) {
                values.remove(i);
                remove(jsValues, i);
                break;
            }
        }

        notifySubscribers();
    }

    @Override
    public void onClear() {
        values.clear();
        clear(jsValues);
{'fraction_non_alphanumeric': 0.11400247831474597, 'fraction_numerical': 0.004731328151402501, 'mean_word_length': 1.8805970149253732, 'pattern_counts': {'":': 0, '<': 48, '<?xml version=': 0, '>': 40, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7662096', 'n_tokens_mistral': 2578, 'n_tokens_neox': 2411, 'n_words': 505}