<% /*
    $Revision$
    $Id$

    File:           model_objects.inc

    Description:    Object model. Still quite incomplete (or "under construction" if you like)
    Parameters:
    Context:

    Notes:          We ondersteunen vooralsnog uitsluitend ruimtegebonden objecten
*/

%>
<!-- #include file="../Shared/discxalg3d.inc"-->
<!-- #include file="./model_custom_fields.inc"-->
<!-- #include file="./model_fac_tracking.inc"-->
<!-- #include file="./model_ins_kenmerk.inc"-->
<!-- #include file="model_issueobjects.inc"-->
<!-- #include file="../ins/ins.inc"-->
<%
function model_objects(ins_key, params)
{
    params = params || {};
    this.table = "ins_v_deelenonderdeel"; // Bij een update (PUT) en een insert (POST) is aangegeven dat het in de "ins_deel" tabel moet.
    this.primary = "ins_deel_key";
    this.records_name = "objects";
    this.record_name = "object";
    this.multi_update = true;
    this.fields = {
        "id":               { dbs: "ins_deel_key",                              typ: "key" },
        "name":             { dbs: "ins_deel_omschrijving",                     typ: "varchar", filter: "like",               label: L("lcl_obj_identification"), track: true},
        "description":      { dbs: "ins_deel_opmerking",                        typ: "varchar", filter: "like",               label: L("lcl_ins_opmerking"),      track: true},
        "objectdiscipline": { dbs: "ins_discipline_key",                        typ: "key",     foreign: "ins_discipline",    label: L("lcl_discipline")},
        "group":            { dbs: "ins_srtdeel.ins_srtgroep_key",              typ: "key",     foreign: "ins_srtgroep",      label: L("lcl_obj_group")},
        "type":             { dbs: "ins_srtdeel_key",                           typ: "key",     foreign: "ins_srtdeel",       label: L("lcl_obj_sort")},
        "placeholdertype":  { dbs: "ins_alg_ruimte_type",                       typ: "varchar", track: true },
        "placeholderkey":   { dbs: "ins_alg_ruimte_key",                        typ: "number",  track: true},
        "placeholderloc":   { dbs: "ins_alg_locatie_key",                       typ: "key",     foreign: "alg_locatie",       label: L("lcl_location")},
        "location":         { dbs: "ins_v_deelenonderdeel_gegevens.alg_locatie_key",       typ: "key",     foreign: "alg_locatie",       label: L("lcl_location")},
        "terrain":          { dbs: "ins_v_deelenonderdeel_gegevens.alg_terreinsector_key", typ: "key",     foreign: "alg_terreinsector", label: L("lcl_obj_bind_t")},
        "building":         { dbs: "ins_v_deelenonderdeel_gegevens.alg_gebouw_key",        typ: "key",     foreign: "alg_gebouw",        label: L("lcl_building")},
        "floor":            { dbs: "ins_v_deelenonderdeel_gegevens.alg_verdieping_key",    typ: "key",     foreign: "alg_verdieping",    label: L("lcl_floor")},
        "room":             { dbs: "ins_v_deelenonderdeel_gegevens.alg_ruimte_key",        typ: "key",     foreign: "alg_ruimte",        label: L("lcl_room")},
        "workplace":        { dbs: "ins_v_deelenonderdeel_gegevens.prs_werkplek_key",      typ: "key",     foreign: "prs_werkplek",      label: L("lcl_obj_bind_w")},
        "owner":            { dbs: "ins_v_deelenonderdeel_gegevens.prs_perslid_key",       typ: "key",     foreign: "prs_perslid",       label: L("lcl_obj_bind_p")},
        "department":       { dbs: "ins_v_deelenonderdeel_gegevens.prs_afdeling_key",      typ: "key",     foreign: "prs_afdeling",      label: L("lcl_obj_bind_a")},
        "state":            { dbs: "ins_deel_state",                            typ: "varchar",                               label: L("lcl_deel_state")},
        "statedate":        { dbs: "ins_deel_statedate",                        typ: "datetime",                              label: L("lcl_deel_statedate")},
        "expiration":       { dbs: "ins_deel_vervaldatum",                      typ: "date",                                  label: L("lcl_ins_vervaldatum"), track: true},
        "active":           { dbs: "ins_deel_actief",                           typ: "check0",                                label: L("lcl_ins_active"),      track: true},
        "manager":          { dbs: "prs_perslid_key_beh",                       typ: "key",     foreign: "prs_perslid",       label: L("lcl_ins_manager"),     track: true},
        "parent":           { dbs: "ins_deel_parent_key",                       typ: "key",     foreign: "ins_deel",          label: L("lcl_ins_parentobject")},
        // TODO if MJB
        "score1":           { dbs: "ins_deel_mjb_score1",                       typ: "varchar", track: true,                  label: L("lcl_ins_deel_mjb_score1")},
        "score2":           { dbs: "ins_deel_mjb_score2",                       typ: "varchar", track: true,                  label: L("lcl_ins_deel_mjb_score2")},
        "dwgx":             { dbs: "ins_deel_dwgx",                             typ: "float",                                 label: L("lcl_ins_deel_dwgx"), track: true},
        "dwgy":             { dbs: "ins_deel_dwgy",                             typ: "float",                                 label: L("lcl_ins_deel_dwgy"), track: true},
        "dwgz":             { dbs: "ins_deel_dwgz",                             typ: "float",                                 label: L("lcl_ins_deel_dwgz"), track: true},
        "dwgrotation":      { dbs: "ins_deel_dwgrotatie",                       typ: "float",                                 label: L("lcl_ins_deel_dwg_rotatie"), track: true},
        "dwgscale":         { dbs: "ins_deel_dwgschaal",                        typ: "float",                                 label: L("lcl_ins_deel_dwg_schaal"), track: true},
        "externnr":         { dbs: "ins_deel_externnr",                         typ: "varchar",                               label: L("extern_nr"),       readonly: !(user.has("WEB_FACTAB") || user.has("WEB_FACXNR"))},
        "externsyncdate":   { dbs: "ins_deel_externsyncdate",                   typ: "datetime",                              label: L("extern_syncdate"), readonly: !(user.has("WEB_FACTAB") || user.has("WEB_FACXNR"))},
        "flag":             { dbs: "ins_deel_flag",                             typ: "number",  track: true,  LOV:"",         label: L("lcl_ins_flags")}
    };

    if (S("ins_deel_flags") > 0)
    {
        var flag_array = [];
        for (var i=0; i<S("ins_deel_flags"); i++)
        {
            flag_array.push(i);
            flag_array.push(L("lcl_ins_flag"+i));
        }
        this.fields.flag.LOV = flag_array.join(";");
    }
    else
    {
        delete this.fields.flag;
    }

    // een include van model_ins_deel_state_history lijkt voor de hand te liggen
    // maar gaf (vast oplosbare) problemen met een dubbele ins_deel in de query
    // Bovendien wil je in de praktijk altijd een datumfilter op de statedatum hebben
    // wat niet kan op een include. Doe daarom maar /api2/statehistory?object=16506&start_statedate=2017-11-01T12:20:16Z&fields=state,statedate
    this.includes = {
        "tracking": {
            "model": new model_tracking(["deel"]),
            "joinfield": "trackingrefkey"
        },
        "custom_fields" : {
            "model": new model_custom_fields(this, new model_ins_kenmerk("D", { internal: true }), { readman: true, readuse: true }),
            "joinfield": "flexparentkey",
            "enable_update": true
        },
        "issueobjects":  {
            "model": new model_issueobjects(),
            "joinfield": "object"
        }
    };


    function _check_authorization(params, method)
    {
        var urole = "fe"; // TODO: Moet echt niet ter zake doen
        var autfunction = urole == "fe"? "WEB_INSUSE" : "WEB_INSMAN";
        params.authparams = user.checkAutorisation(autfunction, null, null, true); // pessimistisch

        params.message = "";
        params.filter.scope = params.filter.scope || "fe";
        var module = "INS";
        var ins_key = params.filter.id || -1;
        var srtdeel_key = -1;
        var srtgroep_key = -1;
        var autfunction = ( params.filter.scope == "fe"
                          ? "WEB_INSUSE"
                          : ( params.filter.scope == "fo"
                            ? "WEB_INSFOF"
                            : "WEB_INSMAN"
                          ));
        // Voor sleutels/cilinders:
        if (  (ins_key      > 0 && ins.isSleCil(ins_key))
           || (srtdeel_key  > 0 && ins.isSleCil(srtdeel_key, "S"))
           || (srtgroep_key > 0 && ins.isSleCil(srtgroep_key, "G"))
           )
        {
            autfunction = "WEB_SLEBOF";
            module = "SLE";
        }

        if (ins_key > 0)
        {
            var this_ins = ins.func_enabled_deel(ins_key, {urole: params.filter.scope});
            user.auth_required_or_abort(this_ins.canChange || this_ins.canChangeOwn); // dat is toch wel het minste
            params.authparams = this_ins.authparams(autfunction);
        }
        else
        {
            params.authparams = user.checkAutorisation(autfunction); // , null, null, true); // pessimistisch
            var this_ins = { canChangeAlg: true };
        }

        params.func_enabled = this_ins || {};
    };

    function _pre_analyze_fields(params, jsondata, method)
    {
        var ins_key = params.filter.id || -1;
        var status = true;
        // POST:
        if (method == "POST")
        {
            if (!jsondata.name || !jsondata.type) //  || !jsondata.objectdiscipline)
            {
                params.message = L("lcl_missing_required_fields");
                status = false;
            }
            if (status)
            {
                params.message = setPlaceholder(ins_key, jsondata);
                status = (params.message == "");
            }
            if (status)
            {
                params.message = checkWithParent(ins_key, jsondata);
                status = (params.message == "");
            }
        }
        //PUT:
        if (method == "PUT")
        {
            // Discipline en objectsoort mogen niet gewijzigd worden.
            delete jsondata.objectdiscipline;
            delete jsondata.type;
            //
            if (jsondata.department || jsondata.owner || jsondata.terrain || jsondata.room || jsondata.workplace )
            {
                params.message = setPlaceholder(ins_key, jsondata);
                status = (params.message == "");
            }
            if (status)
            {
                params.message = checkWithParent(ins_key, jsondata);
                status = (params.message == "");
            }
        }

        if (!status)
        {
            abort_with_warning(params.message);
        }
    };

    function checkWithParent(ins_key, jsondata)
    {
        var msg = "";
        if (jsondata.parent > 0)
        {
            var child_type = jsondata.type;
            if (ins_key > 0)
            {   // srtdeel_key mag niet gewijzigd worden dus lees deze uit het bestaande record.
                var sql = "SELECT ins_srtdeel_key"
                        + "  FROM ins_deel"
                        + " WHERE ins_deel_key = " + ins_key;
                var oRs = Oracle.Execute(sql);
                child_type = oRs("ins_srtdeel_key").Value;
                oRs.Close();
            }

            var sql = "SELECT ins_srtdeel_key"
                    + "  FROM ins_v_aanwezigdeel"
                    + " WHERE ins_deel_key = " + jsondata.parent;
            var oRs = Oracle.Execute(sql);
            if (!oRs.EOF) {
                var parent_type = oRs("ins_srtdeel_key").Value;
                var sql_b = "SELECT (SELECT BITAND(ins_srtdeel_binding, 32)"
                          + "          FROM ins_srtdeel"
                          + "         WHERE ins_srtdeel_key = " + parent_type
                          + "       ) parent_child"
                          + "     , (SELECT BITAND(ins_srtdeel_binding, 32)"
                          + "          FROM ins_srtdeel"
                          + "         WHERE ins_srtdeel_key = " + child_type
                          + "       ) part_child"
                          + "  FROM DUAL";
                var oRs_b = Oracle.Execute(sql_b);
                if (oRs_b("parent_child").Value != 32) { // Het deel mag onderdelen hebben
                    msg = L("lcl_obj_allow_parts");
                }
                else if (oRs_b("part_child").Value != 0) { // Het onderdeel mag geen onderdelen hebben
                    msg = L("lcl_obj_nested_parts");
                }
                oRs_b.Close();
            }
            else {
                msg = L("lcl_obj_not_found");
            }
            oRs.Close();
        }
        return msg;
    }

    function setPlaceholder(ins_key, jsondata)
    {
        // Bepaal met binding of het juiste veld voor plaats/eigenaar zijn ingevuld.
        var msg = "";
        var placeholder = { status: false
                          , ruimte_type: null
                          , ruimte_key:  null
                          , bind_msg: []
                          };

        var srtdeel_key = jsondata.type;
        if (ins_key > 0)
        {   // srtdeel_key mag niet gewijzigd worden dus lees deze uit het bestaande record.
            var sql = "SELECT ins_srtdeel_key"
                    + "  FROM ins_deel"
                    + " WHERE ins_deel_key = " + ins_key;
            var oRs = Oracle.Execute(sql);
            srtdeel_key = oRs("ins_srtdeel_key").Value;
            oRs.Close();
        }

        var sql = "SELECT sd.ins_srtdeel_binding"
                + "     , sg.ins_srtgroep_key"
                + "     , sg.ins_discipline_key"
                + "  FROM ins_srtdeel sd"
                + "     , ins_srtgroep sg"
                + " WHERE sd.ins_srtgroep_key = sg.ins_srtgroep_key"
                + "   AND sd.ins_srtdeel_key = " + srtdeel_key;
        var oRs = Oracle.Execute(sql);
        if (!oRs.eof)
        {
            var bindingBits = oRs("ins_srtdeel_binding").Value;

            if (bindingBits & BIND_AFDELI)
            {
                if (jsondata.department && jsondata.department > 0)
                {
                    placeholder.status = true;
                    placeholder.ruimte_type = "A";
                    placeholder.ruimte_key = jsondata.department;
                }
                else
                    placeholder.bind_msg.push(L("lcl_obj_bind_a"));
            }
            if (bindingBits & BIND_PERSOO)
            {
                if (jsondata.owner && jsondata.owner > 0)
                {
                    placeholder.status = true;
                    placeholder.ruimte_type = "P";
                    placeholder.ruimte_key = jsondata.owner;
                }
                else
                    placeholder.bind_msg.push(L("lcl_obj_bind_p"));
            }
            if (bindingBits & BIND_TERREI)
            {
                if (jsondata.terrain && jsondata.terrain > 0)
                {
                    placeholder.status = true;
                    placeholder.ruimte_type = "T";
                    placeholder.ruimte_key = jsondata.terrain;
                }
                else
                    placeholder.bind_msg.push(L("lcl_obj_bind_t"));
            }
            if (bindingBits & BIND_RUIMTE)
            {
                if(jsondata.room && jsondata.room > 0 )
                {
                    placeholder.status = true;
                    placeholder.ruimte_type = "R";
                    placeholder.ruimte_key = jsondata.room;
                }
                else
                    placeholder.bind_msg.push(L("lcl_obj_bind_r"));
            }
            if (bindingBits & BIND_WERKPL)
            {
                if (jsondata.workplace && jsondata.workplace > 0)
                {
                    placeholder.status = true;
                    placeholder.ruimte_type = "W";
                    placeholder.ruimte_key = jsondata.workplace;
                }
                else
                    placeholder.bind_msg.push(L("lcl_obj_bind_w"));
            }

            if (placeholder.status)
            {
                // Haal de locatie op als ruimtetype W, R of T is.
                var sql = "SELECT alg_locatie_key"
                        + "  FROM (SELECT a.alg_onroerendgoed_keys, null, null prs_werkplek_key, a.alg_ruimte_key, a.alg_verdieping_key, a.alg_gebouw_key, a.alg_terreinsector_key, g.alg_locatie_key, alg_type"
                                + "  FROM alg_v_onroerendgoed a"
                                + "     , alg_gebouw g"
                                + " WHERE g.alg_gebouw_key = a.alg_gebouw_key and a.alg_type in ('R','V','G')"
                                + " UNION "
                                + "SELECT a.alg_onroerendgoed_keys, null, null prs_werkplek_key, a.alg_ruimte_key, a.alg_verdieping_key, a.alg_gebouw_key, a.alg_terreinsector_key, t.alg_locatie_key, alg_type"
                                + "  FROM alg_v_onroerendgoed a"
                                + "     , alg_terreinsector t"
                                + " WHERE t.alg_terreinsector_key = a.alg_terreinsector_key and a.alg_type in ('T')"
                                + " UNION "
                                + "SELECT prs_werkplek_key, null, prs_werkplek_key, alg_ruimte_key, alg_verdieping_key, alg_gebouw_key, null, alg_locatie_key, 'W'"
                                + "  FROM prs_v_werkplek_gegevens"
                                + " UNION "
                                // Doe geen moeite om locatie bij persoon te bepalen. De trigger ins_t_ins_deel_b_iu maakt hem dan alsnog leeg.
                                + "SELECT prs_perslid_key, prs_perslid_key, null, null, null, null, null, -1, 'P'"
                                + "  FROM prs_perslid"
                                + " WHERE prs_perslid_verwijder IS NULL"
                                + ") plts"
                        + " WHERE plts.alg_type = " + safe.quoted_sql(placeholder.ruimte_type)
                        + "   AND plts.alg_onroerendgoed_keys = " + placeholder.ruimte_key;
                var oRs_l = Oracle.Execute(sql);
                if (!oRs_l.eof)
                {   // Zet de (nieuwe) plaats/eigenaar gegevens.
                    jsondata.placeholdertype = placeholder.ruimte_type;
                    jsondata.placeholderkey = placeholder.ruimte_key;
                    jsondata.placeholderloc = oRs_l("alg_locatie_key").Value;
                }
                else
                {
                    msg = L("lcl_obj_unknown_placeholder").format(placeholder.ruimte_type, placeholder.ruimte_key);
                }
                oRs_l.Close();
            }
            else
            {   // Verkeerde/geen binding gebruikt.
                msg = L("lcl_obj_bind_mandatory") +" "+ placeholder.bind_msg.join(" of ");
            }
        }
        else
            msg = L("lcl_obj_unknown_binding");
        oRs.Close();

        return msg;
    }


    this.REST_GET = function _GET(params)
    {
        var withcomponents = true; // default 2025.1 gedrag
        if (params.filter.components == "0")
            withcomponents = false; // oude 2024.3 gedrag (geen onderdelen)
        if (!withcomponents)
        {
            this.tablesql = "ins_deel ins_v_deelenonderdeel";  // voor het gemak alias ins_v_deelenonderdeel
        }

        _check_authorization(params, "GET");
        var query = api2.sqlfields(params, this);

        query.wheres.push("ins_deel_verwijder IS NULL");
        // Toon standaard alleen de niet vervallen objecten, behalve als specifiek op object identificatie wordt gezocht.
        if (!params.filter.expired && !params.filter.name)
        {
            query.wheres.push(" (ins_v_deelenonderdeel.ins_deel_vervaldatum IS NULL OR ins_v_deelenonderdeel.ins_deel_vervaldatum > TRUNC(SYSDATE))");
        }

        query.tables.push("ins_srtdeel");
        query.wheres.push("ins_v_deelenonderdeel.ins_srtdeel_key = ins_srtdeel.ins_srtdeel_key");

        // Als Uitgegeven of Beschikbaar is meegegeven dan overzicht uitleenmodule.
        if (params.filter.lentout || params.filter.avail)
        {
            query.wheres.push("ins_srtdeel_uitleenbaar = 1");
            if (params.filter.lentout && !params.filter.avail)
            {
                query.wheres.push("ins_alg_ruimte_key_org IS NOT NULL");
            }
            if (!params.filter.lentout && params.filter.avail)
            {
                query.wheres.push("ins_alg_ruimte_key_org IS NULL");
            }
        }

        // TODO: Add 3D authorization
        // Alleen nog maar simpele 1D autorisatie
        query.wheres.push(" ins_v_deelenonderdeel.ins_discipline_key IN"
                        + " (SELECT ins_discipline_key"
                        + "    FROM fac_v_webgebruiker"
                        + "   WHERE fac_functie_key = " + params.authparams.autfunctionkey
                        + "     AND prs_perslid_key = " + user_key
                        + "     AND fac_gebruiker_prs_level_read < 9"
                        + "     AND fac_gebruiker_alg_level_read < 9)");

        // TODO: We ondersteunen uitsluitend ruimte- werkplek- en persoonsgebonden objecten
        // MGE: Let op dat de view "ins_v_deel_gegevens" geen onderdelen oplevert omdat de view afdwingt dat ins_deel_parent_key "NULL" moet zijn.
        if (withcomponents)
        {
            query.tables.push("ins_v_deelenonderdeel_gegevens");
        }
        else
        {
            query.tables.push("ins_v_deel_gegevens ins_v_deelenonderdeel_gegevens"); // voor het gemak alias ins_v_deelenonderdeel_gegevens
        }
        query.wheres.push("ins_v_deelenonderdeel.ins_alg_ruimte_type IN ('T', 'R', 'W', 'P', 'A', 'C') ");
        query.wheres.push("ins_v_deelenonderdeel_gegevens.ins_deel_key = ins_v_deelenonderdeel.ins_deel_key");

        var wheres = api2.sqlfilter(params, this)
        query.wheres = query.wheres.concat(wheres);

        var sql = "SELECT " + query.selects.join(", ")
                + "  FROM " + query.tables.join(", ")
                + " WHERE " + query.wheres.join(" AND " )
                + " ORDER BY ins_deel_omschrijving";
        if (query.orderbys.length)
            sql += ", " + query.orderbys.join(", ");

        var json = api2.sql2json (params, sql, this);

        return json;
    };

    this.REST_PUT = function (params, jsondata, the_key) /* update object */
    {
        _check_authorization(params, "PUT");
        _pre_analyze_fields(params, jsondata, "PUT");

        if (params.custom_fields_only)
        {
            var insUpd = { trackarray: [] };
        }
        else
        {
            var dbfields = api2.update_fields(params, this, jsondata); // Build updater

            var wheres = [" ins_deel_key = " + the_key];
            var insUpd = buildTrackingUpdate("ins_deel", wheres.join(" AND " ), dbfields, { noValidateToken: true });
            Oracle.Execute(insUpd.sql);
        }

        params.delayTracking = true;
        var instrack = api2.process_includes(params, this, jsondata, the_key);
        var all_track = (insUpd && insUpd.trackarray ? insUpd.trackarray : []);
        all_track = all_track.concat(instrack);
        if (all_track.length)
        {
            var update_string = L("lcl_ins_is_insupd") + "\n" + all_track.join("\n");
            shared.trackaction("INSUPD", the_key, update_string);
        }

        return { key: the_key };
    };

    this.REST_POST = function (params, jsondata) /* new object */
    {
        params.isNew = true;
        _check_authorization(params, "POST");
        _pre_analyze_fields(params, jsondata, "POST");

        var dbfields = api2.update_fields(params, this, jsondata); // Build updater
        dbfields["id"] = {dbs: "ins_deel_key", typ: "key", seq: "ins_s_ins_inst_keys" };
        var insIns = buildInsert("ins_deel", dbfields, { noValidateToken: true });
        var ins_key = insIns.sequences["ins_deel_key"];

        var err = Oracle.Execute(insIns.sql, true);
        if (err.friendlyMsg)
            abort_with_warning(err.friendlyMsg);

        var instrack = api2.process_includes(params, this, jsondata, ins_key);

        shared.trackaction("INSNEW", ins_key);

        return { key: ins_key, warning: params.message };
    };

    this.xxx_DELETE = function (params) /* delete object */
    {
            // Nog niet ondersteund
    };
}

%>
