// Bandit Manchot, by Seb Luca, UNamur, June 2018

package com.projet.sluca.banditmanchot;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

public class GameActivity extends Activity implements View.OnClickListener
{
    // Création de variables utiles.
    private int credits     = 20;     // provision de crédits, au lancement = 20
    private int victories   = 0;      // nombre de victoires
    private int defeats     = 0;      // nombre de défaites
    private int creditsWon  = 0;      // crédits remportés
    private int creditsLost = 0;      // crédits perdus/dépensés
    private boolean busy    = false;  // état spécifiant si "Play" a été lancé
    private boolean blocked = false;  // état spécifiant si "Stop"  a été lancé
    private boolean turn1   = false;  // bool spécifiant si la roue 1 tourne
    private boolean turn2   = false;  // bool spécifiant si la roue 2 tourne
    private boolean turn3   = false;  // bool spécifiant si la roue 3 tourne
    private int counter1    = 1;      // position de la roue 1, au lancement = 1
    private int counter2    = 2;      // position de la roue 2, au lancement = 2
    private int counter3    = 3;      // position de la roue 3, au lancement = 3
    private int score1      = 1;      // valeur-score relative à la position de la roue 1, au lancement = 1
    private int score2      = 10;     // valeur-score relative à la position de la roue 2, au lancement = 10
    private int score3      = 100;    // valeur-score relative à la position de la roue 3, au lancement = 100

    GlobalDatas globalDatas; // Appel de la classe traitant les variables globales.

    // MediaPlayer spécifique pour réaliser une boucle sonore plus tard.
    static MediaPlayer loop = new MediaPlayer();

    // Variables supplémentaires utiles au code.
    private static int REQUEST_CODE = 1;
    private Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) // ====> Lancement de l'activity <====
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game); // Appel de la vue.
        context = this;

        // Etablissement de la liaison avec les variables globales.
        globalDatas = (GlobalDatas) getApplication();

        refresh(); // Rafraîchissement de l'affichage des données.

        // Ecoute des clics sur le bouton d'envoi ("Play").
        Button btnPlay = (Button) findViewById(R.id.btnPlay);
        btnPlay.setOnClickListener((View.OnClickListener) this);
    }


    @Override
    public void onClick(View paramView) // ====> Effets du clic sur le bouton "Play" <====
    {
        if(!blocked || credits != 0) // Précautions de bloquage pour éviter les clics malvenus.
        {
            soundPlay(1); // Bruitage de bouton, via la méthode "soundPlay()".

            if(!busy) // --> SI PREMIER CLIC SUR "PLAY" (lancer les roues).
            {
                // Enfoncement du bouton "Play" suit à un premier clic.
                Button btnPlay = (Button) findViewById(R.id.btnPlay);
                btnPlay.getBackground().setAlpha(176); // opacité (0-255)
                btnPlay.setText("STOP");

                // Retrait d'un Crédit.
                credits--; creditsLost++;
                refresh(); // Rafraîchissement de l'affichage des données.

                busy = true; // Changement d'état signalant que les roues ont été lancées par un premier clic sur "Play".

                turn1 = true; turn2 = true; turn3 = true; // Etat des 3 roues : actif.

                // Activer le son de roulement en boucle.
                loop = MediaPlayer.create(this,R.raw.rotation);
                loop.setVolume(50, 50);
                loop.start();
                loop.setLooping(true);

                turningWheels(); // Lancement des roues.
            }
            else     // --> SI SECOND CLIC SUR "PLAY" (arrêter les roues).
            {
                blocked = true; // Désactivation totale temporaire du bouton "Play".

                // Désenfoncement et mise en pause du bouton "Play" suite au second clic.
                Button btnPlay = (Button) findViewById(R.id.btnPlay);
                btnPlay.getBackground().setAlpha(255); // opacité (0-255)
                btnPlay.setText("...");

                // Arrêt des roues.
                stop(1); stop(2); stop(3);

                Handler handler = new Handler();  // Temps d'arrêt avant l'annonce des résultats.
                handler.postDelayed(new Runnable()
                {
                    @Override
                    public void run() // Exécution.
                    {
                        // Appel du résultat du jeu en fonction du score par la méthode "results()".
                        // Le premier paramètre spécifie : -1 = Malus , 0 = Neutre , 1 = Bonus. Le second exporte le score.

                        // Calcul du score total relatif à l'image sur laquelle chaque roue s'est arrêtée :
                        Integer scoreTotal = score1 + score2 + score3;

                        if // -> En cas de 2x diamant :
                        (
                           (score1 == 100 && score2 == 100 ||
                            score2 == 100 && score3 == 100 ||
                            score1 == 100 && score3 == 100)
                            && scoreTotal != 300 // refuser en cas de "3 diamants"
                        )
                        {
                            results( 1,  200);
                        }
                        else // -> En cas d'1x diamant :
                          if
                          (
                              (score1 == 100 || score2 == 100 || score3 == 100)
                               && scoreTotal != 111 // refuser en cas de "1 Bonus de chaque"
                               && scoreTotal != 300 // refuser en cas de "3 diamants"
                          )
                        {
                            results( 1,  100);
                        }
                        else // -> Autres cas, en fonction du score total.
                        {
                            if   // -> Si gain d'un bonus
                            (
                                 scoreTotal == 3      ||           // 3 trèfles
                                 scoreTotal == 30     ||           // 3 cloches
                                 scoreTotal == 300    ||           // 3 diamants
                                 scoreTotal == 111                 // 1 Bonus de chaque
                            )
                                 results(  1,   scoreTotal);  // > résultat positif
                            else
                            if   // -> Si affligé d'un malus
                            (
                                 scoreTotal == 3000   ||           // 3 crottes
                                 scoreTotal == 30000  ||           // 3 araignées
                                 scoreTotal == 300000 ||           // 3 crânes
                                 scoreTotal == 111000              // 1 Malus de chaque
                            )
                                 results( -1,  scoreTotal);   // > résultat négatif
                            else // -> Si aucune combinaison
                                 results(  0,  scoreTotal);   // > résultat neutre
                        }
                    }
                }, 1640); // Délai de 1640 ms avant l'annonce des résultats, pour laisser les roues s'arrêter.
            }
        }
    }


    public void refresh() // ====> Rafraîchissement de l'affichage des données <====
    {
        // Crédits possédés
        TextView money = (TextView) findViewById(R.id.credits);
        String value = Integer.toString(credits);
        money.setText(value);

        // Statistiques de jeu
        TextView stats = (TextView) findViewById(R.id.stats);
        stats.setText(victories + "\n" + defeats + "\n" + creditsWon + "\n" + creditsLost);
    }


    public void turningWheels() // ====> Lancement et maintient de la rotation des roues <====
    {
        // Détermination d'un délai, selon que la roue soit en voie de s'arrêter ou non.
        Integer delay = 0;
        if(blocked) delay = 120; // délai plus long avant arrêt
        else        delay =  75; // délai plus court pendant roulement

        // Timer pour les intervalles de changement d'image.
        Handler handler = new Handler();
        handler.postDelayed(new Runnable()
        {
            @Override
            public void run()            // Lancement.
            {
                if(turn1) turning1();    // Chaque roue tournera si son état est actif.
                if(turn2) turning2();
                if(turn3) turning3();

                if(turn1 || turn2 || turn3) turningWheels(); // La méthode sera relancée tant qu'au moins une roue tourne encore.
                else loop.release();                         // Sinon, terminer en faisant cesser la boucle sonore de roulement.
            }
        }, delay);                       // Délai entre chaque relance.
    }


    public void turning1() // ====> Gestion des tours de la roue "symbol1". <====
    {
        ImageView img1 = (ImageView) findViewById(R.id.symbol1);

        if(counter1 == 6) counter1 = 0; // Réinitialisation si est à la dernière image.

        // Prise en compte de l'image actuellement affichée grâce à l'entier "counter1".
             if(counter1 == 0 && turn1){ img1.setImageResource(R.drawable.symbol1); counter1++; score1 = 1; }
        else if(counter1 == 1 && turn1){ img1.setImageResource(R.drawable.symbol2); counter1++; score1 = 10; }
        else if(counter1 == 2 && turn1){ img1.setImageResource(R.drawable.symbol3); counter1++; score1 = 100; }
        else if(counter1 == 3 && turn1){ img1.setImageResource(R.drawable.symbol4); counter1++; score1 = 1000; }
        else if(counter1 == 4 && turn1){ img1.setImageResource(R.drawable.symbol5); counter1++; score1 = 10000; }
        else if(counter1 == 5 && turn1){ img1.setImageResource(R.drawable.symbol6); counter1++; score1 = 100000; }
    }


    public void turning2() // ====> Gestion des tours de la roue "symbol2". <====
    {
        ImageView img2 = (ImageView) findViewById(R.id.symbol2);

        if(counter2 == 6) counter2 = 0; // Réinitialisation si est à la dernière image.

        // Prise en compte de l'image actuellement affichée grâce à l'entier "counter2".
             if(counter2 == 0 && turn2){ img2.setImageResource(R.drawable.symbol1); counter2++; score2 = 1; }
        else if(counter2 == 1 && turn2){ img2.setImageResource(R.drawable.symbol2); counter2++; score2 = 10; }
        else if(counter2 == 2 && turn2){ img2.setImageResource(R.drawable.symbol3); counter2++; score2 = 100; }
        else if(counter2 == 3 && turn2){ img2.setImageResource(R.drawable.symbol4); counter2++; score2 = 1000; }
        else if(counter2 == 4 && turn2){ img2.setImageResource(R.drawable.symbol5); counter2++; score2 = 10000; }
        else if(counter2 == 5 && turn2){ img2.setImageResource(R.drawable.symbol6); counter2++; score2 = 100000; }
    }


    public void turning3() // ====> Gestion des tours de la roue "symbol3". <====
    {
        ImageView img3 = (ImageView) findViewById(R.id.symbol3);

        if(counter3 == 6) counter3 = 0; // Réinitialisation si est à la dernière image.

        // Prise en compte de l'image actuellement affichée grâce à l'entier "counter3".
             if(counter3 == 0 && turn3){ img3.setImageResource(R.drawable.symbol1); counter3++; score3 = 1; }
        else if(counter3 == 1 && turn3){ img3.setImageResource(R.drawable.symbol2); counter3++; score3 = 10; }
        else if(counter3 == 2 && turn3){ img3.setImageResource(R.drawable.symbol3); counter3++; score3 = 100; }
        else if(counter3 == 3 && turn3){ img3.setImageResource(R.drawable.symbol4); counter3++; score3 = 1000; }
        else if(counter3 == 4 && turn3){ img3.setImageResource(R.drawable.symbol5); counter3++; score3 = 10000; }
        else if(counter3 == 5 && turn3){ img3.setImageResource(R.drawable.symbol6); counter3++; score3 = 100000; }
    }


    public void stop(final Integer numRoue) // ====> Arrêt d'une roue dont le numéro est entré en paramètre. <====
    {
        Random whatever = new Random();
        int duration = (whatever.nextInt(480) + 1024); // Détermination d'une durée random.

        Handler handler = new Handler();    // Timer gérant le délai d'arrêt de la roue.
        handler.postDelayed(new Runnable()
        {
            @Override
            public void run()               // Exécution.
            {
                // Déclaration de l'état d'arrêt pour la roue liée au paramètre de méthode.
                if(numRoue == 1) { turn1 = false; soundPlay(3); }
                if(numRoue == 2) { turn2 = false; soundPlay(3); }
                if(numRoue == 3) { turn3 = false; soundPlay(3); }
            }
        }, duration);                       // Délai aléatoire avant l'arrêt total.
    }


    public void results(int type, int score) // ====> Calcul du résultat du jeu en fonction du score obtenu. <====
    {
        String message = ""; // Retiendra un message annonçant le résultat.
        Integer sum = 0;     // Retiendra la valeur d'un bonus/malus.

        if(type <= 0) // --> SI MALUS OU NEUTRE :
        {
            defeats++; // Défaites incrémentées.

            if(type == -1) // --> Si MALUS, calcul de la pénalité.
            {
                     if(score == 3000  ) sum =  2;  // Si 3 crottes   : Malus de  2 Crédits.
                else if(score == 30000 ) sum =  5;  // Si 3 araignées : Malus de  5 Crédits.
                else if(score == 300000) sum = 10;  // Si 3 crânes    : Malus de 10 Crédits.
                else if(score == 111000) sum = 20;  // Si 1 de chaque : Malus de 20 Crédits.

                // Mise à jour des statistiques.
                creditsLost = creditsLost + sum;
                credits = credits - sum;
            }
            // Sinon, c'était une défaite NEUTRE, donc pas de pénalité.

            // Constat des finances du joueur.

            if(type == -1)  // Si défaite avec MALUS.
            {
                message = "You lost " + sum + " Credits."; // Message de perte.
                soundPlay(6); // Bruitage de défaite à Malus, via la méthode "soundPlay()".
            }
            else // Si défaite NEUTRE, message aléatoire :
            {
                int choice = ThreadLocalRandom.current().nextInt(1, 3 + 1); // une random val.

                switch(choice) // Selon la valeur du random, choix du message de perte.
                {
                    case 1 : message = "You missed!";             break ;
                    case 2 : message = "Bad luck!";               break ;
                    case 3 : message = "Try again!";              break ;
                    case 4 : message = "Maybe next time?";        break ;
                    case 5 : message = "This is not your day..."; break ;
                }
                soundPlay(5); // Bruitage de défaite neutre, via la méthode "soundPlay()".
            }

            // Détails complémentaires :

            if(credits <= 0) // > Si faillite :
            {
                credits = 0;
                if(type == -1) message = message + "\nYou are ruined!"; // Si défaite avec MALUS.
                else message = "You are ruined!";                       // Si simple défaite.
            }
        }
        else if(type == 1) // --> SI BONUS :
        {
            victories++; // Victoires incrémentées.

            // Calcul des gains.
                 if(score == 3  ) sum =  2;  // Si 3 trèfles   : Bonus de  2 Crédits.
            else if(score == 30 ) sum =  5;  // Si 3 cloches   : Bonus de  5 Crédits.
            else if(score == 300) sum = 10;  // Si 3 diamants  : Bonus de 10 Crédits.
            else if(score == 111) sum = 20;  // Si 1 de chaque : Bonus de 20 Crédits.
            else if(score == 100) sum =  1;  // Si 1 diamant   : Bonus d'  1 Crédit.
            else if(score == 200) sum =  3;  // Si 2 diamants  : Bonus de  3 Crédits.

            // Mise à jour des statistiques.
            creditsWon = creditsWon + sum;
            credits = credits + sum;

            // Prise en compte de la mise au pluriel, ou non, de "Credit" selon la somme gagnée.
            String crd = "Credit";
            if(sum > 1) crd = crd + "s";

            message = "Bravo, you win " + sum + " " + crd + "!"; // Message de gain.

            soundPlay(4); // Bruitage de gain, via la méthode "soundPlay()".
        }

        refresh();    // Rafraîchissement de l'affichage des données.

        // Affichage du message de résultats.
        Toast toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT);
        toast.setGravity(Gravity.CENTER | Gravity.CENTER_VERTICAL, 0, 336); // position du toast
        TextView v = (TextView) toast.getView().findViewById(android.R.id.message); v.setGravity(Gravity.CENTER); // centrage du texte
        toast.show();

        // Vérifie si la partie est ou non terminée, enquel cas : appel de la fn "over()".
        if(credits <= 0)        over(false); // avec paramètre "faux" si défaite
        else if(credits >= 50)  over(true);  // avec paramètre "vrai" si victoire
        else
        {
            // En revanche, si la partie continue :

            // Retour à l'état normal du bouton "Play".
            Button btnPlay = (Button) findViewById(R.id.btnPlay);
            btnPlay.setText("PLAY");
            blocked = false; // Réactivation du bouton "Play".
            busy = false;    // Retour à l'état inactif.
        }
    }


    public void over(final boolean kind) // ====> Léger délai avant renvoi vers l'écran de fin de jeu adéquat. <====
    {
        // Exportation des stats en variables globales.
        globalDatas.setNbrVictories(victories);
        globalDatas.setNbrDefeats(defeats);
        globalDatas.setCreditsWon(creditsWon);
        globalDatas.setCreditsLost(creditsLost);
        globalDatas.setCredits(credits);

        Handler handler = new Handler();    // Timer.
        handler.postDelayed(new Runnable()
        {
            @Override
            public void run() // Lancement.
            {
                if(kind)       // Renvoi vers le lancement de l'écran de fin en cas de victoire.
                {
                    Intent intent = new Intent(context, WinActivity.class);   // pointe vers WinActivity.
                    startActivityForResult(intent, REQUEST_CODE);             // change d'activity.
                }
                else if(!kind) // Renvoi vers le lancement du Game Over en cas de faillite.
                {
                    Intent intent = new Intent(context, LooseActivity.class); // pointe vers LooseActivity.
                    startActivityForResult(intent, REQUEST_CODE);             // change d'activity.
                }
            }
        }, 2000); // Délai de 2 secondes avant le changement d'activity.
    }


    public void soundPlay(Integer number) // ====> Joue le bruitage dont le numéro est entré en paramètre. <====
    {
        // Catalogue de bruitages :

        MediaPlayer sound = new MediaPlayer();

             if(number == 1){ sound = MediaPlayer.create(this,R.raw.button      );}  // #1
        else if(number == 3){ sound = MediaPlayer.create(this,R.raw.clac        );}  // #3
        else if(number == 4){ sound = MediaPlayer.create(this,R.raw.gain        );}  // #4
        else if(number == 5){ sound = MediaPlayer.create(this,R.raw.defeat      );}  // #5
        else if(number == 6){ sound = MediaPlayer.create(this,R.raw.defeatmalus );}  // #6

        if(sound.isPlaying()) sound.stop();
        sound.start();
    }
}
