using Jypeli;
using static Jypeli.Game;
using System;
using System.Linq;

/// @author  Micke Saarnela
/// @version 11.10.2023
///
/// <summary>
/// Jyväskylän yliopiston Ohjelmointi 1 -kurssin harjoitustyö, syksy 2023.
/// </summary>

namespace Superpallo3000
{
    /// <summary>
    /// Pelin kenttänumeron ja pistelaskurin tarvitsema luokka.
    /// Käytetään myös loppuruudun tekstien esittämiseen.
    /// </summary>
    class Tekstinaytto : GameObject
    {
        /// <summary>   
        /// OlionTilanne tilanne kertoo, missä kohtaa olion koodin suoritus on menossa.
        /// </summary>
        /// 
        /// <remarks>
        /// <code>
        /// Normaali = olio on luotu tai animaatio on suoritettu loppuun
        /// Animaatio = olio suorittaa animaatiota
        /// JatkuvaAnimaatio = olio suorittaa jatkuvaa animaatiota
        /// </code>
        /// </remarks>    
        private enum OlionTilanne : int { Normaali, Animaatio, JatkuvaAnimaatio }

        /// <summary>
        /// Animaation kesto millisekunteina.
        /// </summary>
        private const double ANIMAATION_KESTO = 300.0d;

        /// <summary>
        /// Tekstin värin vaihteluun viiveeseen tehtävä muutos.
        /// </summary>
        private const double JATKUVAN_ANIMAATION_PAIVITYSAJAN_MUUTOS = 1.0d;

        /// <summary>
        /// Tekstin värin vaihtelun päivitysväli.
        /// </summary>
        private const double JATKUVAN_ANIMAATION_PAIVITYSVALI = 2.0d;

        /// <summary>
        /// Tekstin värin vaihtelun viive.
        /// </summary>
        private const double JATKUVAN_ANIMAATION_KULUNEEN_AJAN_KERROIN = -4.0d;

        /// <summary>
        /// Tekstin tavallisen animaation pystysuuntainen liike pikseleinä,
        /// valitaan satunnaisesti kahden numeron väliltä.
        /// </summary>
        private readonly int[] animaationLiikkumavaraPystysuunnassa = { -2, 2 };

        /// <summary>
        /// Tekstin jatkuvan animaation pystysuuntainen liike pikseleinä,
        /// valitaan satunnaisesti kahden numeron väliltä.
        /// </summary>
        private readonly int[] jatkuvanAnimaationLiikkumavara = { -4, 4 };

        /// <summary>
        /// Tekstin taustaväri.
        /// </summary>
        private readonly Color taustavari = Color.Transparent;

        /// <summary>
        /// Tekstin väri valitaan satunnaisesti näistä väreistä.
        /// </summary>
        private readonly Color[] varit = { Color.Aquamarine, Color.Blue, Color.Aqua, Color.Azure };

        /// <summary>
        /// Tekstin väri silloin kun animaatiota ei ole käynnissä.
        /// </summary>
        private readonly Color tekstinVari = Color.Black;

        /// <summary>
        /// Random-luokan olio, tarvitaan Update-funktiossa.
        /// </summary>  
        private readonly Random random = new Random();

        /// <summary>
        /// Olion tilanne.
        /// </summary>
        /// <remarks>Normaali, Animaatio, JatkuvaAnimaatio</remarks>
        private OlionTilanne olionTilanne = OlionTilanne.Normaali;

        /// <summary>
        /// Tekstistä muodostetaan oma Label-luokan olio.       
        /// </summary>
        private Label tekstinaytto;

        /// <summary>
        /// Apumuuttuja, tekstin animaatioon kulunut aika.
        /// </summary>
        private double kulunutAika = 0;

        /// <summary>
        /// Apumuuttuja, tekstin nimaation seuraava päivitysaika.
        /// </summary>
        private double paivitysaika = 0;

        /// <summary>
        /// Luokan konstruktori.
        /// </summary>
        /// <param name="x">Tekstin keskipiste x-akselilla.</param>
        /// <param name="y">Tekstin keskipiste y-akselilla.</param>
        /// <param name="leveys">Tekstille varatun tilan leveys pikseleinä.</param>
        /// <param name="korkeus">Tekstille varatun tilan korkeus pikseleinä.</param>
        /// <param name="kirjasin">Käytettävä kirjasin.</param>
        /// <param name="kirjasimenKoko">Kirjasimen koko.</param>
        /// <param name="tekstinVari">Tekstin väri.</param>
        /// <param name="teksti">Näytettävä teksti merkkijonona.</param>
        /// <param name="tasaus">Tekstin tasaus sille varatussa tilassa: keskelle, vasemmalle, oikealle</param>
        public Tekstinaytto(int x, int y, int leveys, int korkeus, Font kirjasin, int kirjasimenKoko, Color tekstinVari, string teksti, Tasaus tasaus) : base(0, 0)
        {
            Color = taustavari;
            X = x;
            Y = y;
            this.tekstinVari = tekstinVari;

            tekstinaytto = new Label(leveys, korkeus);
            tekstinaytto.Text = teksti;
            tekstinaytto.X = x;
            tekstinaytto.Y = y;
            tekstinaytto.Font = kirjasin;
            tekstinaytto.Font.Size = kirjasimenKoko;
            tekstinaytto.TextColor = tekstinVari;
            tekstinaytto.VerticalAlignment = VerticalAlignment.Center;

            switch (tasaus)
            {
                case Tasaus.Keskelle:
                    tekstinaytto.HorizontalAlignment = HorizontalAlignment.Center;                    
                    break;
                case Tasaus.Vasemmalle:
                    tekstinaytto.HorizontalAlignment = HorizontalAlignment.Left;
                    break;
                case Tasaus.Oikealle:
                    tekstinaytto.HorizontalAlignment = HorizontalAlignment.Right;                    
                    break;
                default:
                    break;
            }
                        
            Instance.Add(tekstinaytto, (int)OlioidenPiirtotasot.UI);
        }


        /// <summary>
        /// Vaihdetaan teksti.
        /// </summary>
        /// <param name="teksti">Uusi teksti merkkijonona.</param>
        public void PaivitaTeksti(string teksti)
        {
            // aloitetaan animaatio, jos teksti on muuttunut
            if (!tekstinaytto.Text.Equals(teksti))
            {
                kulunutAika = 0;
                olionTilanne = OlionTilanne.Animaatio;                
            }

            tekstinaytto.Text = teksti;
        }


        /// <summary>
        /// Asetetaan teksti uuteen paikkaan.
        /// </summary>
        /// <param name="x">Tekstin keskipiste x-akselilla.</param>
        /// <param name="y">Tekstin keskipiste y-akselilla.</param>
        public void AsetaPaikka(int x, int y)
        {            
            tekstinaytto.X = x;
            tekstinaytto.Y = y;              
        }


        /// <summary>
        /// Annetaan kirjasimelle uusi koko.
        /// </summary>
        /// <param name="koko">Kirjasimen koko pikseleinä.</param>
        public void AsetaFontinKoko(int koko)
        {
            tekstinaytto.Font.Size = koko;
        }


        /// <summary>
        /// Vaihdetaan animaation tilaksi jatkuva värin ja position vaihtelu.
        /// </summary>
        public void AloitaJatkuvaAnimaatio()
        {
            kulunutAika = 0;
            paivitysaika = 0;
            olionTilanne = OlionTilanne.JatkuvaAnimaatio;
        }


        /// <summary>
        /// Tuhoteen tekstin olio ja tämä olio.
        /// </summary>
        public override void Destroy()
        {            
            tekstinaytto.Destroy();
            tekstinaytto = null;
            base.Destroy();
        }


        /// <summary>
        /// Jypeli kutsuu tätä funktiota tietyin ajoin.
        /// Päivitetään tekstin väri ja positio.
        /// </summary>
        /// <param name="time">Aika joka on kulunut viimeisen kutsun jälkeen.</param>
        public override void Update(Time time)
        {
            if (IsDestroyed) { }
            else if (olionTilanne == OlionTilanne.Animaatio)
            {
                kulunutAika += time.SinceLastUpdate.TotalMilliseconds;

                if (kulunutAika >= ANIMAATION_KESTO)
                {
                    olionTilanne = OlionTilanne.Normaali;                    
                    tekstinaytto.TextColor = tekstinVari;
                    tekstinaytto.Y = Y;
                }
                else
                {                    
                    tekstinaytto.TextColor = varit[random.Next(varit.Count())];                    
                    tekstinaytto.Y = Y + random.Next(animaationLiikkumavaraPystysuunnassa[0], animaationLiikkumavaraPystysuunnassa[1]);
                }
            }
            else if (olionTilanne == OlionTilanne.JatkuvaAnimaatio)
            {
                kulunutAika += time.SinceLastUpdate.TotalMilliseconds;
                paivitysaika += JATKUVAN_ANIMAATION_PAIVITYSAJAN_MUUTOS;

                if (kulunutAika >= ANIMAATION_KESTO)
                {                   
                    tekstinaytto.TextColor = tekstinVari;
                    tekstinaytto.X = X;
                    tekstinaytto.Y = Y;
                    kulunutAika *= JATKUVAN_ANIMAATION_KULUNEEN_AJAN_KERROIN;
                }
                else if (kulunutAika >= 0 && paivitysaika >= JATKUVAN_ANIMAATION_PAIVITYSVALI)
                {
                    tekstinaytto.TextColor = varit[random.Next(varit.Count())];
                    tekstinaytto.X = X + random.Next(jatkuvanAnimaationLiikkumavara[0], jatkuvanAnimaationLiikkumavara[1]);
                    tekstinaytto.Y = Y + random.Next(jatkuvanAnimaationLiikkumavara[0], jatkuvanAnimaationLiikkumavara[1]);
                    paivitysaika = -JATKUVAN_ANIMAATION_PAIVITYSVALI;
                }
            }

            base.Update(time);
        }

    }

}