#!/bin/bash
# Last update: 16 May 2012
# by Emanuele Tomasi aka targzeta <targzeta@gmail.com>

# Copyright (C) 2010-2012 Emanuele Tomasi aka targzeta <targzeta@gmail.com>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA

#########################
# CONFIGURAZIONE UTENTE #

TMP_DIR=/tmp

# FINE CONFIGURAZIONE UTENTE #
##############################


###############################
# INIZIO FUNZIONI DI UTILITA' #
###############################
#
# Queste sono funzioni utili per tutte le modalita'.
# Sono scritte man mano che se ne ha bisogno

# Scarica l'URL trovato in ${actual_dir}/${UPDATE_FILE_URL} e lo salva,
# in $1 se viene fornito, altrimenti in ${actual_dir}/${UPDATE_FILE_FOR_DIFF}
function _scarica()
{
    local output_document="${actual_dir}"/${UPDATE_FILE_FOR_DIFF}
    [[ "$1" != "" ]] && output_document="$1"

    # Controllo il programma da usare
    local program='wget' # wget di default
    local protocols='i protocolli ftp/http(s)'
    if grep '^svn://' "${actual_dir}"/${UPDATE_FILE_URL} >& /dev/null || \
        [ -f "${actual_dir}"/${UPDATE_DIR}/svn ]
    then # svn
        program='svn'
        protocols='il protocollo svn'
    elif
        grep '^git://' "${actual_dir}"/${UPDATE_FILE_URL} >& /dev/null || \
            [ -f "${actual_dir}"/${UPDATE_DIR}/git ]
    then # git
        program='git'
        protocols='il protocollo git'
    fi

    if ! _check_for_program $program
    then
        if [ $flag_q -eq 0 ]
        then
            ERROR="   $program : comando non trovato. Ne ho bisogno per "\
"usare $protocols!"
        fi
        return 1
    fi

    case $program in
        'svn')
            local current_revision=''
            # Se la modalita' e' 'check', allora scarico il log dall'HEAD sino
            # alla revisione che ho nel file
            # ${actual_dir}/${UPDATE_FILE_FOR_DIFF}
            if [ -f "${actual_dir}"/${UPDATE_FILE_FOR_DIFF} \
                -a $MODALITA == 'check' ]
            then
                current_revision=$(sed -n '/\(.*|\)\(.*|\)\{2\}.*/{
                                   s/[^[:digit:]]*\([[:digit:]]*\).*/\1/;p;q}' \
                                       "${actual_dir}"/${UPDATE_FILE_FOR_DIFF})
                if [ 'x'$current_revision != 'x' ]
                then
                    current_revision=${current_revision}':'
                fi
            fi
            svn log -r ${current_revision}HEAD \
                $(<"${actual_dir}"/${UPDATE_FILE_URL}) > ${output_document}
            ;;
        'git')
            git ls-remote $(<"${actual_dir}"/${UPDATE_FILE_URL}) HEAD\
                > ${output_document}
            ;;
        'wget')
            local q_option=""

            if [ $flag_v -eq 0 ]
            then
                q_option="--quiet"
            fi

            wget --no-check-certificate --tries=1 --timeout=30 $q_option \
                --output-document=${output_document} \
                --input-file="${actual_dir}"/${UPDATE_FILE_URL}
            ;;
    esac

    if [ $? -ne 0 ]
    then
        if [ $flag_q -eq 0 -a $flag_e -eq 0 ]
        then
            ERROR='Errore durante il download!'
        fi
        return 1
    fi

    return 0
}

# Controlla l'esistenza di un programma nel $PATH
#
# PARAMETRI:
# $1: Programma da cercare nel $PATH
#
# RITORNA: 0 se il programma $1 e' trovato
#          1 altrimenti
function _check_for_program()
{
    which $1 >& /dev/null

    return $?
}

# Controlla l'esistenza dei programmi esterni
function _check_ext_program()
{
    local ext_prog=(cat diff tempfile)
    local prog
    local error=0

    for prog in ${ext_prog[@]}
    do
        if ! _check_for_program $prog
        then
            echo "$prog: comando non trovato!"
            error=1
        fi
    done

    (( $error == 1 )) && exit 1
}

# Esce facendo eliminando i file temporanei creati.
# Se il flag_k e' impostato a 1, i file temporanei non verranno
# eliminati.
#
# USATA dalla modalita' check
function _exit()
{
    if [ "x$1" == "x3" ]
    then
        cat <<EOF
Catturato il segnale SIGINT
Elimino i file temporanei ed esco!"
EOF
        flag_k=0
    fi

    if [ $flag_k -eq 1 ]
    then
        cat <<EOF
Il file $TMP_FILE non e' stato eliminato.
Il file $TMP_FILE_ORIG, non e' stato eliminato.
EOF
    else
        rm -f $TMP_FILE $TMP_FILE_ORIG
    fi

    rm $TMP_FILE_FILTER
    exit $1
}

# Controllo se la directory $actual_dir e' conforme, ovvero se ha la
# sottodirectory ${UPDATE_DIR}
function _exists_UPDATE_DIR()
{
    if [ -d "${actual_dir}"/${UPDATE_DIR} ]
    then
        return 0
    fi

    return 1
}

# Controllo se la directory $actual_dir ha il file
# ${UPDATE_DIR}/${UPDATE_FILE_URL}
function _exists_UPDATE_FILE_URL()
{
    if [ -f "${actual_dir}"/${UPDATE_FILE_URL} ]
    then
        return 0
    fi

    return 1
}

# Controllo se la directory $actual_dir contiene il file per la verifica
# ${UPDATE_DIR}/${UPDATE_FILE_FOR_DIFF}
function _exists_UPDATE_FILE_FOR_DIFF()
{
    if [ -f "${actual_dir}"/${UPDATE_FILE_FOR_DIFF} ]
    then
        return 0
    fi

    return 1
}

# Funzione usata per stampare a video. Se il flag globale '-c' vale 1, allora
# esegue una stampa colorata.
# La funzione esegue un 'echo -n', quindi non stampa l'ultimo '\n'.
#
# PARAMENTRI:
# $1: la stringa da stampare
# $2: l'eventuale colore con il quale si vuole stampare la stringa.
#     Puo' valere: 'blue', 'green', 'red' o 'yellow'
function _print()
{
    if [ "x$2" != 'x' -a $GLOB_FLAG_C -eq 0 ]
    then
        local color=''
        case $2 in
            'blue') color='36'
                ;;
            'green') color='32'
                ;;
            'red') color='31'
                ;;
            'yellow') color='33'
                ;;
        esac
        color='\033['${color}';1m'

        echo -ne "${color}$1\033[0m"
    else
        echo -ne "$1"
    fi
}

# Stampa colorata del nome della directory attuale ${actual_dir}
function _print_dirName()
{
    _print '# Directory: ' 'green'
    _print "${actual_dir}\n" 'yellow'
}

# Stampa colorata di cosa si sta scaricando e dove
function _print_scaricoPagina()
{
    _print '  Scarico il file:' 'blue'
    _print "\n\t${actual_dir}/${UPDATE_FILE_FOR_DIFF}\n" 'yellow'
    _print '  dal sito:' 'blue'
    _print "\n\t$(<${actual_dir}/${UPDATE_FILE_URL})\n" 'yellow'
}

# Applica i filtri, se ci sono, ai file $TMP_FILE e $TMP_FILE_ORIG
function _filtra()
{
    local sed_script="${actual_dir}"/${UPDATE_FILE_SED_SCRIPT}
    local compare_only_line="${actual_dir}"/${UPDATE_FILE_COMPARE_ONLY_LINE}
    local filter_line_number="${actual_dir}"/${UPDATE_FILE_FILTER_LINE_NUMBER}
    local filter_line_regex="${actual_dir}"/${UPDATE_FILE_FILTER_LINE_REGEX}
    local filter_word="${actual_dir}"/${UPDATE_FILE_FILTER_WORD}

    if [ -f "$sed_script" -o -f "$compare_only_line" -o \
        -f "$filter_line_number" -o -f "$filter_line_regex" -o \
        -f "$filter_word" ]
    then
        if ! _check_for_program sed
        then
            ERROR='sed: comando non trovato! Non posso usare i filtri!'
            return 1
        fi
    else
        return 0
    fi

    if [ -f "$sed_script" ]
    then
        sed "s/#DIR#/${actual_dir}/g" "$sed_script" > $TMP_FILE_FILTER
        # Applico lo script sed a tutti e due i file in maniera separata
        # il comando 'q' di sed lo termina senza fargli processare l'altro file
        sed -n -f $TMP_FILE_FILTER -i $TMP_FILE
        sed -n -f $TMP_FILE_FILTER -i $TMP_FILE_ORIG
    fi

    if [ -f "$compare_only_line" ]
    then
        # Assicuro che il file delle regole sia vuoto
        cat /dev/null > $TMP_FILE_FILTER

        ( IFS=$'\n\t'
            for regex in $(cat "$compare_only_line")
            do
                echo "/$regex/p;" | \
                    sed "s/#DIR#/${actual_dir}/g" >> $TMP_FILE_FILTER
            done
        )
        sed -n -f $TMP_FILE_FILTER -i $TMP_FILE $TMP_FILE_ORIG
    fi

    if [ -f "$filter_line_number" -o -f "$filter_line_regex" \
        -o -f "$filter_word" ]
    then

        cat /dev/null > $TMP_FILE_FILTER # Svuoto il file per le nuove regole

        if [ -f "$filter_line_number" ]
        then
            ( IFS=$'\n\t'
                for number in $(cat "$filter_line_number")
                do
                    echo "$number d;" >> $TMP_FILE_FILTER
                done
            )
        fi

        if [ -f "$filter_line_regex" ]
        then
            ( IFS=$'\n\t'
                for regex in $(cat "$filter_line_regex")
                do
                    echo "/$regex/d;" | \
                        sed "s/#DIR#/${actual_dir}/g" >> $TMP_FILE_FILTER
                done
            )
        fi

        if [ -f "$filter_word" ]
        then
            ( IFS=$'\n\t'
                for regex in $(cat "$filter_word")
                do
                    echo "s/$regex//g;" | \
                        sed "s/#DIR#/${actual_dir}/g" >> $TMP_FILE_FILTER
                done
            )
        fi
        sed -f $TMP_FILE_FILTER -i $TMP_FILE $TMP_FILE_ORIG
    fi

    return 0
}

# Stampa versione e copyright dello script
function _version()
{
    cat <<EOF
${SCRIPT_NAME} v${SCRIPT_VER}
Written by ${SCRIPT_AUTHOR_NAME} ${SCRIPT_AUTHOR_EMAIL}.

Copyright ${SCRIPT_COPYRIGHT}
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.
EOF
}

# La funzione help dello script
function _help()
{
    cat <<EOF
Uso: ${SCRIPT_NAME} [opzioni] MODALITA [mod_opzioni] arg1...
     ${SCRIPT_NAME} MODALITA -h|--help
     ${SCRIPT_NAME} -v|--version

Opzioni:
  -c    Non colora l'output

MODALITA e' una tra:
EOF
    for mod in ${ELENCO_MODALITA[*]}
    do
        cat <<EOF
        $mod
EOF
    done
    cat <<EOF

by $SCRIPT_AUTHOR_NAME $SCRIPT_AUTHOR_EMAIL
EOF
}

#############################
# FINE FUNZIONI DI UTILITA' #
#############################

############################################
# INIZIO FUNZIONI ASSOCIATE ALLE MODALITA' #
############################################
#
# Ogni modalita' implementa una serie di funzioni
# del tipo _nome-funzione_nome-modalita'.
# Lo script le invoca quando necessario. Queste sono:
#
# - _help_: stampa a video l'help per la modalita'
# _ _flag_: ritorna una stringa rappresentante le opzioni accettate
#           dalla modalita'. Vengono usate con getopts
# - _run_: che implementa la modalita' vera e propria
#
# Se si vuole aggiungere una nuova modalita', bisogna implementarle
# tutte, poiche' lo script le deve poter invocare.

####################
# FUNZIONI _help_ #
####################

function _help_check()
{
    cat <<EOF
Uso: ${SCRIPT_NAME} check [opzioni] dir1...

Controlla se la pagina e' aggiornata.

Opzioni:
-d      mostra l'output di 'diff' quando controlla l'aggiornamento
-e      non mostra gli errori di download
-f      mostra la pagina filtrata (non effettua controlli sull'aggiornamento)
-k      non elimina i file temporanei all'uscita
-n      mostra l'output di 'diff' stampando solo le nuove righe. Ignora '-d'
-o      produce output solo se la pagina e' stata aggiornata. Implica '-s'
-q      quiet. Implica '-s'
-s      non stampa errori sulle directory non conformi
-v      verbose
EOF
}

function _help_db()
{
    cat <<EOF
Uso: ${SCRIPT_NAME} db [opzioni] nome_db dir1...

Esporta/importa i dati relativi alle directory dir1...dirN
(l'URL impostato, filtri, etc...) nel/dal database nome_db.

Opzioni:
-e      esporta le informazioni nel database (formato tar.gz)
-i      importa (quindi imposta) le informazioni dal database
-s      mostra senza impostare le informazioni dal database
EOF
}

function _help_init()
{
    cat <<EOF
Uso: ${SCRIPT_NAME} init [opzioni] dir URL

Inizializza la directory dir tramite l'URL passatogli.

Opzioni:
-g      forza l'uso del protocollo git
-q      quiet
-s      forza l'uso del protocollo svn
-v      verbose

L'URL va quotato se contiene caratteri speciali per la shell,
come ad esempio il carattere '&'.
EOF
}

function _help_not_conform()
{
    cat <<EOF
Uso: ${SCRIPT_NAME} not_conform dir1...

Stampa il nome delle dir non conformi (non inizializzate).
EOF
}

function _help_update()
{
    cat <<EOF
Uso: ${SCRIPT_NAME} update [opzioni] dir1...

Aggiorna, riscaricando la pagina, la directory dir.

Opzioni:
-q      quiet
-v      verbose
EOF
}

function _help_url()
{
    cat <<EOF
Uso: ${SCRIPT_NAME} url dir1...

Stampa l'URL impostato per la directory dir.

Opzioni:
-q      quiet
EOF
}

########################
# FINE FUNZIONI _help_ #
########################

###################
# FUNZIONI _flag_ #
###################

function _flag_check()
{
    # -d: mostra l'output di diff.
    # -f: mostra la pagina filtrata (non effettua controlli sull'aggiornamento)
    # -k: non elimina i file temporanei che crea.
    # -n: mostra l'output di diff sopprimendo le righe eliminate. Ignora '-d'
    # -o: stampa solo i nomi delle directory da aggiornare.
    # -q: quiet
    # -s: non mostra errori o warning sulle directory non conformi,
    #     ovvero che non hanno la sottodirectory ${UPDATE_DIR}.
    # -v: verbose
    echo 'd e f k n o q s v'
}

function _flag_db()
{
    # -e: esporta le informazioni nel database
    # -i: importa le informazioni nel database
    # -s: mostra le informazioni nel database
    echo 'e i s'
}

function _flag_init()
{
    # -g: force git protocol
    # -q: quiet
    # -s: force svn protocol
    # -v: verbose
    echo 'g q s v'
}

function _flag_not_conform()
{
    echo ''
}

function _flag_update()
{
    # -q: quiet
    # -v: verbose
    echo 'q v'
}

function _flag_url()
{
    # -q: quiet
    echo 'q'
}

########################
# FINE FUNZIONI _flag_ #
########################

##################
# FUNZIONI _run_ #
##################

# Controlla aggiornamenti
function _run_check()
{
    while _get_next_dir
    do
        if [ \( $flag_s -eq 0 -a $flag_q -eq 0 -a $flag_o -eq 0 \) \
            -o $flag_v -eq 1 ]
        then
            _print_dirName
        fi

        if _exists_UPDATE_DIR && _exists_UPDATE_FILE_FOR_DIFF && \
            _exists_UPDATE_FILE_URL
        then
            if [ $flag_v -eq 1 ]
            then
                _print '  - Scarico la pagina internet:' 'blue'
                _print "\n\t$(<${actual_dir}/${UPDATE_FILE_URL})\n" 'yellow'
                _print '    nel file:' 'blue'
                _print "\n\t${TMP_FILE}\n\n" 'yellow'
            fi

            if [ $flag_f -eq 0 ]
            then
                if ! _scarica $TMP_FILE
                then
                    if [ $flag_q -eq 0 -a $flag_e -eq 0 ]
                    then
                        if [ \( $flag_s -eq 1 -o $flag_o -eq 1 \) \
                            -a $flag_v -eq 0 ]
                        then
                            _print_dirName
                        fi
                        _print "  ${ERROR}\n"
                        _print 'ERRORE\n\n' 'red'
                    fi
                    continue
                fi
            fi

            if [ $flag_v -eq 1 ]
            then
                _print '  - Copio il file:' 'blue'
                _print "\n\t${actual_dir}/${UPDATE_FILE_FOR_DIFF}\n" 'yellow'
                _print '    nel file temporaneo' 'blue'
                _print "\n\t${TMP_FILE_ORIG}\n\n" 'yellow'
            fi

            cp "${actual_dir}"/${UPDATE_FILE_FOR_DIFF} $TMP_FILE_ORIG

            if [ $flag_v -eq 1 ]
            then
                _print '  - Applico i filtri ai file:' 'blue'
                _print "\n\t${TMP_FILE_ORIG}\n\t${TMP_FILE}\n\n" 'yellow'
            fi

            # APPLICAZIONE DEI FILTRI
            if ! _filtra
            then
                if [ $flag_q -eq 0 ]
                then
                    if [ \( $flag_s -eq 1 -o $flag_o -eq 1 \) \
                        -a $flag_v -eq 0 ]
                    then
                        _print_dirName
                    fi
                    _print "  ${ERROR}\n"
                    _print 'ERRORE\n\n' 'red'
                fi
                continue
            fi
            # FINE APPLICAZIONE DEI FILTRI

            if [ $flag_f -eq 1 ]
            then
                cat $TMP_FILE_ORIG
                continue
            fi

            if [ $flag_v -eq 1 ]
            then
                _print '  - Confronto i file:' 'blue'
                _print "\n\t$TMP_FILE_ORIG\n" 'yellow'
                _print '    e' 'blue'
                _print "\n\t${TMP_FILE}\n" 'yellow'
            fi

            if ! diff $TMP_FILE_ORIG ${TMP_FILE} >& /dev/null
            then
                if [ $flag_q -eq 0 -a \( $flag_o -eq 1 \
                    -o $flag_s -eq 1 \) ]
                then
                    _print_dirName
                elif [ $flag_q -eq 1 -a $flag_o -eq 1 ]
                then
                    echo "$actual_dir"
                fi

                # Se e' settato il flag_d, mostro le differenze tra i file
                if [ $flag_d -eq 1 -o $flag_n -eq 1 ]
                then
                    if [ $flag_n -eq 1 ]
                    then # ... mostro solo le nuove righe
                        diff --new-line-format='> %L' --old-line-format="" \
                            --unchanged-line-format="" $TMP_FILE_ORIG \
                            ${TMP_FILE}
                    else
                        diff $TMP_FILE_ORIG ${TMP_FILE}
                    fi
                fi

                # Se e', stampo da aggiornare
                if [ $flag_q -eq 0 ]
                then
                    _print 'DA AGGIORNARE\n\n' 'yellow'
                fi
            else
                if [ $flag_q -eq 0 -a $flag_o -eq 0 -a $flag_s -eq 1 ]
                then
                    _print_dirName
                fi
                if [ $flag_q -eq 0 -a $flag_o -eq 0 ]
                then
                    _print 'OK\n\n' 'green'
                fi
            fi
        else
            if [ $flag_q -eq 0 -a $flag_s -eq 0 -a $flag_o -eq 0 ]
            then
                _print '  Attenzione: ' 'red'
                _print "${actual_dir} " 'yellow'
                _print 'non ha:' 'red'
                _print '\n\t* o la sottodirectory ' 'blue'
                _print "${UPDATE_DIR}" 'yellow'
                _print '\n\t* o il file ' 'blue'
                _print "${UPDATE_FILE_URL}" 'yellow'
                _print '\n\t* o il file ' 'blue'
                _print "${UPDATE_FILE_FOR_DIFF}\n\n" 'yellow'
            fi
        fi
    done
}

# Esporta/Importa le informazioni in un database in formato tar.gz
function _run_db()
{
    if ! _check_for_program tar
    then
        echo "tar: comando non trovato! Non posso usare la modalita' database!"
        exit 2
    fi
    if ! _check_for_program gzip
    then
        echo "gzip: comando non trovato! Non posso usare la modalita' database!"
        exit 2
    fi

    local nome_db=${ARGV[0]}

    if [ $flag_e -eq 1 -a $flag_i -eq 1 ]
    then
        echo 'Errore: le opzioni "-e" e "-i" sono mutualmente esclusive.'
        exit 2
    fi

    if [ $flag_e -eq 1 ]
    then
        nome_db=${nome_db%.tar.gz}.tar

        while _get_next_dir
        do
            if _exists_UPDATE_FILE_URL
            then
                tar --numeric-owner --ignore-failed-read -rf $nome_db \
                    "$actual_dir"/${UPDATE_FILE_URL} \
                    "$actual_dir"/${UPDATE_FILE_FOR_DIFF} \
                    "$actual_dir"/${UPDATE_FILE_COMPARE_ONLY_LINE} \
                    "$actual_dir"/${UPDATE_FILE_FILTER_WORD} \
                    "$actual_dir"/${UPDATE_FILE_FILTER_LINE_REGEX} \
                    "$actual_dir"/${UPDATE_FILE_FILTER_LINE_NUMBER} 2>/dev/null
            fi
        done

        if [ -f $nome_db ]
        then
            gzip $nome_db
        fi

        return
    fi

    echo -e 'Errore: manca una tra le opzioni "-e" e "-i",'\
         "\n'$SCRIPT_NAME db -h'"' per maggiori informazioni'
}

# Richiesta di inizializzazione della directory
function _run_init()
{
    flag_e=0 # Usato dalla funzione '_scarica()' in caso di errore

    # Controllo che siano stati passati correttamente i parametri
    if [ $ARGC -lt 2 ]
    then
        if [ $flag_q -eq 0 ]
        then
            echo "Errore: manca un parametro, '$SCRIPT_NAME init -h' per" \
                " maggiori informazioni"
        fi
        exit 2
    elif [ $ARGC -gt 2 ]
    then
        if [ $flag_q -eq 0 ]
        then
            echo "Errore: troppi parametri, '$SCRIPT_NAME init -h' per" \
                " maggiori informazioni"
        fi
        exit 2
    fi

    # Setto la variabile ${actual_dir}
    _get_next_dir

    # Controllo che ${actual_dir} sia effettivamente una directory
    if [ ! -d "${actual_dir}" ]
    then
        if [ $flag_q -eq 0 ]
        then
            echo "Errore: ${actual_dir} non e' una directory"
        fi
        exit 2
    fi

    if [ $flag_q -eq 0 ]
    then
        _print_dirName
    fi

    mkdir -p "${actual_dir}"/${UPDATE_DIR}
    echo "${ARGV[1]}" > "${actual_dir}"/${UPDATE_FILE_URL}

    if [ $flag_v -eq 1 ]
    then
        _print_scaricoPagina
    fi

    if [ $flag_g -eq 1 ]
    then
        touch "${actual_dir}"/${UPDATE_DIR}/git
    fi

    if [ $flag_s -eq 1 ]
    then
        touch "${actual_dir}"/${UPDATE_DIR}/svn
    fi

    if ! _scarica
    then
        if [ $flag_q -eq 0 ]
        then
            _print "  ${ERROR}\n"
            _print 'Inizializzazione fallita!!!\n' 'red'
            rm -rf "${actual_dir}"/${UPDATE_DIR}
        fi
        exit 2
    elif [ $flag_q -eq 0 ]
    then
        _print 'INIZIALIZZATA\n' 'green'
    fi
}

# Richiesta per la stampa delle directory non conformi
function _run_not_conform()
{
    while _get_next_dir
    do
        if ! _exists_UPDATE_DIR
        then
            echo "$actual_dir"
        fi
    done
}


# Aggiornamento della pagina ${UPDATE_DIR}/${UPDATE_FILE_URL}
function _run_update()
{
    flag_e=0 # Usato dalla funzione '_scarica()' in caso di errore

    while _get_next_dir
    do
        if _exists_UPDATE_DIR
        then
            if [ $flag_q -eq 0 ]
            then
                _print_dirName
            fi

            if [ $flag_v -eq 1 ]
            then
                _print_scaricoPagina
            fi

            if _scarica
            then
                if [ $flag_v -eq 1 ]
                then
                    _print "  ${actual_dir} " 'yellow'
                    _print "si presume essere aggiornato all'ultima release." \
                        "Vedere il sito:" 'green'
                    _print "\n\t$(<${actual_dir}/${UPDATE_FILE_URL})\n" 'yellow'
                    _print '  per maggiori info\n\n' 'green'
                fi
                if [ $flag_q -eq 0 ]
                then
                    _print 'AGGIORNATA\n' 'green'
                fi
            else
                if [ $flag_q -eq 0 ]
                then
                    _print "  ${ERROR}\n"
                    _print 'ERRORE\n' 'red'
                fi
            fi

            if [ $flag_q -eq 0 ]
            then
                echo
            fi
        fi
    done
}

# Stampa l'URL impostata nel file ${UPDATE_DIR}/${UPDATE_FILE_URL}
function _run_url()
{
    while _get_next_dir
    do
        if _exists_UPDATE_DIR && _exists_UPDATE_FILE_URL
        then
            if [ $flag_q -eq 0 ]
            then
                _print_dirName
            fi

            cat "${actual_dir}"/${UPDATE_FILE_URL}

            if [ $flag_q -eq 0 ]
            then
                echo
            fi
        fi
    done
}

#######################
# FINE FUNZIONI _run_ #
#######################

##########################################
# FINE FUNZIONI ASSOCIATE ALLE MODALITA' #
##########################################


#######################
# INIZIO DELLO SCRIPT #
#######################
# Controllo che tutti i programmi esterni richiesti siano installati nel sistema
_check_ext_program
trap "_exit 3" SIGINT

##########################
# IMPOSTAZIONI VARIABILI #

SCRIPT_NAME=${0#*/}
SCRIPT_VER='1.11'
SCRIPT_AUTHOR_NAME='Emanuele Tomasi aka targzeta'
SCRIPT_AUTHOR_EMAIL='<targzeta@gmail.com>'
SCRIPT_COPYRIGHT='2008-2011 Emanuele Tomasi aka targzeta'
UPDATE_DIR='.check_for_updates'
UPDATE_FILE_URL="${UPDATE_DIR}/url"
UPDATE_FILE_FOR_DIFF="${UPDATE_DIR}/page"
ERROR=''

# FILTRI
# Contiene uno script sed
UPDATE_FILE_SED_SCRIPT=${UPDATE_DIR}/sed_script

# Contiene regex, una per riga, confronta solo le righe che contengono quella
# regex
UPDATE_FILE_COMPARE_ONLY_LINE=${UPDATE_DIR}/compare_only_line

# Contiene un numero, uno per riga, sopprime la riga corrispondente al numero
UPDATE_FILE_FILTER_LINE_NUMBER=${UPDATE_DIR}/filter_line_number

# Contiene regex, una per riga, sopprime le righe in cui compare
UPDATE_FILE_FILTER_LINE_REGEX=${UPDATE_DIR}/filter_line_regex

# Contiene regex, una per riga, sopprime la regex dalla riga in cui compare
UPDATE_FILE_FILTER_WORD=${UPDATE_DIR}/filter_word

# FINE IMPOSTAZIONI VARIABILI #
###############################

# FLAG_GLOBALI #
################
GLOB_FLAG_C=0     # Se vale 1, allora colora l'output

# FINE FLAG_GLOBALI #
#####################


#############################
# CONTROLLO QUALE MODALITA' #
ELENCO_MODALITA=(
    'check'       # Controlla aggiornamenti

    'db'          # Esporta/Importa informazioni in un database

    'init'        # Inizializza la directory $1.
                  # - Crea la sottodirectory ${1}/${UPDATE_DIR}
                  # - Inserisce il link $2 nel file ${1}/${UPDATE_FILE_URL}
                  # - Scarica il link $2 nel file ${1}/${UPDATE_FILE_FOR_DIFF}

    'not_conform' # Stampa solo i nomi delle directory non conformi,
                  # ovvero che non hanno la sottodirectory ${UPDATE_DIR}

    'update'      # Aggiorna la pagina ${1}/${UPDATE_FILE_FOR_DIFF}
                  # ora il programma si suppone aggiornato

    'url'         # Mostra l'URL impostato per il programma
)

if [[ $1 == '-c' ]]
then
    GLOB_FLAG_C=1
    shift
fi

if [[ $1 == "" ]]
then
    cat <<EOF
Errore: manca la modalita' di esecuzione

      ${SCRIPT_NAME} --help

per altre informazioni.
EOF
    exit 1
elif [[ $1 == '--help' || $1 == '-h' ]]
then
    _help
    exit 0
elif [[ $1 == '--version' || $1 == '-v' ]]
then
    _version
    exit 0
else
    MODALITA=""
    for mod in ${ELENCO_MODALITA[*]}
    do
        if [[ $1 == $mod ]]
        then
            MODALITA=$1
            break
        fi
    done

    if [[ $MODALITA == "" ]]
    then
        cat <<EOF
Errore: $1 non e' una modalita' consentita

      ${SCRIPT_NAME} --help

per altre informazioni.
EOF
        exit 1
    fi
fi

shift

# FINE CONTROLLO MODALITA' #
############################

######################
# CONTROLLO DEI FLAG #

# Controllo se e' stato invocato l'help per la modalita'
if [[ $1 == '--help' || $1 == -h ]]
then
    _help_${MODALITA}
    exit 0
fi

FLAGS=":" # I flag accettati dalla modalita'
          # Vengono passati a getopts.
          # Inizializzata a ':' in modo da sopprimere l'output di getopts

# Imposto tutti i flag per la modalilta' a 0
for OPT in $(_flag_${MODALITA})
do
    eval flag_${OPT}=0
    FLAGS=${FLAGS}${OPT}
done

while getopts $FLAGS OPT
do
    if [[  $OPT == '?' ]]
    then
        echo -e "${SCRIPT_NAME}: opzione illegale per la modalita' -- $OPTARG\n"
        _help_${MODALITA}
        exit 1
    fi
    eval flag_${OPT}=1 # Il flag trovato viene impostato ad 1
done

# Mi sposto al primo argomento che non e' un opzione
while (( $OPTIND != 1 ))
do
    shift
    let OPTIND--
done

# FINE CONTROLLO FLAG #
#######################

################################################################################
#                     FUNZIONE _get_next_dir()                                 #
################################################################################
# Ogni volta che viene invocata, imposta $actual_dir come ${ARGV[$CONT_ARGV]}  #
# icrementando $CONT_ARGV.                                                     #
# In pratica ritorna ad uno ad uno i valori della variabile $ARGV.             #
#                                                                              #
# $ARGV contiene tutti i restanti parametri posizionali                        #
# $ARGC contiene il numero di argomenti di ARGV                                #
# $CONT_ARGV dovrebbe essere modificata solo da questa funzione gli serve per  #
#            sapere sino a quale argomento e' arrivata.                        #
#                                                                              #
# RITORNA:                                                                     #
#   0 se ${ARGV[$CONT_ARGV]} != "" ed e' una directory. In questo caso,        #
#        $actual_dir contiene ${ARGV[$CONT_ARGV]}                              #
#                                                                              #
#   1 se ${ARGV[$CONT_ARGV]} == "". $actual_dir non dovrebbe essere considerato#
################################################################################

ARGV=("$@")
ARGC=${#ARGV[*]}
CONT_ARGV=0

function _get_next_dir()
{
    while (( $CONT_ARGV < $ARGC ))
    do
        if [ -d "${ARGV[$CONT_ARGV]}" ]
        then
            actual_dir="${ARGV[$CONT_ARGV]%/}"
            let CONT_ARGV++
            return 0
        fi
        let CONT_ARGV++
    done

    return 1
}
################################################################################
# FINE FUNZIONE _get_next_dir                                                  #
################################################################################

############################
# GESTIONE DELLA MODALITA' #

# La modalita' 'check' prevede l'esecuzione di operazioni, prima
# e dopo la sua invocazione
if [[ $MODALITA == 'check' ]]
then
    TMP_FILE=$(tempfile -p check -d $TMP_DIR)
    TMP_FILE_ORIG=$(tempfile -p check -d $TMP_DIR)
    TMP_FILE_FILTER=$(tempfile -p check -d $TMP_DIR)

    _run_${MODALITA}
    _exit
else # per tutte le altre modalita' basta invocare la funzione associata
    _run_${MODALITA}
fi

# FINE GESTIONE DELLA MODALITA' #
#################################
