import java.util.Objects;

// Copyright Florent Madelaine, (3 juin 2020) 

// florent.madelaine@u-pec.fr

// Ce logiciel est un programme informatique simulant une petite partie du jeu de Memory

// Ce logiciel est regi par la licence CeCILL soumise au droit français et
// respectant les principes de diffusion des logiciels libres. Vous pouvez
// utiliser, modifier et/ou redistribuer ce programme sous les conditions
// de la licence CeCILL telle que diffusee par le CEA, le CNRS et l'INRIA 
// sur le site "http://www.cecill.info".

// En contrepartie de l'accessibilite au code source et des droits de copie,
// de modification et de redistribution accordes par cette licence, il n'est
// offert aux utilisateurs qu'une garantie limitee.  Pour les memes raisons,
// seule une responsabilite restreinte pese sur l'auteur du programme,  le
// titulaire des droits patrimoniaux et les concedants successifs.

// A cet egard  l'attention de l'utilisateur est attiree sur les risques
// associes au chargement,  a l'utilisation,  a la modification et/ou au
// developpement et a la reproduction du logiciel par l'utilisateur etant 
// donne sa specificite de logiciel libre, qui peut le rendre complexe a 
// manipuler et qui le reserve donc a des developpeurs et des professionnels
// avertis possedant  des  connaissances  informatiques approfondies.  Les
// utilisateurs sont donc invites a charger  et  tester  l'adequation  du
// logiciel a leurs besoins dans des conditions permettant d'assurer la
// securite de leurs systemes et ou de leurs donnees et, plus generalement, 
// a l'utiliser et l'exploiter dans les memes conditions de securite. 

// Le fait que vous puissiez acceder a cet en-tete signifie que vous avez 
// pris connaissance de la licence CeCILL, et que vous en avez accepte les
// termes.

/**
 * Classe representant une carte de Memory
 */
public class Carte {
    
    /**
     * Permet de savoir combien on a de cartes en tout.
     * Pas vraiment clair qu'on veuille s'en servir ici. 
     * C'est purement pour des raisons pedagogiques de rappel de ce que veut dire un attribut de classe.
     * 
     * Je ne rentre pas dans les details de la destruction d'objets.
     * Il faut lire la doc a propos de Objects.finalize()
    */
    static int nbreCarte;

    /**
     * False ssi cache
     */
    private boolean visible; 
    
    /**
     * pour pouvoir apparier des cartes.
     */
    private int valeur;    

    /** Constructeur de carte.
    */
    public Carte(int valeur){
        this.nbreCarte ++;
        this.visible=false; // cache par defaut
        this.valeur=valeur;
    }

    // NB. Moralement, les cartes ne devraient pas etre cachees.
    // dans cette version on ne fait rien mais on voudrait idealement que ce ne soit pas possible
    /**
     *  Predicat permettant de tester le fait que deux cartes ont la meme valeur
     * @param Carte la carte a comparer a this. 
     * @return true si elles ont la meme valeur. 
     * @throws NullPointerException si la carte passee en parametre ou this est null.
     * @throws IllegalArgumentException si l'argument n'est pas visible
     * @throws IllegalStateExeption si this n'est pas visible
     */
    public boolean egale(Carte c){
        Objects.requireNonNull(c, "la carte a tester passee en parametre ne peut pas etre null");
        Objects.requireNonNull(this, "la carte qu'on veut comparer (this) ne peut pas etre null");
        return c.valeur == this.valeur;
    }

    public boolean getVisible(){
        return visible;
    }

    /**
     * Methode inversant la visibilite d'une carte.
     */
    public void toggleVisible(){
        this.visible = ! this.visible;
    }

  /**
    * @return String representant la carte (version longue)
    * @see toString
    */ 
    public String toStringLong(){
        return  this.toString() + " parmi " + this.nbreCarte;
    }

    /**
    * @return String representant la carte.
    */ 
    public String toString(){
        return "une carte " + (this.visible ? "visible" + " de valeur " + this.valeur: "cachee");
    }

    /**
     * C'est un peu moche mais on peut pour simplifier mettre des tests manuels dans un main dans chaque classe.
     * C'est plutot mieux que de mettre des print dans chaque methode car vous etes plus sur de la stabilite de vos tests 
     * (vous pouvez rejouer les tests plus tard).
     *
     * Idealement on utilise un outil dedie comme JUnit qui favorise au maximum cette automatisation.
     * @param args pas de parametre en ligne de commande prevu.
     */
    public static void main(String[] args) {
        Carte un = new Carte(1);
        System.out.println(un.toString());
        Carte deux = new Carte (2);
        System.out.println(deux.toString());
        Carte unBis = new Carte(1);
        System.out.println(unBis.toString());

        un.toggleVisible();
        System.out.println(un.toString());
        unBis.toggleVisible();
        System.out.println(unBis.toString());
        System.out.println(un.egale(unBis));
        unBis.toggleVisible();//true
        System.out.println(unBis.toString());

        System.out.println(un.toString());
        deux.toggleVisible();
        System.out.println(deux.toString());
        System.out.println(!un.egale(deux));//not false

        Carte bad = null;
        un.egale(bad);
    }
}


