/****************************************************************************
 * This file is part of the project AqHome.
 * AqHome (c) by 2025 Martin Preuss, all rights reserved.
 *
 * The license for this file can be found in the file COPYING which you
 * should have received along with this file.
 ****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif


#include "./mmodules.h"

#include "aqcgi/service/module.h"

#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>



/* ------------------------------------------------------------------------------------------------
 * defs and enums
 * ------------------------------------------------------------------------------------------------
 */

#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs



/* ------------------------------------------------------------------------------------------------
 * forward declarations
 * ------------------------------------------------------------------------------------------------
 */

static void _createPermDefList(AQCGI_MODULE *m);
static void _createRoleList(AQCGI_MODULE *m);

static AQCGI_MODULE *_loadSubModule(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, const char *sModuleName);
static int _handleRequest(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, const char *sLastPathElem);
static void _handleRqIndex(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf);

static void _handleRqEditModGet(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqEditModPost(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf);

static void _handleRqAddRoleGet(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqAddRolePost(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf);

static void _handleRqEditRoleGet(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqEditRolePost(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf);
static int _getHighestUsedRoleId(const AQCGI_ROLE_LIST *roleList);

static void _handleRqDeleteRole(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf);

static void _writeEditModForm(const AQCGI_MODULE *currentMod, const char *sModName, GWEN_BUFFER *dbuf);
static void _writeRoleListToForm(const AQCGI_ROLE_LIST *roleList,
				 const char *sModName,
				 const AQCGI_PERMDEF_LIST *permDefList,
				 GWEN_BUFFER *dbuf);

static void _setLocationHeaderForMod(AQCGI_REQUEST *rq, const char *page, const char *sModName);
static void _writeEnabledPermissions(const AQCGI_PERMDEF_LIST *permDefList, uint32_t perms, GWEN_BUFFER *dbuf);



/* ------------------------------------------------------------------------------------------------
 * vars
 * ------------------------------------------------------------------------------------------------
 */

static AQH_MODSERVICE_HANDLER_ENTRY _requestTable[]={
  {"index.html",      AQCGI_REQUEST_METHOD_GET,  AQH_MODADMMODULES_PERMS_MODULESREAD,  _handleRqIndex},
  {"editmodule.html", AQCGI_REQUEST_METHOD_GET,  AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqEditModGet},
  {"editmodule.html", AQCGI_REQUEST_METHOD_POST, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqEditModPost},
  {"addrole.html",    AQCGI_REQUEST_METHOD_GET,  AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqAddRoleGet},
  {"addrole.html",    AQCGI_REQUEST_METHOD_POST, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqAddRolePost},
  {"editrole.html",   AQCGI_REQUEST_METHOD_GET,  AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqEditRoleGet},
  {"editrole.html",   AQCGI_REQUEST_METHOD_POST, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqEditRolePost},
  {"delrole.html",    AQCGI_REQUEST_METHOD_GET,  AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqDeleteRole},
  {NULL, 0, 0, NULL}
};



/* ------------------------------------------------------------------------------------------------
 * code
 * ------------------------------------------------------------------------------------------------
 */

void AQH_ModAdmModules_Extend(AQCGI_MODULE *m, AQCGI_SERVICE *sv, const char *baseFolder)
{
  AQH_ModService_Extend(m, sv, baseFolder);
  AQH_ModService_SetHandleRequestFn(m, _handleRequest);
  AQH_ModService_SetLoadSubModuleFn(m, _loadSubModule);
}



int AQH_ModAdmModules_Create(AQCGI_SERVICE *sv)
{
  AQCGI_MODULE *m;
  int rv;

  m=AQCGI_Module_new();
  AQCGI_Module_SetName(m, "modules");
  AQCGI_Module_SetDescr(m, "modules administration module");
  AQCGI_Module_SetGuestPerms(m, 0);

  _createPermDefList(m);
  _createRoleList(m);

  rv=AQCGI_Service_AddModule(sv, m);
  if (rv<0) {
    DBG_INFO(NULL, "here (%d)", rv);
  }
  AQCGI_Module_free(m);
  return rv;
}



void _createPermDefList(AQCGI_MODULE *m)
{
  AQCGI_PERMDEF_LIST *permDefList;

  permDefList=AQCGI_PermDef_List_new();

  AQH_ModService_AddPermDef(permDefList, "ModuleRead",  0x001, "Read modules");
  AQH_ModService_AddPermDef(permDefList, "ModuleWrite", 0x002, "Modify modules");
  AQH_ModService_AddPermDef(permDefList, "ModuleAdd",   0x004, "Add modules");
  AQH_ModService_AddPermDef(permDefList, "ModuleDel",   0x008, "Remove modules");

  AQCGI_Module_SetPermDefList(m, permDefList);
}



void _createRoleList(AQCGI_MODULE *m)
{
  AQCGI_ROLE_LIST *roleList;
  int id=1;

  roleList=AQCGI_Role_List_new();
  AQH_ModService_AddRole(roleList, id++, "admin",
                         AQH_MODADMMODULES_PERMS_MODULESREAD |
                         AQH_MODADMMODULES_PERMS_MODULESWRITE |
                         AQH_MODADMMODULES_PERMS_MODULESADD |
                         AQH_MODADMMODULES_PERMS_MODULESDEL,
                         "Administrator Role");
  AQCGI_Module_SetRoleList(m, roleList);
}



AQCGI_MODULE *_loadSubModule(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, const char *sModuleName)
{
  /* no sub-modules */
  return NULL;
}



int _handleRequest(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, const char *sLastPathElem)
{
  AQH_ModService_HandleRequestWithTable(m, rq, session, sLastPathElem, _requestTable);
  return AQCGI_SendResponse(rq);
}



void _handleRqIndex(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf)
{
  AQCGI_SERVICE *sv;
  GWEN_STRINGLIST *slModules;
  uint32_t perms;

  perms=AQH_ModService_GetUserPerms(m);
  sv=AQH_ModService_GetService(m);
  slModules=AQCGI_Service_ListModules(sv);
  if (slModules) {
    GWEN_STRINGLISTENTRY *se;

    GBAS(dbuf, "<h1>Modules</h1>\n");
    GBAS(dbuf,
         "<table class=\"datatable\">\n"
         "<thead>"
         "<tr><th>Id</th><th>Name</th><th>Description</th><th>Actions</th></tr>\n"
         "</thead>\n"
         "<tbody>\n");
    se=GWEN_StringList_FirstEntry(slModules);
    while(se) {
      const char *sModName;

      sModName=GWEN_StringListEntry_Data(se);
      if (sModName && *sModName) {
        AQCGI_MODULE *currentMod;

        currentMod=AQCGI_Service_LoadModule(sv, sModName);
        if (currentMod) {
          const char *s;
          const char *sName;

          sName=AQCGI_Module_GetName(currentMod);
          GBAS(dbuf, "<tr>");
          GBAA(dbuf, "<td>%lu</td>", (unsigned long int) AQCGI_Module_GetId(currentMod));
          GBAA(dbuf, "<td>%s</td>", sName?sName:"");
          s=AQCGI_Module_GetDescr(currentMod);
          GBAA(dbuf, "<td>%s</td>", s?s:"");

          GBAS(dbuf, "<td>");
          if (perms & AQH_MODADMMODULES_PERMS_MODULESWRITE)
            GBAA(dbuf, "<a href=\"editmodule.html?name=%s\"><img src=\"/pics/edit.png\"></a>", sName?sName:"");
          GBAA(dbuf, "</td>\n");
          GBAA(dbuf, "</tr>\n");
          AQCGI_Module_free(currentMod);
        }
      }
      se=GWEN_StringListEntry_Next(se);
    }
    GBAS(dbuf,
         "</tbody>\n"
         "</table>\n");
    GWEN_StringList_free(slModules);
  }
  if (perms & AQH_MODADMMODULES_PERMS_MODULESADD)
    GBAS(dbuf, "<hr><a href=\"addmodule.html\">Add Module</a>");
}



void _handleRqEditModGet(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf)
{
  AQCGI_SERVICE *sv;
  GWEN_DB_NODE *dbQuery;
  const char *sModName;
  AQCGI_MODULE *currentMod;

  sv=AQH_ModService_GetService(m);
  dbQuery=AQCGI_Request_GetDbQuery(rq);
  sModName=dbQuery?GWEN_DB_GetCharValue(dbQuery, "name", 0, NULL):NULL;
  currentMod=(sModName && *sModName)?AQCGI_Service_LoadModule(sv, sModName):NULL;
  if (currentMod) {
    _writeEditModForm(currentMod, sModName, dbuf);
    AQCGI_Module_free(currentMod);
  }
  else {
    AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html");
    AQCGI_Request_SetResponseCode(rq, 303);
    AQCGI_Request_SetResponseText(rq, "See other");
  }
}



void _handleRqEditModPost(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf)
{
  AQCGI_SERVICE *sv;
  GWEN_DB_NODE *dbPost;
  const char *sModName;
  AQCGI_MODULE *currentMod;

  sv=AQH_ModService_GetService(m);
  dbPost=AQCGI_Request_GetDbPostBody(rq);
  sModName=dbPost?GWEN_DB_GetCharValue(dbPost, "module", 0, NULL):NULL;
  currentMod=(sModName && *sModName)?AQCGI_Service_LoadModule(sv, sModName):NULL;
  if (currentMod) {
    const char *sNewModName;
    const char *sDescr;
    int rv;
    uint32_t perms;
    const AQCGI_PERMDEF_LIST *permDefList;

    permDefList=AQCGI_Module_GetPermDefList(currentMod);
    sNewModName=GWEN_DB_GetCharValue(dbPost, "name", 0, NULL);
    sDescr=GWEN_DB_GetCharValue(dbPost, "descr", 0, NULL);
    perms=AQH_ModService_ReadPermsFromForm(dbPost, permDefList, NULL);
    if (sNewModName && *sNewModName)
      AQCGI_Module_SetName(currentMod, sNewModName);
    AQCGI_Module_SetDescr(currentMod, sDescr);
    AQCGI_Module_SetGuestPerms(currentMod, perms);

    rv=AQCGI_Service_SaveModule(sv, currentMod);
    if (rv<0) {
      GBAS(dbuf, "<h2>Error</h2><p>Error saving module</p>");
      DBG_ERROR(NULL, "Could not save module \"%s\"", sModName);
      AQCGI_Module_free(currentMod);
      return;
    }
    DBG_ERROR(NULL, "Module \"%s\" saved", sModName);
    AQCGI_Module_free(currentMod);
    AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html");
    AQCGI_Request_SetResponseCode(rq, 303);
    AQCGI_Request_SetResponseText(rq, "See other");
  }
  else {
    DBG_ERROR(NULL, "Could not load module \"%s\"", sModName?sModName:"<no name>");
    GBAS(dbuf, "<p>Error loading module.</p>\n");
  }
}



void _handleRqAddRoleGet(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf)
{
  AQCGI_SERVICE *sv;
  GWEN_DB_NODE *dbQuery;
  const char *sModName;
  AQCGI_MODULE *currentMod;
  const AQCGI_PERMDEF_LIST *permDefList;
  uint32_t guestPerms;

  sv=AQH_ModService_GetService(m);
  dbQuery=AQCGI_Request_GetDbQuery(rq);
  sModName=dbQuery?GWEN_DB_GetCharValue(dbQuery, "mod", 0, NULL):NULL;
  currentMod=(sModName && *sModName)?AQCGI_Service_LoadModule(sv, sModName):NULL;
  guestPerms=currentMod?AQCGI_Module_GetGuestPerms(currentMod):0;
  permDefList=currentMod?AQCGI_Module_GetPermDefList(currentMod):NULL;

  if (currentMod) {
    if (permDefList) {
      GBAA(dbuf, "<h2>Add Role for Module %s</h2>\n", sModName?sModName:"");
      GBAS(dbuf,
           "<form action=\"addrole.html\" method=\"post\">\n"
           "<table class=\"formtable\">\n"
           "<tr><td><label for=\"name\">Name:</label></td><td><input type=\"text\" name=\"name\"></td>"
           "<tr><td><label for=\"descr\">Description:</label></td><td><input type=\"text\" name=\"descr\"></td></tr>\n");

      GBAS(dbuf, "<tr><td><label>Permissions:</label></td><td>");
      AQH_ModService_WritePermsToForm(guestPerms, permDefList, NULL, dbuf);
      GBAS(dbuf, "</td></tr>\n");

      GBAS(dbuf, "</table>\n");
      GBAA(dbuf, "<input type=\"hidden\" name=\"mod\" value=\"%s\">\n", sModName?sModName:"");
      GBAS(dbuf, "<input type=\"submit\" value=\"Add\">\n");
      GBAS(dbuf, "</form>\n\n");
    }
    else {
      GBAS(dbuf, "<p>Please add permission definitions first.</p>\n");
      GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
    }
    AQCGI_Module_free(currentMod);
  }
  else {
    GBAS(dbuf, "<p>Error loading module.</p>\n");
    GBAS(dbuf, "<p><a href=\"index.html\"> back to module list</p>\n");
  }
}



void _handleRqAddRolePost(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf)
{
  AQCGI_SERVICE *sv;
  GWEN_DB_NODE *dbPost;
  const char *sModName;
  AQCGI_MODULE *currentMod;
  int newId;
  const char *sName;
  const char *sDescr;
  uint32_t perms;
  AQCGI_PERMDEF_LIST *permDefList;
  AQCGI_ROLE_LIST *roleList;
  int rv;

  /* sample data */
  DBG_ERROR(NULL, "Handling POST request");
  sv=AQH_ModService_GetService(m);
  dbPost=AQCGI_Request_GetDbPostBody(rq);
  sModName=dbPost?GWEN_DB_GetCharValue(dbPost, "mod", 0, NULL):NULL;
  currentMod=(sModName && *sModName)?AQCGI_Service_LoadModule(sv, sModName):NULL;
  permDefList=currentMod?AQCGI_Module_GetPermDefList(currentMod):NULL;
  roleList=currentMod?AQCGI_Module_GetRoleList(currentMod):NULL;
  /* read role values */
  newId=(roleList?_getHighestUsedRoleId(roleList):0)+1;
  sName=dbPost?GWEN_DB_GetCharValue(dbPost, "name", 0, NULL):NULL;
  sDescr=dbPost?GWEN_DB_GetCharValue(dbPost, "descr", 0, NULL):NULL;
  perms=(dbPost && permDefList)?AQH_ModService_ReadPermsFromForm(dbPost, permDefList, NULL):0;

    /* validate */
  if (!(sName && *sName)) {
    DBG_ERROR(NULL, "Missing value for \"name\"");
    GBAS(dbuf, "<p>Missing name.</p>\n");
    GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
    return;
  }

  if (currentMod) {
    AQCGI_ROLE *role;

    /* set new values */
    role=AQCGI_Role_new();
    AQCGI_Role_SetId(role, newId);
    AQCGI_Role_SetName(role, sName);
    AQCGI_Role_SetDescr(role, sDescr);
    AQCGI_Role_SetPerms(role, perms);
    /* add role */
    if (roleList==NULL) {
      roleList=AQCGI_Role_List_new();
      AQCGI_Module_SetRoleList(currentMod, roleList);
    }
    AQCGI_Role_List_Add(role, roleList);

    /* save module */
    rv=AQCGI_Service_SaveModule(sv, currentMod);
    if (rv<0) {
      GBAS(dbuf, "<p>Error saving module.</p>\n");
      GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
      AQCGI_Module_free(currentMod);
      return;
    }
    _setLocationHeaderForMod(rq, "editmodule.html", sModName);
    AQCGI_Request_SetResponseCode(rq, 303);
    AQCGI_Request_SetResponseText(rq, "See Other");
    AQCGI_Module_free(currentMod);
  }
  else {
    GBAS(dbuf, "<p>Error loading module.</p>\n");
    GBAS(dbuf, "<p><a href=\"index.html\"> back to module list</p>\n");
  }
}



void _handleRqEditRoleGet(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf)
{
  AQCGI_SERVICE *sv;
  GWEN_DB_NODE *dbQuery;
  const char *sModName;
  int id;
  const char *sName;
  const char *sDescr;
  uint32_t perms;
  AQCGI_MODULE *currentMod;
  const AQCGI_PERMDEF_LIST *permDefList;
  const AQCGI_ROLE_LIST *roleList;
  const AQCGI_ROLE *role;

  sv=AQH_ModService_GetService(m);
  dbQuery=AQCGI_Request_GetDbQuery(rq);
  sModName=dbQuery?GWEN_DB_GetCharValue(dbQuery, "mod", 0, NULL):NULL;
  id=dbQuery?GWEN_DB_GetIntValue(dbQuery, "id", 0, 0):0;
  currentMod=(sModName && *sModName)?AQCGI_Service_LoadModule(sv, sModName):NULL;
  permDefList=currentMod?AQCGI_Module_GetPermDefList(currentMod):NULL;
  roleList=currentMod?AQCGI_Module_GetRoleList(currentMod):NULL;
  role=roleList?AQCGI_Role_List_GetById(roleList, id):NULL;
  sName=role?AQCGI_Role_GetName(role):NULL;
  sDescr=role?AQCGI_Role_GetDescr(role):NULL;
  perms=role?AQCGI_Role_GetPerms(role):0;

  if (role) {
    GBAA(dbuf, "<h2>Edit Role for Module %s</h2>\n", sModName?sModName:"");
    GBAA(dbuf,
         "<form action=\"editrole.html\" method=\"post\">\n"
         "<table class=\"formtable\">\n"
         "<tr><td><label for=\"name\">Name:</label></td><td><input type=\"text\" name=\"name\" value=\"%s\"></td></tr>\n"
         "<tr><td><label for=\"descr\">Description:</label></td><td><input type=\"text\" name=\"descr\" value=\"%s\"></td></tr>\n",
         sName, sDescr?sDescr:"");

    GBAS(dbuf, "<tr><td><label>Permissions:</label></td><td>");
    AQH_ModService_WritePermsToForm(perms, permDefList, NULL, dbuf);
    GBAS(dbuf, "</td></tr>\n");

    GBAS(dbuf, "</table>\n");

    GBAA(dbuf, "<input type=\"hidden\" name=\"mod\" value=\"%s\">\n", sModName?sModName:"");
    GBAA(dbuf, "<input type=\"hidden\" name=\"oldId\" value=\"%d\">\n", id);
    GBAS(dbuf, "<input type=\"submit\" value=\"Save\">\n");
    GBAS(dbuf, "</form>\n\n");
  }
  else {
    GBAS(dbuf, "<p>Role not found.</p>\n");
    GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
  }
}



void _handleRqEditRolePost(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf)
{
  AQCGI_SERVICE *sv;
  GWEN_DB_NODE *dbPost;
  const char *sModName;
  AQCGI_MODULE *currentMod;
  int oldId;
  const char *sName;
  const char *sDescr;
  uint32_t perms;
  AQCGI_PERMDEF_LIST *permDefList;
  AQCGI_ROLE_LIST *roleList;
  AQCGI_ROLE *role;
  int rv;

  /* sample data */
  sv=AQH_ModService_GetService(m);
  dbPost=AQCGI_Request_GetDbPostBody(rq);
  sModName=dbPost?GWEN_DB_GetCharValue(dbPost, "mod", 0, NULL):NULL;
  currentMod=(sModName && *sModName)?AQCGI_Service_LoadModule(sv, sModName):NULL;
  permDefList=currentMod?AQCGI_Module_GetPermDefList(currentMod):NULL;
  roleList=currentMod?AQCGI_Module_GetRoleList(currentMod):NULL;
  /* read role data */
  oldId=dbPost?GWEN_DB_GetIntValue(dbPost, "oldId", 0, -1):-1;
  sName=dbPost?GWEN_DB_GetCharValue(dbPost, "name", 0, NULL):NULL;
  sDescr=dbPost?GWEN_DB_GetCharValue(dbPost, "descr", 0, NULL):NULL;
  role=roleList?AQCGI_Role_List_GetById(roleList, oldId):NULL;
  perms=(dbPost && permDefList)?AQH_ModService_ReadPermsFromForm(dbPost, permDefList, NULL):0;
  /* validate */
  if (!(sName && *sName)) {
    DBG_ERROR(NULL, "Missing value for \"name\"");
    GBAS(dbuf, "<p>Missing name.</p>\n");
    GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
    return;
  }
  if (role==NULL) {
    DBG_ERROR(NULL, "Role %d not found", oldId);
    GBAS(dbuf, "<p>Role not found.</p>\n");
    GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
    return;
  }

  if (currentMod) {
    /* set new values */
    AQCGI_Role_SetName(role, sName);
    AQCGI_Role_SetDescr(role, sDescr);
    AQCGI_Role_SetPerms(role, perms);

    /* save module */
    rv=AQCGI_Service_SaveModule(sv, currentMod);
    if (rv<0) {
      GBAS(dbuf, "<p>Error saving module.</p>\n");
      GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
      AQCGI_Module_free(currentMod);
      return;
    }

    _setLocationHeaderForMod(rq, "editmodule.html", sModName);
    AQCGI_Request_SetResponseCode(rq, 303);
    AQCGI_Request_SetResponseText(rq, "See Other");
    AQCGI_Module_free(currentMod);
  }
  else {
    GBAS(dbuf, "<p>Error loading module.</p>\n");
    GBAS(dbuf, "<p><a href=\"index.html\"> back to module list</p>\n");
  }
}



void _handleRqDeleteRole(AQCGI_MODULE *m, AQCGI_REQUEST *rq, AQCGI_SESSION *session, GWEN_BUFFER *dbuf)
{
  AQCGI_SERVICE *sv;
  GWEN_DB_NODE *dbQuery;
  const char *sModName;
  int id;
  AQCGI_MODULE *currentMod;
  const AQCGI_ROLE_LIST *roleList;
  AQCGI_ROLE *role;

  sv=AQH_ModService_GetService(m);
  dbQuery=AQCGI_Request_GetDbQuery(rq);
  sModName=dbQuery?GWEN_DB_GetCharValue(dbQuery, "mod", 0, NULL):NULL;
  id=dbQuery?GWEN_DB_GetIntValue(dbQuery, "id", 0, 0):0;
  currentMod=(sModName && *sModName)?AQCGI_Service_LoadModule(sv, sModName):NULL;
  if (currentMod) {
    roleList=currentMod?AQCGI_Module_GetRoleList(currentMod):NULL;
    role=roleList?AQCGI_Role_List_GetById(roleList, id):NULL;
    if (role) {
      int rv;

      AQCGI_Role_List_Del(role);
      AQCGI_Role_free(role);

      /* save module */
      rv=AQCGI_Service_SaveModule(sv, currentMod);
      if (rv<0) {
        GBAS(dbuf, "<p>Error saving module.</p>\n");
        GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
        AQCGI_Module_free(currentMod);
        return;
      }

      _setLocationHeaderForMod(rq, "editmodule.html", sModName);
      AQCGI_Request_SetResponseCode(rq, 303);
      AQCGI_Request_SetResponseText(rq, "See Other");
    }
    else {
      GBAS(dbuf, "<p>Role not found.</p>\n");
      GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
    }
    AQCGI_Module_free(currentMod);
  }
  else {
    GBAS(dbuf, "<p>Error loading module.</p>\n");
    GBAS(dbuf, "<p><a href=\"index.html\"> back to module list</p>\n");
  }
}



void _setLocationHeaderForMod(AQCGI_REQUEST *rq, const char *page, const char *sModName)
{
  GWEN_BUFFER *tbuf;

  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
  GBAA(tbuf, "Location: %s?name=%s", page?page:"", sModName?sModName:"");
  AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(tbuf));
  GWEN_Buffer_free(tbuf);
}



int _getHighestUsedRoleId(const AQCGI_ROLE_LIST *roleList)
{
  int id=0;

  if (roleList) {
    const AQCGI_ROLE *role;

    role=AQCGI_Role_List_First(roleList);
    while(role) {
      int rid;

      rid=AQCGI_Role_GetId(role);
      id=(rid>id)?rid:id;
      role=AQCGI_Role_List_Next(role);
    }
  }
  return id;
}



void _writeEditModForm(const AQCGI_MODULE *currentMod, const char *sModName, GWEN_BUFFER *dbuf)
{
  const char *sName;
  const char *sDescr;
  const AQCGI_PERMDEF_LIST *permDefList;
  const AQCGI_ROLE_LIST *roleList;

  permDefList=AQCGI_Module_GetPermDefList(currentMod);
  roleList=AQCGI_Module_GetRoleList(currentMod);
  sName=AQCGI_Module_GetName(currentMod);
  sDescr=AQCGI_Module_GetDescr(currentMod);
  /* write module info */
  GBAS(dbuf, "<h2>Module Info</h2>\n");
  GBAA(dbuf,
       "<form action=\"editmodule.html\" method=\"post\">\n"
       "<table class=\"formtable\">\n"
       "<tr><td><label for=\"name\">Name:</label></td><td><input type=\"text\" name=\"name\" value=\"%s\"></td></tr>\n"
       "<tr><td><label for=\"descr\">Description:</label></td><td><input type=\"text\" name=\"descr\" value=\"%s\"></td></tr>\n",
       sName?sName:"", sDescr?sDescr:"");

  if (permDefList) {
    GBAA(dbuf, "<tr><td><label>Guest Permissions:</label></td>\n<td>");
    AQH_ModService_WritePermsToForm(AQCGI_Module_GetGuestPerms(currentMod), permDefList, NULL, dbuf);
    GBAA(dbuf, "</td></tr>");
  }
  
  GBAS(dbuf, "</table>\n");
  
  GBAA(dbuf, "<input type=\"hidden\" name=\"module\" value=\"%s\">\n", sModName?sModName:"");
  GBAS(dbuf, "<input type=\"submit\" value=\"Save\">\n</form>\n\n");

  /* write role list */
  GBAS(dbuf, "<h2>User Roles</h2>\n");
  if (roleList)
    _writeRoleListToForm(roleList, sModName, permDefList, dbuf);
  else
    GBAS(dbuf, "<p>none</p>");
  GBAA(dbuf, "<a href=\"addrole.html?mod=%s\"><img src=\"/pics/plus.png\">Add Role</a>\n", sModName?sModName:"");
}



void _writeRoleListToForm(const AQCGI_ROLE_LIST *roleList,
			  const char *sModName,
			  const AQCGI_PERMDEF_LIST *permDefList,
			  GWEN_BUFFER *dbuf)
{
  const AQCGI_ROLE *role;

  GBAS(dbuf,
       "<table class=\"datatable\">\n"
       "<thead><tr><th>Id</th><th>Name</th><th>Permissions</th><th>Description</th><th>Actions</th></tr>\n</thead>\n"
       "<tbody>\n");
  role=AQCGI_Role_List_First(roleList);
  while(role) {
    uint8_t id;
    const char *s;

    GBAS(dbuf, "<tr>");
    /* id */
    id=AQCGI_Role_GetId(role);
    GBAA(dbuf, "<td>%d</td>", id);
    /* name */
    s=AQCGI_Role_GetName(role);
    GBAA(dbuf, "<td>%s</td>", s?s:"");
    /* permissions */
    GBAS(dbuf, "<td>");
    if (permDefList)
      _writeEnabledPermissions(permDefList, AQCGI_Role_GetPerms(role), dbuf);
    GBAS(dbuf, "</td>");
    /* description */
    s=AQCGI_Role_GetDescr(role);
    GBAA(dbuf, "<td>%s</td>", s?s:"");
    /* actions */
    GBAA(dbuf, "<td>");
    GBAA(dbuf, "<a href=\"editrole.html?mod=%s&id=%d\"><img src=\"/pics/edit.png\"></a>", sModName?sModName:"", id);
    GBAA(dbuf, "<a href=\"delrole.html?mod=%s&id=%d\"><img src=\"/pics/minus.png\"></a>", sModName?sModName:"", id);
    GBAA(dbuf, "</td>");
    GBAS(dbuf, "</tr>\n");

    role=AQCGI_Role_List_Next(role);
  }

  GBAS(dbuf, "</tbody>\n</table>\n");
}






void _writeEnabledPermissions(const AQCGI_PERMDEF_LIST *permDefList, uint32_t perms, GWEN_BUFFER *dbuf)
{
  if (permDefList) {
    const AQCGI_PERMDEF *permDef;

    permDef=AQCGI_PermDef_List_First(permDefList);
    while(permDef) {
      const char *s;
      uint32_t mask;

      s=AQCGI_PermDef_GetId(permDef);
      mask=AQCGI_PermDef_GetMask(permDef);
      if (perms & mask)
	GBAA(dbuf, "%s ", s?s:"");
      permDef=AQCGI_PermDef_List_Next(permDef);
    }
  }
}



