package ch.epfl.isochrone.gui;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JComponent;

import ch.epfl.isochrone.tiledmap.TileProvider;

/**
 * Classe servant à modéliser la carte, vue dans la fenêtre graphique
 * 
 * @author Charles Thiebaut (238935)
 * @author Arnaud Delamare (234841)
 * 
 */
public final class TiledMapComponent extends JComponent {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    private int zoom; 
    private List<TileProvider> providerList;
    
    /**
     * Constructeur de la classe
     * 
     * @param zoom
     *        Le niveau de zoom de la carte
     */
    public TiledMapComponent(int zoom)
    {
        super();
        
        if(zoom < 10 || zoom > 19){
            throw new IllegalArgumentException();
        }
        
        this.zoom = zoom; 
        providerList = new LinkedList<TileProvider>();
    }
    
    public int zoom(){
        return zoom;
    }
    
    /**
     * 
     * 
     * @param zoom
     *       le nouveau zoom
     * 
     * @throw IllegalArgumentException
     *        si le zoom n'est pas compris entre 10 et 19
     */
    public void setZoom(int zoom){
        if(zoom < 10 || zoom > 19)
        {
           throw new IllegalArgumentException();       
        }
        
         this.zoom = zoom;
         this.repaint();
    }
    
    /**
     * @param tp
     *        Le fournisseur de tuile à ajouter
     */
    public void addTileProvider(TileProvider tp)
    {
        providerList.add(tp); 
        this.repaint(); 
    }
    
    /**
     * Méthode qui sert à updater le tile provider qui produit la carte isochrone quand on change un paramètre
     * 
     * @param index
     *       L'index de la tuile à remplacer
     * @param tp
     *        Le nouveau TileProvider
     */
    public void replaceTileProvider(int index, TileProvider tp)
    {
        providerList.set(index, tp);
        this.repaint(); 
    }
    
    /**
     * Méthode qui sert à supprimer un tile provider, utile lorsqu'on n'a pas de chemin à dessiner
     * 
     * @param index
     *       L'index de la tuile à remplacer
     */
    public void removeTileProvider(int index)
    {
        if (index>=0 && index<providerList.size())
        {
            providerList.remove(index);
            this.repaint(); 
        }
    }
    
    /**
     * 
     * @return La taille de la map à ce niveau de zoom.
     */
    public Dimension getPreferredSize()
    { 
        return new Dimension((int)Math.pow(2, zoom+8),(int)Math.pow(2, zoom+8));
    }
    
    /**
     * 
     * Méthode servant à peindre la zone affichée sur la fenêtre
     */
    public void paintComponent(Graphics g0)
    {
       Graphics2D g1 = (Graphics2D)g0; 
       Rectangle rect = getVisibleRect();
       
       for (int i=0; i<rect.width/256 + 2; i++)
       {
           for (int j=0; j<rect.height/256 + 2; j++)
           {
               for (int k=0; k<providerList.size(); k++)
               {
                   g1.drawImage(providerList.get(k).tileAt(zoom, (int)(rect.x/256)+i, (int)(rect.y/256)+j).image(), null, rect.x+i*256-rect.x%256, rect.y+j*256-rect.y%256);
                   
                   // a verifier 256.... * / mod 
               }
           }
       }
       
    }
    
    
    
    
}
