#compdef yum

# Main dispatcher
_yum() 
{
	local curcontext="$curcontext" state lstate line

	_arguments -s \
	   {-h,--help}'[show the help message]' \
	   {-t,--tolerant}'[be tolerant of errors]' \
	   '-C[Run entirely from cache]' \
	   '-c[Config file location]:Yum conf file:_files' \
	   '-R[Maximum command wait time (in minutes)]:Max wait time' \
	   '-d[Debug level (0-10)]:Debug level' \
	   '-e[Error level (0-10)]:Error level' \
	   '-y[Answer yes for all questions]' \
	   '--installroot=[Set install root]:Install Root:_files -/' \
	   '*--enablerepo=[Enable or or more repositories]:Repos to enable:_yum_disabled_repos_list' \
	   '*--disablerepo=[Disable one or more repositories]:Disable Repos:_yum_enabled_repos_list' \
	   '--exclude=[Exclude package(s) by name or glob]:Exclude Packages' \
	   '--version[Show yum version]' \
	   '--obseletes[Enable obsoletes processing during updates]' \
	   '--noplugins[Disable yum plugins]' \
	   '*::yum command:_yum_command'
}

(( $+functions[_yum_command] )) || _yum_command() 
{
  	local -a _yum_cmds
  	_yum_cmds=(
		"install:Install the latest version of a package or group of packages"
		"erase:Remove an installed package (with its dependencies)"
		"remove:Remove an installed package (with its dependencies)"
		"clean:Clean local yum cache"
		"deplist:Gives a list of all dependencies for a package"
		"check-update:Check if any updates are available"
		"info:Get description of available packages"
		"list:Is used to list various information about packages"
		"groupinfo:Get info on package groups"
		"groupinstall:Install a package group or groups"
		"groupremove:Remove a package group or groups"
		"grouplist:List package groups"
		"groupupdate:Update a package group or groups"
		"localinstall:Install packages with local rpm files"
		"localupdate:Update packages with local rpm files"
		"makecache:Makes a local yum cache"
		"provides:Find out which package provides some feature or file"
		"whatprovides:Find out which package provides some feature or file"
		"resolvedep:List packages providing the specified dependencies"
		"search:Find any packages matching pattern"
		"shell:Enter the 'yum shell'"
		"update:Update one or more packages"
		"upgrade:Upgrade one or more packages"
  	)

  	if (( CURRENT == 1 )); then
		_describe -t commands 'yum command' _yum_cmds || compadd "$@"
  	else
    	local curcontext="$curcontext"

	    cmd="${${_yum_cmds[(r)$words[1]:*]%%:*}}"
		# Deal with any aliases
		case $cmd in
			remove) cmd="erase";;
			whatprovides) cmd="provides";;
			upgrade) cmd="update";;
		esac
		
    	if (( $#cmd )); then
    		curcontext="${curcontext%:*:*}:yum-${cmd}:"
	
	      	local update_policy
		  	zstyle -s ":completion:${curcontext}:" cache-policy update_policy
		  	if [[ -z "$update_policy" ]]; then
				zstyle ":completion:${curcontext}:" cache-policy _yum_caching_policy
	  		fi

      		_call_function ret _yum_$cmd || _message 'no more arguments'
    	else
      		_message "unknown yum command: $words[1]"
    	fi
    	return ret
  	fi
}

# Fills the installed pkg cache
_yum_all_pkgs()
{
	if ( [[ ${+_all_pkgs} -eq 0 ]] || _cache_invalid ALL ) &&
		! _retrieve_cache ALL;
	then
		local prog="yum -C list all | sed 's/\s.*//' | grep '\.'"
		_all_pkgs=( $(kages $prog 2>/dev/null) )
		_store_cache ALL _all_pkg
	fi
}

# Fills the installed pkg cache
_yum_installed_pkgs()
{
	if ( [[ ${+_installed_pkgs} -eq 0 ]] || _cache_invalid INSTALLED ) &&
		! _retrieve_cache INSTALLED;
	then
		_installed_pkgs=( $(yum -C list installed | sed 's/\s.*//' | grep '\.' 2>/dev/null) )
		_store_cache INSTALLED _installed_pkgs
	fi
}

# Fills the available pkg cache
_yum_available_pkgs()
{
	if ( [[ ${+_available_pkgs} -eq 0 ]] || _cache_invalid AVAILABLE ) &&
		! _retrieve_cache AVAILABLE;
	then
		_available_pkgs=( $(yum -C list available | sed 's/\s.*//' | grep '\.' 2>/dev/null) )
		_store_cache AVAILABLE _available_pkgs
	fi
}

# Fills the upgrade pkg cache
_yum_upgrade_pkgs()
{
	if ( [[ ${+_upgrade_pkgs} -eq 0 ]] || _cache_invalid UPGRADE ) &&
		! _retrieve_cache UPGRADE;
	then
		_upgrade_pkgs=( $(yum -C list upgrade | sed 's/\s.*//' | grep '\.' 2>/dev/null) )
		_store_cache UPGRADE _upgrade_pkgs
	fi
}

# Gets the list of defined repos
yum_repos() {
    local trepo
    local -a tarray
    tarray=( $(egrep -h '(^\[.*\]|^enabled.*=)' /etc/yum.repos.d/*.repo /etc/yum.conf | sed -e 's/ //g' | sed -e 's/\[//g' | sed -e 's/\].*$//g' 2>/dev/null) )
    local -i eindex=0
    local -i dindex=0
    for line in $tarray; do
        if [[ "$line" = "enabled=1" ]]; then
            enabled_yum_repos=($enabled_yum_repos $trepo)
        elif [[ "$line" = "enabled=0" ]]; then
            disabled_yum_repos=($disabled_yum_repos $trepo)
        elif [[ "$line" != "main" ]]; then
            trepo=$line
        fi
    done
}

(( $+functions[_yum_disabled_repos_list] )) || _yum_disabled_repos_list()
{
	yum_repos			
	compadd "$@" -a -- disabled_yum_repos
}

(( $+functions[_yum_enabled_repos_list] )) || _yum_enabled_repos_list()
{
	yum_repos			
	compadd "$@" -a -- enabled_yum_repos
}

# Completion function for erase|remove
(( $+functions[_yum_erase] )) || _yum_erase()
{
	_yum_installed_pkgs
	compadd "$@" -a -- _installed_pkgs
}

# Completion function for install
(( $+functions[_yum_install] )) || _yum_install()
{
	_yum_available_pkgs
	compadd "$@" -a -- _available_pkgs
}

# Completion function for localinstall
(( $+functions[_yum_localinstall] )) || _yum_localinstall()
{
	_files -g '(#i)*.rpm(-.)'
}

# Completion function for localupdate
(( $+functions[_yum_localupdate] )) || _yum_localupdate()
{
	_files -g '(#i)*.rpm(-.)'
}

# Completion function for update/upgrade
(( $+functions[_yum_update] )) || _yum_update()
{
	_yum_upgrade_pkgs
	compadd "$@" -a -- _upgrade_pkgs
}

# Completion function for deplist
(( $+functions[_yum_deplist] )) || _yum_deplist()
{
	_yum_available_pkgs
	compadd "$@" -a -- _available_pkgs
}

_yum_all()
{
	_yum_all_pkgs
	compadd "$@" -a -- _all_pkgs
}
_yum_list_or_info()
{
	local -a listlist
	listlist=(
		"all:all packages in repositories"
		"available:packages available in repositories"
		"updates:packages with updates available"
		"installed:installed packages"
		"extras:packages installed that are not available in any yum repository"
		"obsoletes:packages installed that are obsoleted"
		"recent:packages recently added to repositories"
	)
	
  	if (( CURRENT == 2 )); then
		_describe -t yum-list-subcmds "Yum info/list sub-commands" listlist || _yum_all
	else
	    local subcmd
		subcmd="${${listlist[(r)$words[2]:*]%%:*}}"
		# Deal with any aliases
		case $subcmd in
			installed) _yum_erase;;
			available) _yum_install;;
			updates) _yum_update;;
		esac
	fi
}

# Completion function for list
(( $+functions[_yum_list] )) || _yum_list()
{
	_yum_list_or_info
}

# Completion function for info
(( $+functions[_yum_info] )) || _yum_info()
{
	_yum_list_or_info
}

# Completion function for provides|whatprovides
(( $+functions[_yum_provides] )) || _yum_provides()
{
	_files	
}

# Completion function for resolvedep
(( $+functions[_yum_resolvedep] )) || _yum_resolvedep()
{
	_files	
}

# Completion function for clean
(( $+functions[_yum_clean] )) || _yum_clean()
{
	local -a cleanlist
	cleanlist=(
		"all:all cache"
		"cache:all cache"
		"dbcache:DB cache"
		"headers:cache headers"
		"packages:cache packages"
		"metadata:cache meta-data"
	)
	
  	if (( CURRENT == 2 )); then
		_describe -t yum-clean-subcmds "Yum clean sub-commands" cleanlist 
	fi
}

_yum_caching_policy() 
{
	local _yumrepomds

  	# rebuild if cache is more than a week old
  	oldp=( "$1"(mw+1) )
  	(( $#oldp )) && return 0

  	_yumrepomds=( /var/cache/yum/**/repomd.xml )

  	if (( $#_yumrepomds )); then
    	for repo in $_yumrepomds; do
      		[[ "$repo" -nt "$1" ]] && return 0
    	done
  	fi

  	return 1
}

_yum "$@"
