using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CLPersone
{
    public class Classe : List<Alunno>
    {


        // Stampa tutta la lista degli attributi per tutti i componenti della classe
        public override string ToString()
        {
            string listaStampaAlunni = "";
            foreach (Alunno alunno in this)
            {
                listaStampaAlunni += alunno.ToString();
            }

            return listaStampaAlunni;
        }



        // INTERROGAZIONE 1 : Ricercare gli alunni di una data città
        public Classe RicercaConEspressioniLambda(string parametroCitta)
        {
            Classe listaAlunniFiltrati = new Classe();

            var query = this.Where(dato => dato.Citta == parametroCitta)
                            .OrderByDescending(dato => dato.Eta)
                            .Select(dato => dato);

            foreach (var alunno in query)
            {
                listaAlunniFiltrati.Add(alunno);
            }
    
            return listaAlunniFiltrati;
        }



        // INTERROGAZIONE 2 : Ricercare gli alunni di una data città
        public Classe RicercaConLinq(string parametroCitta)
        {
            Classe listaAlunniFiltrati = new Classe();

            var query = from alunno in this
                        where alunno.Citta == parametroCitta
                        orderby alunno.Eta descending
                        select alunno;

            foreach (var alunno in query)
            {
                listaAlunniFiltrati.Add(alunno);
            }

            return listaAlunniFiltrati;
        }



        // INTERROGAZIONE 3 : Ricercare gli alunni il cui cognome inizia con una data lettera, 
        // e che si trovano in posizione pari nell’elenco

        public Classe RicercaAlunniCheInizianoPerLetteraInPosizionePari(string lettera)
        {
            Classe listaAlunniFiltrati = new Classe();

            var query = this.Where((dato, indice) => dato.Cognome.StartsWith(lettera) && (indice % 2 == 0));

            foreach (var alunno in query)
            {
                listaAlunniFiltrati.Add(alunno);
            }

            return listaAlunniFiltrati;

        }




        // INTERROGAZIONE 4 : Aggiungere un nuovo alunno alla classe, 
        // controllando che non ce ne sia uno con analogo codice fiscale

        public new void Add(Alunno alunno)
        {
            bool elementoInserito = this.Exists(dato => dato.Codice == alunno.Codice);

            if (!elementoInserito)
            {
                base.Add(alunno);
            }
            else
            {
                throw new Exception("Inserimento non possibile. Codice già presente");
            }
        }


        // INTERROGAZIONE 5 : Visualizzare Nome e Cognome degli alunni maschi

        public void NomeCognomeAlunniMaschi()
        {
            var alunniMaschi = this.Where(alunno => alunno.Sesso == "M")
                                    .Select(alunno => new { alunno.Cognome, alunno.Nome });

            foreach (var alunno in alunniMaschi)
            {
                Console.WriteLine(alunno.Cognome + " " + alunno.Nome);
            }
        }




        // INTERROGAZIONE 6 : Visualizzare Nome e Cognome degli alunni maschi
        // 
        // Alternativa alla precedente interrogazione 5,
        // in cui, invece di generare un tipo anonimo,
        // si definisce una classe ad hoc (con relativa collezione)
        public ListaDettaglioNomeCognome NomeCognomeAlunniMaschi2()
        {

            // La classe ListaDettaglioNomeCognome (di cui si trova il codice in fondo a questo file)
            // è definita come una collezione (List<>) di oggetti di tipo DettaglioNomeCognome

            // La classe DettaglioNomeCognome (di cui si trova il codice in fondo a questo file)
            // ha come dati membro Nome e Cognome

            ListaDettaglioNomeCognome listaAlunniEstratti = new ListaDettaglioNomeCognome();


            // implementazione con metodi di estensione
            var alunniMaschi = this.Where((alunno) => alunno.Sesso == "M")
                                   .Select((alunno) => new DettaglioNomeCognome { Nome = alunno.Nome, Cognome = alunno.Cognome });


            listaAlunniEstratti.AddRange(alunniMaschi);

            return listaAlunniEstratti;
        }


        // INTERROGAZIONE 7 : Ricercare gli alunni il cui cognome termina con una data lettera 

        public Classe RicercaAlunniCognomeFiniscePer(string lettera)
        {
            Classe listaAlunniFiltrati = new Classe();

            var query = this.Where(alunno => alunno.Cognome.EndsWith(lettera))
                            .OrderBy(alunno => alunno.Cognome)
                            .ThenBy(alunno => alunno.Nome)
                            .Select(aluuno => aluuno);



            var query2 = from alunno in this
                         where alunno.Cognome.EndsWith(lettera)
                         orderby alunno.Cognome, alunno.Nome
                         select alunno;

            foreach (var alunno in query2)
            {
                listaAlunniFiltrati.Add(alunno);
            }
            
            return listaAlunniFiltrati;
        }


        // INTERROGAZIONE 8 : Ricercare il miglior voto

        public int MigliorVoto()
        {
            return this.Max(alunno => alunno.VotoInformatica);
        }



        // INTERROGAZIONE 9 : Ricercare i primi due alunni di Rovereto presenti nella classe

        public Classe PrimiDueMaggiorenniRovereto()
        {
            Classe listaAlunniFiltrati = new Classe();

            var query = this.Where(alunno => (alunno.Citta == "Rovereto") && (alunno.Eta >= 18))
                            .OrderBy(alunno => alunno.Cognome)
                            .ThenBy(alunno => alunno.Nome)
                            .Select(alunno => alunno)
                            .Take(2);


            foreach (var alunno in query)
            {
                listaAlunniFiltrati.Add(alunno);
            }

            return listaAlunniFiltrati;
        }




        // INTERROGAZIONE 10 : Visualizzare nome e cognome degli alunni, prendendo i cognomi fino alla lettera M

        public void AlunniConCognomeFinoAllaM()
        {
            var alunniFiltrati = this.OrderBy(alunno => alunno.Cognome)
                                     .Select(alunno => new { alunno.Cognome, alunno.Nome })
                                     .TakeWhile(alunno => !alunno.Cognome.StartsWith("N"));


            char letteraConfronto = 'M';

            var alunniFiltrati2 = from alunno in this
                                  orderby alunno.Cognome
                                  where(alunno.Cognome.ToUpper()[0] <= letteraConfronto)
                                  select new {alunno.Cognome, alunno.Nome};

            
            foreach (var alunno in alunniFiltrati2)
            {
                Console.WriteLine(alunno.Cognome + " " + alunno.Nome);
            }
        }



        // INTERROGAZIONE 11 : Ricercare gli alunni con il miglior voto

        public Classe AlunniConVotoMigliore()
        {
            Classe listaAlunniFiltrati = new Classe();

            var query = this.Where(alunno => alunno.VotoInformatica == (this.Max(vMax => vMax.VotoInformatica)))
                            .OrderBy(alunno => alunno.Cognome)
                            .ThenBy(alunno => alunno.Nome)
                            .Select(alunno => alunno);



            var query2 = from alunno in this
                         where alunno.VotoInformatica == (this.Max(vMax => vMax.VotoInformatica))
                         orderby alunno.Cognome, alunno.Nome
                         select alunno;


            foreach (var alunno in query2)
            {
                listaAlunniFiltrati.Add(alunno);
            }

            return listaAlunniFiltrati;
        
        }
             
    }







    // Classe base utilizzata per risolvere l'interrogazione 6
    // evitando di definire un tipo anonimo
    public class DettaglioNomeCognome
    {
        private string nome;

        public string Nome
        {
            get { return nome; }
            set { nome = value; }
        }


        private string cognome;

        public string Cognome
        {
            get { return cognome; }
            set { cognome = value; }
        }
    }


    // Classe utilizzata per risolvere l'interrogazione 6
    // evitando di definire un tipo anonimo
    public class ListaDettaglioNomeCognome : List<DettaglioNomeCognome>
    { }
}
