<% /*
    $Revision$
    $Id$

    File:        scaffolding_search.asp

    Description: Generiek zoekscherm
    Parameters:
    Context:
    Note:

*/ %>
<%
function scf_search_field (model, fld, defaults, scf_params, includefilters)
{
    var xmodel = model;

    if (fld.indexOf(".") > 0) // Bij res_ruimte configurations.res_opstelling_key ofwel <include>.<field>
    {
        includefilters.push(fld);
        xmodel = model.includes[fld.split(".")[0]].model;
        var fld = fld.split(".")[1];
    }

    var field = xmodel.fields[fld];
    if (!field) // Een veld kan verwijderd zijn met delete this.fields.veld.
        return;

    if (field.typ == "time") // Doen we nog niet
        return;

    field.defaultvalue = null;

    if (field.hidden || field.nosearch)
        return;

    if (field.typ == "memo")
        field.typ = "varchar"; // We hoeven geen groot veld om in te zoeken

    var def = field.filterdefault || defaults[fld];
    var defs = scf.parseDefault(def, field);

    if (!("filter" in field) && (!("bits" in field)))
    {   // default filtertypes
        switch (field.typ)
        {
            case "key":
                field.filter = "exact";
                break;
            case "float":
            case "currency":
                field.filter = "range";
                break;
            case "number":
                field.filter = field.LOV?"exact":"range";
                break;
            case "check":
            case "check0":
                field.filter = "exact";
                break;
            case "varchar":
            case "memo":
                field.filter = "like";
                break;
            case "date":
            case "datetime":
                field.filter = "range";
                break;
        }
    }

    var cntfield = 0;
    if (field.filter == 'like' || field.filter == 'exact' || !("filter" in field))
    {
        if (scf_params.fcltfilters && scf_params.fcltfilters[fld])
        {   // pinned filter parameters
            var fldval = scf_params.fcltfilters[fld];
            var LOVval = "";
            if (typeof fldval == "string")
            {
                scf_RWFIELDTR(xmodel, fld, fldval, null, {search: true, extraclass: "pinned"});
            }
            else
            {
                for (var j=0; j<fldval.length; j++)
                {
                    LOVval += fldval[j] + ";" + fldval[j] + (j<fldval.length-1 ? ";" : "");
                }
                field.LOV = LOVval;
                field.emptyoption = null;
                scf_RWFIELDTR(xmodel, fld, defs.vmin, null, {readonly: true, extraclass: "pinned"});
            }
            cntfield = 1;
        }
        else
        {
            if (defs.fixed)
            {
                if (field.showfixedfilter)
                {
                    scf_ROFIELDTR(xmodel, fld, defs.vmin, null);
                    cntfield = 1;
                }
            }
            else
            {
                scf_RWFIELDTR(xmodel, fld, defs.vmin, null, {search: true});
                cntfield = 1;
            }
        }
    }
    else if (field.filter == "range")
    {
        if (!defs.fixed)
        {
            var org_label = field.label;
            field.label = org_label + " " + (field.typ == "date" ? L("lcl_period_from") : L("lcl_from"));
            scf_RWFIELDTR(xmodel, "start_" + fld, defs.vmin, null, {search: true, required: field.filterrequired});
            field.label = org_label + " " + (field.typ == "date" ? L("lcl_period_to") : L("lcl_through"));
            scf_RWFIELDTR(xmodel, "end_" + fld, defs.vmax, null, {search: true, required: field.filterrequired});
            field.label = org_label;
            cntfield = 2;
        }
    }
    else if (field.filter == "parameter")
    {
        scf_RWFIELDTR(xmodel, fld, defs.vmin, null, {search: true});
        cntfield = 1;
    }

    return cntfield;
}

function scaffolding_search(model, scf_params)
{
    scf_params.search = scf_params.search || model.search;
    scf_params.list = scf_params.list || model.list || {};
    scf_params.title_locked = scf_params.title_locked || 0;

    if ("search" in model)
    {
        scf_params.search.title = scf_params.search.title || model.search.title || model.records_title;
        scf_params.search.filters = scf_params.search.filters || model.search.filters || [];
    }
    FCLTHeader.Requires({plugins:[],
                         js: ["jquery-ui.js", "jquery.timepicker-table.js"],
                         css: ["timePicker-table.css"]});
    if ("requires" in scf_params.search)
        FCLTHeader.Requires(scf_params.search.requires);

    if (model.autfunction)
        var authparams = user.checkAutorisation(model.autfunction);

    scf_params.search.autosearch |= getQParamInt("autosearch", 0) == 1;

    if ("hook_pre_search" in model)
        model.hook_pre_search(model.fields);
    %>
    <html>
    <head>
     <% FCLTHeader.Generate() %>
<%
    if (FCLTHeader.filters)
        scf_params.fcltfilters = JSON.parse(FCLTHeader.filters);
%>
        <script>
          <% if ("title" in scf_params.search && !scf_params.title_locked) { %>
              FcltMgr.setTitle("<%=safe.jsstring(scf_params.search.title)%>");
          <% } %>

          <% if (S("fac_usrrap_keepfilter") == 1 && "keepfilter" in scf_params.search) { %>
                if (!window.fcltfilters)
                    window.fcltfilters = FcltMgr.getData("filters_<%=safe.jsstring(scf_params.search.keepfilter)%>");
          <% } %>

          $(function ()
          {
            $("#scfcolpicker table tbody" ).not('thead tr').sortable({ axis: "y", distance: 10 });

            $("#chkall").click(function () // Allemaal aan of uit
            {
                $("#scfcolpicker tr").find("input[type=checkbox]").prop("checked", $(this).prop("checked"))
            });

            $(document).click(function()
            {
                $("#scfcolpicker").hide();
            });

            $("#scfcolpicker").click(function(event)
            {
                event.stopPropagation();
            });

            $("select").not(".notmulti").multiSelectToggle({ xxxlabel: "<span class='autoreport'><%=I("fa-comment")%>&nbsp;</span>" });

            hideEmptySelect();
          });

          function pick_columns(deze)
          {
            $("#scfcolpicker").show();
            updateTableHeaders();
          }

          function min_block_length(arr)
          {
            var i = 0;
            var m = arr[i]; // Ik verwacht minimaal 1 block.
            if (arr.length > 1)
            {
                for (a=0; a<arr.length; a++)
                {
                    if (arr[a] < m)
                    {
                        i = a;
                        m = arr[a];
                    }
                }
            }
            return i;
          }

          function addFilter(sel) // verplaats het van de verborgen optionalfilters tabel naar de echte filtertabel
          {
            var fld = $(sel).val();
            // Welk searchblock heeft het minst aantal regel. Daar moet het filterveld aan toegevoegd worden.
            var index = min_block_length(blkcount);
            // Tel het aantal toegevoegde filtervelden bij het searchblock op. Dit kunnen er ook 2 zijn als het een range veld is.
            blkcount[index] += $("table#optionalfilters").find("#"+fld).length
                             + $("table#optionalfilters").find("#start_"+fld).length
                             + $("table#optionalfilters").find("#end_"+fld).length;
            // Kopieer veld(en) uit optionalfilters naar een van de searchblocken.
            $("table#searchblock_"+index).append($("table#optionalfilters").find("#{0},#start_{0},#end_{0}".format(fld)).addClass("adhoc").closest("tr"));
            $(sel).find("option:selected").remove();
            hideEmptySelect();
          }

          function hideEmptySelect()
          {
            $sel = $("select.notmulti.extrafilter:visible");
            if ($sel.length == 1 && $sel.find("option").length == 1) // altijd 1 lege option-tag
                $sel.parent("div").css("display", "none");
          }

          async function doSubmit()
          {
            $("#scfcolpicker").hide();

            if (!await validateForm("u2"))
              return false;

            var cols = [];
            var groups = [];
            $("#scfcolpicker tr").each(function()
                {
                    if (!this.id)
                        return;

                    if (this.id == "chk_pivot")
                        return;

                    if ($(this).find("input[type=checkbox]").prop("checked"))
                    {
                        cols.push(this.id);
                        var selectgroup = $(this).find("select").val();
                        var defaultgroup = $(this).find("input[type=checkbox]").attr("group");
                        var thisgroup = (selectgroup?selectgroup:defaultgroup);
                        groups.push( (thisgroup?thisgroup:"") );
                    }
                }
            );
            /*
            if ($("show_deleted").is(":checked"))
            {   // het soft_delete veld zit niet in het model
                cols.push("<%=model.soft_delete%>");
                groups.push('G');
            }
            */
            $("#columns").val(cols.join(","));
            $("#groupby").val(groups.join(","));

            if ($("#chk_pivot").length)
                $("#scf_pivot").val($("#chk_pivot").prop("checked")?1:0);

            if ($("#workFrame").is(":visible"))
                $("#workFrame").width($(window).width()); // grafieken 'krimpen' slecht

            <% if (S("fac_usrrap_keepfilter") == 1 && "keepfilter" in scf_params.search) { %>
                var filters = iface.formToString($("form[name=u2]"), false);
                FcltMgr.setData("filters_<%=safe.jsstring(scf_params.search.keepfilter)%>", filters);
            <% } %>

            document.forms.u2.submit();
          }
<%    if (scf_params.search.autosearch)
      { %>
          window.afterfiltersready = function () { doSubmit() };
<%    } %>
        </script>
    </head>

    <body id="searchbody">
<%
      var filtercols = I("fa-search-plus") + "  <span class='extrafilter'>"+L("lcl_scf_extra_filter")+"&nbsp;</span>"
                     + "  <select class='notmulti fld extrafilter' onchange='addFilter(this)'><option></option>";

        for (var fld in model.fields) // Nu alle optionele filters
        {
            var field = model.fields[fld];
            // Deze kun je ook niet aanzetten. Dan is filteren ook niet logisch denk ik
            if (field.hidden || field.nosearch || field.typ=="label" || field.visible == "H")
                continue;
            if (field.typ == "html" || field.typ == "time" || field.typ == "processingtime") // te raar om op te filteren
                continue;
            if (!field.label || field.label == '<hidden>' || !field.dbs)
                continue;
            if (!inArray(fld, scf_params.search.filters))
                filtercols += "<option value='{0}'>{1}</option>".format(fld, model.fields[fld].label);
        }

      filtercols += "</select>";
%>
        <form name="u2" method="get" target="workFrame" onsubmit="doSubmit()">
    <%
        var defaults = shared.qs2json(model); // TODO: Ook via scf_params
        if (!("fcltfilters" in scf_params)) {
            scf_params.fcltfilters = shared.qs2json(model, true);
            if (!isEmptyObject(scf_params.fcltfilters)) {
                Response.Write("<script>var fcltfilters = '" + safe.jsstring(JSON.stringify(scf_params.fcltfilters)) + "';</script>");
            }
        }

        for (var fld in model.fields)
        {
            var field = model.fields[fld];
            if (field.hidden && fld in defaults)
            {
                Response.Write("<input type='hidden' name='" + fld + "' value='" + safe.htmlattr(defaults[fld]) + "'>");
            }
        }
        if (scf_params.transit)
        {
            var tdata = scf_params.transit;
            for (trans in tdata) {
        %>
                <input type='hidden' name='<%=safe.htmlattr(trans)%>' value='<%=safe.htmlattr(tdata[trans])%>'>
        <%  }
        }
    %>
            <input type='hidden' name='mode' value='list'>
            <input type='hidden' name='columns' id='columns'>
            <input type='hidden' name='groupby' id='groupby'>
            <input type='hidden' name='scf_pivot' <%=(model.list.autoPivot&1 ? "" : "class='final' ")%>id='scf_pivot' value='<%=(model.list.autoPivot&2)?1:0%>'>
    <%

        var est_title = "";
        if ("estimated_rows" in model)
            est_title = " <em style='font-size:10px'>estimated {0} rows as of {1}</em>".format(model.estimated_rows, toDateTimeString(model.last_analyzed));
        else
            est_title = " " + safe.html(model.records_title);

        SEARCH_PAGE_START({ header: L("lcl_filterblok") + est_title, ishtmlsafe: true, filtercols: filtercols } );
            var search_blocks = [];
            if (scf_params && scf_params.layout && scf_params.layout.search_block)
            {
                search_blocks = scf_params.layout.search_block;
            }
            else
            {
                search_blocks.push( { filters:(scf_params.search.filters ? scf_params.search.filters : [])
                                    , labels: (scf_params.search.labels  ? scf_params.search.labels  : [])
                                    });
            }

            var blkcount = [];
            for (var sblk=0; sblk<search_blocks.length; sblk++)
            {
                var search = search_blocks[sblk];
                blkcount.push(0);
                SEARCH_BLOCK_START( { volgnr: sblk });
                    if (search.labels)
                    {
                        for (var i=0; i < search.labels.length; i++)
                        {
                            ROFIELDTR("fldtxt", search.labels[i].lbl, search.labels[i].txt, { suppressEmpty: true });
                            blkcount[sblk]++;
                        }
                    }

                    var includefilters = [];
                    for (var i=0; i < search.filters.length; i++)
                    {
                        var fld = search.filters[i];
                        blkcount[sblk] += scf_search_field(model, fld, defaults, scf_params, includefilters)
                    }
                    if (model.soft_delete)
                    {
                        RWCHECKBOXTR("show_deleted", "fldcheck", L("lcl_scf_show_deleted"), defaults["show_deleted"]);
                        blkcount[sblk]++;
                    }
                    if (model.soft_expire)
                    {
                        RWCHECKBOXTR("show_expired", "fldcheck", L("lcl_scf_show_expired"), defaults["show_expired"]);
                        blkcount[sblk]++;
                    }
                    if (scf_params.search.show_filters)
                        scf_params.search.show_filters();

                    if (model.includes)
                    {
                        for (var i in model.includes)
                        {
                            if ("outertoggle" in model.includes[i])
                            {
                                RWCHECKBOXTR("scf_outer", "fldcheck", model.includes[i]["outertoggle"].lbl, model.includes[i]["outertoggle"].def);
                                blkcount[sblk]++;
                            }
                        }
                    }

                    if ((model.list.autoGraph & 1) == 1 || (model.list.autoGraph & 2) == 2)
                    {
                        var filter = "0,1,2,3,4,5";
                        if (model.list.canKaart) {
                            filter += ",6";
                        }
                        if (model.list.canKalender) {
                            filter += ",7";
                            Response.Write("<input type='hidden' name='worker' value='calendar'>");
                            if ((model.list.hasRequiredCalendarFields & 1) || hasQParam("calendarview")) { // &2 = dateTime != basic
                                Response.Write("<input type='hidden' name='calendarview' value='" + getQParamSafe("calendarview", "basic") + "'>");
                            }
                        }
                        var LOV = api2.filterLOV(L("lcl_usrrap_graphtypeLOV"), filter);
                        var sql = api2.splitLOV2sql(LOV);
                        var hidden = (model.list.autoGraph & 3) == 2;
                        if (hidden)
                            scf_RWHIDDENTR(model, "scf_graph_type", model.graph_type.id);
                        else
                        {
                            FCLTselector("scf_graph_type" + (hidden ? "_disabled" : "") ,
                                         sql,
                                         { label: L("lcl_usrrap_graphtype"),
                                           initKey: (model.list.autoGraph & 2) == 2 ? model.graph_type.id : null,
                                           extraclass: "notmulti"
                                         });
                            blkcount[sblk]++;
                        }
                    }

                    if ((model.list.autoCond & 1) == 1)
                    {
                        var on = (model.list.autoCond & 2) == 2;
                        RWCHECKBOXTR("scf_cond", "fldcheck", L("lcl_scf_cond"), on);
                        blkcount[sblk]++;
                    }

                    if (includefilters.length)
                        scf_RWHIDDENTR(model, "includefilter", includefilters.join(","));

                SEARCH_BLOCK_END();
            }

            SIMPLE_BLOCK_START();
                var buttons =  [];
                buttons.push({title: L("lcl_overview_list"), action: "doSubmit()", icon: "fa-clipboard-list", importance: 1 });

                if (model.list && !model.list.fixedColumns)
                    buttons.push({title: L("lcl_scf_columns"), action: "pick_columns(this)", icon: "fa-line-columns", importance: 3 });
                CreateButtons(buttons, { entersubmit: true, showIcons: true });
            SIMPLE_BLOCK_END();
%>
          <script>
            var blkcount = <%="["+ blkcount.join(",") + "]"%>;
          </script>
<%          SEARCH_PAGE_END();
%>
        </form>

        <table id='optionalfilters' style='display:none;'>
<%
        for (var fld in model.fields) // Nu alle optionele filters
        {
            var field = model.fields[fld];
            if (field.typ == "html" || field.typ == "processingtime" || field.nosearch) // te raar om op te filteren
                continue;
            if (!inArray(fld, scf_params.search.filters))
                scf_search_field(model, fld, defaults, scf_params)
        }
%>
        </table>

        <div id="scfcolpicker" style='display:none'>
            <table class="no-floating">
            <%
                if (model.list && model.list.canGroup)
                    Response.Write("<thead><tr><th><input id='chkall' type='checkbox'>" + L("lcl_rap_visible") + "</th><th>" + L("lcl_rap_groupby") + "</th></tr></thead>");
                else
                    Response.Write("<thead><tr><th><input id='chkall'  type='checkbox'>" + L("lcl_rap_visible") + "</th></tr></thead>");

                Response.Write("<tbody>");
                // Bouw het fields object opnieuw op in de volgorde van params.columns. Goed voor sorteren later.
                // Sortering van hide_f sorteer velden lossen we in model_reports wel op.
                var newfields = {};
                for (var i=0; i < scf_params.list.columns.length; i++)
                {
                    var fld = scf_params.list.columns[i];
                    if (fld in model.fields)
                    {
                        newfields[fld] = model.fields[fld];
                        delete model.fields[fld];
                    }
                }
                for (fld in model.fields)
                    newfields[fld] = model.fields[fld];
                model.fields = newfields;

                var url_html = [];
                for (fld in model.fields)
                {
                    var field = model.fields[fld];
                    if (field.hidden || field.typ=="label") // Hidden kun je ook niet aanzetten, en labels idem.
                        continue;
                    if (!field.label || field.label == '<hidden>' || !field.dbs)
                        continue;

                    var on = inArray(fld, scf_params.list.columns) ||
                             field.visible == "U"; // De url-key kolom moet altijd meegenomen worden als url en moet dus altijd aangevinkt zijn.
                    var groupselector = "";
                    var groupdefault = ""
                    if (model.list && field.typ != "varchar" && field.typ != "html" && !field.dbs.match(/_key$/i))
                    {
                        if (model.list.canGroup)
                        {
                            if (field.typ == "date" || field.typ == "datetime")
                                grp = api2.filterLOV(L("lcl_rap_groupbyLOV"), "G,D,W,M,Q,Y,H");
                            else if (field.typ == "time")
                                grp = api2.filterLOV(L("lcl_rap_groupbyLOV"), "G,H");
                            else if (field.typ == 'varchar')
                                grp = api2.filterLOV(L("lcl_rap_groupbyLOV"), "G");
                            else
                                grp = api2.filterLOV(L("lcl_rap_groupbyLOV"), "G,S,C,A");
                            groupselector = "<td>" + api2.splitLOV2select(grp , field.group.id, { selclass: "notmulti" }) + "</td>";
                        }
                        else
                        {
                            if (field.group && field.group.id != "G")
                                groupdefault = field.group.id;
                        }
                    }
                    var html = "\n<tr id='" + fld + "'"
                             + (field.visible == "U"  // De klik-actie kolom niet tonen.
                               ? " style='display: none;'"
                               : "")
                             + "><td><label>"
                             + "<input type='checkbox'" + (on?" checked='1'":"")
                                                        + (groupdefault
                                                          ? " group='" + safe.html(groupdefault) + "'"
                                                          : "")
                                                        + ">"
                             + (field.label || ("<"+field.dbs+">")) + "</label></td>"
                             + groupselector
                             + "</tr>"
                    if (field.visible == "U")
                      url_html.push(html); // Als de kolom als url-key kolom wordt gebruikt dan deze als laatste kolom toevoegen zodat deze nooit als x-as genomen kan worden.
                    else
                      Response.Write(html);
                }
                for (var i = 0; i < scf_params.list.columns.length; i++)
                {
                    var col = scf_params.list.columns[i];
                    if (col.indexOf(".") > 0)
                    {
                        var on = true;
                        var xmodel = model.includes[col.split(".")[0]].model;
                        var field = xmodel.fields[col.split(".")[1]];
                        Response.Write("\n<tr id='" + col + "'><td><label><input type='checkbox'" + (on?" checked='1'":"") + ">"
                                                              + (field.label || ("<"+field.dbs+">")) + "</label></td>");
                    }
                }
                // Kolom "Aantal" is altijd zichtbaar is de lijst met kolommen, behalve als de standaardwaarde "altijd uit"="Nee" is.
                if (model.list.autoCount > 0)
                {
                    var on = (model.list.autoCount & 2) == 2; // Standaard waarde van "Aantal" is "on".
                    var toggle = (model.list.autoCount & 1) == 1; // Veld "Aantal" mag getoggled worden.
                    Response.Write("\n<tr id='scf_count'><td><label><input type='checkbox'"
                                                          + (on?" checked='1'":"")
                                                          + (toggle?"":" disabled")
                                                          + ">"
                                                          + L("lcl_count") + "</label></td></tr>");
                }
                // Idem voor Kolom "Ratio"
                if (model.list.autoRatio > 0)
                {
                    var on = (model.list.autoRatio & 2) == 2; // Standaard waarde van "Aantal" is "on".
                    var toggle = (model.list.autoRatio & 1) == 1; // Veld "Aantal" mag getoggled worden.
                    Response.Write("\n<tr id='scf_ratio'><td><label><input type='checkbox'"
                                                          + (on?" checked='1'":"")
                                                          + (toggle?"":" disabled")
                                                          + ">"
                                                          + L("lcl_ratio") + "</label></td></tr>");
                }
                if (url_html.length)
                { // Er kan maar 1 colom als url-key kolom optreden. We pakken de eerste.
                  Response.Write(url_html[0]);
                }

                if ((model.list.autoPivot & 1) == 1)
                {
                    var on = (model.list.autoPivot & 2) == 2;
                    Response.Write("<tfoot><tr><td><label for='chk_pivot'><input type='checkbox' id='chk_pivot' " + (on?" checked='1'":"") + ">"
                                               + L("lcl_scf_pivot") + "</label></td></tr></tfoot>");
                }
             %>
            </tbody>
            </table>
<%
            buttons = [];
            buttons.push({title: L("lcl_overview_list"), icon: "fa-fclt-save", action: "doSubmit()", importance: 1 });
            buttons.push({title: L("lcl_cancel"), icon: "fa-fclt-cancel", action: "$('#scfcolpicker').hide()", importance: 3 });
            CreateButtons(buttons, { showIcons: true });
%>
        </div>

        <div id="result">
        <iframe width="100%" height="100%" src="<%=rooturl%>/appl/Shared/empty.asp"
                name="workFrame" id="workFrame"  onload="FcltMgr.iframeLoaded(this);$(window.frameElement).change();"
                <% if (scf_params.search.autosearch) { %>skipautoscroll="1"<% } %>
                <% if (scf_params.search.keepfilters) { %>keepfilters="1"<% } %>
                frameborder="0" scrolling="no"></iframe>
        </div>
    </body>
    </html>
<%
}
%>