package esercitazioni.calendario;
/**
 * Questa classe si propone di gestire attravarso l'uso di array
 * i giorni dei mesi di un modello di calendario.
 */
public class Calendario {
    /**
     * array contenete nei propri elementi il numero di giorni
     * di ciascun mese
     */
     private int[] giorni_mesi={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    /**
     * array contenente nei propri elementi il nome di ciascun mese
     */
     private String[] mesi={
        "", "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio"
        , "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre"
        , "Novembre", "Dicembre"
    };
    /**
     * array contenente nei propri elementi il nome di ciascun giorno della
     * settimana
     */
     private String[] giorni_settimana={
        "", "Luned", "Marted", "Mecoled", "Gioved"
        , "Venerd", "Sabato", "Domenica"
    };
    /**
     * array contenente nei propri elementi il nome di ciascun giorno della
     * settimana
     */
     private String[] sigle_g_s={
        "", "Lun", "Mar", "Mer", "Gio"
        , "Ven", "Sab", "Dom"
    };
    /**
     * anno cui  inizializzato il calendario
     */
     private int anno;
     /**
      * mese corrente
      */
      private int mese;
      /**
       * giorno corrente
       */
       private int giorno;
      /**
       * numero del giorno settimanale del primo giorno dell'anno
       * (es. 1 per Luned)
       */
       private int pgs;
     /**
     * costruttore di default
     */
    public Calendario() {
        //scelgo di impostare come anno di default il 2005
        setAnno(2005, 6, 1, 1);
    }
     /**
     * costruttore dove viene inizializzato l'anno ed nome del giorno
     * della settimana del primo giorno dell'anno (es. 1 per luned)
     */
    public Calendario(int a, int pgs) {
        //imposta il mese di default a gennaio
        //imposta il giorno di default a 1
        setAnno(a, pgs, 1, 1);
    }
    /**
    * metodo che permetta di impostare un nuovo anno
    */
    public void setAnno(int a, int pgs, int m, int g){
        //inizializza l'anno del calendario
        anno=a;
        //numero del giorno della settimana per il primo giorno dell'anno
        this.pgs=pgs;
        //test per anno bisestile
        testBisestile();
        //imposta il mese
        setMese(m);
        //imposta il giorno
        setGiorno(g);
    }
    /**
     * determina se l'anno  bisestile, nel qual caso corregge il valore
     * dei giorni del mese di febbraio
     */
    private boolean testBisestile(){
        if((anno % 4)==0){
            //anno bisestile
            giorni_mesi[2]=29;
            return true;
        }
        return false;
    }
    /**
     * dato in input il mese ed il giorno corrente calcola il nome del
     * giorno della settimana
     */
     public String getNomeGiorno(int mese, int giorno){
            return giorni_settimana[getGiornoSettimanale(mese, giorno)];
     }
    /**
     * dato in input il mese ed il giorno calcola il numero del
     * giorno della settimana a partire dal fatto che conosciamo il numero di giorno
     * della settimana del primo giorno dell'anno.
     */
     public int getGiornoSettimanale(int mese, int giorno){
            int totgiorni=0;
            //calcola quanti giorni sono passati dal primo giorno
            //dell'anno tenendo conto dei mesi precedenti a quello corrente
            for(int i=1;i<mese;i++){
                totgiorni+=giorni_mesi[i];
            }
            //somma il giorno e ottiene quanti giorni sono
            //passati dall'inizio dell'anno
            totgiorni+=giorno;
            //tenuto conto che ogni 7 giorni si ripete il giorno della settimana,
            int tmp=((totgiorni-1) % 7)+pgs;
            if(tmp>7)
                     tmp-=7;
            return tmp;
     }
    /**
     * ritorna la data in una stringa con il formato gg/mm/aaaa
     */
     public String getData(){
            return getGiorno()+"/"+getMese()+"/"+getAnno();
     }
    /**
    * stampa la data completa con
    * il giorno della settimana ed il mese scritti per esteso:
    * es. Marted 18 Gennaio 2005 per il giorno corrente
    */
    public String getDataEstesa(){
        return
            giorni_settimana[getGiornoSettimanale(getMese(), getGiorno())]
            +" "+getGiorno()
            +" "+mesi[getMese()]
            +" "+getAnno()
        ;
    }
     /**
      * ritorna l'anno cui il calendario fa riferimento
      */
      public int getAnno(){
             return anno;
      }
     /**
      * ritorna il mese corrente
      */
      public int getMese(){
             return mese;
      }
      /**
       * ritorna il giorno corrente
       */
       public int getGiorno(){
              return giorno;
       }
       /**
        * imposta il mese corrente eseguendo un test
         * sul valore del numero di mese valutando che sia congruo
        */
        public void setMese(int m){
               if( (m>0)&&(m<=12) ){
                   mese=m;
                }else{
                   //MESE NON VALIDO imposta a gennaio
                   mese=1;
                }
        }
       /**
        * imposta il giorno corrente con test di congruit
        */
        public void setGiorno(int g){
               if( (g>0)&&(g<=giorni_mesi[getMese()]) ){
                   giorno=g;
                }else{
                   //giorno NON VALIDO imposta a 1
                   giorno=1;
                }
        }
        /**
         * stampa il mese visualizzando una lista di 7 numeri per ciascuna
         * riga e anteponendo e posticipando un asterisco se in quest mese
         * cade il giorno correntemente impostato.
         * Si sfruttano i metodi print e println per stampare sulla stessa
         * riga o per ricominciare dalla successiva
         */
          public void stampaSempliceMese(int mesedistampa){
                //Stampa il nome del mese convertendolo in maiuscolo
                System.out.println(mesi[mesedistampa].toUpperCase());
                //giorni del mese corrente
                int gm=giorni_mesi[mesedistampa];
                //loop di stampa
                String g;
                for(int i=1; i<=gm; i++){
                    //test se sta stampando il giorno corrente
                    if((i==getGiorno())&&(mesedistampa==getMese()))
                        g="*"+i+"*";
                    else
                        g=" "+i+" ";
                    //per permettere un giusto incolonnamento viene testato
                    //se stiamo stampando un numero a due cifre:
                    //in caso contrario aggiungiamo un ulteriore spazio davanti
                    //alla stringa
                    if(i<10)
                        g=" "+g;
                    if((i % 7)==0){
                        //inizia una nuova riga
                        System.out.println(g);
                    }else{
                        System.out.print(g);
                    }
                }
                //stampa una riga vuota alla fine
                System.out.println();
          }
        /**
         * stampa il mese visualizzando una lista di 7 numeri per ciascuna
         * riga e anteponendo e posticipando un asterisco se in questo mese
         * cade il giorno correntemente impostato.
         * Si sfruttano i metodi print e println per stampare sulla stessa
         * riga o per ricominciare dalla successiva. Per potere ottenere
         * delle colonne equalmente spaziate si far in modo di avere stringhe
         * sempre di 4 caratteri.
         */
          public void stampaMese(int mesedistampa){
                //Stampa il nome del mese convertendolo in maiuscolo
                System.out.println(mesi[mesedistampa].toUpperCase());
                //stampa l'intestazione dei girni della settimana
                for(int i=1;i<=7;i++){
                    System.out.print(sigle_g_s[i]+" ");
                }
                //spazio di una riga tra l'intestazione ed i numeri
                System.out.println();
                //giorni del mese corrente
                int gm=giorni_mesi[mesedistampa];
                //loop di stampa
                /*
                Dal momento che in generale il primo giorno del mese non combacia con il
                luned, mi trovo a dovere inventare un artificio per fare si che nella stampa
                del primo giorno del mese siano lasciate un certo numero di colonne vuote
                a sinistra (es. 0 se  luned e 3 se gioved). Potendo conoscere il primo
                giorno del mese con il metodo getGiornoSettimanale, potr conoscere
                quante colonne lasciare libere stampando una stringa di 4 caratteri spazio.
                */
                int colonnevuote=getGiornoSettimanale(mesedistampa, 1)-1;
                /*
                A questo punto conoscendo il numero di colonne vuote,  come se dovessimo
                stampare un numero di giorni pi grande, quindi sommiamo questo numero
                al numero di giorni del mese
                */
                gm+=colonnevuote;
                /*
                non  ancora finita: per mantenere funzionante il nostro loop di stampa
                introduciamo un contatore che deve contare i giorni vuoti e che faccia
                si che non si debbano stampare numeri di giorno
                */
                int nostampa=0;
                String vuota4="    ";
                String g;
                for(int i=1; i<=gm; i++){
                    if(nostampa<colonnevuote){
                        //incrementa il contatore nostampa
                        nostampa++;
                        //stampa la colonna vuota
                        System.out.print(vuota4);
                    }else{
                        //si rende necessario questo passaggio per potere
                        //riferire il contatore del ciclo for al giorno
                        //che vogliamo stampare
                        int printg=i-colonnevuote;
                        //test se sta stampando il giorno corrente
                        if(
                           (printg==getGiorno())&&
                           (mesedistampa==getMese())
                        )
                           g="*"+printg+"*";
                        else
                            g=" "+printg+" ";
                        //per permettere un giusto incolonnamento viene testato
                        //se stiamo stampando un numero a due cifre:
                        //in caso contrario aggiungiamo un ulteriore spazio davanti
                        //alla stringa
                        if(printg<10)
                            g=" "+g;
                        if((i % 7)==0){
                            //inizia una nuova riga
                            System.out.println(g);
                        }
                        else{
                             System.out.print(g);
                        }
                    }
                }
                //stampa una riga vuota alla fine
                System.out.println();
          }
         /**
          * crea un overloading per stampare il mese corrente
          */
          public void stampaMese(){
                 stampaMese(getMese());
          }

         /**
          * crea un metodo che stampi l'anno in corso
          */
          public void stampaAnno(){
                 for(int i=1;i<13;i++){
                         stampaMese(i);
                 }
          }

}