<% /*
     $Revision$
     $Id$

    File:        scaffolding.inc

    Description:
    Parameters:
    Context:
    */

var mode = getQParamSafe("mode", getQParam("id","")!=""?"wrap":"search");
var title_locked = getQParamInt("title_locked", 0);
if (Request.QueryString("api2").Count > 0)
{
    ANONYMOUS_Allowed = 1; // Eigenlijk niet waar. We regelen echter alles zelf
    mode = "api2";
}

if (mode == "save" || mode == "delete" || mode == "api2")
    var JSON_Result = true;
%>
<!-- #include file="../Shared/common.inc" -->
<!-- #include file="./scaffolding_common.inc" -->
<% if (mode == "wrap" || mode == "show" || mode == "edit" || mode == "search") { %>
<!-- #include file="../Shared/iface.inc" -->
<% } %>
<% if (mode != "save" && mode != "delete" && mode != "api2" && mode != "wrap") { %>
<% if (mode != "list" && mode != "print") { %>
<!-- #include file="../Shared/calendar.inc" -->
<!-- #include file="../Shared/selector.inc" -->
<!-- #include file="../Shared/afdelingselector.inc" -->
<!-- #include file="../Shared/persoonselector.inc" -->
<!-- #include file="../Shared/bedrijfselector.inc" -->
<!-- #include file="../Shared/autorisatieselector.inc" -->
<!-- #include file="../Shared/autorisatiegroepselector.inc" -->
<!-- #include file="../Shared/kostensoortselector.inc" -->
<!-- #include file="../Shared/kostenplaatsselector.inc" -->
<!-- #include file="../Shared/stdmeldingselector.inc" -->
<!-- #include file="../Shared/disciplineselector.inc" -->
<!-- #include file="../Shared/srtgroepselector.inc" -->
<!-- #include file="../Shared/srtdeelselector.inc" -->
<!-- #include file="../Shared/objectselector.inc" -->
<!-- #include file="../Shared/srtcontroleselector.inc" -->
<!-- #include file="../Shared/plaatsselector.inc" -->
<% } %>
<!-- #include file="../Shared/data_recordset.inc" -->
<!-- #include file="../Shared/resultset_table_v2.inc" -->
<% } %>
<!-- #include file="../api2/api2.inc" -->
<!-- #include file="../api2/api2_rest.inc" -->
<!-- #include file="./scaffolding_search.inc" -->
<!-- #include file="./scaffolding_list.inc" -->
<!-- #include file="./scaffolding_wrap.inc" -->
<!-- #include file="./scaffolding_show.inc" -->
<!-- #include file="./scaffolding_import.inc" -->
<!-- #include file="./scaffolding_edit.inc" -->
<!-- #include file="./scaffolding_save.inc" -->
<!-- #include file="./scaffolding_delete.inc" -->
<!-- #include file="./scaffolding_print.inc" -->
<%
function scaffolding(model, scf_params)
{
    scf_params = scf_params || {};
    var trans_fparams = scf_params.transit_flist;
    var trans_qparams = scf_params.transit_qlist;
    scf_params.title_locked = title_locked;
    if (mode == "api2") // Die is heel simpel
    {
        api2_rest.process(model);
        Response.End;
    }

    if (typeof model == "function") // Nieuwe stijl is het een function. Even compatible.
        model = new model();

    var imodel = getQParam("model", ""); // include model
    if (model.includes && imodel in model.includes)
    {
        if ("included" in scf_params)
            scf_params = scf_params.included[imodel] || {}
        else
            scf_params = {}; // settings gelden alleen op het hoofdmodel?
        scf_params.orgmodel = model;
        scf_params.incsetting = model.includes[imodel];
        // scf_params.incsetting.joinfield zal nu ook altijd in de url voorkomen
        // var parent_key = getQParamInt(scf_params.incsetting.joinfield);
        model = model.includes[imodel].model;
        if (model.defaultIcon && !("layout" in scf_params)) {
            scf_params.layout = {
                "miscellaneous": {
                    "icon": model.defaultIcon
                }
            }
        }
        if (typeof model == "function") // Nieuwe stijl is het een function. Even compatible.
            model = new model();
        scf_params.transit = { "model": imodel };
    }

    if (trans_fparams)
    {   // Doorgeven van niet-transit variabelen
        scf_params.transit_flist = trans_fparams;
    }
    if (trans_qparams)
    {   // Doorgeven van niet-transit variabelen
        scf_params.transit_qlist = trans_qparams;
    }


    // Originele URL voor IIRF rewrite
    var orgurl = Request.ServerVariables("HTTP_X_REWRITE_URL");
    if (orgurl.Count)
        scf_params.this_fullpath = String(orgurl).split("?")[0];
    else
    {
        var orgurl = Request.ServerVariables("HTTP_X_ORIGINAL_URL"); // Origineel van IIS Rewriter
        if (orgurl.Count)
            scf_params.this_fullpath = String(orgurl).split("?")[0];
        else
            scf_params.this_fullpath = String(Request.ServerVariables("SCRIPT_NAME"));
    }
    scf_params.this_path = scf_params.this_fullpath.substring(rooturl.length + 1);

    // Algemene normalizing
    def(model, "record_title",  model.record_name);
    def(model, "records_title",  model.records_name);
    for (var fld in model.fields)
        def(model.fields[fld], "label", fld)

    if ("includes" in model)
    {
        for (var inc in model.includes)
            def(model.includes[inc], "joinfield", model.fields.id.dbs);
    }

    def(model, mode, {});
    def(model, "list", {});
    def(model, "edit", {});
    def(model, "print", {});

    if ("id" in model.fields && "name" in model.fields)
        def(model.list, "columns",  ["id", "name"]);
    else
        if ("id" in model.fields)
            def(model.list, "columns",  ["id"]);
        else
            def(model.list, "columns",  []);

    switch (mode)
    {
        case "search":
            scaffolding_search(model, scf_params);
            break;
        case "list":
            scaffolding_list(model, scf_params);
            break;
        case "wrap":
            scaffolding_wrap(model, scf_params);
            break;
        case "show":
            scaffolding_show(model, scf_params);
            break;
        case "import":
            scaffolding_import(model, scf_params);
            break;
        case "edit":
            scaffolding_edit(model, scf_params);
            break;
        case "save":
            scaffolding_save(model, scf_params);
            break;
        case "delete":
            scaffolding_delete(model, scf_params);
            break;
        case "print":
            scaffolding_print(model, scf_params);
            break;
        default:
            abort_with_warning("Unknown scf-mode '{0}'".format(mode));
    }
}

function scf_ROFIELDTR(model, fld, val, key, params)
{
    var params = params || {};
    var field = model.fields[fld];
    if (!field)
    {   // Vanuit scaffolding_search
        field = model.fields[fld.replace(/^(start_|end_)/,"")];
    }
    var txt = val;
    if (txt === null || typeof txt === "undefined")
    {
        if (field.typ == "check")
            txt = 0;
        else if (field.typ == "label")
        {
            scf_LABELTR(fld, field, params);
            return;
        }
        else
            return; // Altijd suppressEmpty
    }
    var org_lcl;
    if (field.islcl && txt && txt.substr(0, 4) == 'lcl_')
    {
        org_lcl = txt;
        txt = L(txt);
        if (__Logging > 0)
            field.label += " <span class='orglcl'>&lt;" + org_lcl + "&gt;</span>";
    }

    if (field.LOV && field.showtransit && (typeof txt != "object"))
    {
        var lov_arr = field.LOV.split(";");
        var i = sharedIndexOf(txt, lov_arr);
        txt = { "id": txt, "name": lov_arr[i+1] };
    }

    var title = "";
    var infoPointer = null;
    var fso = Server.CreateObject("Scripting.FileSystemObject");
    if (typeof txt == "object")
    {
        if ("name" in txt) // Foreigns
        {
            if ("id" in txt)
                title = "Key: " + txt["id"];
            else if ("size" in txt) // Foto's
                title = "Size: {0} bytes".format(txt["size"]);
            if ("content_url" in txt) // Plaatjes en zo
                infoPointer = { Url: txt["content_url"], NewWindow: true };
            else if ("infoPointer" in field)
            {
                infoPointer = field.infoPointer;
                infoPointer.Url += txt.id;
            }
            else if ("foreign" in field)
            {   // Probeer een infopointer te gokken
                var guesses = [field.foreign.modelname, field.foreign.tbl, field.dbs.replace(/\_key$/, "")]
                for (var i = 0; i < guesses.length; i++)
                {
                    var tbl = guesses[i];
                    if (!infoPointer && tbl)
                    {
                        if (tbl.match(/[^a-zA-Z0-9_]/)) // safety, anders fout bij appl\mgt\ins_srtkenmerk.asp?mode=show&id=21
                            continue;

                        var url = "appl/mgt/" + tbl + ".asp";
                        if (fso.FileExists(Server.MapPath("../../" + url)))
                            infoPointer = { Url: url + "?mode=wrap&id=" + txt.id };
                    }
                }
            }
            txt = txt["name"];
        }
        else
        {
            if (field.typ == "datetime")
                txt = toDateTimeString(txt, field.seconds);
            else if (field.typ == "time")
                txt = toTimeString(txt);
            else if (typeof txt == "date" || txt instanceof Date)
                txt = toDateString(txt);
            else if (field.typ == "processingtime")
                if (txt["duration"] != null)
                    txt = txt["duration"] + " " + (txt["unit"]=='U'?L("lcl_mld_hours"):L("lcl_mld_days"));
                else
                    return;
        }
    }
    else if ("infoPointer" in field)
    {
      infoPointer = field.infoPointer;
      infoPointer.Url += val;
      infoPointer.Title += val;
    }
    if (field.iscurrency)
        txt = safe.curr(txt);

    var params = { title: title, infoPointer: infoPointer, org_lcl: org_lcl, secret: field.secret };
    if (field.translate && key)
        params.translate = { fld: field.dbs, key: key }

    if (field.bits)
    {
        var params_bits = params;
        scf_GROUP_START(model, fld, val, params_bits);

        for (var i=0; i < field.bits.length; i++)
        {
            var bit = field.bits[i];
            if (bit.typ == "check")
            {
                params_bits.readonly = true;
                scf_GROUP_CHECK(bit, "bit_group", val, params_bits, key);
            }
            if (bit.typ == "radio")
            {
                params_bits.readonly = true;
                scf_GROUP_RADIO(bit, "bit_group", val, params_bits);
            }
            else if (bit.typ == "LOV")
            {
                var data = (val.id & bit.mask);
                ROFIELDTR("fld", bit.label, data, params);
            }
        }
        scf_GROUP_END();
    }
    else if (field.typ == "check" || field.typ == "check0")
        ROCHECKBOXTR("fld" + (field.extraclass ? " "+field.extraclass : ""), field.label, txt, params);
    else if (field.typ == "float" && field.iscurrency)
        ROFIELDTR("fldshort", field.label, txt, params);
    else
    {
        if (!field.hidden_fld || (field.hidden_fld && field.showtransit))
        {
            if (field.typ == "memo" && !field.secret)
            {
                ROTEXTAREATR("fldtxt", field.label, txt, params);
            }
            else if (field.typ == "color")
            {
                params.datatype = field.typ;
                ROFIELDTR("fldshort", field.label, txt, params);
            }
            else if (field.typ == "symbol")
            {
                ROSYMBOLTR(fld, field.label, val, { "key": key, "module": field.module });
            }
            else if (field.typ == "file")
            {
                FILEPICKERTR(fld, field.label, val, { "key": key, "module": field.module, "readonly": true, "icon": field.icon, "defaultValue": field.defaultValue });
            }
            else if (field.typ == "icon")
            {
                ICONPICKERTR(fld, field.label, val, { "readonly": true });
            }
            else
            {
                ROFIELDTR("fld", field.label, txt, params);
            }
        }
    }
}

function scf_RWFIELDTR(model, fld, val, key, params)
{
    var params = params || {};
    var field = model.fields[fld];

    if (!params.search)
    {
         params.required = field.required;
         params.requiredlevel = field.requiredlevel;
    }

    if (!field)
    {   // Vanuit scaffolding_search
        field = model.fields[fld.replace(/^(start_|end_)/,"")];
    }
    if (field.islcl && val && val.substr(0, 4) == 'lcl_')
    {
        return scf_ROFIELDTR(model, fld, val);
    }

    if (params.search && (field.typ == "check" || field.typ == "check0"))
    {
        if (field.filter != "parameter")
        {
            field.typ = "number";
            field.LOV = "1;" + L("lcl_Yes") + ";0;" + L("lcl_No");
            params.extraclass = "notmulti";
        }
    }
    if (field.foreign)
    {
        if (typeof field.foreign == 'function')
        {
            scf_ROFIELDTR(model, fld, val, key, params); // Te ingewikkeld?
        }
        else
        {
            var predefined = ""; // Een voorgedefinieerde foreign
            var foreign = field.foreign;
            if (typeof foreign == 'string')
            {
                var predefined = field.foreign.toUpperCase();
                foreign = foreignKeyTable(foreign);
                if (!foreign)
                    MISSING_FOREIGN;
            }
            else if (foreign && foreign.selectorforeign)
                predefined = foreign.selectorforeign.toUpperCase();

            if (predefined == "PRS_KOSTENPLAATS")
            {
                FCLTkostenplaatsselector(fld,
                       "sg" + fld,
                       user_key,
                       { label: field.label,
                         kostenplaatsKey: val?val.id:null,
                         filtercode: "foreignfiltercode" in field? field.foreignfiltercode : "AA",
                         required: params.required,
                         whenEmpty: params.search ? L("lcl_search_generic") : null
                       });
            }
            else if (predefined == "PRS_KOSTENSOORT")
            {
                FCLTkostensoortselector(fld,
                       "sg" + fld,
                       { label: field.label,
                         kostensoortKey: val?val.id:null,
                         filtercode: "foreignfiltercode" in field? field.foreignfiltercode : "",
                         required: params.required,
                         whenEmpty: params.search ? L("lcl_search_generic") : null
                       });
            }
            else if (predefined == "PRS_PERSLID")
            {
                var canmultiadd = fld == params.multiadd && !(key > 0);
                FCLTpersoonselector(fld,
                       "sg" + fld,
                       { label: field.label,
                         perslidKey: val?val.id:null,
                         required: params.required,
                         filtercode: "foreignfiltercode" in field ? field.foreignfiltercode : "",
                         preferredKeys: "preferredKeys" in field ? field.preferredKeys : [],
                         multi: canmultiadd,
                         whenEmpty: params.search ? L("lcl_search_generic") : null
                       });
            }
            else if (predefined == "PRS_AFDELING")
            {
                FCLTafdelingselector(fld,
                       "sg" + fld,
                       { label: field.label,
                         departmentKey: val?val.id:null,
                         required: params.required,
                         whenEmpty: params.search ? L("lcl_search_generic") : null
                       });
            }
            else if (predefined == "PRS_BEDRIJF")
            {
                FCLTbedrijfselector(fld, // Supplier.
                       "sg" + fld,
                       { label: L("lcl_bes_Supplier"),
                         companyKey: val?val.id:null,
                         required: params.required,
                         filtercode: "foreignfiltercode" in field?field.foreignfiltercode:"",
                         whenEmpty: params.search ? L("lcl_search_generic") : null
                       });
            }
            else if (predefined == "FAC_FUNCTIE")
            {
                FCLTautorisatieselector(fld,
                       "sg" + fld,
                       { label: field.label,
                         autorisatieKey: val? val.id : null,
                         required: params.required,
                         filtercode: "foreignfiltercode" in field? field.foreignfiltercode : "",
                         // multitoggle: field.multitoggle, // TODO: Moet nog ondersteund worden.
                         whenEmpty: params.search? L("lcl_search_generic") : null
                       });
            }
            else if (predefined == "FAC_GROEP")
            {
                FCLTautorisatiegroepselector(fld,
                       "sg" + fld,
                       { label: field.label,
                         autorisatiegroepKey: val? val.id : null,
                         required: params.required,
                         filtercode: "foreignfiltercode" in field? field.foreignfiltercode : "",
                         whenEmpty: params.search? L("lcl_search_generic") : null
                       });
            }
            else if (predefined == "MLD_STDMELDING")
            {
                params = { label: field.label,
                           stdmelding_key: val?val.id:null,
                           autfunctionKey: -1,
                           onChange: field.onChange,
                           show_expired: true,
                           required: params.required,
                           whenEmpty: params.search ? L("lcl_search_generic") : null,
                           urlAdd: field.urlAdd
                         }
                var srtdisc_found = false;
                if (field.urlAdd)
                  for (var i = 0; i < field.urlAdd.length; i++)
                  {
                    if (field.urlAdd[i].urlParam == "srtdisc_key")
                      srtdisc_found = true;
                  }
                if (!srtdisc_found)
                  params.srtdisc_key = (field.foreignparams && field.foreignparams.srtdisc_key ? field.foreignparams.srtdisc_key : -1);
                FCLTstdmeldingselector(fld,
                                       "sg" + fld,
                                       params);
            }
            else if (predefined == "MLD_DISCIPLINE")
            {
                params = { label: field.label,
                           disc_key: (val ? val.id : null),
                           perslidKey: user_key,
                           module: (field.module ? field.module : "MLDA"),
                           autfunctionKey: -1,
                           onChange: field.onChange,
                           required: params.required,
                           whenEmpty: (params.search ? L("lcl_search_generic") : null),
                           noJustOne: (field.noJustOne ? 1 : 0),
                           urlAdd: field.urlAdd
                         }
                var srtdisc_found = false;
                if (field.urlAdd)
                  for (var i = 0; i < field.urlAdd.length; i++)
                  {
                    if (field.urlAdd[i].urlParam == "srtdisc_key")
                      srtdisc_found = true;
                  }
                if (!srtdisc_found)
                  params.srtdisc_key = (field.foreignparams && field.foreignparams.srtdisc_key ? field.foreignparams.srtdisc_key : -1);
                FCLTdisciplineselector(fld,
                                       "sg" + fld,
                                       params);
            }
            else if (predefined == "INS_DISCIPLINE")
            {
                FCLTdisciplineselector(fld,
                       "sg" + fld,
                       { label: field.label,
                         disc_key: val?val.id:null,
                         perslidKey: -1,
                         module: "INS",
                         autfunctionKey: -1,
                         required: params.required,
                         whenEmpty: params.search ? L("lcl_search_generic") : null,
                         noJustOne: (field.noJustOne ? 1 : 0)
                       });
            }
            else if (predefined == "INS_SRTGROEP")
            {
                FCLTsrtgroepselector(fld,
                       "sg" + fld,
                       { label: field.label,
                         srtgroep_key: val?val.id:null,
                         autfunction: ""
                       });
            }
            else if (predefined == "INS_SRTDEEL")
            {
                var srtdeel_params = {
                        label: field.label,
                        srtdeel_key: val?val.id:null,
                        autfunction: ""
                    };
                if (field.module)
                    srtdeel_params.module = field.module;
                if (field.binding)
                    srtdeel_params.binding = field.binding;

                FCLTsrtdeelselector(fld, "sg" + fld, srtdeel_params);
            }
            else if (predefined == "INS_DEEL")
            {
                var insdeel_params = {
                        label: field.label,
                        objectKey: val?val.id:null,
                        autfunction: "WEB_INSMAN",
                        urlAdd: field.urlAdd
                    };

                FCLTobjectselector(fld, "sg" + fld, insdeel_params);
            }
            else if (predefined == "INS_SRTCONTROLE")
            {
                FCLTsrtcontroleselector(fld,
                       "sg" + fld,
                       { label: field.label,
                         srtcontrole_key: val? val.id : null,
                         filtercode: "foreignfiltercode" in field? field.foreignfiltercode : "PI",
                         urlAdd: field.urlAdd
                       });
            }
            else if (predefined == "INS_SRTINSTALLATIE")
            {
            }
            else if (predefined == "ALG_RUIMTE")
            {
                FCLTplaatsselector(null,
                       { locatiekey:    ( (foreign.selectorparams && foreign.selectorparams.locatiekey)    ? foreign.selectorparams.locatiekey    : -1),
                         gebouwkey:     ( (foreign.selectorparams && foreign.selectorparams.gebouwkey)     ? foreign.selectorparams.gebouwkey     : -1),
                         verdiepingkey: ( (foreign.selectorparams && foreign.selectorparams.verdiepingkey) ? foreign.selectorparams.verdiepingkey : -1),
                         ruimtekey:     ( (foreign.selectorparams && foreign.selectorparams.ruimtekey)     ? foreign.selectorparams.ruimtekey     : (val?val.id:null)),
                         startlevel:    ( (foreign.selectorparams && foreign.selectorparams.startlevel)    ? foreign.selectorparams.startlevel    :  2),
                         eindlevel:     ( (foreign.selectorparams && foreign.selectorparams.eindlevel)     ? foreign.selectorparams.eindlevel     :  5),
                         readonlylevel: ( (foreign.selectorparams && foreign.selectorparams.readonlylevel) ? foreign.selectorparams.readonlylevel : -1),
                         //readonlyshow:  field.showtransit,
                         required: params.required,
                         requiredlevel: params.requiredlevel,
                         filtercode: "foreignfiltercode" in field?field.foreignfiltercode:"FAC",
                         whenEmpty: params.search ? L("lcl_search_generic") : null
                       });
            }
            else if (predefined == "ALG_GEBOUW")
            {
                FCLTplaatsselector(null,
                       { ruimtekey: val?val.id:null,
                         startlevel: 2,
                         eindlevel: 3,
                         required: params.required,
                         requiredlevel: params.requiredlevel,
                         filtercode: "foreignfiltercode" in field?field.foreignfiltercode:"FAC",
                         whenEmpty: params.search ? L("lcl_search_generic") : null
                       });
            }
            else if (predefined == "ALG_LOCATIE")
            {
                FCLTplaatsselector(null,
                       { ruimtekey: val?val.id:null,
                         startlevel: 2,
                         eindlevel: 2,
                         required: params.required,
                         filtercode: "foreignfiltercode" in field?field.foreignfiltercode:"FAC",
                         whenEmpty: params.search ? L("lcl_search_generic") : null
                       });
            }
            else if (predefined.match(/ALG_VERDIEPING|RES_RSV_RUIMTE|MLD_UITVOERENDE|MLD_OPDR|MLD_MELDING|CNT_CONTRACT/) || !foreign)
            {
                if (val && typeof val == "object" && "id" in val)
                    ROFIELDTR("fld", field.label, val.name, params);
                else
                    RWFIELDTR(fld, "fld", field.label, val, params); // dan maar gewoon invulveld
            }
            else // dan maar gewone select
            {
                // we doen automatische listboxen maar vanuit model_generic kan dat te gortig worden
                if (params.search && "num_rows" in field && field.num_rows > 1000) /* of S("qp_maxrows") */
                {
                    field.foreign = null;
                    RWFIELDTR(fld, "fld", field.label, val, params); // dan maar gewoon invulveld
                }
                else
                {
                    var fieldname = (foreign.name||foreign.desc);
                    var sql = "SELECT " + foreign.key
                            + "     , " + fieldname
                            + (foreign.extravalue ? ", " + foreign.extravalue : "")
                            + "  FROM " + foreign.tbl + " " + (foreign.alias||"")
                            + (foreign.where?" WHERE "  + foreign.where:"")
                            + " ORDER BY " + (foreign.order ? foreign.order : "2");
                    var emptyOption = "";
                    if (!params.search)
                    {
                        if ("emptyoption" in field)
                            emptyOption = field.emptyoption;
                        else
                            if (val && val.id && params.required)
                                emptyOption = null;
                    }
                    if (val && typeof val == "object" && "id" in val)
                    {   // dereference
                        val = val.id;
                    }
                    var canmultiadd = (fld == params.multiadd && !(key > 0)); // || foreign.multiselect;

                    var delayload = field.delayload || false;
                    if (delayload) sql = "";  // Laat de selector leeg. Het vullen zal gebeuren vanuit js via een ajax-aanroep.

                    FCLTselector(fld, sql, { label: field.label,
                                             initKey: (val==0 || val ? val : null),         // een key=0 moet ook kunnen!
                                             emptyOption: canmultiadd? null : emptyOption,
                                             selectjustone: foreign.selectjustone,
                                             emptyIsRealValue: (foreign.emptyisrealvalue?foreign.emptyisrealvalue:null),
                                             emptyKey: (field.typ == "key"? -1 : ""),
                                             readonly: (foreign.readonly? foreign.readonly : false),
                                             required: !emptyOption && params.required,
                                             multi: canmultiadd || params.multiselect,
                                             size: field.multiaddsize || 5,
                                             whenEmpty: params.search ? L("lcl_search_generic") : null,
                                             extraParamValue: (foreign.extravalue? foreign.extravalue : null),
                                             onChange: (field.onChange? field.onChange : null)
                                           });
                }
            }
        }
    }
    else if (field.bits)
    {
        var params_bits = params;
        scf_GROUP_START(model, fld, val, params_bits);

        for (var i=0; i < field.bits.length; i++)
        {
            var bit = field.bits[i];
            params_bits.fld_name = fld;
            if (bit.typ == "check")
            {
                scf_GROUP_CHECK(bit, "bit_group", val, params_bits, key);
            }
            else if (bit.typ == "radio")
            {
                scf_GROUP_RADIO(bit, "bit_group", val, params_bits);
            }
            else if (bit.typ == "LOV")
            {
                var data = (val & bit.mask);
                var sql = api2.splitLOV2sql(bit.LOV);
                FCLTselector(bit.name,
                             sql,
                             { label: bit.label,
                               initKey: params.search?"":data
                             });
            }
        }
        scf_GROUP_END();
    }
    else if (field.LOV)
    {
        if (field.required && field.LOV.split(";").length == 2 && val && val.id == field.LOV.split(";")[0])
        {   // Dit zou FCLTselector ook wel mogen doen....
            scf_ROFIELDTR(model, fld, val);
            return;
        }
        var sql = api2.splitLOV2sql(field.LOV);
        var emptyOption = "";
        if (!params.search)
        {
            if ("emptyoption" in field)
                emptyOption = field.emptyoption;
            else
                if (val && ("id" in val) && params.required)
                    emptyOption = null;
        }

        var canmultiadd = (fld == params.multiadd && !(key > 0)); // || foreign.multiselect;
        FCLTselector(fld, sql, { label: field.label,
                                 initKey: params.search?"":(val==0 || val ? val.id : null),         // een key=0 moet ook kunnen!
                                 emptyOption: canmultiadd?null:emptyOption,
                                 emptyIsRealValue: (field.emptyisrealvalue?field.emptyisrealvalue:null),
                                 emptyKey: (field.typ=="key"?-1:""),
                                 readonly: (!params.search && field.readonly?field.readonly:false),
                                 required: params.required,
                                 multi: canmultiadd || params.multiselect,
                                 extraclass: params.extraclass
                               });
    }
    else if (field.typ == "check" || field.typ == "check0")
    {
        RWCHECKBOXTR(fld, "fldcheck", field.label, val);
    }
    else if (field.typ == "processingtime")
    {
        val = (val ? val : {unit: -1, duration: null});
        sql = "SELECT  'U', " + safe.quoted_sql(L("lcl_mld_hours")) + " FROM DUAL"
            + " UNION SELECT 'D', " + safe.quoted_sql(L("lcl_mld_days")) + " FROM DUAL"
            + " ORDER BY 2";
        var selectparams = { fieldName: fld + "_eenheid",
                             sql: sql,
                             params: { id: fld + "_eenheid",
                                       extraclass: "processingtime",
                                       initKey: val.unit
                                     }
                           };
        params.maxlength = 8;
        params.datatype = "processingtime";
        params.selector = selectparams;
        RWFIELDTR(fld, "fld", field.label, val.duration, params);
    }
    else if (fld.match(/^(start_|end_)fclt_d_/))
            FCLTcalendar (fld, { initEmpty: 1,
                                 label: field.label,
                                 volgnr: fld.match(/^start_/)?1:2,
                                 required: true,
                                 autosize: field.autosize
                               });
    else if (( field.typ == "date" || field.typ == "datetime") && field.multiedit && params.multiedit)
            FCLTcalendar(fld, { label    : field.label,
                                datum    : val,
                                timeField: field.typ == "datetime",
                                initEmpty: !val,
                                initTimeEmpty: !val,
                                volgnr   : 1,
                                required : params.required,
                                autosize : field.autosize,
                                onChangeMulti : "onChangeDate('"+fld+"')"
                              });
    else if (field.typ == "date" || (field.typ == "datetime" && params.search))
            FCLTcalendar(fld, { label    : field.label,
                                datum    : val,
                                timeField: false, // (field.typ == "datetime")? beetje overkill voor zoeken
                                initEmpty: !val,
                                initTimeEmpty: !val,
                                volgnr   : 1,
                                required : params.required,
                                autosize : field.autosize,
                                onChange : field.onchange
                              });
    else if (field.typ == "datetime")
            FCLTcalendar(fld, { label    : field.label,
                                datum    : val,
                                timeField: true,
                                initEmpty: !val,
                                initTimeEmpty: !val,
                                timeStep : S("res_h")*60,
                                startTime: S("res_t1"),
                                endTime  : S("res_t2"),
                                volgnr   : 1,
                                required : params.required,
                                autosize : field.autosize
                              });
    else if (field.typ == "label")
    {
        scf_LABELTR(fld, field, params);
    }
    else if (field.typ == "button")
    {
        scf_BUTTONTR(fld, field, params);
    }
    else if (field.typ == "button2")
    {
        scf_BUTTONSPAN(fld, field, params);
    }
    else if (field.typ == "symbol")
    {
        RWSYMBOLTR(fld, field.label, val, { "key": (getQParamInt("scf_clone", 0) == 1 ? -1 : key), "module": field.module });
    }
    else if (field.typ == "file")
    {
        FILEPICKERTR(fld, field.label, val, { "key": (getQParamInt("scf_clone", 0) == 1 ? -1 : key), "module": field.module, "icon": field.icon, "defaultValue": field.defaultValue });
    }
    else if (field.typ == "icon")
    {
        ICONPICKERTR(fld, field.label, val);
    }
    else if (field.typ == "div")
    {
        scf_DIV(fld, field, params);
    }
    else
    {
        if (field.translate && key)
          params.translate = { fld: fld.dbs, key: key };

        params.maxlength = field.len;
        if (field.typ == "memo")
        {
          var pclass = "fldtxt" + (params.required ? " required" : "");
          if (field.bb_codes) {
            if (field.module) {
                params.upload_params = {
                    "module": field.module
                };
            }
          } else {
            params.no_bb_codes = true; // Hier expliciet even niet
          }
          if (field.labelaction)
              params.labelaction = field.labelaction;
          RWTEXTAREATR(fld, pclass, field.label, val, params);
        }
        else if (field.typ == "check0" || field.typ == "check")
        {
          var pclass = "fld";
          RWCHECKBOXTR(fld, pclass, field.label, val, params);
        }
        else
        {
          var pclass = "fld";
          switch (field.typ)
          {
            case "key": params.datatype = "number"; break; // Voor mgt_generic soms
            case "color":
                params.datatype = "color";
                pclass = "fldshort";
                val = sharedTrim(val || "");
                var reghex = new RegExp("^[0-9A-F]{6}$", "i"); // Ben ik een hex-code zonder #-prefix?
                if (val.match(reghex))
                    val = "#" + val;
                break;
            case "varchar":
                          params.datatype = "text";
                          if ("placeholder" in field) {
                            params.placeholder = field.placeholder;
                          }
                          break;
            case "number":
            case "float": params.datatype = (field.iscurrency ? "currency" : field.typ);
                          val = (val && field.iscurrency ? safe.curreditable(parseFloat(val)) : val);
                          pclass = (field.iscurrency ? "fldshort" : pclass) + (field.relativeValuesAllowed ? " relativeValuesAllowed" : "");
                          break;
            default: params.datatype = "";
          }
          RWFIELDTR(fld, pclass, field.label, val, params);
        }
    }
}

function scf_RWHIDDENTR(model, fld, val)
{
    var v_val = val;
    if (val && typeof val == "object" && "id" in val)
        v_val = val.id;

    var field = model.fields[fld];
    if (val && field && (field.typ == "date" || field.typ == "datetime"))
    {
        v_val = val.valueOf();
    }

    var withdefault = (field && field.defaultvalue ? '" default="' + field.defaultvalue : "");
    Response.Write('<input type="hidden" id="'+ fld + '" name="' + fld + withdefault + '" value="' + safe.htmlattr(v_val) + '">');
}

function scf_LABELTR(fld, field, params)
{
    if (field.label || field.labelvalue)
    {
        if (field.labelvalue)
            Response.Write('<tr><td class="label">'+field.label+'</td><td>'+field.labelvalue+'</td></tr>');
        else if (field.bits && field.bits[0].typ != "LOV" && !field.bits[0].label) // prevent extra line when first field.bits has no label
            field.bits[0].label = field.label; // put label in the label of the first bit field
        else
            Response.Write('<tr><td class="label" colspan="2">'+field.label+'</td></tr>');
    }
}

function scf_BUTTONTR(fld, field, params)
{
    Response.Write('<tr>'
                  +'    <td class="label">'
                  +'        <label for="'+fld+'">'+(field.label?field.label:'')+'</label>'
                  +'    </td>'
                  +'    <td>'
                  +'        <button id="'+fld+'" name="'+fld+'">'+field.defaultvalue+'</button>'
                  +'    </td>'
                  +'</tr>');
}

function scf_BUTTONSPAN(fld, field, params)
{
    Response.Write('<tr>'
                  +'    <td class="label">'
                  +'        <label for="'+fld+'">'+(field.label?field.label:'')+'</label>'
                  +'    </td>'
                  +'    <td>'
                  +'        <span class="button-icon-wrapper">'
                  +'            <span class="starticon">'+I(field.icon || "fa-folder-open")+'</span>' /* Tot nog toe alleen als blader/upload-button gebruikt, dus default fa-folder-open */
                  +'            <input type="button" id="'+fld+'" class="button" title="'+field.label+'" value="'+field.defaultvalue+'">'
                  +'        </span>'
                  +'    </td>'
                  +'</tr>');
}

function scf_DIV(fld, field, params)
{
    Response.Write('<div id="'+fld+'" name="'+fld+'">'+field.defaultvalue+'</div>');
}

function scf_GROUP_START(model, fld, val, params)
{
    var field = model.fields[fld];

    scf_RWHIDDENTR(model, fld, val);
    scf_LABELTR(fld, field, params);
}
function scf_GROUP_END()
{
}
function scf_GROUP_CHECK(pgroup, pclass, pvalue, params, pkey)
{
    var params = params||{};
    var group_val = pvalue & pgroup.mask;
    var isallreadonly = params.readonly || (mode == "show");
    var showgroup = (typeof pgroup.showasgroup === "undefined" ? true : pgroup.showasgroup);

    var group_check_arr = [];
    for (var i=0; i<pgroup.radios.length; i++)
    {
        var bit = pgroup.radios[i];
        var defaultchecked = !params.multiedit && pkey < 0 && bit.defaultvalue == 1;
        var ischecked = (bit.mask == 0
                        ? (group_val == bit.mask)
                        : ((group_val & bit.mask) == bit.mask)
                        );
        var isreadonly = isallreadonly || bit.readonly;

        Response.Write("\n<input type=\"hidden\" id=\"has_" + bit.name + "\" name=\"has_" + bit.name + "\" value=\"1\""
                      + (params.readonly ? " disabled" : "")
                      +">");

        if (isreadonly)
        {   // LET OP: Bij readonly wordt dit veld altijd aan de form-parameters meegegeven met waarde "on" of leeg.
            //         Dit is nodig om een aangevinkt bitje ook aangevinkt te laten bij het bewaren.
            var lbl_html = (bit.label ? "<label>" + (bit.label ? bit.label :"") + "</label>" : "");
            var chk_html = "<input type=\"hidden\" id=\"" + bit.name + "\" name=\"" + bit.name + "\""
                        + " value=\"" + (ischecked?"on":"") + "\""
                        + ">";
            chk_html += "<input type=\"checkbox\" id=\"lbl_" + bit.name + "\" name=\"lbl_" + bit.name + "\""
                      + " class=\"fldcheck\""
                      + (ischecked || defaultchecked ? " CHECKED" : "")
                      + " disabled"
                      + (params.html ? params.html : "")
                      + ">";
        }
        else
        {   // LET OP: Bij editable wordt dit veld alleen aan de form-parameter meegegeven als het veld aangevinkt is (en waarde "on" heeft).
            var lbl_html = (bit.label ? "<label for=\"" + bit.name + "\">" + (bit.label ? bit.label :"") + "</label>" : "");
            var chk_html  = "<input type=\"checkbox\" id=\"" + bit.name + "\" name=\"" + bit.name + "\""
                          + " class=\"fldcheck\" data-name=\"" + params.fld_name + "\""
                          + " mask=\"" + bit.mask + "\""
                          + (ischecked || defaultchecked ? " CHECKED" : "")
                          + (params.hidden ? " style=\"visibility:hidden\"" : "")
                          + (params.html ? params.html : "")
                          + ">";
        }
        group_check_arr.push( {lbl: lbl_html, chk: chk_html} );
    }
    if (showgroup)
    {
        Response.Write("<tr " + (params.trclass ? "class=\"" + params.trclass + "\"" : "") + ">");
        if (pgroup.label) {
            Response.Write("<td class=\"label " + pclass + "\">");
            Response.Write("<label>" + (pgroup.label?safe.html(pgroup.label):"") + "</label>");
            Response.Write("</td>");
        } // else label of field will be used (function scf_LABELTR)

        Response.Write("<td>");
        for (var i=0; i<group_check_arr.length; i++)
        {
            Response.Write("<div>");
            Response.Write(group_check_arr[i].chk);
            Response.Write(group_check_arr[i].lbl);
            Response.Write("</div>");
        }
        Response.Write("</td>");
        Response.Write("</tr>");
    }
    else
    {
        for (var i=0; i<group_check_arr.length; i++)
        {
            Response.Write("<tr " + (params.trclass ? "class=\"" + params.trclass + "\"" : "") + ">");
            Response.Write("<td class=\"label\">" + group_check_arr[i].lbl + "</td>");
            Response.Write("<td>" + group_check_arr[i].chk + "</td>");
            Response.Write("</tr>");
        }
    }
}
function scf_GROUP_RADIO(pgroup, pclass, pvalue, params)
{
    var params = params||{};
    var group_val = pvalue & pgroup.mask;
    var isallreadonly = pgroup.readonly || params.readonly || (mode == "show");

    Response.Write("<tr " + (params.trclass ? "class=\"" + params.trclass + "\"" : "") + ">");
    if (pgroup.label) {
      Response.Write("<td class=\"label " + pclass + "\">");
      Response.Write("<label>" + (pgroup.label?safe.html(pgroup.label):"") + "</label>");
      Response.Write("</td>");
    } // else label of field will be used (function scf_LABELTR)

    Response.Write("<td>");
    if (isallreadonly)
    {   // Bij readonly van een radio-group moet wel de huidige waarde bewaard blijven.
        Response.Write("<input name=\"" + pgroup.name + "\" type=\"hidden\" value=\"" + group_val + "\""
                      +">");
    }

    for (var i=0; i<pgroup.radios.length; i++)
    {
        var bit = pgroup.radios[i];
        var ischecked = (params.multiedit ? false : (group_val == bit.mask));
        var isreadonly = isallreadonly || bit.readonly;

        if (mode=="show" && ischecked)
        {
            Response.Write("<span>&nbsp;" + safe.html(bit.label) + "<br></span>");
        }
        else if (mode=="edit")
        {
            Response.Write("\n<input name=\"" + pgroup.name + "\" type=\"radio\""
                          + " id=\"" + pgroup.name + i + "\""
                          + " value=\"" + bit.mask + "\" data-name=\"" + params.fld_name + "\""
                          + (ischecked?" checked":"")
                          + (isreadonly? " disabled" : "")
                          +">");
            Response.Write("<label for=\"" + pgroup.name + i + "\">" + safe.html(bit.label) + "</label><br>");
        }
    }
    Response.Write("</td>");
    Response.Write("</tr>");
}

function scf_create_layout_list(model, p_params, p_fld_arr_all)
{
    var hasFields = false;
    if (p_params.layout && p_params.layout.block)
        for (var i = 0; i < p_params.layout.block.length && !hasFields; i++)
            if ("fields" in p_params.layout.block[i])
                hasFields = true;
    var scf_layout = hasFields ? p_params.layout.block : [];

    var hasmulticolumn = false;
    var fld_arr_layout = [];
    if (p_params.multicolumn && !hasFields) // Geen velden in blokken gedefinieerd, toch multicolumn
    {
        // Geen layout voor show/edit opgegeven, maar wel in twee kolommen tonen.
        // Neem de eerste helft van alle velden en doe alsof het uit de layout komt.
        hasmulticolumn = (p_fld_arr_all.length > 1);
        var col_1_length = ( ((p_fld_arr_all.length % 2)==0) ? (p_fld_arr_all.length/2) : ((p_fld_arr_all.length+1)/2) );
        var i = 0;
        while (i < col_1_length)
        {
            var fld = p_fld_arr_all[i];
            fld_arr_layout.push(fld);
            i++;
        }

        if (p_params.layout && p_params.layout.miscellaneous && typeof p_params.layout.miscellaneous == "object")
        {
            var layout_rest = p_params.layout.miscellaneous;
        }
        else
        {
            var layout_rest = {
                "blockid": "scfblockleft",
                "label": "",
                "icon": "",
                "ishtmlsafe": true,
                "hidden": false,
                "buttons": [],
                "fields": fld_arr_layout
            }
            if (p_params.layout && "block" in p_params.layout && p_params.layout.block instanceof Array && p_params.layout.block.length > 0)
            {
                if ("label" in p_params.layout.block[0])
                    layout_rest.label = p_params.layout.block[0].label;
                if ("icon" in p_params.layout.block[0])
                    layout_rest.icon = p_params.layout.block[0].icon;
            }
            if (layout_rest.label === "")
                layout_rest.label = (p_params.layout && p_params.layout.miscellaneous ? p_params.layout.miscellaneous : model.record_title) + " (1)";
        }
        scf_layout.push(layout_rest);
    }
    else
    {
        // Maak een lijst met velden die in het layout ontwerp van de asp worden gebruikt.
        if (p_params.layout && p_params.layout.block)
        {
            for (var blk in p_params.layout.block)
            {
                var blk_obj = p_params.layout.block[blk];
                for (var fld_nr in blk_obj.fields)
                {
                    var fld = blk_obj.fields[fld_nr];
                    if (!inArray(fld, fld_arr_layout))
                        fld_arr_layout.push(fld);
                }
            }
        }
    }
    // Maak een lijst met velden die niet in het layout ontwerp van de asp zitten.
    // Deze komen in een standaard blok.
    var fld_arr_rest = [];
    for (var i=0 ; i<p_fld_arr_all.length;i++)
    {
        if (!inArray(p_fld_arr_all[i], fld_arr_layout) &&                                       // Het veld zit niet al in een ander gedefinieerd block
                (!p_params.layout ||                                                            // Er is helemaal geen layout gedefinieerd
                (p_params.layout && "block" in p_params.layout && p_fld_arr_all[i] != "id") ||  // Er is wel een layout gedefinieerd en ook blokken, laat dan het id-veld weg
                (p_params.layout && !("block" in p_params.layout))))                            // Er is wel een layout gedefinieerd maar geen blokken
            fld_arr_rest.push(p_fld_arr_all[i]);
    }
    //
    // De te gebruiken layout bevat nu de gedefinieerde blokken plus een blok met overige velden.
    if (fld_arr_rest.length)
    {
        if (p_params.layout && p_params.layout.miscellaneous && typeof p_params.layout.miscellaneous == "object")
        {
            var layout_rest = {
                "fields": fld_arr_rest,
                "label": p_params.layout.miscellaneous.label || model.record_title || L("lcl_mld_miscellaneous_fields"),
                "icon": p_params.layout.miscellaneous.icon || "fa-ellipsis-h"
            };
        }
        else
        {
            var rest_icon = "";
            var rest_label = "";
            if (hasmulticolumn)
            {
                if (p_params.layout && "block" in p_params.layout && p_params.layout.block instanceof Array && p_params.layout.block.length > 1)
                {
                    if ("label" in p_params.layout.block[1])
                        rest_label = p_params.layout.block[1].label;
                    if ("icon" in p_params.layout.block[1])
                        rest_icon = p_params.layout.block[1].icon;
                }
                if (rest_label === "")
                    rest_label = (p_params.layout && p_params.layout.miscellaneous ? p_params.layout.miscellaneous : model.record_title) + " (2)";
            }
            else
            {
                if (p_params.layout)
                {
                    if (p_params.layout.miscellaneous)
                        rest_label = p_params.layout.miscellaneous;
                    else
                    {
                        rest_label = L("lcl_mld_miscellaneous_fields");
                        rest_icon = "fa-ellipsis-h";
                    }
                }
                else
                {
                    rest_label = model.record_title;
                    rest_icon = "fa-cube"; // Generic placeholder dan maar?
                }
            }
            var layout_rest = {
                "blockid": (hasmulticolumn ? "scfblockright" : "scfrest"),
                "label": rest_label,
                "icon": rest_icon,
                "ishtmlsafe": true,
                "hidden": false,
                "buttons": [],
                "fields": fld_arr_rest
            }
        }
        scf_layout.push(layout_rest);
    }
    return scf_layout;
}
%>
