 package ch.epfl.isochrone.tiledmap;

import static ch.epfl.isochrone.math.Math.divF;
import static ch.epfl.isochrone.math.Math.modF;

import java.awt.image.BufferedImage;

/**
 * Interface représentant un modicateur de fournisseur de tuile pour les rendre transparentes
 * 
 * @author Charles Thiebaut (238935)
 * @author Arnaud Delamare (234841)
 * 
 */
public class TransparentTileProvider extends FilteringTileProvider {

    private final double opacity;
    
    /**
     * 
     * @param opacity
     *        L'opacité future des tuiles
     * @param provider
     *        Le fournisseur à transformer
     */
    public TransparentTileProvider (double opacity, TileProvider provider)
    {
        this.opacity=opacity;
        this.provider=provider;
    }
    
    /**
    *
    * Retourne la tile du fournisseur sous-jacent avec la bonne opacité
    * 
    * @param zoom
    *        Le zoom de la Tile
    *        
    * @param x
    *        La position x de la Tile
    *        
    * @param y
    *        La position y de la Tile 
    */
    @Override
    public Tile tileAt(int zoom, int x, int y) {
        
        BufferedImage imageBase =provider.tileAt(zoom, x, y).image();
        
        BufferedImage image = new BufferedImage(imageBase.getWidth(), imageBase.getHeight(), BufferedImage.TYPE_INT_ARGB);
        
        for (int i=0; i<imageBase.getWidth(); i++)
        {
            for (int j=0; j<imageBase.getWidth(); j++)
            {
                image.setRGB(i, j, transformARGB(imageBase.getRGB(i, j)));
            }
        }
        
        
        return new Tile(x,y,zoom,image);
    }
    
    /**
     * Modifie un int de type ARGB en changeant son opacité en celle de l'instance
     */
    @Override
    public int transformARGB(int argb) {
        return argb(opacity, r(argb), g(argb), b(argb));
    }
    
    /**
     * Extrait la valeur de a d'un int de type ARBG
     */
    public double a (int argb)
    {
        return modF(divF(argb,(int)Math.pow(2, 24)),(int)Math.pow(2, 8))/255.0;
    }
    
    /**
     * Extrait la valeur de r d'un int de type ARBG
     */
    public double r (int argb)
    {
        return modF(divF(argb,(int)Math.pow(2, 16)),(int)Math.pow(2, 8))/255.0;
    }
    
    /**
     * Extrait la valeur de g d'un int de type ARBG
     */
    public double g (int argb)
    {
        return modF(divF(argb,(int)Math.pow(2, 8)),(int)Math.pow(2, 8))/255.0;
    }
    
    /**
     * Extrait la valeur de b d'un int de type ARBG
     */
    public double b (int argb)
    {
        return modF(divF(argb,(int)Math.pow(2, 0)),(int)Math.pow(2, 8))/255.0;
    }
    
    /**
     * Transforme 4 valeurs entre 0 et 1 en un int de type ARGB
     */
    public int argb (double a, double r, double g, double b)
    {
        return ((int) Math.pow(2, 24))*((int)(255*a)) + ((int) Math.pow(2, 16))*((int)(255*r)) + + ((int) Math.pow(2, 8))*((int)(255*g)) + + ((int)(255*b));
    }

}
