<?php

/*
   * This file is part of the symfony package.
   * (c) 2008-2009 WaterProof SARL <http://www.waterproof.fr>
   *
   * For the full copyright and license information, please view the LICENSE
   * file that was distributed with this source code.
*/

/**
 * Lists tasks into XML format.
 *
 * @package wpListXMLTaskPlugin
 * @author Nicolas Dubois <ndubois@waterproof.fr>
 * @version SVN: $Id: wpListXMLTask.class.php 18 2009-02-04 10:11:32Z ndubois $
 */
class wpListXMLTask extends sfCommandApplicationTask {
    const VERSION = '1.1.0';

    /**
     *
     * @see sfTask
     */
    protected function configure() {
        $this->name = 'list-xml';
        $this->briefDescription = 'Lists tasks in an XML format';

        $this->detailedDescription = <<<END_OF_DESCRIPTION
The [list-xml|INFO] task lists all tasks into XML format:

  [./symfony list-xml|INFO]
END_OF_DESCRIPTION;
    }

    /**
     *
     * @see sfTask
     */
    protected function execute($arguments = array(), $options = array()) {
        $tasks = array();
        foreach ($this->commandApplication->getTasks() as $name => $task) {
            if ($name != $task->getFullName()) {
                // it is an alias
                continue;
            }
            $task->getNamespace() or $name = '_default:' . $name;
            $tasks[$name] = $task;
        }

        ksort($tasks);

        $simpleXMLElement = new SimpleXMLElement('<tasks />');
        $simpleXMLElement->addAttribute('version', self::VERSION);

        $currentNamespace = null;
        $namespaceIndex = - 1;
        $taskIndex = 0;
        foreach ($tasks as $name => $task) {
            $namespace = $task->getNamespace() ? $task->getNamespace() : 'default';
            if ($currentNamespace != $namespace) {
                $currentNamespace = $namespace;
                $namespaceIndex++;
                $taskIndex = 0;
                $simpleXMLElement->addChild('namespace');
                if ($currentNamespace != 'default') {
                    $simpleXMLElement->namespace[$namespaceIndex]->addAttribute('name', $currentNamespace);
                }
            }

            if ($currentNamespace) {
                $simpleXMLElement->namespace[$namespaceIndex]->addChild('task')->addAttribute('name', $task->getName());
                $currentTask = $simpleXMLElement->namespace[$namespaceIndex]->task[$taskIndex];
            }

            $currentTask->addChild('briefDescription', self::xmlentities($task->getBriefDescription()));
            $currentTask->addChild('detailedDescription', self::xmlentities(@$task->getDetailedDescription()));

            if ($aliases = $task->getAliases()) {
                $currentTask->addChild('aliases');
                foreach($aliases as $alias) {
                    $currentTask->aliases->addChild('alias')->addAttribute('name', $alias);
                }
            }
            if ($arguments = $task->getArguments()) {
                $argumentsNode = $currentTask->addChild('arguments');
                foreach($arguments as $argument) {
                    $argumentNode = $argumentsNode->addChild('argument');
                    $argumentNode->addAttribute('name', $argument->getName());
                    if ($argument->isRequired()) {
                        $argumentNode->addAttribute('required', 'required');
                    }
                    if ($default = $argument->getDefault()) {
                        $argumentsNodeDefaults = $argumentNode->addChild('defaults');
                        if (is_array($default)) {
                            foreach($default as $value) {
                                $argumentsNodeDefaults->addChild('default')->addAttribute('value', $value);
                            }
                        } else {
                            $argumentsNodeDefaults->addChild('default')->addAttribute('value', $default);
                        }
                    }
                    if ($help = $argument->getHelp()) {
                        $argumentNode->addAttribute('help', $help);
                    }
                }
            }

            if ($options = $task->getOptions()) {
                $optionsNode = $currentTask->addChild('options');
                foreach($options as $option) {
                    $optionNode = $optionsNode->addChild('option');
                    $optionNode->addAttribute('name', $option->getName());
                    if ($option->getShortcut()) {
                        $optionNode->addAttribute('shortcut', $option->getShortcut());
                    }
                    if ($option->acceptParameter()) {
                        $optionNode->addAttribute('parameter', $option->isParameterRequired() ? 'required' : 'optional');
                    }
                    if ($default = $option->getDefault()) {
                        $optionsNodeDefaults = $optionNode->addChild('defaults');
                        if (is_array($default)) {
                            foreach($default as $value) {
                                $optionsNodeDefaults->addChild('default')->addAttribute('value', $value);
                            }
                        } else {
                            $optionsNodeDefaults->addChild('default')->addAttribute('value', $default);
                        }
                    }
                    if ($help = $option->getHelp()) {
                        $optionNode->addAttribute('help', $help);
                    }
                }
            }
            $taskIndex++;
        }

        $this->log(@$simpleXMLElement->asXML());
    }

    /**
     * http://us3.php.net/htmlentities
     * tmp1000 at fastmail dot deleteme dot fm
     * 22-Oct-2004 11:07
     */
    protected static function xmlentities($string, $quote_style = ENT_COMPAT) {
        static $trans;
        if (!isset($trans)) {
            $trans = get_html_translation_table(HTML_ENTITIES, $quote_style);
            foreach ($trans as $key => $value)
            $trans[$key] = '&#' . ord($key) . ';';
            // dont translate the '&' in case it is part of &xxx;
            $trans[chr(38)] = '&';
        }
        // after the initial translation, _do_ map standalone '&' into '&#38;'
        return preg_replace("/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/", "&#38;" , strtr(html_entity_decode($string), $trans));
    }
}