<% /*
    $Revision$
    $Id$

    File:           model_reports.inc

    Description:    rapport model voor *de data* van een specifiek rapport.
                    Zal rapporten uitvoeren dus. Het *bewerken* van rapporten gaat via model_reportsx
    Parameters:
    Context:

    Notes:
*/
%>
<!-- #include file="./model_reportsx.inc" -->
<!-- #include file="../fac/fac_usrrap.inc" -->
<%

function model_reports_template()
{
    this.table = "te bepalen";
    this.primary = null;
    this.records_name = "te bepalen";
    this.record_name = "te bepalen";
    this.fields = {/* te bepalen */};
    this.autfunction = null;

    this.REST_GET = report_GET;

    this.REST_PUT = false;
    this.REST_POST = false;
    this.REST_DELETE = false;

    // Let op: wordt ook vanuit fac/fac_report.asp gebruikt voor xml-styled rapporten
    // Ook: de bevroren filtervelden er bij
    this.addfixedfilters = function _addfixedfilters(filter)
    {
        filter.fclt_3d_user_key = user_key; // Die is gemakkelijk
        for (var fld in this.fields)
        {
            var field = this.fields[fld];
            if (!field.filterdefault)
                continue;

            var fixed = field.filterdefault.substr(0,2) == ':!';
            if (!(fld in filter) || fixed) // Filter/fixed?
            {
                var defs = scf.parseDefault(field.filterdefault, field);
                if (field.filter == 'like' || field.filter == 'exact' || !("filter" in field))
                {
                    if (fixed || !(fld in filter))
                        filter[fld] = defs.vmin;
                }
                else if (field.filter == "range")
                {
                    if (fixed || !("start_" + fld in filter))
                        filter["start_" + fld] = defs.vmin;
                    if (fixed || !("end_" + fld in filter))
                        filter["end_" + fld] = defs.vmax;
                }
            }
        }
    };

    // Let op: wordt ook vanuit fac/fac_report.asp gebruikt voor xml-styled rapporten
    // Deze zijn complexer en red ik niet via addfixedfilters
    this.add3d = function _add3d(wheres)
    {
        if (this.autfunction)
        {
            var sql = "SELECT fac_functie_code, fac_functie_min_level, fac_functie_discipline"
                    + "  FROM fac_functie f"
                    + " WHERE f.fac_functie_key = " + this.authparams.autfunctionkey;
            var oRs = Oracle.Execute(sql);

            var bMetALGAuth    = (oRs("fac_functie_min_level").Value & 8) == 8;
            var bMetPRSAuth    = (oRs("fac_functie_min_level").Value & 4) == 4;
            var bMetDiscipline = (oRs("fac_functie_discipline").Value == 1);
            oRs.Close();

            if (bMetALGAuth && "fclt_3d_locatie_key" in this.fields && this.authparams.ALGreadlevel > -1)
            {
                wheres.push(" fclt_3d_locatie_key IN"
                          + "(SELECT alg_locatie_key FROM fac_v_my_locations "
                          + "  WHERE niveau ="+this.authparams.ALGreadlevel
                          + "    AND prs_perslid_key="+user_key+")");
            }
            if (bMetALGAuth && "fclt_3d_gebouw_key" in this.fields && this.authparams.ALGreadlevel > -1)
            {
                wheres.push(" fclt_3d_gebouw_key IN"
                          + "((SELECT alg_gebouw_key FROM fac_v_my_buildings "
                          + "  WHERE niveau ="+this.authparams.ALGreadlevel
                          + "    AND prs_perslid_key="+user_key+"))");
            }
            if (bMetPRSAuth && "fclt_3d_afdeling_key" in this.fields)
            {
                if (this.authparams.PRSreadlevel == 0)
                {
                    wheres.push(" fclt_3d_afdeling_key IN"
                              + " (SELECT a.prs_afdeling_key FROM prs_v_afdeling a "
                	          + "   WHERE a.prs_bedrijf_key = " + user.afdeling().prs_bedrijf_key() + ")");
                }
                else if (this.authparams.PRSreadlevel > 0)
                {
                    wheres.push(" fclt_3d_afdeling_key IN"
                              + "(SELECT prs_afdeling_key FROM prs_v_afdeling_familie a"
                              + "      WHERE a.prs_afdeling_elder_key IN"
                              + "        (SELECT aa.prs_afdeling_elder_key"
                              + "           FROM prs_v_afdeling_familie aa"
                              + "          WHERE aa.prs_afdeling_key = " + user.prs_afdeling_key()
                              + "            AND aa.niveau = " + this.authparams.PRSreadlevel + "))");
                }
            }
            if (bMetDiscipline && "fclt_3d_discipline_key" in this.fields)
            {
                var disciplines = [];
                var sql = "SELECT ins_discipline_key"
                        + "  FROM fac_v_my_disciplines "
                        + " WHERE fac_functie_code = " + safe.quoted_sql(this.autfunction)
                        + "   AND prs_perslid_key=" + user_key;
                var oRs = Oracle.Execute(sql);
                while (!oRs.Eof)
                {
                  disciplines.push(oRs("ins_discipline_key").Value);
                  oRs.MoveNext();
                }
                oRs.Close();
                if (!disciplines.length)
                    disciplines.push(-1);

                wheres.push("fclt_3d_discipline_key IN (" + disciplines.join(",") + ")");
            }
        }

        if ("fac_functie_key" in this.fields)
        {
            var whereor = ["fac_functie_key IS NULL"]
            whereor.push("fac_functie_key IN"
                             + " (SELECT w.fac_functie_key"
                             + "    FROM fac_v_webgebruiker W"
                             + "   WHERE w.prs_perslid_key = " + user_key + ")");
            if (user.has("WEB_UDRMAN"))
            {
                whereor.push("fac_functie_key NOT IN"
                             + "    (SELECT fac_functie_key"
                             + "       FROM fac_functie"
                             + "      WHERE fac_functie_code IN ('WEB_FACFAC', 'WEB_FACTAB'))");
            }
            wheres.push("(" + whereor.join(" OR ") +")");
        }
    };

    this.search = { title: L("lcl_usrrap_report"),
                    filters: [] }
}

// Voltooi model_reports_template voor een bepaald rapport
function model_reports(fac_usrrap_key)
{
    var reportsx = new model_reportsx(fac_usrrap_key, { include: ["columns"], internal: true }); // Internal om wel alle properties te krijgen
    var usrrap = reportsx.data;
    user.auth_required_or_abort(usrrap);

    var model = new model_reports_template();
    model.table = usrrap.viewname;

    if (usrrap.styling && usrrap.styling.id & 8) // Tabelized
        model.table = "T_" + usrrap.viewname.substring(0,28);  // anders mogelijk te lang voor Oracle

    model.record_name = usrrap.viewname.substring(0,1) + usrrap.viewname.substring(1).toLowerCase();
    model.records_name = model.record_name + "s";
    model.record_title = usrrap.name; // (initiele) titel bij urllink
    model.records_title = usrrap.name;
    model.autorefresh = usrrap.autorefresh;
    model.styling = usrrap.styling;
    model.graph_options = usrrap.graph_options;
    model.graph_type = usrrap.graph_type;
    model.list = { columns : [], groupby : [], canGroup: true, canCSV: true, autoCount: usrrap.count.id, autoPivot: usrrap.pivot.id, autoGraph: usrrap.graph.id, autoRatio: usrrap.ratio.id };
    if (model.styling && (model.styling.id & 1))
        model.list.fixedColumns = true;
    model.search.title = L("lcl_usrrap_report") + " " + usrrap.name;

    var keyfield = null;
    if (usrrap.urllink)
    {
        var mtc = usrrap.urllink.match(/(.*)\{(.*)\}/);
        if (!mtc || mtc.length != 3)
            shared.simpel_page("Urllink <em>{0}</em> in rapport moet formaat 'xxxx/yyy.asp?key={keyveld}' hebben.".format(usrrap.urllink));
        model.list.default_url = mtc[1];
        // Voorkom dat hij binnen menu-wrapper wordt getoond
        if (mtc[1].indexOf("?u=") == 0)
             model.list.default_url = "?internal=1&" + mtc[1].substring(1);
        keyfield = mtc[2];
    }

    if (usrrap.authorization)
    {
        var sql = "SELECT fac_functie_code FROM fac_functie WHERE fac_functie_key = " + usrrap.authorization.id;
        var oRs = Oracle.Execute(sql);
        model.autfunction = oRs("fac_functie_code").Value;
        model.authparams = user.checkAutorisation(model.autfunction); // leesrechten is wel het minste
        oRs.Close();
    }

    for (var i = 0; i < usrrap.columns.length; i++)
    {
        var label = safe.html(usrrap.columns[i].caption); // (lcl) Labels worden altijd geacht html-safe te zijn
        label = label.replace(/\\n/g, "<br/>");           // Voor overulen van gewone LCL's ligt de verantwoordelijkheid
                                                          // bij een beheerder maar rapportages wordt misschien wel fe
        var fixedlabel = false;
        if (label && label.substr(0,1) == "!") // Als een label begint met een ! wordt hij niet aangepast bij groepperen
        {
            fixedlabel = true;
            label = label.substr(1);
        }
        var field = { dbs: usrrap.columns[i].name,
                      label: label,
                      orglabel: label,
                      fixedlabel: fixedlabel,
                      sql: usrrap.columns[i].expression,
                      typ: usrrap.columns[i].datatype.id,
                      orgtyp: usrrap.columns[i].datatype.id,
                      group: usrrap.columns[i].group,
                      visible: usrrap.columns[i].visible.id
                    };
        if (field.typ == "number" && field.dbs.match(/_key$/i)) // Vooral de FCLT_3D filters
            field.typ = "key";
        if (field.typ == "number")
        {
            field.total = true;
            field.autofloat = true; // we weten het niet zeker
        }
        if (field.typ == "currency")
            field.total = true;
        if (field.typ == "varchar")
            field.autolike = true;
        if (field.visible == 'H' && field.dbs != keyfield) // Keyfield willen we eigenlijk altijd wel indien mogelijk
            field.hidden = true;

        if (usrrap.columns[i].filter)
        {
            if (usrrap.columns[i].filter.id == "A")
            {
                field.filter = { "date": "range",
                                 "datetime": "range",
                                 "time": "range",
                                 "varchar": "exact"
                               }[ field.typ ] || "exact";
            }
            else
            {
                field.filter = api2.splitLOV("E;exact;L;like;R;range")[usrrap.columns[i].filter.id]
            }
            field.filterdefault = usrrap.columns[i].filterdefault;
        }
        var fld = field.dbs.toLowerCase();

        if (fld == keyfield)
            fld = "id";
        model.fields[fld] = field;
        if (usrrap.columns[i].visible.id == 'V')
        {
            model.list.columns.push(fld);
            model.list.groupby.push(field.group.id);
        }
        if (usrrap.columns[i].filter)
            model.search.filters.push(fld);
    }

    if ((model.list.autoCount & 2) == 2)
    {
        model.list.columns.push("scf_count");
        model.list.groupby.push("");
    }
    if ((model.list.autoRatio & 2) == 2)
    {
        model.list.columns.push("scf_ratio");
        model.list.groupby.push("");
    }

    return model;
}

function report_GET(params)
{
    // Als parameters niet in de url zijn meegegeven is waarschijnlijk rechtstreeks de list
    // aangeroepen. Pak dan de geconfigureerde defaults
    def(params.filter, "scf_pivot", (this.list.autoPivot & 2)?2:0);
    def(params.filter, "scf_graph", (this.list.autoGraph & 2) == 2?"on":"");

    if (!params.columns)
    {
        params.columns = this.list.columns;
        params.groupby = this.list.groupby;
    }

    var groupbys = [];
    var hasAggregate = false; // Als er uitsluitend GROUP BY is zonder ook maar een enkele
                              // aggregate functie zouden effectief dubbelen verwijderd worden.
                              // Dat mag niet zo maar

    if (params.columns && inArray("scf_count", params.columns))
    {
        if (params.columns.length == 1)
            shared.simpel_page(L("lcl_empty_rstable"));

        this.fields["scf_count"] = { dbs: "scf_count", sql: "COUNT(*)", typ: "number", label: L("lcl_count"), orglabel: L("lcl_count"), total: true };
        hasAggregate = true;
    }
    if (params.columns && inArray("scf_ratio", params.columns))
    {
        if (params.columns.length == 1)
            shared.simpel_page(L("lcl_empty_rstable"));

        this.fields["scf_ratio"] = { dbs: "scf_ratio", sql: "RATIO_TO_REPORT(COUNT(*)) OVER() * 100", typ: "float", label: L("lcl_ratio"), orglabel: L("lcl_ratio"), total: true };
        hasAggregate = true;
    }
    if (params.columns && params.groupby && params.groupby.length > 0)
    {
        if (params.columns.length != params.groupby.length)
        {
            __DoLog(params);
            INTERNAL_ERROR_GROUP_MISMATCH;
        }

        // Bouw het fields object opnieuw op in de volgorde van params.columns. Goed voor sorteren later.
        var has_hide_f = false;
        for (var fld in this.fields) // hide_f sorteer velden maakt het veel te ingewikkeld
        {
            if (this.fields[fld].dbs.match(/^hide_f/))
            {
                has_hide_f = true;
                break;
            }
        }
        if (!has_hide_f)
        {
            var newfields = {};
            for (var i=0; i < params.columns.length; i++)
            {
                var fld = params.columns[i];
                if (fld in this.fields)
                {
                    newfields[fld] = this.fields[fld];
                    delete this.fields[fld];
                }
            }
            for (fld in this.fields)
                newfields[fld] = this.fields[fld];
            this.fields = newfields;
        }

        for (var fld in this.fields)
        {
            if (!inArray(fld, params.columns))
            {
                if (this.list && this.list.default_url && fld == "id" && params.groupby[0] != 'U')
                    groupbys.push(this.fields["id"].dbs);
                else
                {
                    if  (params.groupby[0] != 'U' && this.fields[fld].dbs.match(/^hide_f/)) // Doorgaans meenemen om te sorteren
                    {
                        this.fields[fld].hidden = false;
                        params.columns.splice(0, 0, fld);
                        params.groupby.splice(0, 0, "G");
                    }
                    else
                        this.fields[fld].hidden = true; // Onnodige velden niet ophalen
                }
            }
        }

        for (var i=0; i < params.columns.length; i++)
        {
            var fld = params.columns[i];
            if (fld == "scf_count" || fld == "scf_ratio" )
                continue;
            var field = this.fields[fld];
            var field_expression = (field.sql ? field.sql : field.dbs);
            var field_group = (field.sql && field.sql.toUpperCase().indexOf("SELECT") > 0 ? i+1 : null); // Voorkom dat er een subselect in de group_by komt te staan.

            if (!field)
                shared.internal_error("Column {0} not found in report".format(fld));
            field.keepdbsforfilter = true;
            field.orgtyp = field.typ; // wil grafiek graag weten
            hasAggregate = hasAggregate || (params.groupby[i] || "G") != "G";
            switch (params.groupby[i] || "G")
            {
                case "G":
                    if (!field_group)
                        groupbys.push(field_expression);
                    break;
                case "U":
                    field.sql = "DISTINCT(" + field_expression + ")";
                    break;
                case "S":
                    field.sql = "SUM(" + field_expression + ")";
                    if (!field.fixedlabel)
                        field.label = L("lcl_usrrap_label_SUM").format(field.label);
                    field.newtyp = "float";
                    field.total = true;
                    break;
                case "C":
                    field.sql = "COUNT(" + field_expression + ")";
                    if (!field.fixedlabel)
                        field.label = L("lcl_usrrap_label_CNT").format(field.label);
                    field.newtyp = "number";
                    field.total = true;
                    break;
                case "A":
                    field.sql = "AVG(" + field_expression + ")";
                    if (!field.fixedlabel)
                        field.label = L("lcl_usrrap_label_AVG").format(field.label);
                    field.total = false;
                    field.newtyp = "float";
                    break;
                case "H":
                    if (field.typ == "date" || field.typ == "datetime")
                        field.sql = "TO_CHAR(" + field_expression + ", 'YYYY-MM-DD HH24')||':00'";
                    else
                        field.sql = "TO_CHAR(" + field_expression + ", 'HH24')||':00'";
                    field.newtyp = "varchar";
                    groupbys.push(field_group || field.sql);
                    if (!field.fixedlabel)
                        field.label = L("lcl_usrrap_label_HOUR").format(field.label);
                    break;
                case "D":
                    field.sql = "TRUNC(" + field_expression + ", 'DD')";
                    field.newtyp = "date";
                    groupbys.push(field_group || field.sql);
                    if (!field.fixedlabel)
                        field.label = L("lcl_usrrap_label_DAY").format(field.label);
                    break;
                case "W":
                    field.sql = "TO_CHAR(" + field_expression + ", 'YYYY-IW')";
                    field.newtyp = "varchar";
                    groupbys.push(field_group || field.sql);
                    if (!field.fixedlabel)
                        field.label = L("lcl_usrrap_label_WEEK").format(field.label);
                    break;
                case "M":
                    field.sql = "TO_CHAR(" + field_expression + ", 'YYYY-MM')";
                    field.newtyp = "varchar";
                    groupbys.push(field_group || field.sql);
                    if (!field.fixedlabel)
                        field.label = L("lcl_usrrap_label_MONTH").format(field.label);
                    break;
                case "Q":
                    field.sql = "TO_CHAR(" + field_expression + ", 'YYYY-Q')";
                    field.newtyp = "varchar";
                    groupbys.push(field.sql || field.sql);
                    if (!field.fixedlabel)
                        field.label = L("lcl_usrrap_label_QUARTER").format(field.label);
                    break;
                case "Y":
                    field.sql = "TO_CHAR(" + field_expression + ", 'YYYY')";
                    field.newtyp = "varchar";
                    groupbys.push(field_group || field.sql);
                    if (!field.fixedlabel)
                        field.label = L("lcl_usrrap_label_YEAR").format(field.label);
                    break;
            }
        }
    }

    for (var i=0; i < params.columns.length; i++)
    {
        var fld = params.columns[i];
        var field = this.fields[fld];
        if (!field)
            shared.internal_error("Column {0} not found in report".format(fld));
        if (field.dbs.match(/^hide_f/)) // Die willen we uiteindelijk niet zien
        {
            params.columns.splice(i, 1);
            params.groupby.splice(i, 1);
            i--;
        }
    }

    var query = api2.sqlfields(params, this);
    if (!query.selects.length)
        abort_with_warning("No columns defined for report");

    if ("addfixedfilters" in this)
        this.addfixedfilters(params.filter);
    var wheres = api2.sqlfilter(params, this);
    // RWSN#35799 Experimenteel: rapporten waarvan naam begint met OR_ doen een OR op de zichtbare filtervelden
    //if (this.records_title.substr(0,3) == "OR_")
    //{
    //    if (wheres.length)
    //        wheres = ["(" + wheres.join(" OR ") + ")"];
    //}
    if ("add3d" in this)
        this.add3d(wheres);

    query.wheres = query.wheres.concat(wheres);

    var sql = "SELECT " + query.selects.join(", ")
            + "  FROM " + query.tables.join(", ")
            + (query.wheres.length ? " WHERE " + query.wheres.join(" AND " ) : "")

    if (groupbys.length && hasAggregate)
        sql += " GROUP BY " + groupbys.join(", ");

    // Dit moet op volgorde van params.columns, niet per se query.selects
    // Gelukkig hebben we fields ondertussen al in de goede volgorde gezet
    var order = [];
    for (var i=0; i < query.selects.length; i++)
        order.push(i+1)
    sql += " ORDER BY " + order.join(", ");

    var maxcnt = params.filter.showall==1?S("qp_maxrows2"): (params.filter.ismobile?S("qp_maxrows_mobile"):S("qp_maxrows"));
    if (params.filter.scf_pivot == 1)
        params.filter.nolimit = true;
    var sql = "SELECT * FROM (" + sql + ")"
            + (params.filter.nolimit? "" : " WHERE ROWNUM <= " + (maxcnt+1)); // Eentje extra om overflow-melding te triggeren in resultsettable

    for (var fld in this.fields)
    {   // Overrules voor groeperingen
        this.fields[fld].typ = this.fields[fld].newtyp || this.fields[fld].typ;
    }
    params.errmsg = true; // Eventuele fout in query detecteren.
    var json = api2.sql2json (params, sql, this);

    if (params.filter.scf_pivot == 1) // Pivoteren!!!
    {   // De laatste colom beschouwen we als datacol die in de 'cellen' komt
        // De een-na-laatste colom gaan we pivotteren naar kolomkoppen
        var datacol = params.columns[params.columns.length - 1];
        var datagroup = params.groupby[params.groupby.length - 1];
        var pivotcol = params.columns[params.columns.length - 2];

        // Eerst een keer door de json data om de unieke pivotcol waardes te bepalen
        var pcolumns = {};
        for (var i = 0; i < json.length; i++)
        {
            if (pivotcol in json[i])
            {
                var colname = json[i][pivotcol];
                if (colname in pcolumns)
                {
                    pcolumns[colname].cnt ++; // we doen overigens niets met deze telling
                }
                else
                {
                    var collabel;
                    switch (this.fields[pivotcol].typ)
                    {
                        case "datetime":
                            collabel = toDateTimeString(colname);
                            break;
                        case "date":
                            collabel = toDateString(colname);
                            break;
                        case "time":
                            collabel = toTimeString(colname);
                            break;
                        default:
                            collabel = colname;
                    }
                    pcolumns[colname] = { cnt: 1, label: collabel };
                }
            }
        }
        var newdata = [];
        var newrecord = null;
        for (var i = 0; i < json.length; i++)
        {
            var olddata = json[i];
            var equal = !!newrecord;
            // Is het huidige record nog gelijk aan het vorige record (exclusief pivotcol en datacol)
            for (var j = 0; equal && j < params.columns.length - 2; j++)
            {
                var col = params.columns[j];
                equal = String(olddata[col]) == String(newrecord[col]); // Conversie naar String omdat date-objecten
                                                                        // anders niet matchen
            }
            if (!equal)
            {
                if (newrecord)
                    newdata.push(newrecord);
                newrecord = {}; // Begin nieuwe regel in het rapport
                for (var k = 0; k < params.columns.length - 2; k++)
                {
                    var col = params.columns[k];
                    newrecord[col] = olddata[col];
                }
                newrecord[datacol] = 0; // als datacol numeriek was bouw hier een regelsom
            }
            newrecord[olddata[pivotcol]] = olddata[datacol];
            newrecord[datacol] = newrecord[datacol] + olddata[datacol];
        }
        if (newrecord)
            newdata.push(newrecord);

        // Originele pivotcol en datacol verwijderen
        params.columns.splice(params.columns.length - 2, 2);

        // Nieuwe pivot kolommen ook in fields toevoegen
        var cols = [];
        for (var j in pcolumns)
            cols.push(j);
        cols.sort();
        for (j in cols)
        {
            params.columns.push(cols[j]);
            this.fields[cols[j]] = { label: safe.html(pcolumns[cols[j]].label), typ: this.fields[datacol].typ };
            if (this.fields[datacol].typ == 'number' || this.fields[datacol].typ == 'float' || this.fields[datacol].typ == 'currency')
            {
                this.fields[cols[j]].total = true;
            }
        }

        // Een numerieke datacol voegen we (gesommeerd) achteraan toe behalve bij grafieken, daar laten we hem er af
        if (params.filter["scf_graph"] != "on"
               && (this.fields[datacol].typ == 'number' || this.fields[datacol].typ == 'float' || this.fields[datacol].typ == 'currency')
               && datagroup != 'A'
                )
            params.columns.push(datacol);

        this.total_count = newdata.length;
        json = newdata;
    }

    // Filterwaarden van de rapportages verzamelen. Filter parameters kunnen dan aan overzicht meegegeven worden zodat ze ook in de printafdruk worden vermeld.
    json.filterstring = {};
    var filterstring = json.filterstring;
    var filter = params.filter;
    for (var flt in filter)
    { // Ik heb nu een parameter die is doorgegeven.
      // Alleen als een filterveld aanwezig is, wordt die parameter doorgegeven. Alleen dan is field gedefinieerd.
      var l_flt = flt;
      if (flt.substr(0, 6) == "start_")
        l_flt = flt.substr(6);
      else if (flt.substr(0, 4) == "end_")
        l_flt = flt.substr(4);
      var field = this.fields[l_flt];
      if (field)
      { // Field is gedefinieerd, dan is het een parameter van een filterveld.


        // Bij date of datetime filters wordt er bij het label " Van" en " Tot" achter geplakt.
        var vantot = "";
        var startend = "";
        if (flt.substr(0, 6) == "start_")
        {
          vantot = " " + L("lcl_from");
          startend = "start_";
        }
        else if (flt.substr(0, 4) == "end_")
        {
          vantot = " " + L("lcl_to");
          startend = "end_";
        }

        var llabel;
        var lval;
        switch (field.orgtyp)
        {
            case "date":     if (filter[flt] == "")
                               lval = "";
                             else
                             {
                               lval = new Date(parseInt(filter[flt], 10));
                               lval = toDateString(lval);
                             }
                             llabel = "fclt_f_" + startend + field.orglabel + vantot;
                             break;
            case "datetime": if (filter[flt] == "")
                               lval = "";
                             else
                             {
                               lval = new Date(parseInt(filter[flt], 10));
                               lval = toDateTimeString(lval);
                             }
                             llabel = "fclt_f_" + startend + field.orglabel + vantot;
                             break;
            default:         lval = filter[flt];
                             llabel = "fclt_f_" + startend + field.orglabel + vantot;
        }

        // Als lval uit meerdere waarden bestaat dan is lval een object (array).
        if (typeof lval == "object")
          lval = lval.join(", ");
        filterstring[llabel] = lval;
      }
    }

    // De filterwaarden van de rapportage zitten nu in json.filterstring.
    // __Log("Response.Write(JSON.stringify(json.filterstring)) = " + JSON.stringify(json.filterstring));

    return json;
};
%>