package be.msyben.vinylManager.data;

import be.msyben.vinylManager.entities.Album;
import be.msyben.vinylManager.entities.Collection;
import be.msyben.vinylManager.entities.Disque;
import be.msyben.vinylManager.exceptions.VinylManagerException;
import be.msyben.vinylManager.interfaces.ChangeListener;
import be.msyben.vinylManager.interfaces.ChangeNotifier;
import java.util.ArrayList;
import java.util.List;

/**
 * Représente les données.
 * @author Mathieu Syben
 */
public class Data implements ChangeNotifier {


    /**
     * La collection
     */
    private Collection collection;
    /**
     * Les listeners
     */
    private List<ChangeListener> listeners = new ArrayList<ChangeListener>();
    /**
     * Singleton.
     */
    private static Data _instance = null;

    /**
     * Permet de récupérer l'instance.
     * @return 
     */
    public static synchronized Data getInstance(){
        if (_instance == null){
            _instance = new Data();
        }
        return _instance;
    }

    /**
     * Constructeur privé pour le singleton
     */
    private Data(){}

    /**
     * Ajoute un listener.
     * @param listener le listener à ajouter
     */
    @Override
    public void addChangeListener(final ChangeListener listener) {
        this.listeners.add(listener);
    }

    /**
     * Renvoie la collection.
     * @return la collection
     */
    public Collection getCollection() {
        return collection;
    }

    /**
     * Nettoie la collection (en crée une nouvelle).
     */
    public void clear() {
        this.collection = new Collection();
        for (ChangeListener listener : listeners) {
            listener.onChange();
        }
    }

    /**
     * Setter pour la collection.
     * @param collection la collection
     */
    public void setCollection(Collection collection) {
        this.collection = collection;
        for (ChangeListener listener : listeners) {
            listener.onChange();
        }
    }

    /**
     * Supprime un album de la collection.
     * @param album l'album à supprimer
     */
    public void deleteAlbum(Album album) {
        collection.getAlbums().remove(album);
        for (ChangeListener listener : listeners) {
            listener.onDelete(album);
        }
    }

    /**
     * Supprime un disque de la collection.
     * @param album l'album contenant le disque
     * @param disque le disque
     */
    public void deleteDisc(Album album, Disque disque) {
        album.getDisques().remove(disque);
        album.renumberDiscs();
        for (ChangeListener listener : listeners) {
            listener.onChange(album);
        }
    }   

    /**
     * Ajoute un album à la collection
     *
     * @param album L'album à ajouter
     */
    public void addAlbumWithoutListeners(Album album) {
        long lastId = collection.getLastId().longValue();
        lastId++;
        album.setId(lastId);
        collection.setLastId(lastId);
        collection.getAlbums().add(album);
    }

    /**
     * Ajoute un album.
     * @param album l'album à ajouter
     */
    public void addAlbum(Album album) throws VinylManagerException {
        long lastId = collection.getLastId().longValue();
        lastId++;
        album.setId(lastId);
        collection.setLastId(lastId);
        collection.getAlbums().add(album);
        for (ChangeListener listener : listeners) {
            listener.onChange(album);
        }
    }

    /**
     * Edition d'un album.
     * @param album l'album à ajouter
     */
    public void editAlbum(Album album) throws VinylManagerException {
        for (ChangeListener listener : listeners) {
            listener.onChange(album);
        }
    }

    /**
     * Ajout d'un disque.
     * @param album l'album à éditer
     * @param d Le disque à ajouter
     */
    public void addDisque(Album album, Disque d) {
        album.addDisque(d);
        for (ChangeListener listener : listeners) {
            listener.onChange(album, d.getNum()-1);
        }

    }

    /**
     * Edition d'un disque.
     * @param album l'album à éditer
     * @param d Le disque à éditer
     */
    public void editDisque(Album album, Disque d) {
        for (ChangeListener listener : listeners) {
            listener.onChange(album, d.getNum()-1);
        }
    }

    /**
     * Sette la cote d'un album
     * @param a l'album
     * @param cote la cote
     */
    public void setAlbumCote(Album a, int cote, boolean demi) {
        a.setCote(cote);
        a.setCoteDemi(demi);
        for (ChangeListener listener : listeners) {
            listener.refreshCote();
        }

    }
    
    /**
     * Permet d'indiquer que la collection a été modifiée.
     */
    public void notifyChange() {
        for (ChangeListener listener : listeners) {
            listener.onChange();
        }
    }
}
