/**
 *  Rappresenta un conto corrente in una banca
 *
 * @author     Antonio Terreno
 * @created    14 maggio 2002
 */
public class ContoCorrente implements Comparabile {

        /**
         *  Data corrente espressa in giorni
         */
        public static Data data;

        /**
         *  Capitale sociale iniziale della Banca
         */
        public final static int capitaleSocialeBanca = 1000;

        /**
         *  Array dei conti correnti della banca
         */
        public static ContoCorrente[] arrayOfContoCorrente;
        //array di tutti i conti correnti

        static {
                data = new Data();
                arrayOfContoCorrente = new ContoCorrente[100];
        }


        /**
         *  Costruttore per l'oggetto ContoCorrente con un dato nome, con saldo
         *  iniziale pari a saldoIniziale, con numero assegnato automaticamente in base
         *  a numerazioneConti aggiornando totaleSoldiBanca e inserendo il conto in
         *  arrayOfContoCorrente
         *
         * @param  saldoIniziale  Saldo iniziale del conto
         * @param  nome           Nome del correntista
         */
        public ContoCorrente(String nome, int saldoIniziale) {
                nomeCorrentista = nome;
                saldo = saldoIniziale;
                numeroConto = numerazioneConti;
                arrayOfContoCorrente[numerazioneConti] = this;
                numerazioneConti += 1;
                totaleSoldiBanca += saldoIniziale;
                interesseMaturato = 0;
                giornoUltimoInteresse = new Data();
                giornoUltimoInteresse.setData(data.getData());
        }


        /**
         *  Costruttore per l'oggetto ContoCorrente con un dato nome, con saldo
         *  iniziale pari a zero e con numero assegnato automaticamente in base a
         *  numerazioneConti
         *
         * @param  nome  Nome del correntista
         */
        public ContoCorrente(String nome) {
                this(nome, 0);
        }


        /**
         *  Restituisce il totale dei soldi della banca
         *
         * @return    Il valore di totaleSoldiBanca
         */
        public static int getTotaleSoldiBanca() {
                return totaleSoldiBanca;
        }


        /**
         *  Restituisce il numero di conti aperti
         *
         * @return    Il valore di numerazioneConti
         */
        public static int getNumerazioneConti() {
                return numerazioneConti;
        }


        /**
         *  Restituisce l'indice dell'ultimo conto aperto
         *
         * @return    L'indice dell'ultimo conto aperto
         */
        public static int getIndiceUltimoConto() {
                return numerazioneConti - 1;
        }


        /**
         *  Restituisce il numero del conto
         *
         * @return    Il valore di numeroConto
         */
        public int getNumeroConto() {
                return numeroConto;
        }


        /**
         *  Restituisce il nome del correntista
         *
         * @return    Il valore di nomeCorrentista
         */
        public String getNomeCorrentista() {
                return nomeCorrentista;
        }


        /**
         *  Restituisce il nome del titolare di un conto corrente sapendo il numero di cc
         *
         * @param  numConto             Numero del Conto Corrente
         * @return                      Il titolare del conto corrente
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public static String getNomeCorrentista(int numConto) throws MovimentoErrato {
                if (numConto < numerazioneConti) {
                        return arrayOfContoCorrente[numConto].getNomeCorrentista();
                } else {
                        throw new MovimentoErrato(numConto + " non e' un numero di conto valido");
                }
        }


        /**
         *  Restituisce il numero di un conto corrente a partire dal suo nomeCorrentista
         *
         * @param  nome                 Proprietario del conto corrente
         * @return                      Il numero del conto corrente
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public static int getNumContoCorrente(String nome) throws MovimentoErrato {
                int i = 0;
                while ((i < numerazioneConti) && (arrayOfContoCorrente[i].nomeCorrentista != nome)) {
                        i++;
                }
                if (i < numerazioneConti) {
                        return i;
                } else {
                        throw new MovimentoErrato(nome + " non e' non presente");
                }
        }


        /**
         *  Restituisce il saldo di un conto corrente
         *
         * @return    Il valore di saldo
         */
        public int getSaldo() {
                return saldo;
        }


        /**
         *  Restituisce il saldo di un conto corrente
         *
         * @param  numConto             Numero del conto
         * @return                      Il valore di saldo
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public static int getSaldo(int numConto) throws MovimentoErrato {
                if (numConto < numerazioneConti) {
                        return arrayOfContoCorrente[numConto].getSaldo();
                } else {
                        throw new MovimentoErrato(numConto + " non e' un numero di conto valido");
                }
        }


        /**
         *  Restituisce l'attributo saldo di un conto corrente sapendo il nome
         *
         * @param  nome                 Nome del correntista
         * @return                      Il valore di saldo
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public static int getSaldo(String nome) throws MovimentoErrato {
                int i = 0;
                while ((i < numerazioneConti) && (arrayOfContoCorrente[i].nomeCorrentista != nome)) {
                        i++;
                }
                if (i < numerazioneConti) {
                        return arrayOfContoCorrente[i].getSaldo();
                } else {
                        throw new MovimentoErrato(nome + " non e' non presente");
                }
        }



        /**
         *  Restituisce l'interesse maturato ma non ancora accreditato o addebitato
         *
         * @return    Il valore di interesseMaturato
         */
        public int getInteresseMaturato() {
                return interesseMaturato;
        }


        /**
         *  Restituisce un conto corrente a partire dal suo numero
         *
         * @param  numConto  Numero del conto corrente
         * @return           Il valore di contoCorrente
         */
        public ContoCorrente getContoCorrente(int numConto) {
                return arrayOfContoCorrente[numConto];
        }


        /**
         *  Restituisce un conto corrente a partire dal suo nomeCorrentista
         *
         * @param  nome                 Proprietario del conto corrente
         * @return                      Il valore di contoCorrente
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public static ContoCorrente getContoCorrente(String nome) throws MovimentoErrato {
                int i = 0;
                while ((i < numerazioneConti) && (arrayOfContoCorrente[i].nomeCorrentista != nome)) {
                        i++;
                }
                if (i < numerazioneConti) {
                        return arrayOfContoCorrente[i];
                } else {
                        throw new MovimentoErrato(nome + " non e' non presente");
                }
        }


        /**
         *  Stampa a video del conto corrente
         *
         * @return    Stampa a video del conto corrente
         */
        public String toString() {
                return
                                "\n____________________________________________________"
                                 + "\n Data                : " + data.getData()
                                 + "\n Nome del correntista: " + this.getNomeCorrentista()
                                 + "\n Numero del conto    : " + this.getNumeroConto()
                                 + "\n Interessi maturati  : " + this.getInteresseMaturato()
                                 + "\n Saldo               : " + this.getSaldo()
                                 + "\n____________________________________________________";
        }


        /**
         *  Stampa tutti i conti presenti nell'arrayOfContoCorrente
         */
        public static void stampaTuttiIConti() {
                int i;
                for (i = 0; i < numerazioneConti; i++) {
                        System.out.println(arrayOfContoCorrente[i]);
                }
        }


        /**
         *  Controlla che valore sia positivo, aggiorna interessseMaturato in base al
         *  saldo precedente ed effettua il deposito se valore e' negativo non effettua
         *  nessuna operazione ma viene sollevata un eccezione di tipo MovimentoErrato
         *
         * @param  valore               Somma di denaro da depositare
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public void deposita(int valore) throws MovimentoErrato {
                if (valore < 0) {
                        throw new MovimentoErrato("il valore immesso e' negativo");
                }
                calcoloInteresseMaturato();
                saldo += valore;
                totaleSoldiBanca += valore;
        }


        /**
         *  Depostito sul conto con nomeCorrentista = nome
         *
         * @param  valore               Somma di denaro da depositare
         * @param  nome                 Nome del correntista
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public static void deposita(int valore, String nome) throws MovimentoErrato {
                int i = 0;
                while ((i < numerazioneConti) && (arrayOfContoCorrente[i].nomeCorrentista != nome)) {
                        i++;
                }
                if (i < numerazioneConti) {
                        arrayOfContoCorrente[i].deposita(valore);
                } else {
                        throw new MovimentoErrato(nome + " non e' non presente");
                }
        }


        /**
         *  Depostito sul conto con nomeCorrentista = nome
         *
         * @param  valore               Somma di denaro da depositare
         * @param  numConto             Numero del Conto
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public static void deposita(int valore, int numConto) throws MovimentoErrato {
                if (numConto < numerazioneConti) {
                        arrayOfContoCorrente[numConto].deposita(valore);
                } else {
                        throw new MovimentoErrato(numConto + " non e' un numero di conto valido");
                }
        }


        /**
         *  Come deposita ma per il prelievo. Inoltre effettua il controllo se il saldo
         *  diventa negativo, che il passivo non superi il massimo scoperto ammesso e
         *  inoltre che la banca abbia abbastanza soldi in modo che la banca se il
         *  valore e' negativo viene sollevata un'eccezione di tipo MovimentoErrato
         *
         * @param  valore               Somma di denaro da prelevare
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public void preleva(int valore) throws MovimentoErrato {
                int saldoTemp = saldo - valore;
                if (valore < 0) {
                        throw new MovimentoErrato("il valore immesso e' negativo");
                }
                if (saldoTemp < 0) {
                        if ((-saldoTemp) < maxScopertoStandard) {
                                if (valore < totaleSoldiBanca) {
                                        saldo -= valore;
                                        totaleSoldiBanca -= valore;
                                } else {
                                        throw new MovimentoErrato("i soldi della banca sono finiti");
                                }
                        } else {
                                throw new MovimentoErrato("scoperto standard superato");
                        }
                } else {
                        saldo -= valore;
                        totaleSoldiBanca -= valore;
                }
        }


        /**
         *  Esegue un prelievo sul conto di nome
         *
         * @param  valore               Somma da prelevare
         * @param  nome                 Correntista
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public static void preleva(int valore, String nome) throws MovimentoErrato {
                int i = 0;
                while ((i < numerazioneConti) && (arrayOfContoCorrente[i].nomeCorrentista != nome)) {
                        i++;
                }
                if (i < numerazioneConti) {
                        arrayOfContoCorrente[i].preleva(valore);
                } else {
                        throw new MovimentoErrato(nome + " non e' non presente");
                }
        }


        /**
         *  Prelievo sul conto con nomeCorrentista = nome
         *
         * @param  valore               Somma di denaro da prelevare
         * @param  numConto             Numero del Conto
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public static void preleva(int valore, int numConto) throws MovimentoErrato {
                if (numConto < numerazioneConti) {
                        arrayOfContoCorrente[numConto].preleva(valore);
                } else {
                        throw new MovimentoErrato(numConto + " non e' un numero di conto valido");
                }
        }


        /**
         *  Permette di trasferire una somma di denaro da un conto ad un altro della
         *  stessa banca
         *
         * @param  valore               Somma di denaro da trasferire
         * @param  altroContoCorrente   Conto corrente destinatario del trasferimento
         * @exception  MovimentoErrato  Eccezione di tipo MovimentoErrato
         */
        public void trasferisci(int valore, ContoCorrente altroContoCorrente) throws MovimentoErrato {
                this.preleva(valore);
                altroContoCorrente.deposita(valore);
        }


        /**
         *  Calcola le competenze spettanti ad un conto corrente, interesse maturato
         *  meno spese di tenuta conto
         *
         * @return    Interessi maturati meno il forfait spese
         */
        public int calcoloCompetenze() {
                return interesseMaturato - forfaitSpese;
        }


        /**
         *  Addebita o accredita sul conto le competenze relative ad un periodo
         *  calcolate con calcoloCompetenze
         */
        public void calcoloSaldoFinale() {
                saldo += calcoloCompetenze();
                interesseMaturato = 0;
        }


        /**
         *  Calcola gli interessi maturati in data data
         */
        private void calcoloInteresseMaturato() {
                if (saldo > 0) {
                        interesseMaturato += (saldo * tassoStandard * data.diffData(giornoUltimoInteresse) / 36000);
                } else {
                        interesseMaturato += (saldo * tassoPassivoStandard * data.diffData(giornoUltimoInteresse) / 36000);
                }

                giornoUltimoInteresse.setData(data.getData());
        }


        /**
         *  Calcola il saldo finale su tutti i conti della banca
         */
        public static void saldoFinaleTotale() {
                int i;
                for (i = 0; i < numerazioneConti; i++) {
                        arrayOfContoCorrente[i].calcoloSaldoFinale();
                }
        }


        /**
         *  Calcola gli interessi su tutti i conti della banca
         */
        public static void interesseFinaleTotale() {
                int i;
                for (i = 0; i < numerazioneConti; i++) {
                        arrayOfContoCorrente[i].calcoloInteresseMaturato();
                }
        }


        /**
         *  Chiude tutti i conti memorizzati nell'arrayOfContoCorrente
         */
        public static void chiudiTuttiIConti() {
                int i;
                for (i = 0; i < numerazioneConti; i++) {
                        arrayOfContoCorrente[i] = null;
                }
                numerazioneConti = 0;
                totaleSoldiBanca = capitaleSocialeBanca;
        }


        /**
         *  Confronta oggetti di tipo ContoCorrente in base al loro saldo. Nota: non ho considerato
         *  il caso in cui il puntatore fosse nullo poiche' applico un selection sort da 0 a num conti:
         *  magari meno elegante che tuttavia non chiama il metodo compara sugli n-numConti "null"
         *
         * @param  ob                      Oggetto
         * @return                         1,-1,0 a seconda che un'oggetto sia &lt;, &gt; o = ad ob
         * @exception  ClassCastException  Eccezione di tipo ClassCast
         */
        public int compara(Comparabile ob) throws ClassCastException {
                ContoCorrente altroContoCorrente = (ContoCorrente) ob;
                if (this.getSaldo() < altroContoCorrente.getSaldo()) {
                        return -1;
                }
                if (this.getSaldo() > altroContoCorrente.getSaldo()) {
                        return 1;
                }
                return 0;
        }


        private static int numerazioneConti;
        //ultimo numero di conto attribuito
        private static int maxScopertoStandard = 100;
        //massimo saldo negativo standard (euro)
        private static int forfaitSpese = 1;
        //costo forfettario delle spese applicate ad un conto corrente
        private static int totaleSoldiBanca = capitaleSocialeBanca;
        //totale dei soldi in banca

        private static float tassoStandard = 5;
        //tasso annuale percentuale di interesse
        private static float tassoPassivoStandard = 10;
        //tasso annuale percentuale di interesse passivo

        private static String nomeBanca = "Banca Sella";
        //nome della banca

        private int saldo;
        //saldo del conto corrente
        private int numeroConto;
        //numero conto corrente
        private int interesseMaturato;

        private String nomeCorrentista;
        //nome del proprietario del conto

        private Data giornoUltimoInteresse;
        //giorno in cui e' stato attribuito ad un conto l'ultimo interesse

}