package com.srbenoit.modeling.grid;

import java.awt.Color;

/**
 * A granule that interacts with Lennard-Jones potential.
 */
public class Granule extends DynamicGridMember2D {

    /** well depth for Lennard-Jones and soft-sphere interactions */
    private static final double WELL_DEPTH = 0.1;

    /** a class to compute Lennard-Jones forces quickly */
    private static final FastLennardJones LJFORCE;

    /** a class to compute soft sphere forces quickly */
    private static final FastSoftSphere SSFORCE;

    /** viscosity-based damping force */
    private static final double VISC = 0.1;

    static {
        LJFORCE = new FastLennardJones(WELL_DEPTH);
        SSFORCE = new FastSoftSphere(WELL_DEPTH);
    }

    /**
     * Constructs a new <code>Granule</code>
     *
     * @param  xCoord    the X coordinate
     * @param  yCoord    the Y coordinate
     * @param  rad       the radius of the object
     * @param  structId  the ID of the structure (cell) this membrane belongs to
     * @param  mass      the mass of the granule
     */
    public Granule(final double xCoord, final double yCoord, final double rad, final int structId,
        final double mass) {

        super(xCoord, yCoord, rad, EnumElementType.LJ_GRANULE, structId, mass);
    }

    /**
     * Gets the color in which to render the element.
     *
     * @return  the color
     */
    @Override public Color getColor() {

        return Color.BLUE;
    }

    /**
     * Computes the forces on the element.
     */
    @Override public void interactionForce() {

        int count;
        EnumElementType type;
        DynamicGridMember2D near;
        double scale;
        double eps;
        double epsSq;
        double distX;
        double distY;
        double distSq;
        double frcX;
        double frcY;

        frcX = 0;
        frcY = 0;

        count = getNumNeighbors();

        for (int i = 0; i < count; i++) {
            near = (DynamicGridMember2D) getNeighbor(i);
            type = near.getType();

            if (type == EnumElementType.LJ_GRANULE) {

                eps = getRadius() + near.getRadius();
                epsSq = eps * eps;
                distX = near.getPosX() - getPosX();
                distY = near.getPosY() - getPosY();
                distSq = (distX * distX) + (distY * distY);
                scale = -LJFORCE.forceTimesEqDist(distSq / epsSq) / eps;

                frcX += distX * scale;
                frcY += distY * scale;
            } else if (type == EnumElementType.FIXED) {

                eps = getRadius() + near.getRadius();
                epsSq = eps * eps;
                distX = near.getPosX() - getPosX();
                distY = near.getPosY() - getPosY();
                distSq = (distX * distX) + (distY * distY);
                scale = -SSFORCE.forceTimesEqDist(distSq / epsSq) / eps;

                frcX += distX * scale;
                frcY += distY * scale;
            }
        }

        // Damping
        frcX -= VISC * this.getXVel();
        frcY -= VISC * this.getYVel();

        setForce(frcX, frcY);
    }
}
