package com.srbenoit.modeling.cell;

import com.srbenoit.geom.Vector2;
import com.srbenoit.modeling.grid.GridMember2Int;
import com.srbenoit.modeling.grid.PointGridMember2;

/**
 * A fixed element, which does not move, but which can exert soft-sphere forces on other elements.
 */
public class FixedElement extends PointGridMember2 {

    /** the force on the element */
    private final Vector2 force;

    /** working tuple */
    private final Vector2 vec;

    /**
     * Constructs a new <code>FixedElement</code>.
     *
     * @param  xCoord  the X coordinate of the element
     * @param  yCoord  the Y coordinate of the element
     */
    public FixedElement(final double xCoord, final double yCoord) {

        super(xCoord, yCoord);
        this.force = new Vector2();
        this.vec = new Vector2();
    }

    /**
     * Gets the force vector for the filament.
     *
     * @return  the force vector
     */
    public Vector2 getForce() {

        return this.force;
    }

    /**
     * Computes the force on the element.
     *
     * @param  maxForce  the maximum force from non-interaction sources
     */
    public void computeInteractionForce(final double maxForce) {

        GridMember2Int nbr;
        double scale;
        double dist;
        int count;
        double range;

        // Interaction force with membrane or fixed elements
        range = 1.5 * Simulation.getInstance().getMaxSep();
        count = getNumNeighbors();

        for (int i = 0; i < count; i++) {
            nbr = getNeighbor(i);

            if ((nbr instanceof MembraneElement) || (nbr instanceof FixedElement)) {
                dist = nbr.dist(this);

                if (dist < range) {
                    scale = Simulation.SS_FORCE.forceTimesEqDist(dist / range) / range;

                    if (scale > maxForce) {
                        scale = maxForce;
                    }

                    vec.vectorBetween(nbr, this);
                    vec.normalize();
                    vec.scaleVec(scale);
                    this.force.addVec(vec);
                }
            }
        }
    }
}
