package cz.fidentis.analyst.icp;

import cz.fidentis.analyst.mesh.core.MeshPoint;
import java.util.List;

/**
 * Undersampling strategies used to reduce the size of triangle meshes and then 
 * accelerate ICP computation.
 * 
 * @author Radek Oslejsek
 */
public abstract class UndersamplingStrategy {
    
    /**
     * If undersamoling is used, then this configuration parameter 
     * encodes whether the reduction of mesh size is expressed as the percentage 
     * of the original size (number of vertices) or as the maximal number of vertices
     * to be used.
     * 
     * @author Radek Oslejsek
     */
    public enum UndersamplingType {
        PERCENTAGE,
        MAX_VERTICES
    };
    
    private final UndersamplingType undersamplingType;
    private final double undersamplingLimit;
    
    /** 
     * Constructor for no undersampling.
     */
    public UndersamplingStrategy() {
        this.undersamplingType = null;
        this.undersamplingLimit = 0.0;
    }
    
    /**
     * Constructor for PERCENTAGE undersampling type.
     * 
     * @param perc Percentage - a value in (0.0, 1.0&gt;
     * @throws IllegalArgumentException if the input parameter is wrong
     */
    public UndersamplingStrategy(double perc) {
        if (perc <= 0.0 || perc > 1) {
            throw new IllegalArgumentException("perc");
        }
        this.undersamplingType = UndersamplingType.PERCENTAGE;
        this.undersamplingLimit = perc;
    }
    
    /**
     * Constructor for PERCENTAGE undersampling type.
     * 
     * @param max Maximal number of vertices. Must be bigger than zero
     * @throws IllegalArgumentException if the input parameter is wrong
     */
    public UndersamplingStrategy(int max) {
        if (max <= 0) {
            throw new IllegalArgumentException("max");
        }
        this.undersamplingType = UndersamplingType.MAX_VERTICES;
        this.undersamplingLimit = max;
    }
    
    /**
     * Reduces mesh points. Returned {@code MeshPoints} are backed by 
     * original mesh points.
     * 
     * @param meshPoints Original list of mesh points
     * @return Reduced list of mesh points or {@code null}.
     */
    public abstract List<MeshPoint> reduceMeshVertices(List<MeshPoint> meshPoints);
    
    @Override
    public String toString() {
        if (this.undersamplingType == UndersamplingType.PERCENTAGE) {
            return "undersampling to " + (undersamplingLimit * 100) + "%";
        } else {
            return "undersampling to " + undersamplingLimit + " vertices";
        }
    }
    
    /**
     * Returns number of vertices to be returned after undersampling.
     * 
     * @param origVertices Original number of vertices
     * @return number of vertices to be returned after undersampling.
     */
    protected int getNumUndersampledVertices(int origVertices) {
        switch (this.undersamplingType) {
            case PERCENTAGE:
                return (int) (origVertices * this.undersamplingLimit);
            case MAX_VERTICES:
                //nt limit = (int) this.undersamplingLimit;
                //return (limit <= origVertices) ? limit : origVertices;
                return Math.min((int) this.undersamplingLimit, origVertices);
            default:
                return 0;
        }
    }
}
