<% /*
     File:          PDA/resultset_table.inc

     $Revision$
     $Id$

    PAS OP: Soms gebruikt in combinatie met shared/data_recordset.inc.
            Zie het commentaar daarin met betrekking tot het case-sensitive
            zijn van bijvoorbeeld oRs.EOF
   */
%>

<%

function ResultsetTable(params)
{
  this.emptySetString = L("lcl_empty_rstable");
  this.sql = null;
  this.dataset = null; // of sql of dataset meegeven. Data is dan een array van objecten met properies
  this.ID = null;
  this.rowNum = 0;
  this.showAll = null;

  // Mobile params
  this.noSearch = null;
  this.searchInputHtml = "<input type='search' class='list-group-filter " + MOBILE_UI_CLASSES.input + "' placeholder='Filter items...'>";
  this.inset = false;
  this.Counter = {};

  // Card layout params
  this.wrapper = { "layout": "vertical" };

  var param;
  // Neem alle meegegeven parameters mee.
  for (param in params) {
      this[param] = params[param];
  }
}

/*
  ResultsetTable heeft overigens niets meer met <table>'s te maken
  De rows zijn dan ook geen <tr>'s, maar list items (<li>)
*/
ResultsetTable.prototype.processResultset = __rsProcessResultset;
ResultsetTable.prototype.makeTableRow = __rsMakeTableRow;
ResultsetTable.prototype.countHistogram = __rsCountHistogram;
ResultsetTable.prototype.enableMultiactions = __rsEnableMultiactions;

/*global*/ isData = false;

function __rsProcessResultset(processParams)
{
    this.processParams = processParams;
    var copy;

    if (this.sql)
    {
        var oRs = Oracle.Execute(this.sql);
    }
    else
    {
        /*global*/isData = true;
        var oRs = new data_recordset( this.dataset );
    }

    if (oRs == null || oRs.EOF)
    {
        if (!this.emptyWhenNoResult)
            Response.Write("<p>" + this.emptySetString + "</p>");
        if (this.sql) {
          oRs.Close();
        }
        return -1;
    }

    var lastGroup, lastDivider, lastIconHtml = null;
    var html = "";
    var filterCutOff = S("pda_list_show_filter_from");


    var lines = [];
    // Heeft groupSelect een waarde, dan wordt voor deze group de lijst getoond.
    if (this.groupSelect == "") {
      html += __multiActions()
            + "<section class='list-group'" + (this.ID ? " id='" + this.ID + "'" : "") + ">";
    }
    var cnt = 0;
    var trueCount = 0;
    var hasResults = false;
    var initKeyDone = this.initKey == null;

    if (this.groupColumn && this.groupSelect == "")
    {   // we tonen alleen het aantal regels. Laat dan alle complexe processing achterwege
        ResultsetTable.prototype.makeTableRow = function __rsCountTableRow(oRs, cnt) { return "dummy" };
    } else if (this.layout === "card") {
        ResultsetTable.prototype.makeTableRow = __rsMakeCard;
    }

    if (this.multiactions && this.multiactions.length > 0) {
      this.hasMultiactions = true;
      for (var i = 0; i < this.multiactions.length; i++) {
        if (this.multiactions[i].fnCheckIfAny) { // Conditioneel aan? Begin dan eerst uit
          this.multiactions[i].enabled = false;
        } else {
          this.multiactions[i].enabled = true;
        }
      }
    }

    for (cnt = 0; (cnt < (S("qp_maxrows_mobile")) || this.showAll ) &&
                      (cnt < S("qp_maxrows2")) &&
                      !oRs.EOF; cnt++)
    {
      if (this.fnDataFilter && !this.fnDataFilter(oRs))
      {
        oRs.MoveNext();
        continue;
      }
      else if (!hasResults)
        hasResults = true;

      if (this.dividerColumn)
      {
        var safenextDivider = __fnContent(this.dividerColumn)(oRs);
        if (safenextDivider != lastDivider) {
            lines.push("<div class='list-group-item list-group-header'><h2>" + safenextDivider + "</h2></div>");
        }
        lastDivider = safenextDivider;
      }

      if (!initKeyDone && this.initKey && this.keyColumn && this.initKey == __fnContent(this.keyColumn)(oRs))
      {
          lines.unshift(this.makeTableRow(oRs, cnt, false));
          initKeyDone = true;
      }
      else
          lines.push(this.makeTableRow(oRs, cnt, false));

      trueCount++;

      if (this.buildHistogram)
        this.countHistogram(oRs);

      if (this.multiactions) {
        this.enableMultiactions(oRs);
      }

      if ((this.groupColumn || (this.singleLink && trueCount < 2)) && this.linkColumn)
          var lastLink = __fnContent(this.linkColumn)(oRs);

      var numberInGroup = -1;
      if (this.groupColumn)
      {
        lastGroup = __fnContent(this.groupColumn)(oRs);
        if (this.iconColumn) {
          lastIconHtml = "";
          var icon = __fnContent(this.iconColumn)(oRs, this.processParams)
          if (icon) {
            var iconHtml = "";
            if (icon.match(/^</)) { // Ik ben al een plaatje :) of safe html, bv een <div> of <i>
                iconHtml = icon;
            } else if (icon.match(/^fa-/)) {
                iconHtml = I(icon + " fa-2x");
            } else {
                iconHtml = '<img loading="lazy" src="' + safe.htmlattr(icon) + '" alt="' + L("lcl_photos") + '">';
            }
            lastIconHtml = "<div class='list-illustration flex-center'>" + iconHtml + "</div>";
          }
        }
        if (this.numberInGroup)
          numberInGroup = __fnContent(this.numberInGroup)(oRs);
      }

      oRs.MoveNext();

      if (trueCount === 1 && oRs.EOF && this.singleLink && this.linkColumn && lastLink)
      {
          trueCount = -1;
          break;
      }

      if (this.groupColumn)
      {
        var overLimit = (cnt+1 >= (S("qp_maxrows_mobile")) && !this.showAll ) ||
                        (cnt+1 >= S("qp_maxrows2"))

        if (!oRs.EOF)
            var nextGroup = __fnContent(this.groupColumn)(oRs);

        // In jquery-mobile-1.4.2 zijn geneste lijsten niet meer toegestaan.
        // De *_list.asp wordt nu geplitst: is groupSelect leeg dan worden de groepen getoond
        // Heeft groupSelect een waarde, dan wordt voor deze group de lijst getoond.
        if (this.groupSelect == "")
        { // Toon de groepen
          if (oRs.EOF || overLimit || nextGroup != lastGroup)
          {
            html += "<a href='" + lastLink + "' class='list-group-item list-group-item-action'>"
                  + (this.iconColumn ? lastIconHtml : "")
                  + "<h6 class='limit-lines-2'>" + lastGroup + "</h6>"
                  + "<div class='list-aside badge text-bg-secondary'>" + (numberInGroup > 0 ? numberInGroup : lines.length) + "</div>"
                  + "</a>";
            lines = [];
          }
        }
        else
        { // Toon de lijst van een geselecteerde groep
          if (oRs.EOF || overLimit)
          {
            html += __multiActions()
            if (!this.noSearch) {
              html += this.searchInputHtml;
            }
            html += "<section class='list-group'" + (this.ID ? " id='"+this.ID + "'" : "") + ">"
                  + lines.join("\n")
                  + "</section>";
            lines = [];
          }
        }
      }
    }

    if (trueCount === -1) // 1 result in list, which we should click instantly
    {
        Response.Write("<script>$(function() { window.location.href = \""+ lastLink.replace(new RegExp("\"", "g"), "'") +"\"; })</script>"); // " (even aantal aanhalingstekens i.v.m. formatting editter).
        if (this.sql) {
          oRs.Close();
        }
        return -1;
    }

    if (cnt === 0 || !hasResults)
    {
        Response.Write("<p>" + this.emptySetString + "</p>");
        if (this.sql) {
          oRs.Close();
        }
        return -1;
    }

    if (this.groupSelect == "")
        html += "</section>";
    if (this.layout === "card") {
        html += CARDS_WRAPPER_START_HTML(this.wrapper)
              + lines.join("")
              + CARDS_WRAPPER_END_HTML(this.wrapper);
    } else if (!this.groupColumn) {
        var html = __multiActions();
        if (!this.noSearch && cnt > filterCutOff) {
          html += this.searchInputHtml;
        }
        html += "<section class='list-group'" + (this.ID ? " id='" + this.ID + "'" : "") + ">"
              + lines.join("\n")
              + "</section>";
    }

    if (!oRs.EOF) // en dus overLimit
    {
        var maxrows = (this.showAll ? S("qp_maxrows2") : S("qp_maxrows_mobile"));
        html += __multiActions()
              + "<section class='list-group'><div class='list-group-item'>" + L("lcl_max_lines_reached").format(maxrows) + "</div></section>";
    } else if (false && /* future-use */ cnt > 5) {
        Response.Write('<script>$(function() { $(".count-badge").text("' + cnt + '"); });</script>');
    }

    Response.Write(html);

    if (this.sql) {
        oRs.close();
    }

    if (this.buildHistogram)
        return this.Counter;
    else
        return this.rowNum; // simpel return aantal rows
}

function __multiActions() {
  var html = "";
  var multiactionCount = 0;
  for (var i in this.multiactions) {
    multiactionCount = multiactionCount + (this.multiactions[i].enabled ? 1 : 0);
  }
  if (multiactionCount) {
    html += "<script>"
          + "  function doAm(event, fnAction) {"
          + "    var key_arr = [];"
          + "    $('.bulkable.bulk-selected').each((i, elem) => {"
          + "        key_arr.push($(elem).data('row-key'));"
          + "    });"
          + "    if (key_arr.length === 0) {"
          + "      return;"
          + "    }"
          + "    var confirm_text = key_arr.length === 1 ? L(\"lcl_shared_doaction1\") : L(\"lcl_shared_doaction\");"
          + "    confirm_text = confirm_text.format(event.currentTarget.dataset.title, key_arr.length);"
          + "    FcltMgr.confirm(confirm_text, _ => window[fnAction](key_arr));"
          + "  }"
          + "</script>"
          + "<div class='multiactions'>"
          + "  <span class='left multiaction-wrapper'>"
          + "    <span class='cancel multiaction tappable'>" + I("fa-times fa-lg") + "</span>"
          + "    <span class='multiaction-count' data-count='0'></span>"
          + "  </span>"
          + "  <span class='right multiaction-wrapper'>"
    for (var i in this.multiactions) {
      if (this.multiactions[i].enabled) {
        html += "<span class='multiaction tappable' onclick='doAm(event, \"" + safe.htmlattr(this.multiactions[i].action) + "\")' data-title='" + safe.htmlattr(this.multiactions[i].caption) + "'>"
              + I(this.multiactions[i].icon + " fa-lg") + "</span>"
      }
    }
    html += "  </span>"
          + "</div>";
  }
  return html;
}

function __rsMakeCard(oRs) {
    // HIER START EEN NIEUWE REGEL
    var data = {};
    if (this.data) {
      for (var i in this.data) {
        data[this.data[i]] = oRs(this.data[i]).Value;
      }
    }

    var icon = "";
    var cardClass = "";
    if (this.hasMultiactions) {
      cardClass = "bulkable";
    }
    if (this.swipeable) {
      cardClass = cardClass + (cardClass ? " " : "") + "swipeable";
    }
    if (this.iconColumn) {
      icon = __fnContent(this.iconColumn)(oRs, this.processParams);
      if (icon) {
        if (icon.match(/^fa-/)) {
            icon = I(icon);
        } else if (!icon.match(/^</)) { // Zal wel een src van een plaatje zijn dan
            icon = '<img loading="lazy" src="' + safe.htmlattr(icon) + '" alt="' + L("lcl_photos") + '">';
        }
        cardClass = cardClass + (cardClass ? " " : "") + "with-icon icon-color";
      }
    }

    var horiz = this.wrapper.layout === "horizontal";

    var line = "";
    if (horiz) {
      line += "<div class='row g-0 h-100 flex-nowrap'>";
    }

    if (icon) {
      line += "  <div class='col card-illustration flex-center'>" + icon + "</div>";
    }

    line += "  <div class='col " + (horiz ? "card-content" : "card-body") + "'>";

    line += "    <div class='card-title'>";
    if (this.headerColumn) {
      line += __fnContent(this.headerColumn)(oRs, this.processParams);
    }
    line += "    </div>";

    line += "    <div class='card-descr'>";
    if (this.contentColumn) {
      line += __fnContent(this.contentColumn)(oRs, this.processParams);
    }
    line += "    </div>";

    line += "  </div>";

    if (horiz) { // Sluit de row af
      line += "</div>";
    }

    var cardParams = {
      data: data,
      cls: cardClass,
      noPadding: true
    };

    // Klikbaar als <a>nchor
    if (this.linkColumn) {
      var lnk = __fnContent(this.linkColumn)(oRs, this.processParams);
      if (lnk) {
        line = "<a href='" + safe.htmlattr(lnk) + "' class='card-link' data-ajax='false'>" + line + "</a>";
        cardParams.card_class = "tappable";
      }
    }

    // Wrap het in een CARD
    line = CARD_START_HTML(cardParams)
         + line
         + CARD_END_HTML(cardParams);

    this.rowNum++;

    return line;
}

function __rsMakeTableRow(oRs)
{
    // HIER START EEN NIEUWE REGEL
    var line = "";

    /* Layout;
    ___________________________
    |      |  headerColumn     |
    | Icon |  contentColumn    |
    |______|___________________|
    */

    this.rowNum ++;

    // Icon
    var iconHtml = "";
    if (this.iconColumn) {
      var icon = __fnContent(this.iconColumn)(oRs, this.processParams)
      if (icon) {
        if (icon.match(/^<img/)) { // Ik ben al een plaatje :)
            iconHtml = icon;
        } else if (icon.match(/^fa-/)) {
            iconHtml = '<span class="pda-list-icon">' + I(icon + " fa-2x") + '</span>';
        } else if (icon.match(/^</)) { // safe html, bv een <div> of <i>
            iconHtml = '<span class="pda-list-icon">' + icon + '</span>';
        } else {
            iconHtml = '<img loading="lazy" src="' + safe.htmlattr(icon) + '" alt="' + L("lcl_photos") + '">';
        }
        iconHtml = "<div class='list-illustration flex-center'>" + iconHtml + "</div>";
      }
    }

    // Header
    var headerHtml = "<div class='list-header text-primary'>";
    if (this.headerColumn) {
      var headerText = __fnContent(this.headerColumn)(oRs, this.processParams);
      if (headerText) {
        headerHtml += "<h6 class='limit-lines-2'>" + headerText + "</h6>";
      }
    }
    if (this.detailColumn) {
      var detailText = __fnContent(this.detailColumn)(oRs, this.processParams);
      if (detailText) {
        headerHtml += "<div class='list-header-detail text-secondary'>" + detailText + "</div>";
      }
    }
    headerHtml += "</div>";
    if (this.subheaderColumn) {
      var subheaderText = __fnContent(this.subheaderColumn)(oRs, this.processParams);
      if (subheaderText) {
        headerHtml += "<div class='subheader'>" + subheaderText +"</div>";
      }
    }

    // Body
    var contentHtml = "<div class='list-body'>";

    if (this.asideColumn) {
      var asideText = __fnContent(this.asideColumn)(oRs, this.processParams);
      if (asideText) {
        contentHtml += "<div class='list-aside badge text-bg-secondary'>" + asideText + "</div>";
      }
    }
    contentHtml += "</div>";

    line = iconHtml + "<div class='list-content flex-column'>" + headerHtml + contentHtml + "</div>";

    var thisRowClass = "flex-center-y gap-3 list-group-item";

    if (this.hasMultiactions) {
      thisRowClass += " bulkable";
    }

    if (this.rowClass) {
      thisRowClass += " " + __fnContent(this.rowClass)(oRs, this.processParams);
    }

    var thisRowDataAttribute = "";
    if (this.multiactions && this.keyColumn) {
      thisRowDataAttribute = " data-row-key='" + oRs(this.keyColumn).Value + "'";
    }

    var linkAttrHtml = null;
    if (this.linkColumn) {
      linkAttrHtml = "href='" + safe.htmlattr(__fnContent(this.linkColumn)(oRs, this.processParams)) + "'";
    } else if (this.click) {
      linkAttrHtml = "href='#' onclick='" + safe.htmlattr(__fnContent(this.click)(oRs, this.processParams)) + "'";
    }
    if (linkAttrHtml) {
      thisRowClass += " list-group-item-action";
      return "<a " + linkAttrHtml + " class='" + thisRowClass + "'" + thisRowDataAttribute + ">" + line + "</a>";
    }

    return "<div class='" + thisRowClass + "'" + thisRowDataAttribute + ">" + line + "</div>";
}

function __rsCountHistogram(oRs)
{
    var i, kolomnaam, kolomval, cnt;
    for (i= 0; i < oRs.Fields.Count; i++)
    {
        kolomnaam = oRs.Fields(i).Name;
        if (kolomnaam.toUpperCase() == this.keyColumn.toUpperCase())
            continue;
        kolomval = oRs.Fields(i).Value;
        if (!this.Counter[kolomnaam])
            this.Counter[kolomnaam] = {};
        if (!this.Counter[kolomnaam][kolomval])
            this.Counter[kolomnaam][kolomval] = 1;
        else
            this.Counter[kolomnaam][kolomval] += 1
    }
}

function __rsEnableMultiactions(oRs) {
  for (var i = 0; i < this.multiactions.length; i++) {
    if (this.multiactions[i].enabled === false) {
      this.multiactions[i].enabled = this.multiactions[i].fnCheckIfAny(oRs);
    }
  }
}

// Levert een html-safe waarde op
ResultsetTable.formatValue = function (val, params) //datatype, decimals)
{
    if (val == null)
    {
        return "";
    }
    if (typeof val == "object" && "name" in val) // Vanuit API2
        val = val["name"];

    // Eerst de geforceerde datatypes
    switch (params.datatype)
    {
        case "date"    : return toDateString(val);
        case "datetime": return toDateTimeString(val, false);
        case "time"    : { val = toTimeString(val);
                           if (params.datatype == "time" && params.nomidnight && val == "00:00")
                             val = "";
                           return val;
                         }
        case "currency": return safe.curr(val);
        case "float"   : return safe.displayfloat(val, params.decimals);
        case "number"  : return val;
        case "html"    : return val;
    }

    // Autotypering "datum"
    if (typeof val == "date" || val instanceof Date)
        return toDateTimeString(val);   // PF: heb ik ff getweakt, moet natuurlijk niet zo (date vs datetime)

    if (!val)
        return "";

    // default datatype is "string"
    val = String(val);

    val = shared.stripbbcodes(val);

    return safe.html(val); // altijd simpelweg hele tekst
}
function __fnContent(fnContent)
{
    if (fnContent instanceof Function)
        return fnContent;

    return function (oRs)
    {
        return ResultsetTable.formatValue(oRs.Fields(fnContent).Value, {datatype: this.datatype, decimals: this.decimals, nomidnight: this.nomidnight})
    } ;
}
%>
