package skadistats.clarity.analyzer.replay;

import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableListBase;
import skadistats.clarity.model.Entity;
import skadistats.clarity.model.FieldPath;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public class ObservableEntity extends ObservableListBase<ObservableEntityProperty> {

    private final Entity entity;
    private final StringProperty index;
    private final StringProperty name;

    private List<FieldPath> indices = new LinkedList<>();
    private List<ObservableEntityProperty> properties = new LinkedList<>();
    private boolean changeActive = false;

    public ObservableEntity(Entity entity) {
        this.entity = entity;
        index = new ReadOnlyStringWrapper(String.valueOf(entity.getIndex()));
        name = new ReadOnlyStringWrapper(entity.getDtClass().getDtName());
        List<FieldPath> fieldPaths = entity.getDtClass().collectFieldPaths(entity.getState());
        for (FieldPath fieldPath : fieldPaths) {
            indices.add(fieldPath);
            properties.add(new ObservableEntityProperty(entity, fieldPath));
        }
    }

    public ObservableEntity(int index) {
        this.entity = null;
        this.index = new ReadOnlyStringWrapper(String.valueOf(index));
        this.name = new ReadOnlyStringWrapper("");
    }


    @Override
    public ObservableEntityProperty get(int index) {
        return properties.get(index);
    }

    @Override
    public int size() {
        return indices.size();
    }

    private int getIndexForFieldPath(FieldPath fieldPath) {
        return Collections.binarySearch(indices, fieldPath);
    }

    private void ensureChangeOpen() {
        if (!changeActive) {
            changeActive = true;
            beginChange();
        }
    }

    void commitChange() {
        if (changeActive) {
            changeActive = false;
            endChange();
        }
        for (ObservableEntityProperty property : properties) {
            if (property.isDirty()) {
                property.valueProperty().invalidate();
                property.setDirty(false);
            }
        }
    }

    void update(FieldPath[] fieldPaths, int num) {
        for (int i = 0; i < num; i++) {
            int idx = getIndexForFieldPath(fieldPaths[i]);
            if (idx < 0) {
                ensureChangeOpen();
                idx = 1 - idx;
                indices.add(idx, fieldPaths[i]);
                properties.add(new ObservableEntityProperty(entity, fieldPaths[i]));
                nextAdd(idx, idx);
            } else {
                properties.get(idx).setDirty(true);
            }
        }
    }

    public String getIndex() {
        return index.get();
    }

    public StringProperty indexProperty() {
        return index;
    }

    public void setIndex(String index) {
        this.index.set(index);
    }

    public String getName() {
        return name.get();
    }

    public StringProperty nameProperty() {
        return name;
    }

    public void setName(String name) {
        this.name.set(name);
    }

    @Override
    public String toString() {
        return String.format("%s(%s)", getName(), getIndex());
    }
}

@@ -2475,16 +2475,18 @@
 dx =
- 1
  - idx
+ - 1
 ;%0A  

fix index for new property being computed incorrectly