package testPackage;

//pour que la méthode clone puisse être appelée il faut implémenter cette interface (c'est une manière de typer un objet : il est clonable)
public class Bidule implements Cloneable {

       private int valeur;
       private Personne personne;
       private int compteur;

       public Bidule(int valeur) {
              this.valeur = valeur;
              personne = new Personne("toto "+valeur);
              compteur = 0;
       }

       @Override
       public String toString() {
              return super.toString()+" contient -> valeur = "+valeur+" ; personne = "+personne;
       }

       public void setValeur(int valeur) {
              this.valeur = valeur;
       }

       public void incrementCompteur() {
           compteur++;
       }

       // seul l'accesseur permettant de récupérer la valeur de personne est disponible : on ne permet pas la modification du pointeur
       public Personne getPersonne() {
              return personne;
       }

       /**
        * Remarque : il est possible de changer la visibilité d'une méthode protected en public dans la sous classe (mais pas de private vers une autre).
        */
       @Override
       public Bidule clone() throws CloneNotSupportedException { // on garde la même signature : on ne pas savoir si tous les attributs seront clonables

              Bidule nouveauBidule = (Bidule) super.clone();

              // À ce point précis du code, nouveauBidule partage l'attribut personne avec l'objet sur lequel clone est appelée.
              // Si on veut une copie profonde, il faut faire la copie soi-même dans le code, comme ci-dessous.

              if(this.personne != null){ // cela n'arrivera jamais ici car l'accès à personne est verouillé en écriture MAIS prenez cette bonne habitude.
                                                           // Ici, si l'attribut this.personne est null alors la ligne suivante plante.
                     nouveauBidule.personne = getPersonne().clone();
                     // Il faut toujours utiliser la méthode clone de l'attribut si possible (pas un constructeur)
                     // car on ne connait pas forcément le vrai type que contient l'attribut
              }
              return nouveauBidule;
       }

       @Override
       public boolean equals(Object obj) {
              if(obj instanceof Bidule){
                     Bidule otherBidule = (Bidule) obj; // le "cast" est obligatoire pour pouvoir accéder aux attributs car on a "Object" en paramètre dans la signature

                     // tous les attributs doivent vérifier l'égalité logique :
                     return valeur == otherBidule.valeur && compteur == otherBidule.compteur && getPersonne().equals(otherBidule.getPersonne());
              }
              return false; //car même pas du même type !!
       }

       public static void main(String[] args) {
              Bidule bidule1 = new Bidule(2);
              System.out.println("bidule1 = "+bidule1);System.out.println();
              bidule1.incrementCompteur();

              Bidule bidule2 = new Bidule(4);

              System.out.println("bidule2 = "+bidule2);

              System.out.println("\n----------clonage de bidule1 dans bidule2------------\nRésultat :\n");

              try {
                     bidule2 = (Bidule) bidule1.clone();
              } catch (CloneNotSupportedException e) {
                     e.printStackTrace();
              }

              System.out.println("bidule1 = "+bidule1);

              System.out.println("\nbidule2 = "+bidule2);
              System.out.println("\nbidule1.equals(bidule2) apres clonage (doit retourne vrai) -> "+bidule1.equals(bidule2)+"\n");


              System.out.println("----------manipulation du clone bidule2 sur value :  --- bidule2.setValeur(9); ---\nRésultat :\n");

              bidule2.setValeur(9);

              System.out.println("bidule1 = "+bidule1);
              System.out.println("\nbidule2 = "+bidule2);

              System.out.println("\nbidule1.equals(bidule2) apres manipulation (doit retourne faux) -> "+bidule1.equals(bidule2)+"\n");

              System.out.println("\n\n-----manipulation du clone bidule2 sur personne : --- bidule2.getPersonne().setName(\"bidule\"); ---\nRésultat :\n");

              bidule2.getPersonne().setName("bidule");

              System.out.println("bidule1 = "+bidule1);
              System.out.println("\nbidule2 = "+bidule2);

       }

}