#!/bin/bash

#
# pacaur: an AUR helper that minimizes user interaction
#

version="4.5.5"

#
# Config
#

# internationalization
LC_COLLATE=C                                # getopts sorting
TEXTDOMAIN='pacaur'
TEXTDOMAINDIR='/usr/share/locale'

# determine config location
if [[ -n "${XDG_CONFIG_DIRS}" ]]; then
    for i in ${XDG_CONFIG_DIRS//:/ }; do
        [[ -d "$i" ]] && export XDG_CONFIG_DIRS="$i" && break
    done
fi
configdir="${XDG_CONFIG_DIRS:-/etc/xdg}/pacaur"
userconfigdir="${XDG_CONFIG_HOME:-${HOME}/.config}/pacaur"
userpacmandir="${XDG_CONFIG_HOME:-${HOME}/.config}/pacman"

# source makepkg variables
if [[ -r "$MAKEPKG_CONF" ]]; then
    source "$MAKEPKG_CONF"
else
    source /etc/makepkg.conf
    if [[ -r "$userpacmandir/makepkg.conf" ]]; then
        source "$userpacmandir/makepkg.conf"
    elif [[ -r "$HOME/.makepkg.conf" ]]; then
        source "$HOME/.makepkg.conf"
    fi
fi

# set variables
tmpdir="${TMPDIR:-/tmp}/pacaurtmp-$USER"    # temp directory
clonedir="${AURDEST:-$tmpdir}"              # clone directory
editor="${EDITOR:-vi}"                      # build files editor
displaybuildfiles=full                      # display build files (none|diff|full)
fallback=true                               # pacman fallback to the AUR
silent=false                                # silence output
sortby=popularity                           # sort method (name|votes|popularity)
sudoloop=false                              # prevent sudo timeout

# set pacman binary
pacmanbin="${PACMAN:-pacman}"

# set AUR variables
aururl="aur.archlinux.org"
aurrpc="/rpc.php?type=multiinfo&v=4"

# source xdg config
source "$configdir/config"
[[ -r "$userconfigdir/config" ]] && source "$userconfigdir/config"

# set up directories
[[ ! -d "$tmpdir" ]] && mkdir -m 700 -p "$tmpdir"
[[ ! -d "$clonedir" ]] && mkdir -p "$clonedir"

#
# Functions
#

ClassifyPkgs() {
    if [[ $fallback = true ]]; then
        [[ $repo ]] && repopkgs=(${pkgs[@]})
        [[ $aur ]] && aurpkgs=(${pkgs[@]})
        if [[ ! $repo && ! $aur ]]; then
            unset noaurpkgs
            for i in "${pkgs[@]}"; do
                [[ $i == aur/* ]] && aurpkgs+=(${i:4}) && continue # search aur/pkgs in AUR
                noaurpkgs+=($i)
            done
            [[ -n "${noaurpkgs[@]}" ]] && norepopkgs=($(LANG=C $pacmanbin -Sp ${noaurpkgs[@]} 2>&1 >/dev/null | awk '{print $NF}'))
            for i in "${norepopkgs[@]}"; do
                [[ ! " ${noaurpkgs[@]} " =~ [a-zA-Z0-9\.\+-]+\/$i[^a-zA-Z0-9\.\+-] ]] && aurpkgs+=($i) # do not search repo/pkgs in AUR
            done
            repopkgs=($(LC_COLLATE=C comm -23 <(tr ' ' '\n' <<< ${noaurpkgs[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${aurpkgs[@]} | LC_COLLATE=C sort -u)))
        fi
    else
        [[ ! $aur ]] && repopkgs=(${pkgs[@]}) || aurpkgs=(${pkgs[@]})
    fi
}

Core() {
    GetIgnoredPkgs
    [[ $upgrade ]] && UpgradeAur
    IgnoreChecks
    DepsSolver
    IgnoreDepsChecks
    ProviderChecks
    ConflictChecks
    ReinstallChecks
    OutofdateChecks
    Prompt
    MakePkgs
}

UpgradeAur() {
    Note "i" $"${colorW}Starting AUR upgrade...${reset}"
    aurpkgs+=($(cower -u ${coweropts[@]} ${pkgs[@]} --color=never 2>&1 | awk '{print $2}'))

    # foreign packages check
    foreignpkgs=($($pacmanbin -Qmq))
    allaurpkgs=($(GetJson "var" "$(DownloadJson ${foreignpkgs[@]})" "Name"))
    aurforeignpkgs=($(LC_COLLATE=C comm -23 <(tr ' ' '\n' <<< ${foreignpkgs[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${allaurpkgs[@]} | LC_COLLATE=C sort -u)))
    for i in "${aurforeignpkgs[@]}"; do
        Note "w" $"${colorW}$i${reset} is ${colorY}not present${reset} in AUR -- skipping"
    done

    # add devel packages
    if [[ $devel ]]; then
        for i in "${allaurpkgs[@]}"; do
            [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< $i)" ]] && aurpkgs+=($i)
        done
    fi

    # avoid possible duplicate
    aurpkgs=($(tr ' ' '\n' <<< ${aurpkgs[@]} | sort -u))

    NothingToDo ${aurpkgs[@]}
}

IgnoreChecks() {
    [[ -z "${ignoredpkgs[@]}" ]] && return

    checkaurpkgs=(${aurpkgs[@]})
    unset aurpkgs

    # check targets
    json=$(DownloadJson ${checkaurpkgs[@]})
    checkaurpkgsAname=($(GetJson "var" "$json" "Name"))    # return sorted results
    checkaurpkgsAver=($(GetJson "var" "$json" "Version"))
    checkaurpkgsQver=($(expac -Q '%v' "${checkaurpkgsAname[@]}"))
    for ((i=0; i<${#checkaurpkgsAname[@]}; i++)); do
        [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< ${checkaurpkgsAname[$i]})" ]] && checkaurpkgsAver[$i]=$"latest"
    done
    for ((i=0; i<${#checkaurpkgs[@]}; i++)); do
        if [[ " ${ignoredpkgs[@]} " =~ " ${checkaurpkgs[$i]} " ]]; then
            if [[ ! $upgrade && ! $noconfirm ]]; then
                if ! Proceed "y" $"${checkaurpkgs[$i]} is in IgnorePkg/IgnoreGroup. Install anyway?"; then
                    Note "w" $"${colorW}${checkaurpkgs[$i]}${reset}: ignoring package upgrade"
                    rmaurpkgs+=(${checkaurpkgs[$i]})
                    continue
                fi
            else
                Note "w" $"${colorW}${checkaurpkgs[$i]}${reset}: ignoring package upgrade (${colorR}${checkaurpkgsQver[$i]}${reset} => ${colorG}${checkaurpkgsAver[$i]}${reset})"
                rmaurpkgs+=(${checkaurpkgs[$i]})
                continue
            fi
        fi
        aurpkgs+=(${checkaurpkgs[$i]})
    done

    NothingToDo ${aurpkgs[@]}
}

DepsSolver() {
    Note "i" $"resolving dependencies..."

    # remove AUR pkgs versioning
    for ((i=0; i<${#aurpkgs[@]}; i++)); do
        aurpkgs[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${aurpkgs[$i]})
    done
    deps+=(${aurpkgs[@]})

    # target providers
    json=$(DownloadJson ${aurpkgs[@]})
    aurpkgsproviders=($(GetJson "array" "$json" "Provides"))

    # target providers check
    if [[ -n "${aurpkgsproviders[@]}" ]]; then
        for ((i=0; i<${#aurpkgsproviders[@]}; i++)); do
            unset aurpkgsprovidersname
            aurpkgsprovidersname=${aurpkgsproviders[$i]} && aurpkgsprovidersname=${aurpkgsproviders%[=><]*}
        done
    fi

    [[ -z "${foreignpkgs[@]}" ]] && foreignpkgs=($($pacmanbin -Qmq))
    FindDepsAur ${aurpkgs[@]}

    # get AUR packages info
    json=$(DownloadJson ${deps[@]})
    depsAname=($(GetJson "var" "$json" "Name"))    # return sorted results
    depsAver=($(GetJson "var" "$json" "Version"))
    depsAood=($(GetJson "var" "$json" "OutOfDate"))
    for ((i=0; i<${#depsAname[@]}; i++)); do
        depsQver[$i]=$(expac -Qs '%v' "^${depsAname[$i]}$")
        [[ -z "${depsQver[$i]}" ]] && depsQver[$i]="#"  # avoid empty elements shift
        [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< ${depsAname[$i]})" ]] && depsAver[$i]=$"latest"
    done

    # no results check
    for i in "${errdeps[@]}"; do
        Note "f" $"no results found for $i"
    done
    [[ -n "${errdeps[@]}" ]] && exit 1

    # return all binary deps
    FindDepsRepo ${repodeps[@]}
}

FindDepsAur() {
    [[ $nodeps && $count -ge 2 ]] && return
    [[ -z "${depspkgsaur[@]}" ]] && depspkgsaur=(${aurpkgs[@]})

    json=$(DownloadJson ${depspkgsaur[@]})

    # target check
    [[ -z "${prevdepspkgsaur[@]}" ]] && errdeps+=($(LC_COLLATE=C comm -3 <(tr ' ' '\n' <<< $(GetJson "var" "$json" "Name") | sort -u) <(tr ' ' '\n' <<< ${aurpkgs[@]} | sort -u)))

    # AUR versioning check
    if [[ -n "${prevdepspkgsaur[@]}" ]]; then
        for ((i=0; i<${#prevdepspkgsaur[@]}; i++)); do
            unset prevname prevver prevaurver
            prevname=${prevdepspkgsaur[$i]} && prevname=${prevname%[><]*} && prevname=${prevname%=*}
            prevver=${prevdepspkgsaur[$i]} && prevver=${prevver#*=} && prevver=${prevver#*[><]}
            prevaurver=($(GetJson "varvar" "$json" "Version" "$prevname"))

            # not found in AUR nor repo
            if [[ ! $prevaurver ]]; then
                [[ ! " ${errdeps[@]} " =~ " ${prevdepspkgsaur[$i]} " ]] && [[ ! " ${aurpkgsprovidersname[@]} " =~ " ${prevdepspkgsaur[$i]} " ]] && errdeps+=(${prevdepspkgsaur[$i]})
                continue
            fi

            case "${prevdepspkgsaur[$i]}" in
                *">"*|*"<"*|*"="*)
                    # found in AUR but version not correct
                    case "${prevdepspkgsaur[$i]}" in
                        *">="*) [[ $(vercmp "$prevaurver" "$prevver") -ge 0 ]] && continue;;
                        *"<="*) [[ $(vercmp "$prevaurver" "$prevver") -le 0 ]] && continue;;
                        *">"*)  [[ $(vercmp "$prevaurver" "$prevver") -gt 0 ]] && continue;;
                        *"<"*)  [[ $(vercmp "$prevaurver" "$prevver") -lt 0 ]] && continue;;
                        *"="*)  [[ $(vercmp "$prevaurver" "$prevver") -eq 0 ]] && continue;;
                    esac
                    [[ ! " ${errdeps[@]} " =~ " ${prevdepspkgsaur[$i]} " ]] && errdeps+=(${prevdepspkgsaur[$i]})
                ;;
                *) continue;;
            esac
        done
    fi

    depspkgs=($(GetJson "array" "$json" "Depends"))

    # cached packages makedeps check
    if [[ ! $PKGDEST || $rebuild ]]; then
        depspkgs+=($(GetJson "array" "$json" "MakeDepends"))
        depspkgs+=($(GetJson "array" "$json" "CheckDepends"))
    else
        for ((i=0; i<${#depspkgsaur[@]}; i++)); do
            depsAname=$(GetJson "varvar" "$json" "Name" "${depspkgsaur[$i]}")
            depsAver=$(GetJson "varvar" "$json" "Version" "${depspkgsaur[$i]}")
            GetBuiltPkg "$depsAname-$depsAver" "$PKGDEST"
            if [[ ! $builtpkg ]]; then
                depspkgs+=($(GetJson "arrayvar" "$json" "MakeDepends" "${depspkgsaur[$i]}"))
                depspkgs+=($(GetJson "arrayvar" "$json" "CheckDepends" "${depspkgsaur[$i]}"))
            fi
            unset builtpkg
        done
    fi

    # workaround for limited RPC support of architecture dependent fields
    if [[ ${CARCH} == 'i686' ]]; then
        for i in "${depspkgs[@]}"; do
             [[ -n "$(grep -E "^lib32\-" <<< $i)" ]] && depspkgs=($(tr ' ' '\n' <<< ${depspkgs[@]} | sed "s/^$i$//g"))
        done
    fi

    # remove installed deps
    if [[ ! $foreign && ! $devel ]]; then
        depspkgs=($($pacmanbin -T ${depspkgs[@]} | sort -u))
    else
        # remove versioning and check providers
        unset vcsdepspkgs
        for ((i=0; i<${#depspkgs[@]}; i++)); do
            depspkgs[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${depspkgs[$i]})
            unset j && j=($(expac -Qs '%n %P' "^${depspkgs[$i]}$" | grep -E "([^a-zA-Z0-9_@\.\+-]${depspkgs[$i]}|^${depspkgs[$i]})" | grep -E "(${depspkgs[$i]}[^a-zA-Z0-9\.\+-]|${depspkgs[$i]}$)" | awk '{print $1}'))
            if [[ -n "$j" ]]; then
                depspkgs[$i]="$j"
                [[ $devel ]] && [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< $j)" ]] && vcsdepspkgs+=($j)
            else
                foreignpkgs+=(${depspkgs[$i]})
            fi
        done
        # reorder devel
        if [[ $devel ]]; then
            [[ ! $foreign ]] && depspkgs=($($pacmanbin -T ${depspkgs[@]} | sort -u))
            depspkgs=($(LC_COLLATE=C comm -3 <(tr ' ' '\n' <<< ${depspkgs[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${vcsdepspkgs[@]} | LC_COLLATE=C sort -u)))
        fi
        # remove installed binary packages only
        if [[ $foreign ]]; then
            depspkgs=($(LC_COLLATE=C comm -12 <(tr ' ' '\n' <<< ${depspkgs[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${foreignpkgs[@]} | LC_COLLATE=C sort -u)))
        fi
    fi

    # split binary and AUR depends pkgs
    unset depspkgsaur
    if [[ -n "${depspkgs[@]}" ]]; then
        # remove all pkgs versioning
        if [[ $nodeps && $count -eq 1 ]]; then
            for ((i=0; i<${#depspkgs[@]}; i++)); do
                depspkgs[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${depspkgs[$i]})
            done
        # assume installed deps
        elif [[ -n "${assumeinstalled[@]}" ]]; then
            # remove versioning
            for ((i=0; i<${#assumeinstalled[@]}; i++)); do
                unset assumedepspkgs
                assumeinstalled[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${assumeinstalled[$i]})
                for ((j=0; j<${#depspkgs[@]}; j++)); do
                    assumedepspkgs[$j]=$(awk -F ">|<|=" '{print $1}' <<< ${depspkgs[$j]})
                    [[ " ${assumedepspkgs[@]} " =~ " ${assumeinstalled[$i]} " ]] && depspkgs[$j]=${assumeinstalled[$i]};
                done
            done
            depspkgs=($(LC_COLLATE=C comm -23 <(tr ' ' '\n' <<< ${depspkgs[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${assumeinstalled[@]} | LC_COLLATE=C sort -u)))
        fi
        if [[ -n "${depspkgs[@]}" ]]; then
            depspkgsaur=($(LANG=C $pacmanbin -Sp ${depspkgs[@]} 2>&1 >/dev/null | awk '{print $NF}'))
            repodeps+=($(LC_COLLATE=C comm -23 <(tr ' ' '\n' <<< ${depspkgs[@]} | LC_COLLATE=C sort -u)  <(tr ' ' '\n' <<< ${depspkgsaur[@]} | LC_COLLATE=C sort -u)))
        fi
    fi
    unset depspkgs

    # dependency cycle check
    [[ -n "${prevdepspkgsaur[@]}" ]] && [[ "${prevdepspkgsaur[*]}" == "${depspkgsaur[*]}" ]] && Note "e" $"dependency cycle detected"

    if [[ -n "${depspkgsaur[@]}" ]]; then
        # store for AUR version check
        [[ ! $nodeps ]] && prevdepspkgsaur=(${depspkgsaur[@]})

        # remove AUR pkgs versioning
        for ((i=0; i<${#depspkgsaur[@]}; i++)); do
            depspkgsaur[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${depspkgsaur[$i]})
        done

        # ensure correct dependency order
        depspkgsaur=($(tr ' ' '\n' <<< ${depspkgsaur[@]} | sort -u))
        for ((i=0; i<${#depspkgsaur[@]}; i++)); do
            if [[ " ${deps[@]} " =~ " ${depspkgsaur[$i]} " ]]; then
                deps=($(tr ' ' '\n' <<< ${deps[@]} | sed "s/^${depspkgsaur[$i]}$//g"))
                aurdepspkgs=($(tr ' ' '\n' <<< ${aurdepspkgs[@]} | sed "s/^${depspkgsaur[$i]}$//g"))
            fi
        done
    fi

    if [[ -n "${depspkgsaur[@]}" ]]; then
        aurdepspkgs+=(${depspkgsaur[@]})
        deps+=(${depspkgsaur[@]})
        FindDepsAur ${depspkgsaur[@]}
    fi
}

FindDepsRepo() {
    [[ -z "${repodeps[@]}" ]] && return

    # reduce root binary deps
    repodeps=($(tr ' ' '\n' <<< ${repodeps[@]} | sort -u))

    for i in "${repodeps[@]}"; do
        allrepopkgs+=($(pactree -su "$i"))
        providersrepopkgs+=($(pactree -s "$i" | grep " provides " | awk '{print $NF}' | sort -u))
    done
    providersrepopkgs=($(tr ' ' '\n' <<< ${providersrepopkgs[@]} | sort -u))

    # remove pactree deps of default providers if non default provider is already installed
    if [[ -n "${providersrepopkgs[@]}" ]]; then
        for i in "${providersrepopkgs[@]}"; do
            j=($(expac -Qs '%n %P' "^$i$" | grep -E "([^a-zA-Z0-9_@\.\+-]$i|^$i)" | grep -E "($i[^a-zA-Z0-9\.\+-]|$i$)" | awk '{print $1}'))
            [[ -n "$j" ]] && [[ "$j" != "$(expac -Ss '%n' "^$i$" | tr '\n' ' ' | awk '{print $1}')" ]] && providersrepopkgsrm+=($(pactree -su "$i"))
        done
        if [[ -n "${providersrepopkgsrm[@]}" ]]; then
            providersrepopkgsrm=($($pacmanbin -T ${providersrepopkgsrm[@]} | sort -u))
            allrepopkgs=($(LC_COLLATE=C comm -23 <(tr ' ' '\n' <<< ${allrepopkgs[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${providersrepopkgsrm[@]} | LC_COLLATE=C sort -u)))
        fi
    fi

    repodepspkgs=($($pacmanbin -T ${allrepopkgs[@]} | sort -u))
}

IgnoreDepsChecks() {
    [[ -z "${ignoredpkgs[@]}" ]] && return

    # add checked targets
    deps=(${aurpkgs[@]})

    # check dependencies
    for i in "${repodepspkgs[@]}"; do
        if [[ " ${ignoredpkgs[@]} " =~ " $i " ]]; then
            Note "w" $"${colorW}$i${reset}: ignoring package upgrade"
            Note "e" $"Unresolved dependency '${colorW}$i${reset}'"
        fi
    done
    for i in "${aurdepspkgs[@]}"; do
        # skip already checked dependencies
        [[ " ${aurpkgs[@]} " =~ " $i " ]] && continue
        [[ " ${rmaurpkgs[@]} " =~ " $i " ]] && Note "e" $"Unresolved dependency '${colorW}$i${reset}'"

        if [[ " ${ignoredpkgs[@]} " =~ " $i " ]]; then
            if [[ ! $noconfirm ]]; then
                if ! Proceed "y" $"$i dependency is in IgnorePkg/IgnoreGroup. Install anyway?"; then
                    Note "e" $"Unresolved dependency '${colorW}$i${reset}'"
                fi
            else
                Note "w" $"${colorW}$i${reset}: ignoring package upgrade"
                Note "e" $"Unresolved dependency '${colorW}$i${reset}'"
            fi
        fi
        deps+=($i)
    done
}

ProviderChecks() {
    [[ -z "${repodepspkgs[@]}" ]] && return

    allproviders=($(expac -S '%S' "${repodepspkgs[@]}" | sort -u))
    # remove installed providers
    providersdeps=($($pacmanbin -T ${allproviders[@]} | sort -u))

    for ((i=0; i<${#providersdeps[@]}; i++)); do
        providers=($(expac -Ss '%n' "^${providersdeps[$i]}$" | sort -u))
        [[ ! ${#providers[@]} -gt 1 ]] && continue

        # skip if already provided
        if [[ -n "${providerspkgs[@]}" ]]; then
            providerspkgs=($(tr ' ' '|' <<< ${providerspkgs[@]}))
            provided+=($(expac -Ss '%S' "^(${providerspkgs[*]})$"))
            [[ " ${provided[@]} " =~ " ${providersdeps[$i]} " ]] && continue
        fi

        if [[ ! $noconfirm ]]; then
            Note "i" $"${colorW}There are ${#providers[@]} providers available for ${providersdeps[$i]}:${reset}"
            expac -S -1 '   %!) %n (%r) ' "${providers[@]}"

            local nb=-1
            providersnb=$(( ${#providers[@]} -1 )) # count from 0
            while [[ $nb -lt 0 || $nb -ge ${#providers} ]]; do

                printf "\n%s " $"Enter a number (default=0):"
                read -n $(echo -n $providersnb | wc -m) nb
                echo

                case $nb in
                    [0-9]|[0-9][0-9]) [[ $nb -lt 0 || $nb -ge ${#providers[@]} ]] && echo && Note "f" $"invalid value: $nb is not between 0 and $providersnb" && ((i--)) || break;;
                    '') nb=0;;
                    *) Note "f" $"invalid number: $nb";;
                esac
            done
        else
            local nb=0
        fi
        providerspkgs+=(${providers[$nb]})
        [[ $nb -ne 0 ]] && rmproviderpkgs+=(${providersdeps[$i]})
    done

    repoprovidersconflictingpkgs+=(${providerspkgs[@]})

    # pactree always return default choice so update binary deps list
    if [[ -n "${rmproviderpkgs[@]}" ]]; then
        # remove deps of default providers
        for i in "${rmproviderpkgs[@]}"; do
            providerpkgsrm+=($(pactree -su "$i"))
        done
        providerpkgsrm=($($pacmanbin -T ${providerpkgsrm[@]} | sort -u))
        repodepspkgs=($(LC_COLLATE=C comm -23 <(tr ' ' '\n' <<< ${repodepspkgs[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${providerpkgsrm[@]} | LC_COLLATE=C sort -u)))

        # add deps of selected providers instead
        providerspkgs=($(tr '|' ' ' <<< ${providerspkgs[@]}))
        for i in "${providerspkgs[@]}"; do
            providerdeps+=($(pactree -su "$i"))
        done
        repodepspkgs+=($($pacmanbin -T ${providerdeps[@]} | sort -u))
    fi

    # get binary packages info
    if [[ -n "${repodepspkgs[@]}" ]]; then
        repodepspkgs=($(expac -S -1 '%n' "${repodepspkgs[@]}" | LC_COLLATE=C sort -u))
        repodepsSver=($(expac -S -1 '%v' "${repodepspkgs[@]}"))
        repodepsQver=($(expac -Q '%v' "${repodepspkgs[@]}"))
        repodepsSrepo=($(expac -S -1 '%r/%n' "${repodepspkgs[@]}"))
    fi
}

ConflictChecks() {
    Note "i" $"looking for inter-conflicts..."

    allQprovides=($(expac -Q '%n'))
    allQprovides+=($(expac -Q '%S')) # no versioning
    allQconflicts=($(expac -Q '%C'))

    # AUR conflicts
    Aprovides=(${depsAname[@]})
    Aprovides+=($(GetJson "array" "$json" "Provides"))
    Aconflicts=($(GetJson "array" "$json" "Conflicts"))
    # remove AUR versioning
    for ((i=0; i<${#Aprovides[@]}; i++)); do
        Aprovides[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${Aprovides[$i]})
    done
    for ((i=0; i<${#Aconflicts[@]}; i++)); do
        Aconflicts[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${Aconflicts[$i]})
    done
    aurconflicts+=($(LC_COLLATE=C comm -12 <(tr ' ' '\n' <<< ${Aprovides[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${allQconflicts[@]} | LC_COLLATE=C sort -u)))
    aurconflicts+=($(LC_COLLATE=C comm -12 <(tr ' ' '\n' <<< ${Aconflicts[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${allQprovides[@]} | LC_COLLATE=C sort -u)))
    aurconflicts=($(tr ' ' '\n' <<< ${aurconflicts[@]} | LC_COLLATE=C sort -u))

    for i in "${aurconflicts[@]}"; do
        unset aurAconflicts
        [[ " ${depsAname[@]} " =~ " $i " ]] && aurAconflicts=($i)
        for j in "${depsAname[@]}"; do
            [[ " $(GetJson "arrayvar" "$json" "Conflicts" "$j") " =~ " $i " ]] && aurAconflicts+=($j)
        done

        for j in "${aurAconflicts[@]}"; do
            unset k Aprovides
            k=($(expac -Qs '%n %P' "^$i$" | grep -E "([^a-zA-Z0-9_@\.\+-]$i|^$i)" | grep -E "($i[^a-zA-Z0-9\.\+-]|$i$)" | awk '{print $1}'))
            [[ ! $installpkg && ! " ${aurdepspkgs[@]} " =~ " $j " ]] && continue # skip if downloading target only
            [[ "$j" == "$k" || -z "$k" ]] && continue # skip if reinstalling or if no conflict exists

            Aprovides=($j)
            if [[ ! $noconfirm && ! " ${aurconflictingpkgs[@]} " =~ " $k " ]]; then
                if ! Proceed "n" $"$j and $k are in conflict ($i). Remove $k?"; then
                    aurconflictingpkgs+=($j $k)
                    aurconflictingpkgsrm+=($k)
                    for ((l=0; l<${#depsAname[@]}; l++)); do
                        [[ " ${depsAname[$l]} " =~ "$k" ]] && depsQver[$l]=$(expac -Qs '%v' "^$k$")
                    done
                    Aprovides+=($(GetJson "arrayvar" "$json" "Provides" "$j"))
                    # remove AUR versioning
                    for ((i=0; i<${#Aprovides[@]}; i++)); do
                        Aprovides[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${Aprovides[$i]})
                    done
                    [[ ! " ${Aprovides[@]} " =~ " $k " && ! " ${aurconflictingpkgsrm[@]} " =~ " $k " ]] && CheckRequires $k
                    break
                else
                    Note "f" $"unresolvable package conflicts detected"
                    Note "f" $"failed to prepare transaction (conflicting dependencies)"
                    Note "e" $"$j and $k are in conflict"
                fi
            fi
            Aprovides+=($(GetJson "arrayvar" "$json" "Provides" "$j"))
            # remove AUR versioning
            for ((i=0; i<${#Aprovides[@]}; i++)); do
                Aprovides[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${Aprovides[$i]})
            done
            [[ ! " ${Aprovides[@]} " =~ " $k " && ! " ${aurconflictingpkgsrm[@]} " =~ " $k " ]] && CheckRequires $k
        done
    done

    NothingToDo ${deps[@]}

    # repo conflicts
    if [[ -n "${repodepspkgs[@]}" ]]; then
        repodepsprovides=(${repodepspkgs[@]})
        repodepsprovides+=($(expac -S '%S' "${repodepspkgs[@]}")) # no versioning
        repodepsconflicts=($(expac -S '%H' "${repodepspkgs[@]}"))

        # versioning check
        unset checkedrepodepsconflicts
        for ((i=0; i<${#repodepsconflicts[@]}; i++)); do
            unset repodepsconflictsname repodepsconflictsver localver
            repodepsconflictsname=${repodepsconflicts[$i]} && repodepsconflictsname=${repodepsconflictsname%[><]*} && repodepsconflictsname=${repodepsconflictsname%=*}
            repodepsconflictsver=${repodepsconflicts[$i]} && repodepsconflictsver=${repodepsconflictsver#*=} && repodepsconflictsver=${repodepsconflictsver#*[><]}
            [[ $repodepsconflictsname ]] && localver=$(expac -Q '%v' $repodepsconflictsname)

            if [[ $localver ]]; then
                case "${repodepsconflicts[$i]}" in
                        *">="*) [[ $(vercmp "$repodepsconflictsver" "$localver") -ge 0 ]] && continue;;
                        *"<="*) [[ $(vercmp "$repodepsconflictsver" "$localver") -le 0 ]] && continue;;
                        *">"*)  [[ $(vercmp "$repodepsconflictsver" "$localver") -gt 0 ]] && continue;;
                        *"<"*)  [[ $(vercmp "$repodepsconflictsver" "$localver") -lt 0 ]] && continue;;
                        *"="*)  [[ $(vercmp "$repodepsconflictsver" "$localver") -eq 0 ]] && continue;;
                esac
                checkedrepodepsconflicts+=($repodepsconflictsname)
            fi
        done

        repoconflicts+=($(LC_COLLATE=C comm -12 <(tr ' ' '\n' <<< ${repodepsprovides[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${allQconflicts[@]} | LC_COLLATE=C sort -u)))
        repoconflicts+=($(LC_COLLATE=C comm -12 <(tr ' ' '\n' <<< ${checkedrepodepsconflicts[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${allQprovides[@]} | LC_COLLATE=C sort -u)))
        repoconflicts=($(tr ' ' '\n' <<< ${repoconflicts[@]} | LC_COLLATE=C sort -u))
    fi

    for i in "${repoconflicts[@]}"; do
        unset Qprovides
        repoSconflicts=($(expac -S '%n %C %S' "${repodepspkgs[@]}" | grep -E "[^a-zA-Z0-9_@\.\+-]$i" | grep -E "($i[^a-zA-Z0-9\.\+-]|$i$)" | awk '{print $1}'))
        for j in "${repoSconflicts[@]}"; do
            unset k && k=($(expac -Qs '%n %P' "^$i$" | grep -E "([^a-zA-Z0-9_@\.\+-]$i|^$i)" | grep -E "($i[^a-zA-Z0-9\.\+-]|$i$)" | awk '{print $1}'))
            [[ "$j" == "$k" || -z "$k" ]] && continue # skip when no conflict with repopkgs

            if [[ ! $noconfirm && ! " ${repoconflictingpkgs[@]} " =~ " $k " ]]; then
                if ! Proceed "n" $"$j and $k are in conflict ($i). Remove $k?"; then
                    repoconflictingpkgs+=($j $k)
                    repoconflictingpkgsrm+=($k)
                    repoprovidersconflictingpkgs+=($j)
                    Qprovides=($(expac -Ss '%S' "^$k$"))
                    [[ ! " ${Qprovides[@]} " =~ " $k " && ! " ${repoconflictingpkgsrm[@]} " =~ " $k " ]] && CheckRequires $k
                    break
                else
                    Note "f" $"unresolvable package conflicts detected"
                    Note "f" $"failed to prepare transaction (conflicting dependencies)"
                    Note "e" $"$j and $k are in conflict"
                fi
            fi
            Qprovides=($(expac -Ss '%S' "^$k$"))
            [[ ! " ${Qprovides[@]} " =~ " $k " ]] && CheckRequires $k
        done
    done
}

ReinstallChecks() {
    depsAtmp=(${depsAname[@]})
    for ((i=0; i<${#depsAtmp[@]}; i++)); do
        [[ ! $foreign ]] && [[ ! " ${aurpkgs[@]} " =~ " ${depsAname[$i]} " || " ${aurconflictingpkgs[@]} " =~ " ${depsAname[$i]} " ]] && continue
        [[ -z "${depsQver[$i]}" || "${depsQver[$i]}" = '#' || $(vercmp "${depsAver[$i]}" "${depsQver[$i]}") -gt 0 ]] && continue
        [[ ! $installpkg && ! " ${aurdepspkgs[@]} " =~ " ${depsAname[$i]} " ]] && continue
        if [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< ${depsAname[$i]})" ]]; then
            Note "w" $"${colorW}${depsAname[$i]}${reset} latest revision -- fetching"
        else
            if [[ ! $needed ]]; then
                Note "w" $"${colorW}${depsAname[$i]}-${depsQver[$i]}${reset} is up to date -- reinstalling"
            else
                Note "w" $"${colorW}${depsAname[$i]}-${depsQver[$i]}${reset} is up to date -- skipping"
                deps=($(tr ' ' '\n' <<< ${deps[@]} | sed "s/^${depsAname[$i]}$//g"))
                unset depsAname[$i] depsQver[$i] depsAver[$i] depsAood[$i]
            fi
        fi
    done
    [[ $needed ]] && depsAname=(${depsAname[@]}) && depsQver=(${depsQver[@]}) && depsAver=(${depsAver[@]}) && depsAood=(${depsAood[@]})

    NothingToDo ${deps[@]}
}

OutofdateChecks() {
    for ((i=0; i<${#depsAname[@]}; i++)); do
        [[ "${depsAood[$i]}" -gt 0 ]] && Note "w" $"${colorW}${depsAname[$i]}-${depsAver[$i]}${reset} has been flagged ${colorR}out of date${reset} on ${colorY}$(date -d "@${depsAood[$i]}" "+%Y-%m-%d")${reset}"
    done
}

Prompt() {
    # compute binary size
    if [[ -n "${repodepspkgs[@]}" ]]; then
        binaryksize=($(expac -S -1 '%k' "${repodepspkgs[@]}"))
        binarymsize=($(expac -S -1 '%m' "${repodepspkgs[@]}"))
        sumk=0
        summ=0
        for ((i=0; i<${#repodepspkgs[@]}; i++)); do
            GetBuiltPkg "${repodepspkgs[$i]}-${repodepsSver[$i]}" '/var/cache/pacman/pkg'
            [[ $builtpkg ]] && binaryksize=(${binaryksize[@]/${binaryksize[$i]}/0})
            sumk=$((sumk + ${binaryksize[$i]}))
            summ=$((summ + ${binarymsize[$i]}))
        done
        sumk=$(awk '{ printf("%.2f\n", $1/$2) }' <<< "$sumk 1048576")
        summ=$(awk '{ printf("%.2f\n", $1/$2) }' <<< "$summ 1048576")
    fi

    # cached packages check
    for ((i=0; i<${#depsAname[@]}; i++)); do
        [[ ! $PKGDEST || $rebuild ]] && break
        GetBuiltPkg "${depsAname[$i]}-${depsAver[$i]}" "$PKGDEST"
        [[ $builtpkg ]] && cachedpkgs+=(${depsAname[$i]}) && depsAcached[$i]=$"(cached)" || depsAcached[$i]=""
        unset builtpkg
    done

    if [[ -n "$(grep '^VerbosePkgLists' '/etc/pacman.conf')" ]]; then
        strname=$"Name"; stroldver=$"Old Version"; strnewver=$"New Version"; strsize=$"Download Size"
        depsArepo=(${depsAname[@]/#/aur/})
        lname=$(GetLength ${depsArepo[@]} ${repodepsSrepo[@]} "$strname")
        lver=$(GetLength ${depsQver[@]} ${depsAver[@]} ${repodepsQver[@]} ${repodepsSver[@]} "$stroldver" "$strnewver")
        lsize=$(GetLength "$strsize")

        # local version column cleanup
        for ((i=0; i<${#deps[@]}; i++)); do
            [[ "${depsQver[$i]}" =~ '#' ]] && unset depsQver[$i]
        done
        # show detailed output
        printf "\n${colorY}%s${reset}\n\n" $"AUR Packages  (${#deps[@]}):"
        printf "${colorW}%-${lname}s  %-${lver}s  %-${lver}s${reset}\n\n" "$strname" "$stroldver" "$strnewver"
        for ((i=0; i<${#deps[@]}; i++)); do
            printf "%-${lname}s  ${colorR}%-${lver}s${reset}  ${colorG}%-${lver}s${reset}  %${lsize}s\n" "${depsArepo[$i]}" "${depsQver[$i]}" "${depsAver[$i]}" "${depsAcached[$i]}";
        done

        if [[ -n "${repodepspkgs[@]}" ]]; then
            for ((i=0; i<${#repodepspkgs[@]}; i++)); do
                binarysize[$i]=$(awk '{ printf("%.2f\n", $1/$2) }' <<< "${binaryksize[$i]} 1048576")
            done
            printf "\n${colorY}%s${reset}\n\n" $"Repo Packages (${#repodepspkgs[@]}):"
            printf "${colorW}%-${lname}s  %-${lver}s  %-${lver}s  %s${reset}\n\n" $"Name" $"Old Version" $"New Version" $"Download Size"
            for ((i=0; i<${#repodepspkgs[@]}; i++)); do
                printf "%-${lname}s  ${colorR}%-${lver}s${reset}  ${colorG}%-${lver}s${reset}  %${lsize}s\n" "${repodepsSrepo[$i]}" "${repodepsQver[$i]}" "${repodepsSver[$i]}" $"${binarysize[$i]} MiB";
            done
        fi
    else
        # show version
        for ((i=0; i<${#deps[@]}; i++)); do
            depsver="${depsver}${depsAname[$i]}-${depsAver[$i]}  "
        done
        for ((i=0; i<${#repodepspkgs[@]}; i++)); do
            repodepspkgsver="${repodepspkgsver}${repodepspkgs[$i]}-${repodepsSver[$i]}  "
        done
        printf "\n${colorY}%-17s${reset} %s\n" $"AUR Packages  (${#deps[@]}):" "$depsver"
        [[ -n "${repodepspkgs[@]}" ]] && printf "${colorY}%-17s${reset} %s\n" $"Repo Packages (${#repodepspkgs[@]}):" "$repodepspkgsver"
    fi

    if [[ -n "${repodepspkgs[@]}" ]]; then
        strrepodlsize=$"Repo Download Size:"; strrepoinsize=$"Repo Installed Size:"; strsumk=$"$sumk MiB"; strsumm=$"$summ MiB"
        lreposizelabel=$(GetLength "$strrepodlsize" "$strrepoinsize")
        lreposize=$(GetLength "$strsumk" "$strsumm")
        printf "\n${colorW}%-${lreposizelabel}s${reset}  %${lreposize}s\n" "$strrepodlsize" "$strsumk"
        printf "${colorW}%-${lreposizelabel}s${reset}  %${lreposize}s\n" "$strrepoinsize" "$strsumm"
    fi

    echo
    if [[ ! $noconfirm ]]; then
        [[ $installpkg ]] && action=$"installation" || action=$"download"
        if ! Proceed "y" $"Proceed with $action?"; then
            exit
        fi
    fi
}

DownloadPkgs() {
    Note "i" $"${colorW}Retrieving package(s)...${reset}"
    GetPkgbase $@

    # clone
    cd "$clonedir"
    for i in ${basepkgs[@]}; do
        if [[ ! -d "$i" ]]; then
            if [[ $clonedir != $tmpdir ]]; then
                git clone https://aur.archlinux.org/$i.git
            else
                git clone --depth=1 https://aur.archlinux.org/$i.git
            fi
        else
            cd "$clonedir/$i"
            git reset --hard HEAD &>/dev/null # updated pkgver of vcs packages prevent pull
            [[ -e ".git/FETCH_HEAD" && $displaybuildfiles = diff ]] && cp -pf ".git/FETCH_HEAD" ".git/FETCH_HEAD.prev"
            git pull
        fi
        cd "$clonedir"
    done
}

EditPkgs() {
    [[ $noedit ]] && return
    for i in "$@"; do
        [[ " ${cachedpkgs[@]} " =~ " $i " ]] && continue
        cd "$clonedir/$i"
        unset timestamp
        GetInstallScripts $i
        if [[ ! $edit ]]; then
            if [[ ! $displaybuildfiles = none ]]; then
                if [[ -e ".git/FETCH_HEAD.prev" && $displaybuildfiles = diff ]]; then
                    # show diff
                    if Proceed "y" $"View $i build files diff?"; then
                        timestamp=$(stat -c %Y "$clonedir/$i/.git/FETCH_HEAD.prev")
                        git show --since $timestamp
                        Note "s" $"${colorW}$i${reset} build files diff viewed"
                    fi
                else
                    # show pkgbuild
                    if Proceed "y" $"View $i PKGBUILD?"; then
                        [[ -e "PKGBUILD" ]] && $editor "PKGBUILD" && Note "s" $"${colorW}$i${reset} PKGBUILD viewed" || Note "e" $"Could not open ${colorW}$i${reset} PKGBUILD"
                    fi
                    # show install script
                    if [[ -n "${installscripts[@]}" ]]; then
                        for j in "${installscripts[@]}"; do
                            if Proceed "y" $"View $j script?"; then
                                [[ -e "$j" ]] && $editor "$j" && Note "s" $"${colorW}$j${reset} script viewed" || Note "e" $"Could not open ${colorW}$j${reset} script"
                            fi
                        done
                    fi
                fi
            fi
        else
            # show pkgbuild and install script
            [[ -e "PKGBUILD" ]] && $editor "PKGBUILD" && Note "s" $"${colorW}$i${reset} PKGBUILD viewed" || Note "e" $"Could not open ${colorW}$i${reset} PKGBUILD"
            if [[ -n "${installscripts[@]}" ]]; then
                for j in "${installscripts[@]}"; do
                    [[ -e "$j" ]] && $editor "$j" && Note "s" $"${colorW}$j${reset} script viewed" || Note "e" $"Could not open ${colorW}$j${reset} script"
                done
            fi
        fi
    done
}

MakePkgs() {
    # download
    DownloadPkgs ${deps[@]}
    EditPkgs ${basepkgs[@]}

    # current orphan packages
    oldorphanpkgs=($($pacmanbin -Qdtq))

    # initialize sudo
    if sudo $pacmanbin -V > /dev/null; then
        [[ $sudoloop = true ]] && SudoV &
    fi

    # split packages support
    for ((i=0; i<${#pkgsbase[@]}; i++)); do
        for ((j=0; j<${#deps[@]}; j++)); do
            [[ "${pkgsbase[$i]}" = "${pkgsbase[$j]}" ]] && [[ ! " ${pkgsdeps[@]} " =~ " ${deps[$j]} " ]] && pkgsdeps+=(${deps[$j]})
        done
        pkgsdeps+=("#")
    done
    pkgsdeps=($(sed 's/ # /\n/g' <<< ${pkgsdeps[@]} | tr -d '#' | sed '/^ $/d' | tr ' ' ',' | sed 's/^,//g;s/,$//g'))

    # reverse deps order
    basepkgs=($(awk '{for (i=NF;i>=1;i--) print $i}' <<< ${basepkgs[@]} | awk -F "\n" '{print}'))
    pkgsdeps=($(awk '{for (i=NF;i>=1;i--) print $i}' <<< ${pkgsdeps[@]} | awk -F "\n" '{print}'))

    # integrity check
    for ((i=0; i<${#basepkgs[@]}; i++)); do
        # get splitted packages list
        pkgsdepslist=($(awk -F "," '{for (k=1;k<=NF;k++) print $k}' <<< ${pkgsdeps[$i]}))

        # cache check
        unset builtpkg
        if [[ -z "$(grep -E "\-(bzr|git|hg|svn)$" <<< ${basepkgs[$i]})" ]]; then
            for j in "${pkgsdepslist[@]}"; do
                depsAver="$(GetJson "varvar" "$json" "Version" "$j")"
                [[ $PKGDEST && ! $rebuild ]] && GetBuiltPkg "$j-$depsAver" "$PKGDEST"
            done
        fi

        # install vcs clients (checking pkgbase extension only does not take fetching specific commit into account)
        unset vcsclients
        vcsclients=($(grep -E "makedepends = (bzr|git|mercurial|subversion)$" "$clonedir/${basepkgs[$i]}/.SRCINFO" | awk -F " " '{print $NF}'))
        for j in "${vcsclients[@]}"; do
            if [[ ! "${vcschecked[@]}" =~ "$j" ]]; then
                [[ -z "$(expac -Qs '%n' "^$j$")" ]] && sudo $pacmanbin -S $j --asdeps --noconfirm
                vcschecked+=($j)
            fi
        done

        if [[ ! $builtpkg || $rebuild ]]; then
            cd "$clonedir/${basepkgs[$i]}"
            Note "i" $"Checking ${colorW}${pkgsdeps[$i]}${reset} integrity..."
            if [[ $silent = true ]]; then
                makepkg -f --verifysource ${makeopts[@]} &>/dev/null
            else
                makepkg -f --verifysource ${makeopts[@]}
            fi
            (( $? > 0)) && errmakepkg+=(${pkgsdeps[$i]})
            # silent extraction and pkgver update only
            makepkg -od --noprepare --skipinteg ${makeopts[@]} &>/dev/null
        fi
    done
    for i in "${errmakepkg[@]}"; do
        Note "f" $"failed to verify ${colorW}$i${reset} integrity"
    done
    [[ -n "${errmakepkg[@]}" ]] && exit 1

    # set lock
    [[ -e "$tmpdir/build.lck" ]] && Note "e" $"build.lck exists in $tmpdir" && exit 1
    touch "$tmpdir/build.lck"

    # install provider packages and repo conflicting packages that makepkg --noconfirm cannot handle
    if [[ -n "${repoprovidersconflictingpkgs[@]}" ]]; then
        Note "i" $"Installing ${colorW}${repoprovidersconflictingpkgs[@]}${reset} dependencies..."
        sudo $pacmanbin -S ${repoprovidersconflictingpkgs[@]} --ask 36 --asdeps --noconfirm
    fi

    # main
    for ((i=0; i<${#basepkgs[@]}; i++)); do

        # get splitted packages list
        pkgsdepslist=($(awk -F "," '{for (k=1;k<=NF;k++) print $k}' <<< ${pkgsdeps[$i]}))

        cd "$clonedir/${basepkgs[$i]}"

        # build devel if necessary only (supported protocols only)
        unset aurdevelpkgsAver
        if [[ -n "$(grep -E "\-(bzr|git|hg|svn)$" <<< ${basepkgs[$i]})" ]]; then
            # retrieve updated version
            aurdevelpkgsAver=($(makepkg --packagelist | awk -F "-" '{print $(NF-2)"-"$(NF-1)}'))
            aurdevelpkgsAver=${aurdevelpkgsAver[0]}

            # check split packages update
            unset basepkgsupdate checkpkgsdepslist
            for j in "${pkgsdepslist[@]}"; do
                aurdevelpkgsQver=$(expac -Qs '%v' "^$j$")
                if [[ -n $aurdevelpkgsQver && $(vercmp "$aurdevelpkgsQver" "$aurdevelpkgsAver") -ge 0 ]] && [[ $needed && ! $rebuild ]]; then
                    Note "w" $"${colorW}$j${reset} is up-to-date -- skipping"
                    continue
                else
                    basepkgsupdate='true'
                    checkpkgsdepslist+=($j)
                fi
            done
            [[ $basepkgsupdate ]] && pkgsdepslist=(${checkpkgsdepslist[@]}) || continue
        fi

        # check package cache
        for j in "${pkgsdepslist[@]}"; do
            unset builtpkg
            [[ $aurdevelpkgsAver ]] && depsAver="$aurdevelpkgsAver" || depsAver="$(GetJson "varvar" "$json" "Version" "$j")"
            [[ $PKGDEST && ! $rebuild ]] && GetBuiltPkg "$j-$depsAver" "$PKGDEST"
            if [[ $builtpkg ]]; then
                if [[ " ${aurdepspkgs[@]} " =~ " $j " || $installpkg ]]; then
                    Note "i" $"Installing ${colorW}$j${reset} cached package..."
                    sudo $pacmanbin -U $builtpkg --ask 36 ${pacopts[@]} --noconfirm
                    [[ ! " ${aurpkgs[@]} " =~ " $j " ]] && sudo $pacmanbin -D $j --asdeps ${pacopts[@]} &>/dev/null
                else
                    Note "w" $"Package ${colorW}$j${reset} already available in cache"
                fi
                pkgsdeps=($(tr ' ' '\n' <<< ${pkgsdeps[@]} | sed "s/^$j,//g;s/,$j$//g;s/,$j,/,/g;s/^$j$/#/g"))
                continue
            fi
        done
        [[ "${pkgsdeps[$i]}" = '#' ]] && continue

        # build
        Note "i" $"Building ${colorW}${pkgsdeps[$i]}${reset} package(s)..."

        # install then remove binary deps
        makeopts=(${makeopts[@]/-r/})

        if [[ ! $installpkg ]]; then
            unset isaurdeps
            for j in "${pkgsdepslist[@]}"; do
                [[ " ${aurdepspkgs[@]} " =~ " $j " ]] && isaurdeps=true
            done
            [[ $isaurdeps != true ]] && makeopts+=("-r")
        fi

        if [[ $silent = true ]]; then
            makepkg -sfc ${makeopts[@]} --noconfirm &>/dev/null
        else
            makepkg -sfc ${makeopts[@]} --noconfirm
        fi

        # error check
        if (( $? > 0)); then
            errmakepkg+=(${pkgsdeps[$i]})
            continue  # skip install
        fi

        # retrieve filename
        unset builtpkgs builtdepspkgs
        for j in "${pkgsdepslist[@]}"; do
            unset builtpkg
            [[ $aurdevelpkgsAver ]] && depsAver="$aurdevelpkgsAver" || depsAver="$(GetJson "varvar" "$json" "Version" "$j")"
            GetBuiltPkg "$j-$depsAver" "$clonedir/${basepkgs[$i]}"
            [[ " ${aurdepspkgs[@]} " =~ " $j " ]] && builtdepspkgs+=($builtpkg) || builtpkgs+=($builtpkg)
        done

        # install
        if [[ $installpkg || -z "${builtpkgs[@]}" ]]; then
            Note "i" $"Installing ${colorW}${pkgsdeps[$i]}${reset} package(s)..."
            # metadata mismatch warning
            [[ -z "${builtdepspkgs[@]}" && -z "${builtpkgs[@]}" ]] && Note "f" $"${colorW}${pkgsdeps[$i]}${reset} package(s) failed to install. Check .SRCINFO for mismatching data with PKGBUILD."
            [[ -n "${builtdepspkgs[@]}" ]] && sudo $pacmanbin -U ${builtdepspkgs[@]} --ask 36 --asdeps ${pacopts[@]} --noconfirm
            [[ -n "${builtpkgs[@]}" ]] && sudo $pacmanbin -U ${builtpkgs[@]} --ask 36 ${pacopts[@]} --noconfirm
        fi

        # set dep status
        if [[ $installpkg ]]; then
            for j in "${pkgsdepslist[@]}"; do
                [[ ! " ${aurpkgs[@]} " =~ " $j " ]] && sudo $pacmanbin -D $j --asdeps ${pacopts[@]} &>/dev/null
                [[ " ${pacopts[@]} " =~ " --asdeps " ]] && sudo $pacmanbin -D $j --asdeps ${pacopts[@]} &>/dev/null
                [[ " ${pacopts[@]} " =~ " --asexplicit " ]] && sudo $pacmanbin -D $j --asexplicit ${pacopts[@]} &>/dev/null
            done
        fi
    done

    # remove AUR deps
    if [[ ! $installpkg ]]; then
        [[ -n "${aurdepspkgs[@]}" ]] && aurdepspkgs=($(expac -Q '%n' "${aurdepspkgs[@]}"))
        if [[ -n "${aurdepspkgs[@]}" ]]; then
            Note "i" $"Removing installed AUR dependencies..."
            sudo $pacmanbin -Rsn ${aurdepspkgs[@]} --noconfirm
        fi
        # readd removed conflicting packages
        [[ -n "${aurconflictingpkgsrm[@]}" ]] && sudo $pacmanbin -S ${aurconflictingpkgsrm[@]} --ask 36 --asdeps --needed --noconfirm
        [[ -n "${repoconflictingpkgsrm[@]}" ]] && sudo $pacmanbin -S ${repoconflictingpkgsrm[@]} --ask 36 --asdeps --needed --noconfirm
    fi

    # remove locks
    [[ -e "$tmpdir/sudov.lck" ]] && rm "$tmpdir/sudov.lck"
    rm "$tmpdir/build.lck"

    # new orphan packages check
    orphanpkgs=($($pacmanbin -Qdtq))
    neworphanpkgs=($(LC_COLLATE=C comm -23 <(tr ' ' '\n' <<< ${orphanpkgs[@]} | LC_COLLATE=C sort -u) <(tr ' ' '\n' <<< ${oldorphanpkgs[@]} | LC_COLLATE=C sort -u)))
    for i in "${neworphanpkgs[@]}"; do
        Note "w" $"${colorW}$i${reset} is a ${colorY}new orphan${reset} package"
    done

    # makepkg failure check
    for i in "${errmakepkg[@]}"; do
        Note "f" $"failed to build ${colorW}$i${reset} package(s)"
    done

    # exit error code
    [[ -z "${errmakepkg[@]}" ]] && exit
}

SearchInfoAur() {
    if [[ -z "$(grep -E "\-\-[r]?sort" <<< ${coweropts[@]})" ]]; then
        [[ $sortby = votes ]] && coweropts+=("--rsort=votes");
        [[ $sortby = popularity ]] && coweropts+=("--rsort=popularity");
    fi
    cower ${coweropts[@]} $@
}

CheckRepo() {
    GetIgnoredPkgs
    repopkgsQood=($($pacmanbin -Quq $@))
    if [[ -n "${repopkgsQood[@]}" ]]; then
        [[ $quiet ]] && tr ' ' '\n' <<< ${repopkgsQood[@]} && return
        repopkgsQver=($(expac -Q '%v' "${repopkgsQood[@]}"))
        repopkgsSver=($(expac -S -1 '%v' "${repopkgsQood[@]}"))
        repopkgsSrepo=($(expac -S -1 '%r' "${repopkgsQood[@]}"))
        repopkgsQgrp=($(expac -Qv -l "#" '(%G)' "${repopkgsQood[@]}"))
        for ((i=0; i<${#repopkgsQood[@]}; i++)); do
            [[ "${repopkgsQgrp[$i]}" = '(None)' ]] && unset repopkgsQgrp[$i] || repopkgsQgrp[$i]=$(tr '#' ' ' <<< ${repopkgsQgrp[$i]})
            [[ " ${ignoredpkgs[@]} " =~ " ${repopkgsQood[$i]} " ]] && repopkgsQignore[$i]=$"[ ignored ]"
        done
        lname=$(GetLength "${repopkgsQood[@]}")
        lQver=$(GetLength "${repopkgsQver[@]}")
        lSver=$(GetLength "${repopkgsSver[@]}")
        lrepo=$(GetLength "${repopkgsSrepo[@]}")
        lgrp=$(GetLength "${repopkgsQgrp[@]}")
        for ((i=0; i<${#repopkgsQood[@]}; i++)); do
            printf "${colorB}::${reset} ${colorM}%-${lrepo}s${reset}  ${colorW}%-${lname}s${reset}  ${colorR}%-${lQver}s${reset}  ->  ${colorG}%-${lSver}s${reset}  ${colorB}%-${lgrp}s${reset}  ${colorY}%s${reset}\n" "${repopkgsSrepo[$i]}" "${repopkgsQood[$i]}" "${repopkgsQver[$i]}" "${repopkgsSver[$i]}" "${repopkgsQgrp[$i]}" "${repopkgsQignore[$i]}"
        done
    fi
}

CheckAur() {
    GetIgnoredPkgs
    aurpkgsQood=($(cower ${coweropts[@]} $@ --color=never))

    # add devel packages
    if [[ $devel ]]; then
        foreignpkgs=($($pacmanbin -Qmq))
        for i in "${foreignpkgs[@]}"; do
            [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< $i)" ]] && aurpkgsQood+=($i)
        done
    fi

    if [[ -n "${aurpkgsQood[@]}" ]]; then
        [[ $quiet ]] && tr ' ' '\n' <<< ${aurpkgsQood[@]} && return
        json=$(DownloadJson ${aurpkgsQood[@]})
        aurpkgsAname=($(GetJson "var" "$json" "Name"))    # return sorted results
        aurpkgsAver=($(GetJson "var" "$json" "Version"))
        aurpkgsQver=($(expac -Q '%v' "${aurpkgsAname[@]}"))
        for ((i=0; i<${#aurpkgsAname[@]}; i++)); do
            [[ " ${ignoredpkgs[@]} " =~ " ${aurpkgsAname[$i]} " ]] && aurpkgsQignore[$i]=$"[ ignored ]"
            [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< ${aurpkgsAname[$i]})" ]] && aurpkgsAver[$i]=$"latest"
        done
        [[ ! $lname ]] && lname=$(GetLength "${aurpkgsAname[@]}")
        [[ ! $lQver ]] && lQver=$(GetLength "${aurpkgsQver[@]}")
        [[ ! $lSver ]] && lSver=$(GetLength "${aurpkgsAver[@]}")
        [[ ! $lrepo ]] && lrepo=3
        for ((i=0; i<${#aurpkgsAname[@]}; i++)); do
            printf "${colorB}::${reset} ${colorM}%-${lrepo}s${reset}  ${colorW}%-${lname}s${reset}  ${colorR}%-${lQver}s${reset}  ->  ${colorG}%-${lSver}s${reset}  ${colorB}%-${lgrp}s${reset}  ${colorY}%s${reset}\n" "aur" "${aurpkgsAname[$i]}" "${aurpkgsQver[$i]}" "${aurpkgsAver[$i]}" " " "${aurpkgsQignore[$i]}"
        done
    fi
}

CleanCache() {
    if [[ $PKGDEST && $PKGDEST != '/var/cache/pacman/pkg/' ]]; then
        [[ $count -eq 1 ]] && printf "\n%s\n %s\n" $"Packages to keep:" $"All locally installed packages"
        printf "\n%s %s\n" $"AUR cache directory:" "$PKGDEST"
        if [[ $count -eq 1 ]]; then
            if Proceed "y" $"Do you want to remove all other packages from AUR cache?"; then
                printf "%s\n" $"removing old packages from cache..."
                paccache -ruq -k0 -c $PKGDEST
            fi
        else
            if ! Proceed "n" $"Do you want to remove ALL files from AUR cache?"; then
                printf "%s\n" $"removing all files from AUR cache..."
                paccache -rq -k0 -c $PKGDEST
            fi
        fi
    fi
    if [[ $SRCDEST ]]; then
        [[ $count -eq 1 ]] && printf "\n%s\n %s\n" $"Sources to keep:" $"All development packages sources"
        printf "\n%s %s\n" $"AUR source cache directory:" "$SRCDEST"
        if [[ $count -eq 1 ]]; then
            if Proceed "y" $"Do you want to remove all non development files from AUR source cache?"; then
                printf "%s\n" $"removing non development files from source cache..."
                rm -f $SRCDEST/* &>/dev/null
            fi
        else
            if ! Proceed "n" $"Do you want to remove ALL files from AUR source cache?"; then
                printf "%s\n" $"removing all files from AUR source cache..."
                rm -rf $SRCDEST/* &>/dev/null
            fi
        fi
    fi
}

GetIgnoredPkgs() {
    ignoredpkgs+=($(grep '^IgnorePkg' '/etc/pacman.conf' | awk -F '=' '{print $NF}' | tr -d "'\""))
    [[ -e "$HOME/.config/cower/config" ]] && ignoredpkgs+=($(grep '^IgnorePkg' "$HOME/.config/cower/config" | awk -F '=' '{print $NF}' | tr -d "'\""))
    ignoredpkgs=(${ignoredpkgs[@]//,/ })
}

GetInstallScripts() {
    [[ ! -d "$clonedir/$1" ]] && return
    unset installscriptspath installscripts
    installscriptspath=($(find "$clonedir/$1/" -maxdepth 1 -name "*.install"))
    [[ -n "${installscriptspath[@]}" ]] && installscripts=($(basename -a ${installscriptspath[@]}))
}

GetBuiltPkg() {
    # check PKGEXT suffixe first, then default .xz suffixe for repository packages in pacman cache
    # and lastly all remaining suffixes in case PKGEXT is locally overridden
    for pkgext in ${PKGEXT} .tar.xz .tar .tar.gz .tar.bz2 .tar.lzo .tar.lrz .tar.Z; do
        builtpkg="$2/$1-${CARCH}$pkgext"
        [[ ! -f "$builtpkg" ]] && builtpkg="$2/$1-any$pkgext"
        [[ -f "$builtpkg" ]] && break;
    done
    [[ ! -f "$builtpkg" ]] && unset builtpkg
}

GetPkgbase() {
    json=$(DownloadJson "$@")
    for i in "$@"; do
        pkgsbase+=($(GetJson "varvar" "$json" "PackageBase" "$i"))
    done
    for i in "${pkgsbase[@]}"; do
        [[ " ${basepkgs[@]} " =~ " $i " ]] && continue
        basepkgs+=($i)
    done
}

DownloadJson() {
    urlencodedpkgs=($(sed 's/+/%2b/g;s/@/%40/g' <<< $@)) # pkgname consists of alphanum@._+-
    urlargs="$(printf "&arg[]=%s" "${urlencodedpkgs[@]}")"
    # ensure the URI length is shorter than 8190 bytes (52 for AUR path, 13 reserved)
    if [[ "${#urlargs}" -lt 8125 ]]; then
        curl -sfg --compressed -C 0 "https://$aururl$aurrpc$urlargs"
    else
        # split and merge json stream
        urlpkgs=($@)
        urlencodedpkgs1=($(sed 's/+/%2b/g;s/@/%40/g' <<< ${urlpkgs[@]:0:$((${#urlpkgs[@]}/2))}))
        urlencodedpkgs2=($(sed 's/+/%2b/g;s/@/%40/g' <<< ${urlpkgs[@]:$((${#urlpkgs[@]}/2))}))
        urlargs1="$(printf "&arg[]=%s" "${urlencodedpkgs1[@]}")"
        urlargs2="$(printf "&arg[]=%s" "${urlencodedpkgs2[@]}")"
        curl -sfg --compressed -C 0 "https://$aururl$aurrpc$urlargs1" "https://$aururl$aurrpc$urlargs2" \
            | sed 's/\(]}{\)\([A-Za-z0-9":,]\+[[]\)/,/;s/\("resultcount":\)\([0-9]\+\)/"resultcount":0/g'
    fi
}

GetJson() {
    if json_verify -q <<< "$2"; then
        case "$1" in
            var)
                json_reformat <<< "$2" | tr -d "\", " | grep -Po "$3:.*" | sed -r "s/$3:/$3#/g" | awk -F "#" '{print $2}';;
            varvar)
                json_reformat <<< "$2" | tr -d ", " | sed -e "/\"Name\":\"$4\"/,/}/!d" | \
                tr -d "\"" | grep -Po "$3:.*" | sed -r "s/$3:/$3#/g" | awk -F "#" '{print $2}';;
            array)
                json_reformat <<< "$2" | tr -d ", " | sed -e "/^\"$3\"/,/]/!d" | tr -d '\"' \
                | tr '\n' ' ' | sed "s/] /]\n/g" | cut -d' ' -f 2- | tr -d '[]"' | tr -d '\n';;
            arrayvar)
                json_reformat <<< "$2" | tr -d ", " | sed -e "/\"Name\":\"$4\"/,/}/!d" | \
                sed -e "/^\"$3\"/,/]/!d" | tr -d '\"' | tr '\n' ' ' | cut -d' ' -f 2- | tr -d '[]';;
        esac
    else
        Note "e" "Could not connect to the AUR"
    fi
}

CheckRequires() {
    Qrequires=$(expac -Q '%n %D' | grep -E " $@[\+]*[^a-zA-Z0-9_@\.\+-]+" | awk '{print $1}' | tr '\n' ' ')
    if [[ -n "${Qrequires[@]}" ]]; then
        Note "f" $"failed to prepare transaction (could not satisfy dependencies)"
        Note "e" $"${Qrequires[@]}: requires $@"
    fi
}

Proceed() {
    Y="$(gettext pacman Y)"; y="${Y,,}";
    N="$(gettext pacman N)"; n="${N,,}"
    case "$1" in
        y)  printf "${colorB}%s${reset} ${colorW}%s${reset}" "::" $"$2 [Y/n] "
            read -n 1 answer
            echo
            case $answer in
                $Y|$y|'') return 0;;
                *) return 1;;
            esac;;
        n)  printf "${colorB}%s${reset} ${colorW}%s${reset}" "::" $"$2 [y/N] "
            read -n 1 answer
            echo
            case $answer in
                $N|$n|'') return 0;;
                *) return 1;;
            esac;;
    esac
}

Note() {
    case "$1" in
        i) echo -e "${colorB}::${reset} $2";;       # info
        s) echo -e "${colorG}::${reset} $2";;       # success
        w) echo -e "${colorY}::${reset} $2";;       # warn
        f) echo -e "${colorR}::${reset} $2" >&2;;   # fail
        e) echo -e "${colorR}::${reset} $2" >&2;    # error
           exit 1;;
    esac
}

GetLength() {
    local length=0
    for i in "$@"; do
        x=${#i}
        [[ $x -gt $length ]] && length=$x
    done
    echo $length
}

NothingToDo() {
    [[ -z "$@" ]] && printf "%s\n" $" there is nothing to do" && exit || return 0
}

SudoV() {
    touch "$tmpdir/sudov.lck"
    while [[ -e "$tmpdir/sudov.lck" ]]; do
        sudo $pacmanbin -V > /dev/null
        sleep 2
    done
}

trap Cancel INT
Cancel() {
    echo
    [[ -e "$tmpdir/sudov.lck" ]] && rm "$tmpdir/sudov.lck"
    [[ -e "$tmpdir/build.lck" ]] && rm "$tmpdir/build.lck"
    exit
}

Usage() {
    printf "%s\n" $"usage:  pacaur <operation> [options] [target(s)] -- See also pacaur(8)"
    printf "%s\n" $"operations:"
    printf "%s\n" $" pacman extension"
    printf "%s\n" $"   -S, -Q           extend pacman operations to the AUR"
    printf "%s\n" $" AUR specific"
    printf "%s\n" $"   -s, --search     search AUR for matching strings"
    printf "%s\n" $"   -i, --info       view package information"
    printf "%s\n" $"   -d, --download   download target(s) -- pass twice to download AUR dependencies"
    printf "%s\n" $"   -m, --makepkg    download and make target(s)"
    printf "%s\n" $"   -y, --sync       download, make and install target(s)"
    printf "%s\n" $"   -k, --check      check for AUR update(s)"
    printf "%s\n" $"   -u, --update     update AUR package(s)"
    printf "%s\n" $" general"
    printf "%s\n" $"   -v, --version    display version information"
    printf "%s\n" $"   -h, --help       display help information"
    echo
    printf "%s\n" $"options:"
    printf "%s\n" $" pacman extension - can be used with the -S, -Ss, -Si, -Sii, -Sw, -Su, -Qu, -Sc, -Scc operations"
    printf "%s\n" $"   -a, --aur        only search, build or install target(s) from the AUR"
    printf "%s\n" $"   -r, --repo       only search, build or install target(s) from the repositories"
    printf "%s\n" $" general"
    printf "%s\n" $"   -e, --edit       edit target(s) PKGBUILD and view install script"
    printf "%s\n" $"   -q, --quiet      show less information for query and search"
    printf "%s\n" $"   --devel          consider AUR development packages upgrade"
    printf "%s\n" $"   --foreign        consider already installed foreign dependencies"
    printf "%s\n" $"   --ignore         ignore a package upgrade (can be used more than once)"
    printf "%s\n" $"   --needed         do not reinstall already up-to-date target(s)"
    printf "%s\n" $"   --noconfirm      do not prompt for any confirmation"
    printf "%s\n" $"   --noedit         do not prompt to edit files"
    printf "%s\n" $"   --rebuild        always rebuild package(s)"
    printf "%s\n" $"   --silent         silence output"
    echo
}

Version() {
    echo "pacaur $version"
}

#
# Main
#

# get short arguments
args=($@)
for i in "${args[@]}"; do
    [[ "$i" =~ ^-[a-zA-Z0-9] ]] && opts+=($i)
done

# get options
count=0
while [[ -n "${!OPTIND}" ]]; do
    while getopts "sidmykufecqrahvxVDFQRSTUbglnoptw-:" OPT; do
        pacmanarg+=("-$OPT");
        case "$OPT" in
            -)
                case "$OPTARG" in
                    search) operation=sync; search=true; coweropts+=("-s"); aur='1';;
                    info) operation=sync; info=true; coweropts+=("-i"); aur='1';;
                    download) operation=download && ((count++));;
                    makepkg) operation=sync; coweropts+=("-f"); aur='1';;
                    sync) operation=sync; installpkg=true; coweropts+=("-f"); aur='1';;
                    check) operation=upgrades; coweropts+=("-uq"); aur='1';;
                    update) operation=sync; upgrade=true; installpkg=true; coweropts+=("-f"); selective=true; aur='1';;
                    force) coweropts+=("-f"); pacopts+=("--force");;
                    edit) edit=true; [[ ! $pacQ && ! $operation ]] && operation=editpkg;;
                    quiet) quiet=true; pacopts+=("--quiet"); coweropts+=("-q"); color=never;;
                    repo) repo='1';;
                    aur) aur='1';;
                    devel) devel=true;;
                    foreign) foreign=true;;
                    ignore) ignoredpkgs+=(${!OPTIND}); ignoreopts+=("--ignore ${!OPTIND}"); shift;;
                    color) color=${!OPTIND}; pacopts+=("--color ${!OPTIND}") && coweropts+=("--color=${!OPTIND}"); shift;;
                    ignore-ood) coweropts+=("--ignore-ood");;
                    no-ignore-ood) coweropts+=("--no-ignore-ood");;
                    ignorerepo=*) coweropts+=("--${OPTARG}");;
                    asort) coweropts+=("--sort=name");;
                    vsort) coweropts+=("--rsort=votes");;
                    psort) coweropts+=("--rsort=popularity");;
                    asdep|asdeps) pacopts+=("--asdeps"); makeopts+=("--asdeps");;
                    needed) needed=true; pacopts+=("--needed"); makeopts+=("--needed");;
                    nodeps) nodeps=true; pacopts+=("--nodeps"); makeopts+=("--nodeps"); ((count++));;
                    assume-installed) assumeinstalled+=(${!OPTIND}); pacopts+=("--assume-installed ${!OPTIND}"); shift;;
                    noconfirm) noconfirm=true; pacopts+=("--noconfirm");;
                    noedit) noedit=true;;
                    rebuild) rebuild=true;;
                    silent) silent=true; makeopts+=("--log");;
                    domain) aururl=${!OPTIND}; coweropts+=("--domain ${!OPTIND}"); shift;;
                    root) pacopts+=("--root ${!OPTIND}"); shift;;
                    version) Version; exit;;
                    help) Usage; exit;;
                    *) pacopts+=("--$OPTARG");;
                esac;;
            s)  [[ $pacS ]] && operation=sync && search=true && coweropts+=("-s");
                [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; search=true; coweropts+=("-s"); aur='1';;
            i)  [[ $pacS ]] && operation=sync && info=true && coweropts+=("-i");
                [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; info=true; coweropts+=("-i"); aur='1';;
            d)  [[ $pacS ]] && nodeps=true && pacopts+=("--nodeps") && makeopts+=("--nodeps") && ((count++));
                [[ $pac || $pacQ || $pacS ]] && continue || operation=download && ((count++));;
            m)  [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; coweropts+=("-f"); aur='1';;
            y)  [[ $pacS ]] && operation=sync && refresh=true;
                [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; installpkg=true; coweropts+=("-f"); aur='1';;
            k)  [[ $pac || $pacQ || $pacS ]] && continue || operation=upgrades; coweropts+=("-uq"); aur='1';;
            u)  [[ $pacQ ]] && operation=upgrades && coweropts+=("-uq");
                [[ $pacS ]] && operation=sync && upgrade=true && coweropts+=("-f");
                [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; upgrade=true; installpkg=true; coweropts+=("-f"); selective=true; aur='1';;
            f)  [[ $pac || $pacQ || $pacS ]] && continue || coweropts+=("-f");;
            e)  [[ $pacQ ]] && pacopts+=("--explicit") && continue || edit=true;
                [[ ! $operation ]] && operation=editpkg;;
            c)  [[ $pacS ]] && operation=sync && cleancache=true && ((count++));
                [[ $pac || $pacQ || $pacS ]] && continue;;
            q)  quiet=true; pacopts+=("--quiet"); coweropts+=("-q"); color=never;;
            r)  repo='1';;
            a)  aur='1';;
            Q)  pacQ='1';;
            S)  pacS='1'; operation=sync; coweropts+=("-f");
                [[ "${opts[@]}" =~ "w" ]] && continue || installpkg=true;
                [[ "${opts[@]}" =~ "g" || "${opts[@]}" =~ "l" || "${opts[@]}" =~ "p" ]] && unset operation;;
            [A-Z]) pac='1';;
            h)  [[ "${opts[@]}" =~ ^-[A-Z] ]] && unset operation && continue || Usage; exit;;
            v)  [[ "${opts[@]}" =~ ^-[A-Z] ]] && continue || Version; exit;;
            *)  continue;;
        esac
    done
    # packages
    [[ -z "${!OPTIND}" ]] && break || pkgs+=(${!OPTIND})
    shift $OPTIND
    OPTIND=1
done

# color
if [[ -n "$(grep '^Color' '/etc/pacman.conf')" && $color != 'never' ]]; then
    [[ $color = 'always' ]] && coweropts+=("--color=always") || coweropts+=("--color=auto")
    reset="\e[0m"
    colorR="\e[1;31m"
    colorG="\e[1;32m"
    colorY="\e[1;33m"
    colorB="\e[1;34m"
    colorM="\e[1;35m"
    colorW="\e[1;39m"
elif [[ -z "$(grep '^Color' '/etc/pacman.conf')" && ($color = 'always' || $color = 'auto') ]]; then
    pacopts+=("--color $color") && coweropts+=("--color=$color")
    reset="\e[0m"
    colorR="\e[1;31m"
    colorG="\e[1;32m"
    colorY="\e[1;33m"
    colorB="\e[1;34m"
    colorM="\e[1;35m"
    colorW="\e[1;39m"
else
    [[ $color != 'always' && $color != 'auto' ]] && makeopts+=("--nocolor")
fi

# sanity check
pacmanarg=(${pacmanarg[@]/--/})
pacmanarg=(${pacmanarg[@]/-r/})
pacmanarg=(${pacmanarg[@]/-a/})
[[ $operation = sync && ! $search && ! $info && ! $cleancache ]] && [[ "$EUID" -eq 0 ]] && Note "e" $"you cannot perform this operation as root"
[[ $pacS ]] && pacmanarg=(${pacmanarg[@]/-e/})
[[ $pacS ]] && [[ $search && $info ]] && coweropts=(${coweropts[@]/-i/})
[[ $pacS ]] && [[ $cleancache ]] && unset search info upgrade
[[ ! $editor ]] && [[ ! -f /usr/bin/vi ]] && Note "e" $"${colorW}editor${reset} variable unset"
[[ $operation = sync && ! $search && ! $info && ! $cleancache ]] && [[ $displaybuildfiles = diff && $clonedir = $tmpdir ]] && Note "e" $"${colorW}clonedir${reset} or ${colorW}\$AURDEST${reset} should be set to a non volatile memory location"
[[ ! -w "$clonedir" ]] && Note "e" $"${colorW}$clonedir${reset} does not have write permission."
[[ -z "${pkgs[@]}" ]] && [[ $operation = download || $operation = sync || $operation = editpkg ]] && [[ ! $refresh && ! $upgrade && ! $cleancache ]] && Note "e" $"no targets specified (use -h for help)"
[[ $repo && $aur ]] && Note "e" $"target not found"

# operations
case $operation in
    download)
        # download (-d) handling
        if [[ $count -gt 1 ]]; then
            ClassifyPkgs ${pkgs[@]}
            DepsSolver
            DownloadPkgs ${deps[@]}
        else
            DownloadPkgs ${pkgs[@]}
        fi
        EditPkgs ${pkgsbase[@]}
        exit;;
    editpkg)
        # edit (-e) handling
        GetPkgbase ${pkgs[@]}
        EditPkgs ${pkgsbase[@]}
        exit;;
    sync)
        # search (-Ss, -s) handling
        if [[ $search ]]; then
            if [[ ! $aur ]]; then
                [[ $refresh ]] && sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${pkgs[@]}
                [[ ! $refresh ]] && $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${pkgs[@]}
            fi
            [[ ! $repo ]] && [[ $fallback = true || $aur ]] && SearchInfoAur ${pkgs[@]}
        # info (-Si, -i) handling
        elif [[ $info ]]; then
            [[ -z "${pkgs[@]}" ]] && $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} || ClassifyPkgs ${pkgs[@]}
            if [[ -n "${repopkgs[@]}" ]]; then
                [[ $refresh ]] && sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
                [[ ! $refresh ]] && $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
            fi
            if [[ -n "${aurpkgs[@]}" ]]; then
                [[ $refresh ]] && [[ -z "${repopkgs[@]}" ]] && sudo $pacmanbin -Sy ${pacopts[@]} ${ignoreopts[@]}
                [[ $fallback = true && ! $aur ]] && Note "w" $"Package(s) ${colorW}${aurpkgs[*]}${reset} not found in repositories, trying ${colorM}AUR${reset}..."
                SearchInfoAur ${aurpkgs[@]}
            fi
        # clean (-Sc) handling
        elif [[ $cleancache ]]; then
            [[ ! $aur ]] && sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
            [[ ! $repo ]] && [[ $fallback = true || $aur ]] && CleanCache ${pkgs[@]}
        # sysupgrade (-Su, -u) handling
        elif [[ $upgrade ]]; then
            [[ ! $selective ]] && ClassifyPkgs ${pkgs[@]} && unset pkgs # selective upgrade switch
            [[ ! $aur ]] && sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
            [[ ! $repo ]] && [[ $aur ]] && [[ $refresh ]] && [[ -z "${repopkgs[@]}" ]] && sudo $pacmanbin -Sy ${pacopts[@]} ${ignoreopts[@]}
            [[ -n "${aurpkgs[@]}" ]] && [[ $fallback = true && ! $aur ]] && Note "w" $"Package(s) ${colorW}${aurpkgs[*]}${reset} not found in repositories, trying ${colorM}AUR${reset}..."
            [[ ! $repo ]] && [[ $fallback = true || $aur ]] && Core ${aurpkgs[@]}
        # sync (-S, -y), downloadonly (-Sw, -m), refresh (-Sy)
        else
            [[ -z "${pkgs[@]}" ]] && sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} || ClassifyPkgs ${pkgs[@]}
            [[ -n "${repopkgs[@]}" ]] && sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
            if [[ -n "${aurpkgs[@]}" ]]; then
                [[ $refresh ]] && [[ -z "${repopkgs[@]}" ]] && sudo $pacmanbin -Sy ${pacopts[@]} ${ignoreopts[@]}
                [[ $fallback = true && ! $aur ]] && Note "w" $"Package(s) ${colorW}${aurpkgs[*]}${reset} not found in repositories, trying ${colorM}AUR${reset}..."
                Core ${aurpkgs[@]}
            fi
        fi
        exit;;
    upgrades)
        # upgrades (-Qu, -k) handling
        [[ ! $aur ]] && CheckRepo ${pkgs[@]}
        [[ ! $repo ]] && [[ $fallback = true || $aur ]] && CheckAur ${pkgs[@]}
        exit;;
    *)  # others operations handling
        if [[ -z "${pkgs[@]}" && -n "$(grep -e "-[F]" <<< ${pacmanarg[@]})" && -n "$(grep -e "-[y]" <<< ${pacmanarg[@]})" ]]; then
            sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${pkgs[@]}
        elif [[ -z "${pkgs[@]}" || -n "$(grep -e "-[DFQTglp]" <<< ${pacmanarg[@]})" ]] && [[ ! " ${pacopts[@]} " =~ " --asdeps " && ! " ${pacopts[@]} " =~ " --asexp " ]]; then
            $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${pkgs[@]}
        else
            sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${pkgs[@]}
        fi
        exit;;
esac
# vim:set ts=4 sw=2 et:
