#compdef symfony
# ------------------------------------------------------------------------------
# Description
# -----------
#
#  Completion script for Symfony (http://www.symfony-project.org).
#
# ------------------------------------------------------------------------------
# Authors
# -------
#
#  * aki77 (https://github.com/aki77)
#
# ------------------------------------------------------------------------------
# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
# vim: ft=zsh sw=2 ts=2 et
# ------------------------------------------------------------------------------


_symfony () {
    local curcontext="$curcontext" state line expl ret=1 cache_version

    cache_version=$(_get_sf_cache_var version)
    (( ${(P)+cache_version} == 0 )) && {
        eval $cache_version=${${${(z)$($service -V)}[3]}%.*}
    }

    if [ ${(P)cache_version} = "1.0" ] ; then
        _symfony10
        return
    fi

    _arguments -C \
        '(-T --tasks)'{-T,--tasks}'[list of the symfony tasks]' \
        '(-V --version)'{-V,--version}'[version]' \
        '1: :->tasks' \
        '*:: :->args' && ret=0

    case $state in
        tasks)
            _sf_tasks
            ;;
        args)
            local task args

            task=$words[1]
            args=(
                ${${${${${(M)${${${(z)${${"$($service help $task)"#*Usage:}#[[:cntrl:]]}%%[[:cntrl:]]*}//\[/}//\]/}:#--*}%%\"*}/=/"=-"}/(#b)--(app|application)=-/--$match[1]=-:application:_sf_apps}//(#b)--(env|environment)=-/--$match[1]=-:environment:_sf_environments}
            )

            case $task in
                help)
                    args+=(
                        ':task:_sf_tasks'
                    )
                    ;;

                app:routes)
                    args+=(
                        ':application:_sf_apps'
                        ':"route name":'
                    )
                    ;;

                configure:author)
                    _message 'project author'
                    ;;

                configure:database)
                    _message 'database dsn'
                    ;;

                generate:app)
                    _message 'new application name'
                    ;;

                generate:module)
                    args+=(
                        ':application:_sf_apps'
                        ':"new module name":'
                    )
                    ;;

                generate:project)
                    _message 'new project name'
                    ;;

                generate:task)
                    _message 'new task name'
                    ;;

                i18n:extract)
                    args+=(
                        ':application:_sf_apps'
                        ':"target culture":'
                    )
                    ;;

                i18n:find)
                    args+=(
                        ':application:_sf_apps'
                    )
                    ;;

                log:rotate)
                    args+=(
                        ':application:_sf_apps'
                        ':environment:_sf_environments'
                    )
                    ;;

                plugin:add-channel)
                    _message 'channel name'
                    ;;

                plugin:install)
                    _message 'plugin name'
                    ;;

                plugin:publish-assets)
                    args+=(
                        ':plugin:_sf_plugins'
                    )
                    ;;

                plugin:uninstall)
                    _message 'plugin name'
                    ;;

                plugin:upgrade)
                    _message 'plugin name'
                    ;;

                project:deploy)
                    _message 'server name'
                    ;;

                project:disable|project:enable)
                    args+=(
                        ':environment:_sf_environments'
                        '*:application:_sf_apps'
                    )
                    ;;

                project:optimize)
                    args+=(
                        ':application:_sf_apps'
                        ':environment:_sf_environments'
                    )
                    ;;

                propel:data-dump|doctrine:data-dump)
                    _message 'target filename'
                    ;;

                propel:data-load|doctrine:data-load)
                    args+=(
                        '*:file:_files'
                    )
                    ;;

                propel:generate-admin)
                    args+=(
                        ':application:_sf_apps'
                        ':model:_sf_models'
                    )
                    ;;

                propel:generate-module|propel:init-admin)
                    args+=(
                        ':application:_sf_apps'
                        ':module:_sf_modules_candidate'
                        ':model:_sf_models'
                    )
                    ;;

                propel:generate-module-for-route|doctrine:generate-module-for-route)
                    args+=(
                        ':application:_sf_apps'
                        ':"route name":'
                    )
                    ;;

                doctrine:create-model-tables|doctrine:delete-model-files)
                    args+=(
                        '*:model:_sf_doctrine_models'
                    )
                    ;;

                doctrine:generate-admin)
                    args+=(
                        ':application:_sf_apps'
                        '*:model:_sf_doctrine_models'
                    )
                    ;;

                doctrine:generate-module)
                    args+=(
                        ':application:_sf_apps'
                        ':module:_sf_doctrine_modules_candidate'
                        ':model:_sf_doctrine_models'
                    )
                    ;;

                test:coverage)
                    args+=(
                        '*:file:_files'
                    )
                    ;;

                test:functional)
                    args+=(
                        ':application:_sf_apps'
                        '*:test:_sf_functionaltests'
                    )
                    ;;

                test:unit)
                    args+=(
                        '*:test:_sf_unittests'
                    )
                    ;;

            esac

            _arguments "$args[@]" && ret=0
            return
            ;;
    esac
    return ret
}

_symfony10 () {
    local curcontext="$curcontext" state line expl ret=1

    _arguments -C \
        '(-T --tasks)'{-T,--tasks}'[list of the symfony tasks]' \
        '(-V --version)'{-V,--version}'[version]' \
        '1: :->tasks' \
        '*:: :->args' && ret=0

    case $state in
        tasks)
            _sf10_tasks
            ;;
        args)
            local task args

            task=$words[1]
            args=()

            case $task in
                init-project)
                    _message 'new project name'
                    ;;

                init-app)
                    _message 'application name'
                    ;;

                init-module)
                    args+=(
                        ':application:_sf_apps'
                    )
                    ;;

                init-batch)
                    args+=(
                        ':skeleton name:compadd default rotate'
                        ':"script name":'
                        ':application:_sf_apps'
                    )
                ;;

                init-controller)
                    args+=(
                        ':application:_sf_apps'
                        ':environment:_sf_environments'
                        ':"script name":'
                        ':"debug?":compadd true false'
                    )
                    ;;

                log-rotate)
                    args+=(
                        ':application:_sf_apps'
                        ':environment:_sf_environments'
                    )
                    ;;

                propel-load-data|propel-build-all-load)
                    args+=(
                        ':application:_sf_apps'
                        ':environment:_sf_environments'
                        ':fixtures:_sf_fixtures'
                    )
                    ;;

                clear-cache|cc)
                    args+=(
                        ':application:_sf_apps'
                        ':what:compadd template config'
                    )
                    ;;

                sync)
                    args+=(
                        ':environment:_sf_environments'
                        ':"real run?":compadd go'
                    )
                ;;

                propel-init-crud|propel*-init-admin|propel-generate-crud)
                    args+=(
                        ':application:_sf_apps'
                        ':module:_sf_modules_candidate'
                        ':model:_sf_models'
                    )
                    ;;

                doctrine-init-admin|doctrine-generate-crud)
                    args+=(
                        ':application:_sf_apps'
                        ':module:_sf_doctrine_modules_candidate'
                        ':model:_sf_doctrine_models'
                    )
                ;;

                test-unit)
                    args+=(
                        ':test:_sf_unittests'
                    )
                    ;;

                test-functional)
                   args+=(
                        ':application:_sf_apps'
                        ':test:_sf_functionaltests'
                    )
                ;;

            esac

            _arguments "$args[@]" && ret=0
            return
            ;;
    esac
    return ret
}

_sf_tasks () {
    local tmp ns line cache_task

    cache_task=$(_get_sf_cache_var task)
    (( ${(P)+cache_task} == 0 )) && {
        tmp=(
            ${${${(f)${"$($service -T)"##*Available tasks:}}##[[:blank:]][[:blank:]]}%%[[:blank:]]*}
        )
        eval "$cache_task=()"
        ns=''

        for line in $tmp; do
            if [ $line[1] = ":" ] ; then
                eval "$cache_task+=( ${ns}${line#:} )"
            else
                ns="${line}:"
            fi
        done
    }

    _wanted symfony-task expl 'Symfony task' compadd -a $cache_task
}

_sf10_tasks () {
    local sf_tasks

    sf_tasks=(
        ${${${(f)${"$($service -T)"#available pake tasks:}%%task aliases:*}#[[:blank:]][[:blank:]]}/[[:blank:]]*>[[:blank:]]/:}
    )

    _describe -t symfony-tasks 'Symfony task' sf_tasks
}

_sf_apps () {
    _wanted application expl 'application' compadd \
        ${$(echo apps/*):t}
}

_sf_environments () {
    local app

    app=$([ -f apps/"$words[2]"/config/settings.yml ] && echo $words[2] || echo frontend)
    if [ -r apps/$app/config/settings.yml ] ; then
        _wanted environment expl 'environment' compadd \
            ${${${(M)${(@f)"$(<apps/$app/config/settings.yml)"}:#[[:alpha:]]*}%%:*}:#all}
    fi
}

_sf_plugins () {
    _wanted application expl 'plugin' compadd \
        ${$(echo plugins/*):t}
}

_sf_models () {
    _wanted application expl 'model' compadd \
        $(_get_sfmodels)
}

_sf_doctrine_models () {
    _wanted model expl 'model' compadd \
        $(_get_sf_doctrine_models)
}


_sf_modules_candidate () {
    _wanted module expl 'module' compadd \
        ${$(_get_sfmodels):l}
}

_sf_doctrine_modules_candidate () {
    _wanted module expl 'module' compadd \
        ${$(_get_sf_doctrine_models):l}
}

_sf_unittests () {
    _wanted test expl 'test' compadd \
        ${${${$(echo test/unit/**/*Test.php):r}#test/unit/}%Test}
}

_sf_functionaltests () {
    _wanted test expl 'test' compadd \
        ${${$(echo test/functional/$words[2]/*ActionsTest.php):t:r}%Test}
}

_sf_fixtures () {
    _files -W $(pwd)/data
}

_get_sfmodels () {
    echo ${${$(echo lib/model/*Peer.php):t:r}%Peer}
}

_get_sf_doctrine_models () {
    echo ${${$(echo lib/model/doctrine/*Table.class.php):t:r:r}%Table}
}

_get_sf_cache_var () {
    echo ${$(echo "_sf_cache_${(j:_:)@}$(pwd)")//[^[:alnum:]]/_}
}

_symfony "$@"