/**
  * @param AJXP_Plugin $plugin
  * @param array $apis
  * @return string
  */
 public static function makeMarkdown($plugin, $apis)
 {
     $md = "\n\n";
     $md .= "## " . $plugin->getManifestLabel() . "  ";
     $md .= "\n" . $plugin->getManifestDescription() . "\n\n";
     $id = $plugin->getId();
     foreach ($apis as $index => $api) {
         $md .= "\n";
         $md .= "- **" . $api["path"] . "**  \n";
         $md .= "  " . $api["operations"][0]["notes"] . "  \n";
         $md .= "  [Details](" . API_DOC_PAGE . "" . $id . "/" . $api["operations"][0]["nickname"] . "_" . strtolower($api["operations"][0]["method"]) . "_" . $index . ")";
     }
     return $md;
 }
 public function listActions($dir, $root = NULL, $hash = null, $returnNodes = false)
 {
     $allNodes = array();
     $parts = explode("/", $dir);
     $pServ = AJXP_PluginsService::getInstance();
     $activePlugins = $pServ->getActivePlugins();
     $types = $pServ->getDetectedPlugins();
     if (count($parts) == 1) {
         // list all types
         if (!$returnNodes) {
             AJXP_XMLWriter::sendFilesListComponentConfig('<columns switchGridMode="filelist" template_name="ajxp_conf.plugins_folder">
         <column messageId="ajxp_conf.101" attributeName="ajxp_label" sortType="String"/>
         </columns>');
         }
         ksort($types);
         foreach ($types as $t => $tPlugs) {
             $meta = array("icon" => "folder_development.png", "plugin_id" => $t);
             $nodeKey = "/{$root}/actions/" . $t;
             if (in_array($nodeKey, $this->currentBookmarks)) {
                 $meta = array_merge($meta, array("ajxp_bookmarked" => "true", "overlay_icon" => "bookmark.png"));
             }
             $xml = AJXP_XMLWriter::renderNode($nodeKey, ucfirst($t), false, $meta, true, false);
             if ($returnNodes) {
                 $allNodes[$nodeKey] = $xml;
             } else {
                 print $xml;
             }
         }
     } else {
         if (count($parts) == 2) {
             // list plugs
             $type = $parts[1];
             if (!$returnNodes) {
                 AJXP_XMLWriter::sendFilesListComponentConfig('<columns switchDisplayMode="detail" template_name="ajxp_conf.plugins_folder">
             <column messageId="ajxp_conf.101" attributeName="ajxp_label" sortType="String"/>
             <column messageId="ajxp_conf.103" attributeName="actions" sortType="String"/>
         </columns>');
             }
             $pObject = new AJXP_Plugin("", "");
             foreach ($types[$type] as $pId => $pObject) {
                 $actions = $pObject->getManifestRawContent("//action/@name", "xml", true);
                 $actLabel = array();
                 if ($actions->length) {
                     foreach ($actions as $node) {
                         $actLabel[] = $node->nodeValue;
                     }
                 }
                 $meta = array("icon" => "preferences_plugin.png", "plugin_id" => $pObject->getId(), "actions" => implode(", ", $actLabel));
                 $nodeKey = "/{$root}/actions/{$type}/" . $pObject->getName();
                 if (in_array($nodeKey, $this->currentBookmarks)) {
                     $meta = array_merge($meta, array("ajxp_bookmarked" => "true", "overlay_icon" => "bookmark.png"));
                 }
                 $xml = AJXP_XMLWriter::renderNode($nodeKey, $pObject->getManifestLabel(), false, $meta, true, false);
                 if ($returnNodes) {
                     $allNodes[$nodeKey] = $xml;
                 } else {
                     print $xml;
                 }
             }
         } else {
             if (count($parts) == 3) {
                 // list actions
                 $type = $parts[1];
                 $name = $parts[2];
                 $mess = ConfService::getMessages();
                 if (!$returnNodes) {
                     AJXP_XMLWriter::sendFilesListComponentConfig('<columns switchDisplayMode="full" template_name="ajxp_conf.plugins_folder">
             <column messageId="ajxp_conf.101" attributeName="ajxp_label" sortType="String" defaultWidth="10%"/>
             <column messageId="ajxp_conf.103" attributeName="parameters" sortType="String" fixedWidth="30%"/>
         </columns>');
                 }
                 $pObject = new AJXP_Plugin("", "");
                 $pObject = $types[$type][$name];
                 $actions = $pObject->getManifestRawContent("//action", "xml", true);
                 $allNodesAcc = array();
                 if ($actions->length) {
                     foreach ($actions as $node) {
                         $xPath = new DOMXPath($node->ownerDocument);
                         $callbacks = $xPath->query("processing/serverCallback", $node);
                         if (!$callbacks->length) {
                             continue;
                         }
                         $callback = $callbacks->item(0);
                         $actName = $actLabel = $node->attributes->getNamedItem("name")->nodeValue;
                         $text = $xPath->query("gui/@text", $node);
                         if ($text->length) {
                             $actLabel = $actName . " (" . $mess[$text->item(0)->nodeValue] . ")";
                         }
                         $params = $xPath->query("processing/serverCallback/input_param", $node);
                         $paramLabel = array();
                         if ($callback->getAttribute("developerComment") != "") {
                             $paramLabel[] = "<span class='developerComment'>" . $callback->getAttribute("developerComment") . "</span>";
                         }
                         $restPath = "";
                         if ($callback->getAttribute("restParams")) {
                             $restPath = "/api/{$actName}/" . ltrim($callback->getAttribute("restParams"), "/");
                         }
                         if ($restPath != null) {
                             $paramLabel[] = "<span class='developerApiAccess'>" . "API Access : " . $restPath . "</span>";
                         }
                         if ($params->length) {
                             $paramLabel[] = "Expected Parameters :";
                             foreach ($params as $param) {
                                 $paramLabel[] = '. [' . $param->getAttribute("type") . '] <b>' . $param->getAttribute("name") . ($param->getAttribute("mandatory") == "true" ? '*' : '') . '</b> : ' . $param->getAttribute("description");
                             }
                         }
                         $parameters = "";
                         $meta = array("icon" => "preferences_plugin.png", "action_id" => $actName, "parameters" => '<div class="developerDoc">' . implode("<br/>", $paramLabel) . '</div>', "rest_params" => $restPath);
                         $nodeKey = "/{$root}/actions/{$type}/" . $pObject->getName() . "/{$actName}";
                         if (in_array($nodeKey, $this->currentBookmarks)) {
                             $meta = array_merge($meta, array("ajxp_bookmarked" => "true", "overlay_icon" => "bookmark.png"));
                         }
                         $allNodes[$nodeKey] = $allNodesAcc[$actName] = AJXP_XMLWriter::renderNode($nodeKey, $actLabel, true, $meta, true, false);
                     }
                     ksort($allNodesAcc);
                     if (!$returnNodes) {
                         print implode("", array_values($allNodesAcc));
                     }
                 }
             }
         }
     }
     return $allNodes;
 }