<commit_before>package org.meganekkovr;

import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v4.util.ArrayMap;
import android.view.View;

import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.meganekkovr.animation.EntityAnimator;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Entity is a basic class in Meganekko. It is something on VR scene.
 * Entity has transform information such as {@link #setPosition(float, float, float) position},
 * {@link #setScale(float, float, float) scale}, and {@link #setRotation(Quaternionf) rotation}.
 * It can have child Entities and {@link Component}s.
 * Entity which will be rendered has to have {@link GeometryComponent} and {@link SurfaceRendererComponent}.
 */
public class Entity {
    private final NativePointer nativePointer;
    private final Map<Class<? extends Component>, Component> components = new ArrayMap<>();
    private final List<Entity> children = new CopyOnWriteArrayList<>();
    private final Vector3f position = new Vector3f();
    private final Vector3f scale = new Vector3f(1, 1, 1);
    private final Quaternionf rotation = new Quaternionf();
    private final Matrix4f localMatrix = new Matrix4f();
    private final Matrix4f worldModelMatrix = new Matrix4f();
    private final float[] matrixValues = new float[16];
    private MeganekkoApp app;
    private Entity parent;
    private boolean localMatrixUpdateRequired = true;
    private boolean worldMatrixUpdateRequired = true;
    private int id;
    private float opacity = 1.0f;
    private boolean updateOpacityRequired;
    private boolean visible = true;

    public Entity() {
        nativePointer = NativePointer.getInstance(newInstance());
    }

    private static native void addSurfaceDef(long nativePtr, long surfacesPointer);

    private static native void setWorldModelMatrix(long nativePtr, float[] matrix);

    /**
     * Create Entity from {@link View}. New Entity has plane geometry.
     *
     * @param view View for surface.
     * @return new Entity
     */
    public static Entity from(View view) {

        final Entity entity = new Entity();
        entity.add(SurfaceRendererComponent.from(view));
        entity.add(GeometryComponent.from(view));

        return entity;
    }

    /**
     * Create Entity from {@link Drawable}. New Entity has plane geometry.
     *
     * @param drawable Drawable for surface.
     * @return new Entity
     */
    public static Entity from(Drawable drawable) {

        final Entity entity = new Entity();
        entity.add(SurfaceRendererComponent.from(drawable));
        entity.add(GeometryComponent.from(drawable));

        return entity;
    }

    /**
     * Override this to create own native instance.
     * Native class must be derived from {@code mgn::Entity}.
     *
     * @return Native pointer value return from C++ {@code new}.
     */
    protected native long newInstance();

    /**
     * This method is not valid until this is attached to {@link Scene}.
     *
     * @return MeganekkoApp.
     */
    public MeganekkoApp getApp() {
        return app;
    }

    /**
     * For internal use only.
     *
     * @param app
     */
    void setApp(MeganekkoApp app) {
        this.app = app;

        // Propagate to children
        for (Entity child : children) {
            child.setApp(app);
        }
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    /**
     * Set string id.
     *
     * @param id ID
     */
    public void setId(String id) {
        setId(id.hashCode());
    }

    /**
     * Find {@link Entity} from children. Typically, id is {@code R.id.xxx} value.
     *
     * @param id ID
     * @return Found Entity or {@code null} if it has no matched Entity with id.
     */
    @Nullable
    public Entity findById(int id) {

        if (this.id == id) return this;

        for (Entity child : children) {
            Entity found = child.findById(id);
            if (found != null) return found;
        }

        return null;
    }

    /**
     * Find {@link Entity} from children.
     *
     * @param id ID
     * @return Found Entity or {@code null} if it has no matched Entity with id.
     */
    public Entity findById(String id) {
        return findById(id.hashCode());
    }

    /**
     * Called at every frame update.
     *
     * @param frame Frame information
     */
    public void update(FrameInput frame) {

        // Update local model matrix if necessary.
        if (localMatrixUpdateRequired) {
            updateLocalMatrix();
            invalidateWorldModelMatrix();
            localMatrixUpdateRequired = false;
        }

        // Update world model matrix if necessary.
        if (worldMatrixUpdateRequired) {
            updateWorldModelMatrix();
            worldMatrixUpdateRequired = false;

            // Update native side values
            worldModelMatrix.get(matrixValues);
            setWorldModelMatrix(nativePointer.get(), matrixValues);
        }

        // Update opacity if necessary.
        if (updateOpacityRequired) {
            updateOpacity();
            updateOpacityRequired = false;
        }

        // Notify to components
        for (Component component : components.values()) {
            component.update(frame);
        }

        // Notify to children
        for (Entity child : children) {
            child.update(frame);
        }
    }

    /**
     * Update local matrix.
     */
    public void updateLocalMatrix() {
        localMatrix.identity();
        localMatrix.translate(position);
        localMatrix.rotate(rotation);
        localMatrix.scale(scale);
    }

    /**
     * Update world model matrix.
     */
    public void updateWorldModelMatrix() {

        // parentMatrix * worldModelMatrix
        Entity parent = getParent();
        if (parent != null) {
            Matrix4f parentMatrix = parent.getWorldModelMatrix();
            parentMatrix.mul(localMatrix, worldModelMatrix);
        } else {

            // worldModelMatrix = localMatrix
            worldModelMatrix.set(localMatrix);
        }
    }

    /**<commit_msg>Change update() priority.<commit_after>package org.meganekkovr;

import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v4.util.ArrayMap;
import android.view.View;

import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.meganekkovr.animation.EntityAnimator;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Entity is a basic class in Meganekko. It is something on VR scene.
 * Entity has transform information such as {@link #setPosition(float, float, float) position},
 * {@link #setScale(float, float, float) scale}, and {@link #setRotation(Quaternionf) rotation}.
 * It can have child Entities and {@link Component}s.
 * Entity which will be rendered has to have {@link GeometryComponent} and {@link SurfaceRendererComponent}.
 */
public class Entity {
    private final NativePointer nativePointer;
    private final Map<Class<? extends Component>, Component> components = new ArrayMap<>();
    private final List<Entity> children = new CopyOnWriteArrayList<>();
    private final Vector3f position = new Vector3f();
    private final Vector3f scale = new Vector3f(1, 1, 1);
    private final Quaternionf rotation = new Quaternionf();
    private final Matrix4f localMatrix = new Matrix4f();
    private final Matrix4f worldModelMatrix = new Matrix4f();
    private final float[] matrixValues = new float[16];
    private MeganekkoApp app;
    private Entity parent;
    private boolean localMatrixUpdateRequired = true;
    private boolean worldMatrixUpdateRequired = true;
    private int id;
    private float opacity = 1.0f;
    private boolean updateOpacityRequired;
    private boolean visible = true;

    public Entity() {
        nativePointer = NativePointer.getInstance(newInstance());
    }

    private static native void addSurfaceDef(long nativePtr, long surfacesPointer);

    private static native void setWorldModelMatrix(long nativePtr, float[] matrix);

    /**
     * Create Entity from {@link View}. New Entity has plane geometry.
     *
     * @param view View for surface.
     * @return new Entity
     */
    public static Entity from(View view) {

        final Entity entity = new Entity();
        entity.add(SurfaceRendererComponent.from(view));
        entity.add(GeometryComponent.from(view));

        return entity;
    }

    /**
     * Create Entity from {@link Drawable}. New Entity has plane geometry.
     *
     * @param drawable Drawable for surface.
     * @return new Entity
     */
    public static Entity from(Drawable drawable) {

        final Entity entity = new Entity();
        entity.add(SurfaceRendererComponent.from(drawable));
        entity.add(GeometryComponent.from(drawable));

        return entity;
    }

    /**
     * Override this to create own native instance.
     * Native class must be derived from {@code mgn::Entity}.
     *
     * @return Native pointer value return from C++ {@code new}.
     */
    protected native long newInstance();

    /**
     * This method is not valid until this is attached to {@link Scene}.
     *
     * @return MeganekkoApp.
     */
    public MeganekkoApp getApp() {
        return app;
    }

    /**
     * For internal use only.
     *
     * @param app
     */
    void setApp(MeganekkoApp app) {
        this.app = app;

        // Propagate to children
        for (Entity child : children) {
            child.setApp(app);
        }
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    /**
     * Set string id.
     *
     * @param id ID
     */
    public void setId(String id) {
        setId(id.hashCode());
    }

    /**
     * Find {@link Entity} from children. Typically, id is {@code R.id.xxx} value.
     *
     * @param id ID
     * @return Found Entity or {@code null} if it has no matched Entity with id.
     */
    @Nullable
    public Entity findById(int id) {

        if (this.id == id) return this;

        for (Entity child : children) {
            Entity found = child.findById(id);
            if (found != null) return found;
        }

        return null;
    }

    /**
     * Find {@link Entity} from children.
     *
     * @param id ID
     * @return Found Entity or {@code null} if it has no matched Entity with id.
     */
    public Entity findById(String id) {
        return findById(id.hashCode());
    }

    /**
     * Called at every frame update.
     *
     * @param frame Frame information
     */
    public void update(FrameInput frame) {

        // Notify to components
        for (Component component : components.values()) {
            component.update(frame);
        }

        // Notify to children
        for (Entity child : children) {
            child.update(frame);
        }

        // Update local model matrix if necessary.
        if (localMatrixUpdateRequired) {
            updateLocalMatrix();
            invalidateWorldModelMatrix();
            localMatrixUpdateRequired = false;
        }

        // Update world model matrix if necessary.
        if (worldMatrixUpdateRequired) {
            updateWorldModelMatrix();
            worldMatrixUpdateRequired = false;

            // Update native side values
            worldModelMatrix.get(matrixValues);
            setWorldModelMatrix(nativePointer.get(), matrixValues);
        }

        // Update opacity if necessary.
        if (updateOpacityRequired) {
            updateOpacity();
            updateOpacityRequired = false;
        }
    }

    /**
     * Update local matrix.
     */
    public void updateLocalMatrix() {
        localMatrix.identity();
        localMatrix.translate(position);
        localMatrix.rotate(rotation);
        localMatrix.scale(scale);
    }

    /**
     * Update world model matrix.
     */
    public void updateWorldModelMatrix() {

        // parentMatrix * worldModelMatrix
        Entity parent = getParent();
        if (parent != null) {
            Matrix4f parentMatrix = parent.getWorldModelMatrix();
            parentMatrix.mul(localMatrix, worldModelMatrix);
        } else {

            // worldModelMatrix = localMatrix
            worldModelMatrix.set(localMatrix);
        }
    }

    /**
{'fraction_non_alphanumeric': 0.09658821671142, 'fraction_numerical': 0.003001105670510188, 'mean_word_length': 2.320136339800734, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, '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': '5706889', 'n_tokens_mistral': 3404, 'n_tokens_neox': 3311, 'n_words': 1046}