#!/bin/bash -u
cd `dirname $0`
# ***********************************************
#
# dumpDB v0.1.1 (WIP)
# by LV loicverstaevel.com
#
# DumpDB is a bash dump&deploy script meant to take the tedium out of
# synchronizing different environment versions of a Wordpress site.
# It allows working in a local environment to rapidly "push" or "pull"
# changes to the staging/production server with a single command.
#
# ***********************************************

version=0.1.1
config_file=dumpdb-config
temp_file=dumpdb-temp

# ========================================
#  GLOBAL VARIABLES
# ========================================

# message colors
red=$(tput setaf 1 || tput AF 1)
green=$(tput setaf 2 || tput AF 2)
yellow=$(tput setaf 3 || tput AF 3)
blue=$(tput setaf 4 || tput AF 4)
magenta=$(tput setaf 5 || tput AF 5)
cyan=$(tput setaf 6 || tput AF 6)
reset=$(tput sgr0)
bold=$(tput bold)

# Date placeholders (for naming the SQL dump files)
today=$(date +"%y%m%d")
now=$(date +"%y%m%d-%H%M")

dumpdb_path="https://bitbucket.org/rnyrfn/dumpdb/raw/master/private/dumpdb"

# initialize variable. Used because we need to test the SSH connection only once.
checked=

msgSuccess='Success:'
msgError='Error:'

# ========================================
#  INIT
# ========================================

if [[ -f $config_file ]]
then
    #source the config file
    . $config_file
else
    echo "${red}$msgError$reset Could not locate $config_file."
    exit 1
fi

if [[ -f $temp_file ]]
then
    #source the temp file. The temp file is used once per "session". It serves to avoid prompting the user for questions they've already answered. It is created during the first prompt, then deleted after the search and replace.
    . $temp_file
fi

l_root="$(dirname "${PWD}")"

# $l_site_dir is the absolute path to your local site. This is automatically
# deduced based on the directory into which you moved DumpDB.
l_site_dir="$(dirname "${PWD}")"/$l_web_dir

# $l_web_dir is the name of your site's root directory (same as $l_site_dir,
# but with the preceding directory path stripped off).
l_web_dir="${l_site_dir##*/}"

# Arbitrary name for the dump files which will be transferred across servers.
l_db_name_latest=latest-local.sql
r_db_name_latest=latest-remote.sql

# This is the arbitrary name and path to your database backups folder.
l_db_dir=database/local
r_db_dir=database/production
r_db_dir_alt=database/staging

# Arbitrary name for the dump files which will be transferred across servers.
l_db_name=latest-local.sql
r_db_name_latest=latest-remote.sql

# The --port flag has to be uppercase for `scp`, lowercase for `ssh`. sigh.
ssh_port_define="-p $r_port "
scp_port_define="-P $r_port "

ssh_port=${r_port:+$ssh_port_define}
scp_port=${r_port:+$scp_port_define}


# ====================================
#  FUNCTIONS
# ====================================

# ---------------------------------------------------------
# help ()
# Print list of valid DumpDB commands.
# ---------------------------------------------------------
help () {

cat <<EOF
    ${blue}
    DumpDB List of Commands$reset
    • auto_update
    • test_ssh
    • get_local_db_details
    • backup_local_db
    • search_replace_local
    • do_remote_replace_db
    • upload_local_db
    • upload_script
    • say_goodbye

EOF

    exit 0
}

# ---------------------------------------------------------
# auto_update ()
# Check if the github hosted version of DumpDB is newer (different) from this
# version. If so, it will download the newer one and ask the user to relaunch.
# This function is enabled by default, but can be disabled by changing
# auto_update=false in DumpDB-config.
# ---------------------------------------------------------
auto_update () {

    if command -v curl >/dev/null 2>&1
    then
        curl_exists=true
    else
        if command -v wget >/dev/null 2>&1
        then
            wget_exists=true
        else
            echo >&2 "${red}$msgError$reset Could not run auto-update, your system has neither curl nor wget installed."
        fi
    fi

    echo "${blue}Checking for updates to DumpDB...$reset"

    #run a diff command to test the difference between the bitbucket DumpDB versus
    #the local one. We use basename rather than hard-coding the filename,
    #DumpDB, in case the user is using a different name, eg. DumpDB-live,
    #myDumpDB, etc...
    needs_updating=$(diff <(curl -s $dumpdb_path) ./$(basename $0))

    if [[ "$needs_updating" ]]
    then
        echo "There is a newer version of DumpDB available. Would you like to update?"
        OPTIONS="Yes No"
        select opt in $OPTIONS
        do
            echo
            case $opt in
                "Yes")
                    echo "Downloading newer version of DumpDB..."
                    #backup the old DumpDB, just in case
                    #cp $(basename $0) $(basename $0).bak

                    if [[ ${curl_exists-} ]]
                    then
                        #-s is silent mode, -o specifies a filename of your choosing
                        curl -s $dumpdb_path -o $(basename $0)
                    elif [[ ${wget_exists-} ]]
                    then
                        #-q is quiet mode, -O specifies the filename
                        wget -q --no-check-certificate -O $(basename $0) $dumpdb_path
                    fi

                    echo "${green}${msgSuccess}$reset Update complete. Please relaunch DumpDB."
                    echo
                    break
                    ;;
                "No")
                    echo "You chose not to update. To disable auto-updating, set auto_update=false in dumpdb-config."
                    echo
                    break
                    ;;
                *) echo "Invalid option, please type y or n.";;
            esac
        done
    else
        echo "${blue}Your version of DumpDB is up-to-date.$reset"
    fi

    cat <<EOT > $temp_file
auto_update_checked=true
EOT

}

# ---------------------------------------------------------
# test_ssh ()
# Check if the SSH connection is working.
# ---------------------------------------------------------
test_ssh () {
    echo "${blue}Checking if SSH connection is working...$reset"
    echo
    echo "ssh -q $ssh_port$r_user@$r_host exit"

    #first test method
    ssh -q $ssh_port$r_user@$r_host exit

    if [ $? == 0 ] # check if the SSH connection is working
    then
        echo
        echo "${green}${msgSuccess}$reset SSH connection is working."
        echo
    else
        echo "Test failed. Trying again..."
        echo "ssh -q -o BatchMode=yes -o ConnectTimeout=5 ${ssh_port}$r_user@$r_host echo ok 2>&1"
        return_code=$(ssh -q -o BatchMode=yes -o ConnectTimeout=5 ${ssh_port}$r_user@$r_host echo ok 2>&1)
        #echo return code is $return_code

        #second test method, in case first one fails. For some reason a
        #functioning Arvixe connection returns an error code of 1 for the above
        #test, even if it's working
        if [[ $return_code == 'ok' ]] # check if the SSH connection is working
        then
            echo
            echo "${green}${msgSuccess}$reset SSH connection is working."
        else
            echo "$red$msgError$reset could not connect to host. Confirm that the SSH connection, $yellow$r_user$reset@$yellow$r_host$reset, is working."
        exit 1
        fi
    fi

    echo
}

# ---------------------------------------------------------
# get_local_db_details ()
# Extract the local database details from config file
# ---------------------------------------------------------
get_local_db_details () {
    echo "${blue}Fetching local database login details...$reset"

    # If private/config.php is not found then search
    # for the local DB info in wp-config.php
    if [[ -f config.php ]]
    then
        local_config_file=config.php
    else
        cd ../$l_web_dir

	    if [[ -f wp-config.php ]]
	    then
	        local_config_file=wp-config.php
	    else
	        echo "${red}$msgError$reset Could not locate config.php or wp-config.php"
	        exit 1
	    fi
    fi

    #This tells us how many times DB_USER has been set in the config file.
    number_of_environments=$(grep -c "'DB_USER', '[^']*'.*" $local_config_file)

    #grep returns "filename.php:3" if there's 3 hits. We want to strip away
    #everything up to the colon and just save the number
    number_of_environments=$(echo $number_of_environments | sed -e 's/.*://')

    #This detects if there's anything weird going on in the config file. If there
    #are more than one instances of DB_USER, that's weird.
    if [[ $number_of_environments < 2 ]]
    then
        return_local_standard
    elif [[ ${local_chosen-} != "true" ]]
    then
        return_local_nonstandard
    fi

    #Local paths
    l_db_name_now=$now-$l_db_name.sql
    l_db_path_now=$l_root/$l_db_dir/$l_db_name_now
}

# ---------------------------------------------------------
# return_local_standard ()
# A standard wp-config file has one set of environment variables declared. A
# non-standard has more than one. This function fetches the local database
# login details from a normal config file.
# ---------------------------------------------------------
return_local_standard () {

    #grep the config file for the MySQL login details
    l_db_name=$(sed -n "s/.*DB_NAME', '\([^']*\)'.*/\1/p" $local_config_file)
    l_db_user=$(sed -n "s/.*DB_USER', '\([^']*\)'.*/\1/p" $local_config_file)
    l_db_pass=$(sed -n "s/.*DB_PASSWORD', '\([^']*\)'.*/\1/p" $local_config_file)
    l_db_host=$(sed -n "s/.*DB_HOST', '\([^']*\)'.*/\1/p" $local_config_file)
}

# ---------------------------------------------------------
# return_local_nonstandard ()
# If multiple environments are specified in the same wp-config file, this
# function extracts the set of parameters it feels correspond to the local
# environment.
# ---------------------------------------------------------
return_local_nonstandard () {

    #grep the config file for all relevants hits, and saves them to their
    #respective category. All hits are delimited by spaces.
    all_db_name=$(sed -n "s/.*DB_NAME', '\([^']*\)'.*/\1/p" $local_config_file)
    all_db_user=$(sed -n "s/.*DB_USER', '\([^']*\)'.*/\1/p" $local_config_file)
    all_db_pass=$(sed -n "s/.*DB_PASSWORD', '\([^']*\)'.*/\1/p" $local_config_file)
    all_db_host=$(sed -n "s/.*DB_HOST', '\([^']*\)'.*/\1/p" $local_config_file)

    #This splits the previous values into arrays
    name_array=(${all_db_name// / })
    user_array=(${all_db_user// / })
    pass_array=(${all_db_pass// / })
    host_array=(${all_db_host// / })

    #Checking if DB_HOST was empty for any environments. This means it
    #wasn't hard-coded, and is using _ENV{DATABASE-SERVER} instead. Rather than
    #leave it blank, we want to assign it the value "unset"
    for (( i = 0 ; i < $number_of_environments ; i++ ))
    do

        #when -u is set for bash, one valid way to test the existence of a
        #variable, without getting an "unbound variable" error, is to set
        #default value to empty like this ${variable-}

        if [ -z "${host_array[$i]-}" ]
        then
            db_host=${DATABASE_SERVER:=unset}
            [[ $db_host ]] && host_array[$i]=$db_host
        fi

    done

    #env_array will be the final list of remote environments
    declare -a env_array=()

    #for each environment detected, let's test if it's local by checking if
    #anything is set to "root". We're assuming no-one's using "root" as their remote
    #login or password.
    for (( i = 0 ; i < $number_of_environments ; i++ ))
    do

        #add the current environment to the array
        env_array[$i]=$i

        #this will create array set_0, set_1, set_2 etc... which will reorganize all the grepped values into their respective environment
        eval "declare -a "set_${i}"=( ${name_array[$i]} ${user_array[$i]} ${pass_array[$i]} ${host_array[$i]:-} )"

        #because we're using arrays we have to use some indirect referencing trickery to iterate properly
        _set="set_$i"[@]
        set=( "${!_set}" )

        #k is a separate counter to iterate through the four environment variables
        k=0
        for j in "${set[@]}"
        do
            #out of all the environments, let's set the default to 0
            local_env=0
            if [ $j == "root" ]
            then
                #hopefully only one of the environments is using root as a login
                local_env=$i
            fi

            #remove the local environment from the final array, so the user doesn't
            #have to consider it.
            unset env_array[$local_env]

        done

    done

    #Now that we've figured out which environment is the local one, let's set all
    #the variables to use for the local mysql operations
    local_env_ref_0=set_$local_env[0]
    local_env_ref_1=set_$local_env[1]
    local_env_ref_2=set_$local_env[2]
    local_env_ref_3=set_$local_env[3]

    l_db_name=${!local_env_ref_0}
    l_db_user=${!local_env_ref_1}
    l_db_pass=${!local_env_ref_2}
    l_db_host=${!local_env_ref_3}

    local_chosen=true

    echo "============================================================"
    echo " LOCAL DATABASE DETAILS"
    echo "============================================================"
    echo

    echo "local DB_NAME is:       $l_db_name"
    echo "local DB_USER is:       $l_db_user"
    echo "local DB_PASSWORD is:   $l_db_pass"
    echo "local DB_HOST is:       $l_db_host"

}

# ---------------------------------------------------------
# backup_local_db ()
# Back up the local database.
# ---------------------------------------------------------
backup_local_db () {

    get_local_db_details

    echo
    echo "${blue}Backing up the local database...$reset"

    cd "$l_root"

    if [ ! -d $l_db_dir ]
    then
        mkdir $l_db_dir;
    fi

    cd $l_db_dir

    echo "${l_mysqldump:-mysqldump} -u$l_db_user -p$l_db_pass -h $l_db_host $l_db_name | bzip2 -c > ${l_db_name_now}.bz2"
    echo

    set -o pipefail

    "${l_mysqldump:-mysqldump}" "-u$l_db_user" "-p$l_db_pass" -h "$l_db_host" "$l_db_name" | bzip2 -c > "${l_db_name_now}.bz2"

    if [[ $? -eq 0 ]]
    then
        echo "$green$msgSuccess$reset Local database backed up to: $(pwd)/${l_db_name_now}.bz2"
    else
        echo "$red$msgError$reset Database was not backed up. There is a problem with your local MySQL details. Exiting."
        exit 1
    fi

    #echo ${yellow}cp ${l_db_name_now}.bz2 ${l_db_name_latest}.bz2$reset
    cp ${l_db_name_now}.bz2 ${l_db_name_latest}.bz2

}

# ---------------------------------------------------------
# search_replace_local ()
# Duplicate databe for every environments with right URLs.
# ---------------------------------------------------------
search_replace_local () {

    echo "${blue}Search and replace baseroot URL...$reset"

    cd "$l_root/database"

    if [[ "${r_web_addr_alt}" ]]
    then

	    if [ ! -d "staging" ]
	    then
	        mkdir "staging";
	    fi

		cd "staging"

		"${l_mysqldump:-mysqldump}" "-u$l_db_user" "-p$l_db_pass" -h "$l_db_host" "$l_db_name" > "${l_db_name_now}"
    	cat "$l_db_name_now" | sed "s/$l_web_addr/$r_web_addr_alt/g" | bzip2 -c > "${l_db_name_now}.bz2"
    	rm "${l_db_name_now}"

	    if [[ $? -eq 0 ]]
	    then
	        echo "$green$msgSuccess$reset Database duplicated to: $(pwd)/${l_db_name_now}.bz2"
	    else
	        echo "$red$msgError$reset Database was not duplicated. Exiting."
	        exit 1
	    fi

		cp ${l_db_name_now}.bz2 ${r_db_name_latest}.bz2

    fi

    cd "$l_root/database"

    if [ ! -d "production" ]
    then
        mkdir "production";
    fi

    cd "production"

	"${l_mysqldump:-mysqldump}" "-u$l_db_user" "-p$l_db_pass" -h "$l_db_host" "$l_db_name" > "${l_db_name_now}"
	cat "$l_db_name_now" | sed "s/$l_web_addr/$r_web_addr/g" | bzip2 -c > "${l_db_name_now}.bz2"
	rm "${l_db_name_now}"

    if [[ $? -eq 0 ]]
    then
        echo "$green$msgSuccess$reset Database duplicated to: $(pwd)/${l_db_name_now}.bz2"
    else
        echo "$red$msgError$reset Database was not duplicated. Exiting."
        exit 1
    fi

	cp ${l_db_name_now}.bz2 ${r_db_name_latest}.bz2

}

# ---------------------------------------------------------
# get_remote_db_details ()
# Extract the remote database details from wp-config.php
# ---------------------------------------------------------
get_remote_db_details () {

    echo "${blue}Fetching remote database login details...$reset"

    # If private/config.php is not found then search
    # for the local DB info in wp-config.php
    if [[ -f config.php ]]
    then
        local_config_file=config.php
    else
        cd ../$l_web_dir

	    if [[ -f wp-config.php ]]
	    then
	        local_config_file=wp-config.php
	    else
	        echo "${red}$msgError$reset Could not locate config.php or wp-config.php"
	        exit 1
	    fi
    fi

    #This tells us how many times DB_USER has been set in the config file.
    number_of_environments=$(grep -c "'DB_USER', '[^']*'.*" $local_config_file)

    #grep returns "filename.php:4" if there's 4 hits. We want to strip away
    #everything up to the colon and just save the number
    number_of_environments=$(echo $number_of_environments | sed 's/.*://')
    #echo no. of envs = $number_of_environments
    echo

    #This detects if there's anything weird going on in the config file. If there
    #are more than one instances of DB_USER, that's weird.
    if [[ $number_of_environments > 1 ]]
    then
        return_remote_nonstandard
    else
        return_remote_standard
    fi

}

# ---------------------------------------------------------
# return_remote_standard ()
# Get the remote database login details. Used if the config file has only one
# environment specified.
# ---------------------------------------------------------
return_remote_standard () {

    #grep the config file for the MySQL login details
    r_db_name=$(sed -n "s/.*DB_NAME', '\([^']*\)'.*/\1/p" $local_config_file)
    r_db_user=$(sed -n "s/.*DB_USER', '\([^']*\)'.*/\1/p" $local_config_file)
    r_db_pass=$(sed -n "s/.*DB_PASSWORD', '\([^']*\)'.*/\1/p" $local_config_file)
    r_db_host=$(sed -n "s/.*DB_HOST', '\([^']*\)'.*/\1/p" $local_config_file)

}

# ---------------------------------------------------------
# return_remote_nonstandard ()
# Some wp-config files have multiple sets of configuration variables, one
# for each environment (local, dev, production/live etc...).
# This function collects all the login info it can find, organizes it into
# sets, auto-detects which one is the local set, and if necessary asks the user
# which remote server they want to sync with.
# ---------------------------------------------------------
return_remote_nonstandard () {

    echo "DumpDB has detected multiple remote environment configurations in your config file."

    #grep the config file for all relevants hits, and saves them to their
    #respective category. All hits are delimited by spaces.
    all_db_name=$(sed -n "s/.*DB_NAME', '\([^']*\)'.*/\1/p" $local_config_file)
    all_db_user=$(sed -n "s/.*DB_USER', '\([^']*\)'.*/\1/p" $local_config_file)
    all_db_pass=$(sed -n "s/.*DB_PASSWORD', '\([^']*\)'.*/\1/p" $local_config_file)
    all_db_host=$(sed -n "s/.*DB_HOST', '\([^']*\)'.*/\1/p" $local_config_file)

    #This splits the previous values into arrays
    name_array=(${all_db_name// / })
    user_array=(${all_db_user// / })
    pass_array=(${all_db_pass// / })
    host_array=(${all_db_host// / })

    #Checking if DB_HOST was empty for any environments. This means it
    #wasn't hard-coded, and is using _ENV{DATABASE-SERVER} instead. Rather than
    #leave it blank, we want to assign it the value "unset"
    for (( i = 0 ; i < $number_of_environments ; i++ ))
    do

        #when -u is set for bash, one valid way to test the existence of a
        #variable, without getting an "unbound variable" error, is to set #default value to empty like this ${variable-e

        if [ -z "${host_array[$i]-}" ]
        then
            db_host=${DATABASE_SERVER:=unset}

            if [[ $db_host ]]
            then
                host_array[$i]=$db_host
            fi
        fi

    done

    #env_array will be the final list of remote environments
    declare -a env_array=()

    #for each environment detected, let's test if it's local by checking if
    #anything is set to "root". We're assuming no-one's using "root" as their remote
    #login or password.
    for (( i = 0 ; i < $number_of_environments ; i++ ))
    do

        #add the current environment to the array
        env_array[$i]=$i

        #this will create array set_0, set_1, set_2 etc... which will reorganize all the grepped values into their respective environment
        eval "declare -a "set_${i}"=( ${name_array[$i]} ${user_array[$i]} ${pass_array[$i]} ${host_array[$i]} )"

        #because we're using arrays we have to use some indirect referencing trickery to iterate properly
        _set="set_$i"[@]
        set=( "${!_set}" )

        #k is a separate counter to iterate through the four environment variables
        k=0
        for j in "${set[@]}"
        do
            #out of all the environments, let's set the default to 0
            local_env=0
            if [ $j == "root" ]
            then
                #hopefully only one of the environments is using root as a login
                local_env=$i
            fi

            #remove the local environment from the final array, so the user doesn't
            #have to consider it.
            unset env_array[$local_env]

            #don't print the local details, and if we're remote, we only need to
            #output these once, when the correct remote settings are selected
            if [[ "$i" -ne "$local_env" ]]
            then

                #Display the title, "Environment #x", only once, on the first
                #pass through the current environment's config values
                [[ $k == 0 ]] && echo "    ENVIRONMENT #$i"
                header=
                case $k in
                    0 )
                        header="DB_NAME" ;;
                    1 )
                        header="DB_USER" ;;
                    2 )
                        header="DB_PASS" ;;
                    3 )
                        header="DB_HOST" ;;
                esac
                echo "    $header:      $j"

                ((k++))
            fi

        done
        echo

    done

    echo
    #Now that we've narrowed down the possibilities of what might be a remote
    #server, prompt the user to pick which one to synchronize
    echo "Synchronize with which remote server?"
    select m in "${env_array[@]}"
    do

        echo
        echo "You chose Environment #$m as your remote server."
        echo

        remote_env=$m

        #DumpDB will only use one set of remote environment variables, so set them
        #here based on the user's choice
        remote_env_ref_0=set_$remote_env[0]
        remote_env_ref_1=set_$remote_env[1]
        remote_env_ref_2=set_$remote_env[2]
        remote_env_ref_3=set_$remote_env[3]

        r_db_name=${!remote_env_ref_0}
        r_db_user=${!remote_env_ref_1}
        r_db_pass=${!remote_env_ref_2}
        r_db_host=${!remote_env_ref_3:-$db_host}

        echo "============================================================"
        echo " REMOTE DATABASE DETAILS"
        echo "============================================================"
        echo

        echo "remote DB_NAME is:       $r_db_name"
        echo "remote DB_USER is:       $r_db_user"
        echo "remote DB_PASSWORD is:   $r_db_pass"
        echo "remote DB_HOST is:       $r_db_host"

        echo
        # a flag which indicates whether the user has selected a remote environment already. This is so it doesn't pester the user repeatedly with this request.
        remote_chosen=true

        cat <<EOT >> $temp_file
r_db_name=${!remote_env_ref_0}
r_db_user=${!remote_env_ref_1}
r_db_pass=${!remote_env_ref_2}
r_db_host=${!remote_env_ref_3:-$db_host}

remote_chosen=true
EOT

        break

    done

    echo
}

# ---------------------------------------------------------
# mysql_check_local ()
# Check if the local database is empty.
# ---------------------------------------------------------
mysql_check_local () {

    echo "${blue}Checking if the local database was really emptied...$reset"

    get_local_db_details

    db_exists=$("${l_mysql:-mysql}" -s "-u$l_db_user" "-p$l_db_pass" -h "$l_db_host" --batch --skip-column-names -e "SHOW DATABASES LIKE '$l_db_name'" | grep $l_db_name)

    if [[ ! "$db_exists" ]]
    then
        echo
        echo "${red}$msgError${reset} "${l_mysql:-mysql}" could not connect to database $l_db_name. Check that your login details are set correctly and that the database exists. Exiting."
        exit 1;
    fi

    rows=$("${l_mysql:-mysql}" "-u$l_db_user" "-p$l_db_pass" -h "$l_db_host" --show-warnings -Bse "select count(distinct \`table_name\`) from \`information_schema\`.\`columns\` where \`table_schema\` = '$l_db_name'")

    if [ "$rows" == "0" ]; then
        echo "$green$msgSuccess$reset The database $l_db_name is empty, it has $rows rows."
    else
        echo "$red$msgError$reset Database $l_db_name is not empty, it still has $rows rows."
        exit 1
    fi
}

# ---------------------------------------------------------
# check_if_chosen ()
# Find out if the user has already been prompted to select a remote
# configuration. This only applies for nonstandard wp-configs.
# ---------------------------------------------------------
check_if_chosen () {

    #After the first time the user has selected his remote environment, a
    #temporary file is created which stores the remote database login values.
    #This function sources those values from the temp file, rather than
    #prompting the user again and recalculating.

    if [[ "${remote_chosen:-}" != "true" ]]
    then
        get_remote_db_details
    fi

}

# ---------------------------------------------------------
# do_check_for_dirs ()
# Login and verify that the remote paths are set correctly
# ---------------------------------------------------------
do_check_for_dirs () {

    echo ${blue}"Checking for existence of remote directories...$reset"

    ssh -q ${ssh_port}"$r_user"@"$r_host" "if [[ ! -d "$r_web_dir" ]]; then echo "Remote directory does not exist: $r_web_dir"; exit 1; fi; cd "$r_web_dir";"
    # if [[ ! -d "$r_db_dir" ]]; then mkdir "$r_db_dir"; fi;

    checked=true
}

# ---------------------------------------------------------
# mysql_check_remote ()
# Check if the remote database is empty.
# ---------------------------------------------------------
mysql_check_remote () {

    echo "${blue}Checking if the remote database was really emptied...$reset"

    #remote_chosen=false
    check_if_chosen

    db_exists=$(mysql "-u$r_db_user" "-p$r_db_pass" -h "$r_db_host" -BNse "SHOW DATABASES LIKE '$r_db_name'" | grep $r_db_name)

    if [[ ! "$db_exists" ]]
    then
        echo "${red}$msgError${reset} mysql could not connect to database $r_db_name. Check that your login details are set correctly and that the database exists. Exiting."
        exit 1;
    fi

    rows=$(mysql "-u$r_db_user" "-p$r_db_pass" -h "$r_db_host" --show-warnings -Bse "select count(distinct \`table_name\`) from \`information_schema\`.\`columns\` where \`table_schema\` = '$r_db_name'")

    if [ "$rows" == "0" ]; then
        echo "$green$msgSuccess$reset The database $r_db_name is empty."
    else
        echo "$red$msgError$reset Database $r_db_name is not empty, it still has $rows rows."
        exit 1
    fi

}

# ---------------------------------------------------------
# do_remote_replace_db ()
# Login to remote server and execute replace_remote_db() method.
# ---------------------------------------------------------
do_remote_replace_db () {

    [[ "$checked" ]] || do_check_for_dirs

    #echo ${yellow}"ssh -qt $ssh_port$r_user@$r_host cd "$r_web_dir/private"; chmod +x $(basename $0); ./$(basename $0) replace_remote_db;"$reset
    ssh -qt $ssh_port$r_user@$r_host "cd $r_web_dir/private; chmod +x $(basename $0); if [ ! -f .bashrc -a -f /etc/profile ]; then . /etc/profile; fi; ./$(basename $0) replace_remote_db;"

}

# ---------------------------------------------------------
# replace_remote_db ()
# Drop and recreate remote database.
# ---------------------------------------------------------
replace_remote_db () {

    check_if_chosen

    echo "${blue}Dropping remote database...$reset"

    echo

    if [[ ! "$no_drop" ]]
    then

        echo "${yellow}mysql -u$r_db_user -p$r_db_pass -h $r_db_host --show-warnings -Bs<<EOF >/dev/null 2>&1
        create database if not exists $r_db_name;
        drop database $r_db_name;
        create database $r_db_name;$reset"
        # do this if the standard `drop database` command is available
        mysql -u$r_db_user -p$r_db_pass -h $r_db_host --show-warnings -Bs<<EOF >/dev/null 2>&1
        create database if not exists $r_db_name;
        drop database $r_db_name;
        create database $r_db_name;
EOF

    else
        # otherwise do this if `drop database` is not available
        sql_show="show databases; create database if not exists $r_db_name;"

        echo "mysql -u$r_db_user -p$r_db_pass -h $r_db_host --show-warnings -Bse $sql_show"

        mysql -u$r_db_user -p$r_db_pass -h $r_db_host --show-warnings -Bse "$sql_show" >/dev/null 2>&1

        mysql -u $r_db_user -p$r_db_pass -h $r_db_host $r_db_name -sNe "show tables" | gawk -v drop_command="drop table " '{print drop_command $1";"}' | mysql -u $r_db_user -p$r_db_pass -h $r_db_host $r_db_name

        sql_create="create database $r_db_name"
        mysql -u$r_db_user -p$r_db_pass -h $r_db_host --show-warnings -Bse "$sql_create" >/dev/null 2>&1

    fi

    mysql_check_remote || exit 1

    echo
    echo "${blue}Replacing contents of remote database...$reset"
    echo
    cd $r_web_dir/$r_db_dir_alt

    echo "${yellow}bunzip2 < ${r_db_name}.bz2 | mysql -u$r_db_user -p$r_db_pass -h $r_db_host $r_db_name --show-warnings"

    set -o pipefail

    if bunzip2 < ${r_db_name_latest}.bz2 | mysql -u$r_db_user -p$r_db_pass -h $r_db_host $r_db_name --show-warnings
    then
        echo
        echo "$green$msgSuccess$reset Replaced database contents."
    else
        echo
        echo "$red$msgError$reset Failed to replace contents of remote database."
    fi

    echo
}

# ---------------------------------------------------------
# upload_local_db ()
# Upload local scripts and database backup file to the remote server
# ---------------------------------------------------------
upload_local_db () {

    echo "${blue}Uploading dump file to remote server...$reset"
    echo

    # check if we've already checked the remote path structure. If not, check now
    [[ "$checked" ]] || do_check_for_dirs

    cd "$l_root/$r_db_dir_alt"

    r_alt_db_path=${r_db_dir_alt}/${r_db_name_latest}

    if [[ -f "${r_db_name_latest}.bz2" ]]
    #if [[ -f "${r_db_name_latest}.bz2" ]]
    then
        echo "${yellow}scp -q $scp_port${r_db_name_latest}.bz2 $r_user@$r_host:$r_web_dir/$r_db_dir_alt"$reset
        scp -q ${scp_port}${r_db_name_latest}.bz2 $r_user@$r_host:$r_web_dir/$r_db_dir_alt

	    echo
	    #test whether the file was actually uploaded or not
	    echo "${yellow}if ssh -q ${ssh_port}"$r_user"@"$r_host" test -e "$r_web_dir"/"$r_alt_db_path".bz2"$reset
	    if ssh -q ${ssh_port}"$r_user"@"$r_host" test -e "$r_web_dir"/"$r_alt_db_path".bz2
	    then
	        echo
	        echo "$green$msgSuccess$reset Dump file uploaded to: $r_web_dir/${r_alt_db_path}.bz2"
	    else
	        echo
	        echo "$red$msgError$reset Upload failed. The file "$r_web_dir"/"$r_alt_db_path".bz2 could not be found on the remote server."
	        exit 1
	    fi
	    echo
    else
        echo "$red$msgError$reset Could not locate the local dump file at $(pwd)/${r_alt_db_path}.bz2."
        echo
        exit 1
    fi

    cd "$l_root/$r_db_dir"

    r_db_path=${r_db_dir}/${r_db_name_latest}

    if [[ -f "${r_db_name_latest}.bz2" ]]
    #if [[ -f "${r_db_name_latest}.bz2" ]]
    then
        echo "${yellow}scp -q $scp_port${r_db_name_latest}.bz2 $r_user@$r_host:$r_web_dir/$r_db_dir"$reset
        scp -q ${scp_port}${r_db_name_latest}.bz2 $r_user@$r_host:$r_web_dir/$r_db_dir

	    echo
	    #test whether the file was actually uploaded or not
	    echo "${yellow}if ssh -q ${ssh_port}"$r_user"@"$r_host" test -e "$r_web_dir"/"$r_db_path".bz2"$reset
	    if ssh -q ${ssh_port}"$r_user"@"$r_host" test -e "$r_web_dir"/"$r_db_path".bz2
	    then
	        echo
	        echo "$green$msgSuccess$reset Dump file uploaded to: $r_web_dir/${r_db_path}.bz2"
	    else
	        echo
	        echo "$red$msgError$reset Upload failed. The file "$r_web_dir"/"$r_db_path".bz2 could not be found on the remote server."
	        exit 1
	    fi
	    echo
    else
        echo "$red$msgError$reset Could not locate the local dump file at $(pwd)/${r_db_path}.bz2."
        echo
        exit 1
    fi

}

# ---------------------------------------------------------
# upload_script ()
# Upload a copy of sync script to FTP
# ---------------------------------------------------------
upload_script () {
    echo "${blue}Uploading sync script...$reset"

    echo "cd $l_root/private"
    cd "$l_root/private"

    # check if we've already checked the remote path structure. If not, check now
    [[ "$checked" ]] || do_check_for_dirs

    #we only need to upload the temp_file if it exists.
    if [[ -f $temp_file ]]
    then
        upload_temp=$temp_file
    fi

    echo "scp -q $scp_port$(basename $0) $config_file ${upload_temp-} $r_user@$r_host:$r_web_dir/private"
    echo
    scp -q ${scp_port}$(basename $0) $config_file ${upload_temp-} $r_user@$r_host:$r_web_dir"/private"
    echo
    echo "$green$msgSuccess$reset Uploaded $(basename $0) and $config_file to: $r_web_dir/private."

    echo
}

# ---------------------------------------------------------
# say_goodbye ()
# Print exit message.
# ---------------------------------------------------------
say_goodbye () {
    echo
    cd "$l_site_dir"
    if [[ -f $temp_file ]]
    then
        rm $temp_file
    fi
    echo "${blue}Exiting. Thanks for using DumpDB.$reset"
    echo
}


# ====================================
#  ROUTINES
# ====================================

# ---------------------------------------------------------
# push ()
# Execute a sequence of commands to update your remote server with the contents
# of your local server.
# ---------------------------------------------------------
push () {

	auto_update

	backup_local_db

	search_replace_local

	#upload_local_db
	
	#do_remote_replace_db

	upload_script

	say_goodbye

}

# ---------------------------------------------------------
# pull ()
# Execute a sequence of commands to update your local server with the contents
# of your remote server.
# ---------------------------------------------------------
pull () {

    say_goodbye

}


# ====================================
#  ACTUAL SCRIPT EXECUTION
# ====================================

echo
echo "${blue}DumpDB v$version$reset > $yellow${@:-push}$reset"
echo

# if an argument is passed (the number of arguments is not equal to zero), then check if that command is valid or not.
if [ $# -ne 0 ]
then
    # place all the command names in an array
    declare -a list_of_methods=(auto_update test_ssh get_local_db_details backup_local_db search_replace_local mysql_check_local upload_local_db mysql_check_remote get_remote_db_details do_remote_replace_db replace_remote_db say_goodbye)

    # function to check if an item exists in an array
    contains_element () {
      local e
      for e in "${list_of_methods[@]}"
          do [[ "$e" == "${1:-push}" ]] && return 0
      done
      return 1
    }

    contains_element "$@"

    # if command is invalid, list the valid ones
    if [[ $? -eq 1 ]]
    then
        echo ${red}$msgError$reset Command not found: ${yellow}"$@"$reset

        help
    fi

fi

# script will execute whichever method is passed to it as an argument.
# The default is to run the `push` method.
${@:-push}

exit
