<% /*
     $Revision$
     $Id$

     File:               shared/PRSFunctions.asp
     Description:        Generieke serverside PRS functies
     Parameters:
     Context:
     Result:
     Note:
*/

/************************************************************\
 * Bepaal allerlei gegevens van een persoon
 * Input: prsKey (moet bestaan)
 * Result: Perslid object
\************************************************************/
function Perslid(prsKey)
{
  this._prs_perslid_key = prsKey;
  // De memoized functie wordt gebruikt om ander functies geheel transparant te cachen
  // Vooral bij mld_list.inc waar per regel nog wel eens mld_func_enabled wordt aangeroepen
  // kan dit flink schelen
  this.func_enabled_readit_memoized =
            memoize(this.func_enabled_readit, this);
  this.checkAutorisation_readit_memoized =
            memoize(this.checkAutorisation_readit, this);
}

// Forceer het ophalen van prs_perslid data
Perslid.prototype._require_prs_perslid = function __require_prs_perslid()
{
  if (this._prs_perslid_key <= 0)
  {
    __DoLog("Perslid key: " + this._prs_perslid_key  + " bestaat helemaal niet. Had je dat niet eerder kunnen bedenken?", "#FFFF00");
    return;
  }

  if (this._prs_afdeling_key)
    return; // We waren al klaar

  var sql = "SELECT p.prs_perslid_key"
          + "     , p.prs_perslid_geslacht"
          + "     , p.prs_afdeling_key"
          + "     , p.fac_profiel_key"
          + "     , p.prs_perslid_telefoonnr"
          + "     , p.prs_perslid_mobiel"
          + "     , p.prs_perslid_email"
          + "     , p.prs_perslid_nr"
          + "     , p.mld_adres_key"
          + "     , p.prs_srtperslid_key"
          + "     , p.prs_perslid_login"
          + "     , p.prs_perslid_oslogin"
          + "     , p.prs_perslid_oslogin2"
          + "     , p.prs_perslid_wachtwoord_hash"
          + "     , p.prs_perslid_otpsecret"
          + "     , prs_perslid_credentials_datum"
          + "     , p.alg_onroerendgoed_keys"
          + "     , p.alg_onroerendgoed_type"
          + "     , p.prs_perslid_bezetdatum"
          + "     , prs_perslid_srtnoti_mode"
          + "     , p.prs_perslid_naam"
          + "     , p.prs_perslid_tussenvoegsel"
          + "     , p.prs_perslid_voorletters"
          + "     , p.prs_perslid_voornaam"
          + "     , p.prs_perslid_titel titel"
          + "     , prs_perslid_lang"
          + "     , prs_perslid_flags"
          + "     , prs_perslid_options"
          + "     , prs_perslid_wachtwoord_exp"
          + "     , prs_perslid_apikey"
          + "     , prs_perslid_terms_version"
          + "  FROM prs_perslid p"
          + " WHERE p.prs_perslid_key = " + this._prs_perslid_key
  var oRs = Oracle.Execute(sql);

  this._prs_afdeling_key = oRs("prs_afdeling_key").value;
  //this._naam = oRs("naam").value; wordt on-demand afzonderlijk opgehaald
  this._prs_perslid_geslacht = oRs("prs_perslid_geslacht").value;
  this._prs_perslid_telefoonnr = oRs("prs_perslid_telefoonnr").value;
  this._prs_perslid_mobiel = oRs("prs_perslid_mobiel").value;
  this._fac_profiel_key = oRs("fac_profiel_key").value;
  this._prs_perslid_email = oRs("prs_perslid_email").value;
  this._prs_perslid_nr = oRs("prs_perslid_nr").value;
  this._prs_srtperslid_key = oRs("prs_srtperslid_key").value;
  this._objAfdeling = null;
  this._mld_adres_key = oRs("mld_adres_key").Value;
  this._prs_perslid_login = oRs("prs_perslid_login").value;  // last login
  this._prs_perslid_oslogin = oRs("prs_perslid_oslogin").value;
  this._prs_perslid_oslogin2 = oRs("prs_perslid_oslogin2").value;
  this._prs_perslid_haspw = (oRs("prs_perslid_wachtwoord_hash").value != null);
  this._prs_perslid_otpsecret = oRs("prs_perslid_otpsecret").value;
  this._prs_perslid_credentials_datum = new Date(oRs("prs_perslid_credentials_datum").Value);
  this._alg_onroerendgoed_keys = oRs("alg_onroerendgoed_keys").value;
  this._alg_onroerendgoed_type = oRs("alg_onroerendgoed_type").value;
  this._prs_perslid_bezetdatum = oRs("prs_perslid_bezetdatum").value;
  this._prs_collegas = null;
  this._prs_noti_niks = oRs("prs_perslid_srtnoti_mode").value==0;
  this._prs_noti_portal = (oRs("prs_perslid_srtnoti_mode").value&1)==1;
  this._prs_noti_email = (oRs("prs_perslid_srtnoti_mode").value&2)==2;
  this._prs_noti_sms = (oRs("prs_perslid_srtnoti_mode").value&4)==4;
  this._prs_noti_popup = (oRs("prs_perslid_srtnoti_mode").value&8)==8;
  this._prs_perslid_achternaam = oRs("prs_perslid_naam").value;
  this._prs_perslid_tussenvoegsel = oRs("prs_perslid_tussenvoegsel").value;
  this._prs_perslid_voorletters = oRs("prs_perslid_voorletters").value;
  this._prs_perslid_voornaam = oRs("prs_perslid_voornaam").value;
  this._prs_perslid_titel = oRs("titel").value;
  this._prs_perslid_lang = oRs("prs_perslid_lang").value||S("db_lang");
  this._prs_perslid_flags = oRs("prs_perslid_flags").value;
  this._prs_perslid_options = oRs("prs_perslid_options").value;
  if (oRs("prs_perslid_wachtwoord_exp").Value != null)
    this._prs_perslid_wachtwoord_exp = new Date(oRs("prs_perslid_wachtwoord_exp").Value);
  this._prs_perslid_apikey = oRs("prs_perslid_apikey").value;
  this._prs_perslid_terms_version = oRs("prs_perslid_terms_version").value;

  if (this._prs_perslid_options)
  {
    try
    {
        // Ik zou liever myJSON.parse gebruiken maar JSON is lang niet altijd aanwezig
        this._prs_perslid_options = eval("(" + this._prs_perslid_options + ")");
    }
    catch (e)
    {   // Zou niet mogen gebeuren maar vanwege zeer hoge impact (gebruiker
        // kan echt niets meer) toch maar onderscheppen.
        __DoLog("eval van options mislukt: " + e.description, "#FF0000")
        __DoLog(this._prs_perslid_options);
        this._prs_perslid_options = { version: FCLTVersion }; // Resetten dan maar (database nog ongewijzigd)
    }
  }
  else
      this._prs_perslid_options = { version: FCLTVersion };

  oRs.close();
}

// Forceer het ophalen van plaats data van prs_perslid
// Zal nooit virtuele werkplekken bevatten!
Perslid.prototype._require_prs_perslid_plaats = function __require_prs_perslid_plaats (params)
{
  if (!params) params = {};

  this._require_prs_perslid();
  if (!this._werkplekken)
  {
    this._werkplekken = [];
    //this._prs_perslidwerkplek_bezetting = [];
    var sql = "SELECT w.prs_werkplek_key"
            + ", w.prs_perslidwerkplek_bezetting"
            + ", w.prs_perslidwerkplek_key"
            + " FROM prs_perslidwerkplek w"
            + ", prs_v_werkplek_gegevens wg"
            + " WHERE w.prs_werkplek_key = wg.prs_werkplek_key"
            + "   AND w.prs_perslid_key = " + this._prs_perslid_key
            + "   AND prs_werkplek_virtueel <> 1"
            + " ORDER BY COALESCE(w.prs_perslidwerkplek_volgnr,9999) ASC," // ingevulde volgnummers vooraan
            + "          w.prs_perslidwerkplek_bezetting DESC" // dan hoogste bezetting
            + ",         wg.prs_werkplek_aanduiding"; // dan op plaatsaanduiding
    var oRs = Oracle.Execute(sql);
    while (!oRs.eof)
    {
        this._werkplekken.push(new Werkplek(oRs("prs_werkplek_key")));
        this._werkplekken[this._werkplekken.length-1]._prs_perslidwerkplek_key = oRs("prs_perslidwerkplek_key").Value;
        this._werkplekken[this._werkplekken.length-1].prs_perslidwerkplek_key = function () { return this._prs_perslidwerkplek_key };

        //this._prs_perslidwerkplek_bezetting.push({ bezetting: oRs("prs_perslidwerkplek_bezetting").value });
        oRs.MoveNext();
    }
    oRs.close();
  }

  if (params.withcurrent && !this._standplaats)
  {
      this._standplaats = { _alg_locatie_key: -1,
                            _alg_gebouw_key: -1,
                            _alg_verdieping_key: -1,
                            _alg_ruimte_key: -1
                          }

      var sql = "";
      switch (this._alg_onroerendgoed_type)
      {
        case "L":
        {
          this._standplaats._alg_locatie_key = this._alg_onroerendgoed_keys;
          break;
        }
        case "T":
        case "G":
        case "V":
        case "R":
        {
          var sql = "SELECT g.alg_locatie_key, og.alg_gebouw_key, og.alg_verdieping_key, og.alg_ruimte_key"
                  + "  FROM alg_v_onroerendgoed og" // Vervallen onroerendgoed blijft dus verborgen
                  + "     , alg_gebouw g"
                  + " WHERE og.alg_gebouw_key = g.alg_gebouw_key"
                  + "   AND og.alg_onroerendgoed_keys = " + this._alg_onroerendgoed_keys
                  + "   AND alg_type = " + safe.quoted_sql(this._alg_onroerendgoed_type);
          break;
        }
        case "W":
        {
          var sql = "SELECT g.alg_locatie_key, og.alg_gebouw_key, og.alg_verdieping_key, og.alg_ruimte_key"
                  + "  FROM prs_werkplek w"
                  + "     , alg_v_onroerendgoed og" // Vervallen onroerendgoed blijft dus verborgen
                  + "     , alg_gebouw g"
                  + " WHERE w.prs_alg_ruimte_key = og.alg_onroerendgoed_keys"
                  + "   AND og.alg_gebouw_key = g.alg_gebouw_key"
                  + "   AND og.alg_type = 'R'"
                  + "   AND w.prs_werkplek_key = " + this._alg_onroerendgoed_keys;
          break;
        }
      }
      if (sql)
      {
          var oRs2 = Oracle.Execute(sql);
          if (!oRs2.eof)
          {
            this._standplaats._alg_locatie_key = oRs2("alg_locatie_key").value;
            this._standplaats._alg_gebouw_key = oRs2("alg_gebouw_key").value;
            this._standplaats._alg_verdieping_key = oRs2("alg_verdieping_key").value;
          }
          oRs2.close()
      }
    }
}

Perslid.prototype.werkplekken = function()
{
    this._require_prs_perslid_plaats();
    return this._werkplekken;
}

Perslid.prototype.prs_perslidwerkplek_bezetting = function()
{
    this._require_prs_perslid_plaats();
    return this._prs_perslidwerkplek_bezetting;
}

Perslid.prototype.prs_perslid_key = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_key;
}

Perslid.prototype.prs_afdeling_key = function()
{
  this._require_prs_perslid();
  return this._prs_afdeling_key;
}

Perslid.prototype.prs_srtperslid_key = function()
{
  this._require_prs_perslid();
  return this._prs_srtperslid_key;
}

Perslid.prototype.naam = function naam()
{
  this._require_prs_perslid();
  if (!this._naam && this._prs_perslid_key > 0)
  {
    var sql = "SELECT prs_perslid_naam_friendly"
            + "  FROM prs_v_perslid_fullnames_all"
            + " WHERE prs_perslid_key = " + this._prs_perslid_key;
    var oRs = Oracle.Execute(sql);
    this._naam = oRs("prs_perslid_naam_friendly").Value;
    oRs.Close()
 }
  return this._naam;
}

Perslid.prototype.prs_perslid_geslacht = function prs_perslid_geslacht()
{
  this._require_prs_perslid();
  return this._prs_perslid_geslacht;
}

Perslid.prototype.prs_perslid_telefoonnr = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_telefoonnr;
}

Perslid.prototype.prs_perslid_mobiel = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_mobiel;
}

Perslid.prototype.fac_profiel_key = function()
{
  this._require_prs_perslid();
  return this._fac_profiel_key;
}

Perslid.prototype.prs_perslid_email = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_email;
}

Perslid.prototype.prs_perslid_nr = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_nr;
}

Perslid.prototype.prs_srtperslid = function()
{
  this._require_prs_perslid();
  // moeite van cachen niet waard.
  var sql = "SELECT "+ lcl.xsqla('sp.prs_srtperslid_omschrijving','sp.prs_srtperslid_key')
          + "  FROM prs_srtperslid sp"
          + " WHERE prs_srtperslid_key = " + this._prs_srtperslid_key;
  var oRs = Oracle.Execute(sql);
  var result = oRs("prs_srtperslid_omschrijving").Value;
  oRs.Close()

  return result;
}

Perslid.prototype.mld_adres_key = function()
{
  this._require_prs_perslid();
  return this._mld_adres_key;
}

Perslid.prototype.login = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_login;
}
Perslid.prototype.oslogin = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_oslogin;
}
Perslid.prototype.oslogin2 = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_oslogin2;
}

Perslid.prototype.haspw = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_haspw;
}

Perslid.prototype.otpsecret = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_otpsecret;
}

Perslid.prototype.alg_onroerendgoed_keys = function()
{
  this._require_prs_perslid();
  return this._alg_onroerendgoed_keys;
}

Perslid.prototype.alg_onroerendgoed_type = function()
{
  this._require_prs_perslid();
  return this._alg_onroerendgoed_type;
}

Perslid.prototype.prs_perslid_bezetdatum = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_bezetdatum;
}

Perslid.prototype.noti_niks = function()
{
  this._require_prs_perslid();
  return this._prs_noti_niks;
}
Perslid.prototype.noti_portal = function()
{
  this._require_prs_perslid();
  return this._prs_noti_portal;
}
Perslid.prototype.noti_email = function()
{
  this._require_prs_perslid();
  return this._prs_noti_email;
}
Perslid.prototype.noti_sms = function()
{
  this._require_prs_perslid();
  return this._prs_noti_sms;
}
Perslid.prototype.noti_popup = function()
{
  this._require_prs_perslid();
  return this._prs_noti_popup;
}
Perslid.prototype.prs_perslid_achternaam = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_achternaam;
}
Perslid.prototype.prs_perslid_tussenvoegsel = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_tussenvoegsel;
}
Perslid.prototype.prs_perslid_voorletters = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_voorletters;
}
Perslid.prototype.prs_perslid_voornaam = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_voornaam;
}
Perslid.prototype.prs_perslid_titel = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_titel;
}

// Echt uit de database
Perslid.prototype.dblang = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_lang;
}

// Zo mogelijk uit cache zodat minder vaak prs_perslid query
Perslid.prototype.lang = function()
{
  var user_lang = Session("user_lang");
  if (typeof user_lang == "undefined")
    return this.dblang();
  return user_lang;
}

// Let op: newval alleen te gebruiken vanuit ASP-bestanden die Shared/json2.js includen!
//         Bij newval is het resultaat true/false of het opslaan al dan niet gelukt is.
//         Het 'misluk' als alle settings samen meer dan 4000 karakters zouden worden.
Perslid.prototype.options = function(optionname, newval)
{
  this._require_prs_perslid();

  if (typeof newval == "undefined")
    return this._prs_perslid_options[optionname];

  // else // Bijwerken
  if (newval === null)
      delete this._prs_perslid_options[optionname];
  else
      this._prs_perslid_options[optionname] = newval;
  this._prs_perslid_options.version = FCLTVersion;
  var newjson = JSON.stringify(this._prs_perslid_options);
  if (newjson.length < 4000)
  {
      var sql = "UPDATE prs_perslid"
              + "   SET prs_perslid_options = " + safe.quoted_sql(newjson)
              + " WHERE prs_perslid_key = " + this._prs_perslid_key;
      Oracle.Execute(sql, true);
      return true;
  }
  else
  {   // safe.quoted_sql zou afkappen op 4000 karakters en daarmee een ongeldige JSON genereren
      __DoLog("newjson zou te lang worden. Niet opgeslagen.", "#FF0000");
      __DoLog(newjson);
      return false;
  }
}

Perslid.prototype.isSystemUser = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_flags & 1;
}
Perslid.prototype.isUnapprovedUser = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_flags & 2;
}
Perslid.prototype.isGroupedUser = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_flags & 4;
}
Perslid.prototype.isBlockedUser = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_flags & 8;
}

Perslid.prototype.password_expired = function _password_expired()
{
  this._require_prs_perslid();
  if (!this._prs_perslid_wachtwoord_exp)
    return false;
  return this._prs_perslid_wachtwoord_exp < (new Date);
}

Perslid.prototype.terms_version = function _terms_version()
{
  this._require_prs_perslid();
  return this._prs_perslid_terms_version;
}

// Als de credentials zijn gewijzigd *nadat* je bent ingelogd
// gaan we moeilijk doen (vanuit common.inc)
Perslid.prototype.credentials_changed = function _credentials_changed()
{
  this._require_prs_perslid();
  var login_date = new Date(Session("login_date"));
  var is_changed = false;
  if (this._prs_perslid_credentials_datum > login_date)
  {
    __DoLog("Session is expired! cred={0}, login={1}".format(toDateTimeString(this._prs_perslid_credentials_datum, true), toDateTimeString(login_date, true)), "#f00");
    is_changed = true;
  }
  return is_changed;
}

Perslid.prototype.prs_perslid_apikey = function()
{
  this._require_prs_perslid();
  return this._prs_perslid_apikey;
}

Perslid.prototype._require_kpn_string = function()
{
  if (!this._kpn_string)
  {
    this._require_prs_perslid();
    this._kpn_string ="-";
    this._kpn_budgethouderkey = -1;
    if (this.afdeling().prs_kostenplaats_key())
    {
      var oRs = Oracle.Execute("SELECT " + S("prs_kpn_string") +", k.prs_perslid_key"
                             + "  FROM prs_kostenplaats k"
                             + " WHERE k.prs_kostenplaats_key = " + this.afdeling().prs_kostenplaats_key());
      this._kpn_string = '' + oRs(0).value;
      this._kpn_budgethouderkey = oRs(1).value;
      oRs.close();
    }
  }
}

Perslid.prototype.kpn_string = function()
{
    this._require_kpn_string();
    return this._kpn_string;
}
// Meer info kun je krijgen door een user object met deze key te maken.
Perslid.prototype.kpn_budgethouderkey = function()
{
    this._require_kpn_string();
    return this._kpn_budgethouderkey;
}

// De volgende 5 functies zijn een beetje gemakzucht, ze pakken de locatie_key etc van de eerste werkplek of geven -1
Perslid.prototype.alg_locatie_key = function _alg_locatie_key(params)
{
  this._require_prs_perslid_plaats();
  if (!params) params = {};
  if (params.withcurrent)
  {
    if (this._alg_onroerendgoed_type == 'L')
        return this._alg_onroerendgoed_keys; // goedkoop

    this._require_prs_perslid_plaats({ withcurrent: true });
    return this._standplaats._alg_locatie_key || -1;
  }
  if (this._werkplekken.length)
    return this._werkplekken[0].alg_locatie_key();
  else
    return -1;
}

Perslid.prototype.alg_gebouw_key = function(params)
{
  this._require_prs_perslid_plaats();
  if (!params) params = {};
  if (params.withcurrent)
  {
    if (this._alg_onroerendgoed_type == 'L')
        return -1; // goedkoop
    if (this._alg_onroerendgoed_type == 'G')
        return this._alg_onroerendgoed_keys; // goedkoop

    this._require_prs_perslid_plaats({ withcurrent: true });
    return this._standplaats._alg_gebouw_key || -1; // Bij geen gebouw -1 teruggeven
  }
  if (this._werkplekken.length)
    return this._werkplekken[0].alg_gebouw_key();
  else
    return -1;
}

Perslid.prototype.alg_verdieping_key = function(params)
{
  this._require_prs_perslid_plaats();
  if (!params) params = {};
  if (params.withcurrent)
  {
    if (this._alg_onroerendgoed_type == 'L' ||
        this._alg_onroerendgoed_type == 'G')
        return -1; // goedkoop
    if (this._alg_onroerendgoed_type == 'V')
        return this._alg_onroerendgoed_keys; // goedkoop

    this._require_prs_perslid_plaats({ withcurrent: true });
    return this._standplaats._alg_verdieping_key || -1; // Bij geen verdieping -1 teruggeven
  }
  if (this._werkplekken.length)
    return this._werkplekken[0].alg_verdieping_key();
  else
    return -1;
}

Perslid.prototype.alg_ruimte_key = function(params)
{
  this._require_prs_perslid_plaats();
  if (!params) params = {};
  if (params.withcurrent)
  {
    if (this._alg_onroerendgoed_type == 'L' ||
        this._alg_onroerendgoed_type == 'G' ||
        this._alg_onroerendgoed_type == 'V')
        return -1; // goedkoop
    if (this._alg_onroerendgoed_type == 'R')
        return this._alg_onroerendgoed_keys; // goedkoop

    this._require_prs_perslid_plaats({ withcurrent: true });
    return this._standplaats._alg_ruimte_key || -1; // Bij geen verdieping -1 teruggeven
  }
  if (this._werkplekken.length)
    return this._werkplekken[0].alg_ruimte_key();
  else
    return -1;
}

Perslid.prototype.prs_werkplek_key = function(params)
{
  this._require_prs_perslid_plaats();
  if (!params) params = {};
  if (params.withcurrent)
  {
    if (this._alg_onroerendgoed_type == 'W')
        return this._alg_onroerendgoed_keys; // goedkoop

    // Als ik op locatie/gebouw/verdieping/ruimte geregistreerd ben, weet ik hiervan geen werkplek
    // Dan je werkplek op deze lokatie zoeken?
    // Eerst maar eens: ik weet geen werkplek
    return -1;
  }
  if (this._werkplekken.length)
    return this._werkplekken[0].prs_werkplek_key();
  else
    return -1;
}

Perslid.prototype.aantal_werkplekken = function()
{
  this._require_prs_perslid_plaats();
  return this._werkplekken.length;
}

Perslid.prototype.afdeling = function()
{
  this._require_prs_perslid();
  if (this._objAfdeling == null)
    this._objAfdeling = new Afdeling(this._prs_afdeling_key)
  return this._objAfdeling;
}

Perslid.prototype.locatie = function(params)
{
  this._require_prs_perslid_plaats();
  if (this._objLocatie == null)
    this._objLocatie = new Locatie(this.alg_locatie_key(params))
  return this._objLocatie;
}

Perslid.prototype.gebouw = function(params)
{
  this._require_prs_perslid_plaats();
  if (this._objGebouw == null)
    this._objGebouw = new Gebouw(this.alg_gebouw_key(params))
  return this._objGebouw;
}

Perslid.prototype.verdieping = function(params)
{
  this._require_prs_perslid_plaats();
  if (this._objVerdieping == null)
    this._objVerdieping = new Verdieping(this.alg_verdieping_key(params))
  return this._objVerdieping;
}

Perslid.prototype.ruimte = function(params)
{
  this._require_prs_perslid_plaats();
  if (this._objRuimte == null)
    this._objRuimte = new Ruimte(this.alg_ruimte_key(params))
  return this._objRuimte;
}

Perslid.prototype.werkplek = function(params)
{
  this._require_prs_perslid_plaats();
  if (this._objWerkplek == null)
    this._objWerkplek = new Werkplek(this.prs_werkplek_key(params))
  return this._objWerkplek;
}

Perslid.prototype.photoinfo = function(geslacht) // geslacht is optioneel voor de avatar
{
    // via S("prs_photo_kenmerk_key") == -1 is tonen/niet tonen te regelen. Daar doen we hier niets mee, dan upload je maar niet.
    var keyStr = "0000000" + this._prs_perslid_key;
    var subfolder = "P" + keyStr.substr(keyStr.length-7,4) + "___/P" + this._prs_perslid_key;
    var url = S("prs_image_path") + subfolder + "/SML/";
    var path = Server.MapPath(url) + "/";

    var jpgfile = null;
    var fso = Server.CreateObject("Scripting.FileSystemObject")
    __Log("Photo zoeken in: " + path);
    if (fso.FolderExists(path))
    {
      // zoek de eerste jpg
      var f = fso.GetFolder(path);
      var fc = new Enumerator(f.files);
      for (; !fc.atEnd() && !jpgfile; fc.moveNext())
      {
        fsoFile = fc.item();
        if (fsoFile.Name.match(/\.jpg$/i))
        {
            jpgfile = fsoFile.Name;
        }
        else
            __Log("Skip: " + jpgfile);
      }
      if (jpgfile)
      {

        return {
                    photomap : url,
                    photopath : url + jpgfile,
                    photopaththumb : url +'thumb/'+jpgfile
               };
      }
    }
    // else unknown
    if (typeof geslacht == 'undefined')
    {
        this._require_prs_perslid(); // Nu pas! Kan heel duur zijn voor prs_phonebook_list.asp
        geslacht = this._prs_perslid_geslacht;
    }

    var result = { isDefault: true };
    result.photomap = url;
    result.photopath = rooturl + "/appl/pictures/";
    switch (geslacht)
    {
        case 0: result.photopath += 'avatar0.jpg';
                break;
        case 1: result.photopath += 'avatar1.jpg';
                break;
        default: result.photopath += 'avatarx.jpg';
                break;
    }
    result.photopaththumb = result.photopath; // altijd gelijk
    return result;
}

Perslid.prototype.isBudgethouder = function()
{
    var budgethouder = false;
    var sql = "SELECT COUNT(*)"
            + "  FROM prs_v_aanwezigkostenplaats k "
            + " WHERE k.prs_perslid_key = " + this._prs_perslid_key;
    var oRs = Oracle.Execute(sql);
    if (oRs(0).value > 0)
        budgethouder = true;
    oRs.close();
    return budgethouder;
}

// Ben ik contactpersoon van *een* bedrijf (maakt niet uit welke)
Perslid.prototype.isContactpersoon = function(bedrijf_key)
{
    var contactpersoon = false;
    var sql = "SELECT COUNT(*)"
            + "  FROM prs_contactpersoon cp"
            + " WHERE cp.prs_perslid_key = " + this._prs_perslid_key
            + "   AND cp.prs_contactpersoon_verwijder IS NULL";
    if (bedrijf_key)
      sql += " AND prs_bedrijf_key = " + bedrijf_key;
    var oRs = Oracle.Execute(sql);
    if (oRs(0).value > 0)
        contactpersoon = true;
    oRs.close();
    return contactpersoon;
}

// checkAutorisation
// @param autfunction of array met autfuncion
// @param isOptional
// @param ins_discipline_key
// result:
// null als helemaal geen rechten (alles level 9) maar wel isOptional
// melding 'U bent niet geauthoriseerd' als helemaal geen rechten en niet isOptional
// anders: { PRSreadlevel: 0, PRSwritelevel: 1, ALGreadlevel: 0, ALGwritelevel: 1, autfunctionkey: 64 }
// Standaard controleren we dat *optimistisch*: de rechten voor één disciplines is voldoende!
// wanneer checkPessimistic is meegegeven controleren we dat *pessimistisch*: je moet de rechten voor alle disciplines hebben!

Perslid.prototype.checkAutorisation = function checkAutorisation(autfunction, isOptional, ins_discipline_key, checkPessimistic)
{
  return this.checkAutorisation_readit_memoized(autfunction, isOptional, ins_discipline_key, checkPessimistic);
}
// Leesbare shortcut
Perslid.prototype.has = function(autfunction) { return this.checkAutorisation_readit_memoized(autfunction, true); }

// internal. Do not use...
Perslid.prototype.checkAutorisation_readit = function _checkAutorisation_readit(autfunction, isOptional, ins_discipline_key, checkPessimistic)
{
  // IN:  globals user_key,
  // IN:  autfunction 'WEB_MLDBOF' of de key daarvan als je die al hebt
  // OUT: PRSreadlevel, PRSwritelevel, ALGreadlevel, ALGwritelevel, autfunctionkey, autfunction
  var result = { autfunction: autfunction,
                 PRSreadlevel: -1,
                 PRSwritelevel: -1,
                 ALGreadlevel: -1,
                 ALGwritelevel: -1,
                 autfunctionkey: -1 };

  if (autfunction=="*")
        return result;

  result.PRSreadlevel  = 99;     // No authorization by default
  result.PRSwritelevel = 99;     // No authorization by default
  result.ALGreadlevel  = 99;     // No authorization by default
  result.ALGwritelevel = 99;     // No authorization by default
  var thisfunc_enabled = false; // No authorization by default
  result.autfunctionkey = -1; // Kan heel handig zijn.

  var where;
  if (typeof autfunction == "number")
    where = "f.fac_functie_key = " + autfunction;
  else if (typeof autfunction == "object" && autfunction instanceof Array)
    where = "f.fac_functie_code IN (" + safe.quoted_sql_join(autfunction) + ")";
  else
    where = "f.fac_functie_code = " + safe.quoted_sql(autfunction);

  var oRs = Oracle.Execute("SELECT f.fac_functie_code,"
                         + "       f.fac_functie_key,"
                         + "       fac_functie_discipline,"
                         + "       fac_functie_min_level"
                         + "  FROM fac_functie f "
                         + " WHERE " + where);
  result.autfunctionkeys = [];
  if (!oRs.Eof)
  {
    while (!oRs.Eof)
    {
        result.autfunctionkey = oRs("fac_functie_key").value;
        result.autfunction = oRs("fac_functie_code").value;
        result.fac_functie_discipline = oRs("fac_functie_discipline").value;
        result.fac_functie_min_level = oRs("fac_functie_min_level").value;
        result.autfunctionkeys.push(result.autfunctionkey);
        oRs.MoveNext();
    }

  // MIN om te kijken over alle mogelijke disciplines en functies heen
    var sql = "SELECT COALESCE(MIN(FAC_GEBRUIKER_PRS_LEVEL_READ), 9) pread"
            + ", COALESCE(MIN(FAC_GEBRUIKER_PRS_LEVEL_WRITE), 9) pwrite"
            + ", COALESCE(MIN(FAC_GEBRUIKER_ALG_LEVEL_READ), 9) aread"
            + ", COALESCE(MIN(FAC_GEBRUIKER_ALG_LEVEL_WRITE), 9) awrite"
            + " FROM fac_v_webgebruiker w"
            + " WHERE w.prs_perslid_key = " + this._prs_perslid_key
            + " AND w.fac_functie_key IN (" + result.autfunctionkeys.join(",") + ")";
    if (typeof ins_discipline_key != 'undefined' && ins_discipline_key)
        sql += " AND ins_discipline_key = " + ins_discipline_key

    if (checkPessimistic)
    {
        sql = "SELECT COALESCE(MAX(pread),9),"
            + "       COALESCE(MAX(pwrite),9),"
            + "       COALESCE(MAX(aread),9),"
            + "       COALESCE(MAX(awrite),9)"
            + "  FROM ("+sql+" GROUP BY ins_discipline_key)"
    }

    var oRs2 = Oracle.Execute(sql)
    // Let op: door de MIN() hierboven zal er eigenlijk altijd een record zijn.
    if (!oRs2.Eof)
    { // the next statements do not need execution if this fac_functie.fac_functie_discipline != 1
      result.PRSreadlevel  = oRs2(0).value;
      result.PRSwritelevel = oRs2(1).value;
      result.ALGreadlevel  = oRs2(2).value;
      result.ALGwritelevel = oRs2(3).value;
      thisfunc_enabled = (result.PRSreadlevel < 9 || result.PRSwritelevel < 9 || result.ALGreadlevel < 9 || result.ALGwritelevel < 9);
    }
    oRs2.Close();
  }
  oRs.Close();
  if (thisfunc_enabled)
  {
    __Log('Authorization for '+autfunction+'('+result.autfunctionkey+')='
        + '('+result.PRSreadlevel+','+result.PRSwritelevel+','+result.ALGreadlevel+','+result.ALGwritelevel+')');
    return result;
  }
  else
  {
    __Log('NOT Authorized for ' + autfunction);
    if (isOptional)
      return null;
    else
    {
      if (Request.QueryString("api2").Count > 0)
      {
        Response.Status = '403 Forbidden';
        // Response.Write(L("lcl_no_auth")); ?
        Response.End();
      }
      shared.simpel_page(L("lcl_no_auth"));
    }
  }
}

// autoUrole
// @param preferredurole: een voorkeurs urole
// @param autfunctions: { fe: "WEB_MLDORD", bo: "WEB_ORDBOF", fo: "WEB_ORDBOF", b2: "WEB_ORDBO2", mi: "WEB_ORDBOF" }
// @param isOptional
// @param ins_discipline_key -->nog niet
// gekeken wordt of er uberhaubt (lees)rechten zijn voor autfunctions[urole]
//    zoja --> returnwaarde 'urole'
//    zoniet --> probeer de autfunctions totdat je ergens wel rechten voor hebt en lever die urole op
// melding 'U bent niet geauthoriseerd' als nog steeds geen rechten
Perslid.prototype.autoUrole = function autoUrole(preferredurole, autfunctions, isOptional)
{
    var authparams = user.checkAutorisation(autfunctions[preferredurole], true);
    if (authparams)
        return preferredurole;

    for (urole in autfunctions)
    {
        var authparams = user.checkAutorisation(autfunctions[urole], true);
        if (authparams)
        {
            __Log("autoUrole switch van " + preferredurole + " naar " + urole);
            return urole;
        }
    }
    if (!isOptional)
    {
        // nergens rechten voor? Dan houdt het op
        shared.simpel_page(L("lcl_no_auth"));
    }
}

// Deze functie aan te roepen als ontdekt wordt dat de autorisatie ongeldig is.
// Alleen te gebruiken in onvoorziene situaties ('de gebruiker had hier niet mogen/kunnen komen')
Perslid.prototype.auth_required_or_abort = function(hasAuth, badbody)
{
    if (!hasAuth)
    {
        shared.simpel_page(badbody || L("lcl_no_auth"));
    }
}

// Deze functie aan te roepen als ontdekt wordt dat de voorwaarde ongeldig is.
// Alleen te gebruiken in onvoorziene situaties ('de gebruiker had hier niet mogen/kunnen komen')
Perslid.prototype.anything_todo_or_abort = function(hasAuth, badbody)
{
    if (!hasAuth)
    {
        shared.simpel_page(badbody || L("lcl_shared_no_action"));
    }
}


// internal. Do not use...
// Levert een array op per fac_functie_code met de levels
Perslid.prototype.func_enabled_readit = function _func_enabled_readit(module, ins_discipline_key, checkOptimistic)
{
    var sql;
    var multidisc = String(ins_discipline_key).indexOf(",") > 0;

    // JGL: Is de MIN in deze SQL wel nodig eigenlijk? (ik denk: hier wel, bij multidisc niet?)
    if (!multidisc)
    {
        var sql = "SELECT f.fac_functie_code, f.fac_functie_key, fac_functie_min_level"
                  + ",    COALESCE(MIN(FAC_GEBRUIKER_PRS_LEVEL_READ ), 9) FAC_GEBRUIKER_PRS_LEVEL_READ"
                  + ",    COALESCE(MIN(FAC_GEBRUIKER_PRS_LEVEL_WRITE), 9) FAC_GEBRUIKER_PRS_LEVEL_WRITE"
                  + ",    COALESCE(MIN(FAC_GEBRUIKER_ALG_LEVEL_READ ), 9) FAC_GEBRUIKER_ALG_LEVEL_READ"
                  + ",    COALESCE(MIN(FAC_GEBRUIKER_ALG_LEVEL_WRITE), 9) FAC_GEBRUIKER_ALG_LEVEL_WRITE"
                  + " FROM fac_v_webgebruiker w, fac_functie f"
                  + " WHERE w.prs_perslid_key = " + this._prs_perslid_key
                  + "   AND w.fac_functie_key = f.fac_functie_key"
                  + (ins_discipline_key <= 0 || ins_discipline_key == null? "" : "   AND ins_discipline_key = " + ins_discipline_key)
                  + (module != "*" ? "   AND fac_functie_module = " + safe.quoted_sql(module) : "")
                  + " GROUP BY f.fac_functie_code, f.fac_functie_key, fac_functie_min_level"
    }
    else // wel multidisc
    {
    // TODO: voor leesrechten willen we misschien *optimistisch* controleren?
    //       Dan moeten we hieronder ook afzonderlijk de MIN bepalen per discipline
      var sqlA = "SELECT f.fac_functie_code, f.fac_functie_key, fac_functie_min_level, ins_discipline_key"
              + ",    COALESCE(MIN(FAC_GEBRUIKER_PRS_LEVEL_READ ), 9) FAC_GEBRUIKER_PRS_LEVEL_READ"
              + ",    COALESCE(MIN(FAC_GEBRUIKER_PRS_LEVEL_WRITE), 9) FAC_GEBRUIKER_PRS_LEVEL_WRITE"
              + ",    COALESCE(MIN(FAC_GEBRUIKER_ALG_LEVEL_READ ), 9) FAC_GEBRUIKER_ALG_LEVEL_READ"
              + ",    COALESCE(MIN(FAC_GEBRUIKER_ALG_LEVEL_WRITE), 9) FAC_GEBRUIKER_ALG_LEVEL_WRITE"
              + " FROM fac_v_webgebruiker w, fac_functie f"
              + " WHERE w.prs_perslid_key = " + this._prs_perslid_key
              + "   AND w.fac_functie_key = f.fac_functie_key"
              + (module != "*" ? "   AND fac_functie_module = " + safe.quoted_sql(module) : "")
              + " GROUP BY f.fac_functie_code, f.fac_functie_key, fac_functie_min_level, ins_discipline_key"

        sql = "SELECT fac_functie_code, fac_functie_key, fac_functie_min_level"
              + ",    " + (checkOptimistic? "MIN" : "MAX") + "(FAC_GEBRUIKER_PRS_LEVEL_READ ) FAC_GEBRUIKER_PRS_LEVEL_READ"
              + ",    " + (checkOptimistic? "MIN" : "MAX") + "(FAC_GEBRUIKER_PRS_LEVEL_WRITE) FAC_GEBRUIKER_PRS_LEVEL_WRITE"
              + ",    " + (checkOptimistic? "MIN" : "MAX") + "(FAC_GEBRUIKER_ALG_LEVEL_READ ) FAC_GEBRUIKER_ALG_LEVEL_READ"
              + ",    " + (checkOptimistic? "MIN" : "MAX") + "(FAC_GEBRUIKER_ALG_LEVEL_WRITE) FAC_GEBRUIKER_ALG_LEVEL_WRITE"
              + " FROM (" + sqlA + ")"
              + " WHERE ins_discipline_key IN (" + ins_discipline_key + ") "
              + " GROUP BY fac_functie_code, fac_functie_key, fac_functie_min_level"
    }

    var oRs = Oracle.Execute(sql)
    var result = [];
    while (!oRs.eof)
    {
        result.push({ fac_functie_code: oRs("fac_functie_code").Value,
                      autfunctionkey: oRs("fac_functie_key").Value,
                      fac_functie_min_level: oRs("fac_functie_min_level").Value,
                      PRSreadlevel  : oRs("FAC_GEBRUIKER_PRS_LEVEL_READ").Value,
                      PRSwritelevel : oRs("FAC_GEBRUIKER_PRS_LEVEL_WRITE").Value,
                      ALGreadlevel  : oRs("FAC_GEBRUIKER_ALG_LEVEL_READ").Value,
                      ALGwritelevel : oRs("FAC_GEBRUIKER_ALG_LEVEL_WRITE").Value
                    });
        oRs.MoveNext();
    }
    oRs.close();
    return result;
}

// Zie http://unscriptable.com/index.php/2009/05/01/a-better-javascript-memoizer/
// memoize: a general-purpose function to enable a function to use memoization
//   func: the function to be memoized
//   context: the context for the memoized function to execute within
//   Note: the function must use explicit, primitive parameters (or objects
//     that generate unique strings in a toString() method)
function memoize (func, context) {
    function memoizeArg (argPos) {
        var cache = {};
        return function _memoize() {
            if (argPos == 0) {
                if (!(arguments[argPos] in cache)) {
                    cache[arguments[argPos]] = func.apply(context, arguments);
                }
                return cache[arguments[argPos]];
            }
            else {
                if (!(arguments[argPos] in cache)) {
                    cache[arguments[argPos]] = memoizeArg(argPos - 1);
                }
                return cache[arguments[argPos]].apply(this, arguments);
            }
        }
    }
    // JScript doesn't grok the arity property, but uses length instead
    var arity = func.arity || func.length;
    return memoizeArg(arity - 1);
}

// func_enabled
// Controleert *voor een bestaande entiteit*, *gegeven allerlei keys*
//             welke functies (van een bepaalde module) lees en/of schrijfrechten hebben.
// Result:
//  Meldig 'U bent niet geauthoriseerd' als helemaal geen (lees)rechten
//  Anders worden twee functies opgeleverd: canRead("WEB_MLDFOF") en canWrite("WEB_MLDFOF")
//
// ins_discipline_key mag ook een string van discipline_keys gescheiden door komma's zijn!
// Standaard controleren we dat *pessimistisch*: je moet de rechten voor alle disciplines hebben!
// wanneer checkOptimistic is meegegeven controleren we dat *optimistisch*: je moet de rechten van minstens één discipline hebben!

// LET OP: als je een discipline_key meegeeft worden alleen funcodes opgeleverd die discipline-afhankelijk zijn.
//         Voor andere funcodes gebruik je maar bijvoorbeeld (user.checkAutorisation("WEB_ORDSUP", true) != null)
// OLDSTYLE, Deprecated
Perslid.prototype.func_enabled = function _func_enabled_DEPRECATED(module, ins_discipline_key, alg_key, prs_key, checkOptimistic, isOptional)
{
    return this.func_enabled2(module, { ins_discipline_key: ins_discipline_key,
                                        alg_key: alg_key,
                                        prs_key: prs_key,
                                        checkOptimistic: checkOptimistic,
                                        isOptional: isOptional });
}

// params: { ins_discipline_key, alg_key, loc_key, prs_key, checkOptimistic, isOptional, knownread)
// Let op: als je alg_key meegeeft wordt eventuele loc_key genegeerd
// De loc_key kan ook een array zijn.
Perslid.prototype.func_enabled2 = function _func_enabled2(module, params)
{
    params = params || {};
    var loc_key_array = [];
    if (!(params.alg_key > 0))
    {
      if (typeof params.loc_key == "object" && params.loc_key instanceof Array)
        // params.alg_key is een array.
        loc_key_array = params.loc_key;
      else if (params.loc_key > 0)
        // params.alg_key is geen array.
        loc_key_array.push(params.loc_key);
    }

    // twee vars die aangeven hoe dichtbij parameters alg_key en prs_key bij 'onszelf' zitten.
    // alglevel=5 geeft bijvoorbeeld aan dat wij een werkplek hebben op alg_key
    // alglevel=4 geeft bijvoorbeeld aan dat wij een werkplek hebben op dezelfde verdieping als alg_key etc.
    var ALGLevel = -2; // Nog onbepaald
    var PRSLevel = -2; // Nog onbepaald

    var func_enabled = { _funcodes: [],
                         canWrite : function (funcode)
                                    {
                                      if (this._funcodes[funcode]) // Rechten op te vragen via canWrite
                                        return this._funcodes[funcode].canWrite;
                                      else // Geen rechten voor funcode
                                        return false;
                                    },
                         canRead : function (funcode)
                                   {
                                     return this._funcodes[funcode] != null;
                                   },
                         authparams : function (funcode)
                                   {
                                        if (this._funcodes[funcode])
                                            return this._funcodes[funcode];
                                        else
                                            return {fac_functie_code: funcode,
                                                      fac_functie_min_level: 15,
                                                      PRSreadlevel  : 9,
                                                      PRSwritelevel : 9,
                                                      ALGreadlevel  : 9,
                                                      ALGwritelevel : 9};
                                   }
                        };

    var anyfound = false;
    var oRs;
    var coRs = this.func_enabled_readit_memoized(module, params.ins_discipline_key, params.checkOptimistic);
    var i = 0;
    for (i in coRs)
    {
        oRs = coRs[i];
        // in mld_list.inc weten we vaak al dat wel leesrechten hebben.
        // als de scrrijfrechten dan hetzelfde niveau hebben, kunnen we de schrijfrechten heel goedkoop bepalen
        if (params.knownread &&
            oRs.ALGreadlevel == oRs.ALGwritelevel &&
            oRs.PRSreadlevel == oRs.PRSwritelevel
           )
        {
            canRead = true;
            canWrite = true;
        }
        else
        if (params.knownread &&
            (oRs.ALGwritelevel == 9 || oRs.PRSwritelevel == 9)
           )
        {
            canRead = true;
            canWrite = false;
        }
        else
        {
            if (params.knownread)
            {
                __Log("Autorisatielevels verschillen voor functie {0}, discipline_key: {1}. Dat is inefficient.", oRs.fac_functie_code, params.ins_discipline_key);
            }
            var fac_functie_min_level = oRs.fac_functie_min_level;

            var canRead = (oRs.ALGreadlevel < 9 || oRs.PRSreadlevel < 9); // voor min_level 0,1,2,3
            var canWrite = canRead && (oRs.ALGwritelevel < 9 || oRs.PRSwritelevel < 9); // voor min_level 0,1,2,3
            if (fac_functie_min_level & 8) // ALG
            {
                canRead = canRead && (oRs.ALGreadlevel < 9);
                canWrite = canWrite && canRead && (oRs.ALGwritelevel < 9);
            }
            if (fac_functie_min_level & 4) // PRS
            {
                canRead = canRead && (oRs.PRSreadlevel < 9);
                canWrite = canWrite && canRead && (oRs.PRSwritelevel < 9);
            }

            if ((   oRs.PRSreadlevel > -1  && oRs.PRSreadlevel < 9)
                 || oRs.PRSwritelevel > -1 && oRs.PRSwritelevel < 9)
            {   // Alleen als echt nodig is bepalen
                if (PRSLevel == -2) // Nog geen uitsluitsel
                {
                    if (params.prs_key == user_key) // snel klaar, altijd goed
                        PRSLevel = 8;
                    else // Misschien via afdeling
                    {
                        if (params.prs_key)
                        {   // optimalisatie: haal de andere afd_key met een losse query op.
                            var afd_key = new Perslid(params.prs_key).prs_afdeling_key();
                        }
                        else
                            var afd_key = params.afd_key; // Misschien al meegegeven
                        if (afd_key > 0)
                        {
                            var sql = "SELECT MAX (a.niveau) niveau"
                                    + "  FROM prs_v_afdeling_familie a, prs_v_afdeling_familie aa"
                                    + " WHERE a.prs_afdeling_key = " + afd_key //   -- de ander
                                    + "   AND a.prs_afdeling_elder_key = aa.prs_afdeling_elder_key"
                                    + "   AND aa.prs_afdeling_key = " + this.prs_afdeling_key(); // zelf
                            var oRs2 = Oracle.Execute(sql);
                            PRSLevel = oRs2("niveau").Value; // NULL als ander bedrijf of alleen bedrijf als gelijke parent
                            oRs2.Close();
                            if (!(PRSLevel > 0)) // nog niet gevonden
                            {
                                var my_bedrijf = this.afdeling().prs_bedrijf_key();
                                var other_bedrijf = new Afdeling(afd_key).prs_bedrijf_key();
                                PRSLevel = (my_bedrijf == other_bedrijf?0:-1);
                            }
                            __Log("PRSLevel vastgesteld op: " + PRSLevel);
                        }
                    }
                }
            }
            if (   (oRs.ALGreadlevel > -1  && oRs.ALGreadlevel < 9)
                || (oRs.ALGwritelevel > -1 && oRs.ALGwritelevel < 9))
            {   // Alleen als echt nodig is bepalen
               if (ALGLevel == -2)
               {
                  if (loc_key_array.length > 0)
                  { // kijk of loc binnen de scope valt
                    __Log("Checking loc_key: " + loc_key_array.join(","));
                    var ALGLevel = -1; // Default heeel ver weg
                    sql = "SELECT max(niveau)"
                        + " FROM fac_v_my_locations"
                        + " WHERE prs_perslid_key = " + user_key
                        + " AND alg_locatie_key IN (" + loc_key_array.join(",") + ")";
                    var oRs3 = Oracle.Execute(sql);
                    ALGLevel = oRs3(0).value == null? -1 : oRs3(0).value;
                    oRs3.Close();
                  }
                  else if (params.alg_key > 0)
                  {
                    __Log("Checking alg_key: " + params.alg_key);
                    var sql = "SELECT COALESCE(g.alg_locatie_key, -1) alg_locatie_key"
                            + ",      COALESCE(g.alg_gebouw_key, -1) alg_gebouw_key"
                            + ",      COALESCE(g.alg_verdieping_key, -1) alg_verdieping_key"
                            + ",      COALESCE(g.alg_ruimte_key, -1) alg_ruimte_key"
                            + " FROM alg_v_allonroerendgoed g"
                            + " WHERE g.alg_onroerendgoed_keys(+) = " + params.alg_key

                    var oRs2 = Oracle.Execute(sql);
                    if (!oRs2.eof)
                    {
                      var loc_key  = oRs2("alg_locatie_key").value;
                      var bld_key  = oRs2("alg_gebouw_key").value;
                      var flo_key  = oRs2("alg_verdieping_key").value;
                      var room_key = oRs2("alg_ruimte_key").value;
                      if (room_key != -1)
                      { // kijk of room binnen de scope valt
                        sql = "SELECT max(niveau)"
                            + " FROM fac_v_my_rooms"
                            + " WHERE prs_perslid_key = " + user_key
                            + " AND alg_ruimte_key = " + room_key;
                      }
                      else if (flo_key != -1)
                      { // kijk of flo binnen de scope valt
                        sql = "SELECT max(niveau)"
                            + " FROM fac_v_my_floors"
                            + " WHERE prs_perslid_key = " + user_key
                            + " AND alg_verdieping_key = " + flo_key;
                      }
                      else if (bld_key != -1)
                      { // kijk of bld binnen de scope valt
                        sql = "SELECT max(niveau)"
                            + " FROM fac_v_my_buildings"
                            + " WHERE prs_perslid_key = " + user_key
                            + " AND alg_gebouw_key = " + bld_key;
                      }
                      else if (loc_key != -1)
                      { // kijk of loc binnen de scope valt
                        sql = "SELECT max(niveau)"
                            + " FROM fac_v_my_locations"
                            + " WHERE prs_perslid_key = " + user_key
                            + " AND alg_locatie_key = " + loc_key;
                      }
                      var oRs3 = Oracle.Execute(sql);
                      ALGLevel = oRs3(0).value==null?-1:oRs3(0).value;
                      oRs3.Close();
                    }
                    else
                    {
                      __Log ('ATTENTIE: Waarom is deze key onbekend!?!');
                      ALGLevel = -2;
                    }
                    oRs2.Close();
                  }
                  else
                  {
                    if (module != "*" && module != "CNT")
                        __Log("Vreemd: {0}, geen loc_key of alg_key meegegeven terwijl wel alg-scope is beperkt".format(oRs.fac_functie_code), "#ff0000");
                  }
                  __Log("ALGLevel vastgesteld op: " + ALGLevel);
              }
            }
            if (fac_functie_min_level & 8 && ALGLevel >= -1) // ALG en we hebben een key gehad
            {
                canRead = canRead && oRs.ALGreadlevel <= ALGLevel;
                canWrite = canWrite && canRead && oRs.ALGwritelevel <= ALGLevel;
            }
            if (fac_functie_min_level & 4 && PRSLevel >= -1) // PRS en we hebben een key gehad
            {
                canRead = canRead && oRs.PRSreadlevel <= PRSLevel;
                canWrite = canWrite && canRead && oRs.PRSwritelevel <= PRSLevel;
            }
        }
        if (canRead)
        {
            func_enabled._funcodes[oRs.fac_functie_code] = oRs;
            func_enabled._funcodes[oRs.fac_functie_code].canWrite = canWrite;
            anyfound = true;
        }
    }

    if (!anyfound)
    {
        __Log('NOT Authorized for ' + module +
                    " disc: " + params.ins_discipline_key +
                    " ALGLevel: " + ALGLevel +
                    " alg: " + params.alg_key +
                    " prs: " + params.prs_key +
                    " PRSLevel: " + PRSLevel);
        user.auth_required_or_abort(params.isOptional);
     };
     func_enabled.anyfound = anyfound;

     return func_enabled;
}

Perslid.prototype._require_prs_collegas = function __require_prs_collegas()
{
    if (!this._prs_collegas)
    {
        this._prs_collegas = [];
        this._prs_collegas[this._prs_perslid_key] = true;
        var sql = "SELECT prs_perslid_key"
                + "  FROM prs_collega"
                + " WHERE prs_perslid_key_alt = " + this._prs_perslid_key;
        if (S("prs_collegas_groep") > 0)
        {
            sql += " UNION ALL"
                + " SELECT prs_perslid_key "
                + "  FROM fac_gebruikersgroep fgg "
                + " WHERE EXISTS "
                + "          (SELECT 1 "
                + "             FROM fac_groep fg, fac_gebruikersgroep fgg2 "
                + "            WHERE fgg.fac_groep_key = fg.fac_groep_key "
                + "              AND fgg2.fac_groep_key = fg.fac_groep_key "
                + "              AND fgg2.prs_perslid_key = " + this._prs_perslid_key
                + "              AND fg.fac_groep_collega = 1)";
        }
        var oRs = Oracle.Execute(sql);
        while (!oRs.Eof)
        {
            this._prs_collegas[oRs("prs_perslid_key").Value]=true;
            oRs.MoveNext();
        }
        oRs.Close();
    }
    return this._prs_collegas;
}

// heeft persoon prs_key *mij* gedefinieerd als vervanger
Perslid.prototype.isCollega = function (prs_key)
{
    this._require_prs_collegas();
    return this._prs_collegas[prs_key] == true;
}

Perslid.prototype.hasCollegas = function (prs_key)
{
    this._require_prs_collegas();
    var lijst = this.collegakeylist();
    return lijst.indexOf(",") > 0; // Zelf zit je er ook altijd in
}

// Komma-gescheiden lijst van jezelf en al je collega's
Perslid.prototype.collegakeylist = function ()
{
    this._require_prs_collegas();
    var prsKeys = [];
    for (var prs_key in this._prs_collegas)
    {
        prsKeys.push(prs_key);
    }
    if (S("prs_collegas_groep") > 0 && prsKeys.length > S("prs_collegas_groep") > 0)
    {
        __DoLog("Te veel vervangers gedefinieerd ({0}). Alle vervangers worden genegeerd.".format(prsKeys.length), "#FF0000");
        return String(this._prs_perslid_key); // Dan negeren we alle collega's
    }
    return prsKeys.join(", ");
}

// =================================================================================================
// =================================================================================================

/************************************************************\
 * Bepaal allerlei gegevens van een afdeling
 * Input: afdKey (moet bestaan)
 * Result: Afdeling object
\************************************************************/
function Afdeling(afdKey)
{
  var sql = " SELECT d.prs_afdeling_key"
          + ", " + S("prs_dep_string") + " naam"
          + ", d.prs_kostenplaats_key"
          + ", " + S("prs_kpn_string") + " prs_kpn_string"
          + ", k.prs_kostenplaats_module"
          + ", mld_adres_key"
          + " FROM prs_v_aanwezigafdeling d" // Een vervallen afdeling blijft dus verborgen
          + ", prs_kostenplaats k"
          + " WHERE d.prs_kostenplaats_key = k.prs_kostenplaats_key(+)"
          + " AND d.prs_afdeling_key = " + afdKey;
  var oRs = Oracle.Execute(sql);
  if (!oRs.eof)
  {
    this._prs_afdeling_key = oRs("prs_afdeling_key").value; // afdKey
    this._naam = oRs("naam").value;
    this._prs_kostenplaats_key = oRs("prs_kostenplaats_key").value;
    this._kpn_naam = oRs("prs_kpn_string").value;
    this._mld_adres_key = oRs("mld_adres_key").value;
    this._kpn_module = oRs("prs_kostenplaats_module").value;
  }
  oRs.close();
}

Afdeling.prototype.prs_afdeling_key = function()
{
  return this._prs_afdeling_key;
}

Afdeling.prototype.prs_kostenplaats_key = function()
{
  return this._prs_kostenplaats_key;
}

Afdeling.prototype.kpn_string = function()
{
  if (!this._kpn_string)
  {
    this.kpn_string ="-";
    if (this.prs_kostenplaats_key())
    {
      var oRs = Oracle.Execute("SELECT " + S("prs_kpn_string") + " FROM prs_kostenplaats k"
                              + " WHERE k.prs_kostenplaats_key = "+ this.prs_kostenplaats_key());
      _kpn_string = '' + oRs(0).value;
      oRs.close();
    }
  }
  return this._kpn_string;
}

Afdeling.prototype.naam = function()
{
  return this._naam;
}

Afdeling.prototype.kpn_naam = function()
{
  return this._kpn_naam;
}

Afdeling.prototype.kpn_module = function()
{
  return this._kpn_module;
}

Afdeling.prototype.prs_bedrijf_key = function() // Voorheen user_comp
{
  if (!this._prs_bedrijf_key)
  {
    var sql = "SELECT ab.prs_bedrijf_key"
            + "  FROM prs_v_afdeling_boom ab"
            + " WHERE ab.prs_afdeling_key = " + this._prs_afdeling_key
    var oRs = Oracle.Execute(sql);
    this._prs_bedrijf_key = oRs(0).value;
    oRs.close();
  }
  return this._prs_bedrijf_key;
}

Afdeling.prototype.mld_adres_key = function()
{
    return this._mld_adres_key;
}
/************************************************************\
 * Bepaal allerlei gegevens van een Locatie
 * Input: locKey (moet bestaan)
 * Result: Locatie object
\************************************************************/
function Locatie(locKey)
{
  var sql = " SELECT l.alg_locatie_key"
          + ", l.alg_locatie_omschrijving naam"
          + ", l.alg_locatie_plaats"
          + ", " + S("alg_loc_string") + " locatie_string"
          + ", l.alg_locatie_code"
          + "   FROM alg_v_aanweziglocatie l" // Een vervallen locatie blijft dus verborgen
          + "  WHERE l.alg_locatie_key = " + locKey;
  var oRs = Oracle.Execute(sql);
  if (!oRs.eof)
  {
    this._alg_locatie_key = oRs("alg_locatie_key").value; // locKey
    this._naam = oRs("naam").value;
    this._locatie_string = oRs("locatie_string").value;
    this._alg_locatie_plaats = oRs("alg_locatie_plaats").value;
    this._alg_locatie_code = oRs("alg_locatie_code").value;
  }
  oRs.close();
}

Locatie.prototype.alg_locatie_key = function()
{
  return this._alg_locatie_key;
}

Locatie.prototype.naam = function()
{
  return this._naam;
}

Locatie.prototype.locatie_string = function()
{
  return this._locatie_string;
}

Locatie.prototype.alg_locatie_plaats = function()
{
  return this._alg_locatie_plaats;
}

Locatie.prototype.alg_locatie_code = function()
{
  return this._alg_locatie_code;
}

/************************************************************\
 * Bepaal allerlei gegevens van een Gebouw
 * Input: bldKey (moet bestaan)
 * Result: Gebouw object
\************************************************************/
function Gebouw(bldKey)
{
  var sql = " SELECT g.alg_gebouw_key"
          + ", g.alg_gebouw_naam naam"
          + ", g.alg_gebouw_code"
          + ", g.alg_gebouw_omschrijving"
          + ", " + S("prs_kpn_string") + " kpn_naam"
          + ", g.prs_kostenplaats_key"
          + ", g.mld_adres_key"
          + "   FROM alg_v_aanweziggebouw g, prs_kostenplaats k" // Een vervallen gebouw blijft dus verborgen
          + "  WHERE g.alg_gebouw_key = " + bldKey
          + "    AND k.prs_kostenplaats_key(+) = g.prs_kostenplaats_key";
  var oRs = Oracle.Execute(sql);
  if (!oRs.eof)
  {
    this._alg_gebouw_key = oRs("alg_gebouw_key").value; // bldKey
    this._naam = oRs("naam").value;
    this._alg_gebouw_code = oRs("alg_gebouw_code").value;
    this._alg_gebouw_omschrijving = oRs("alg_gebouw_omschrijving").value;
    this._kpn_naam = oRs("kpn_naam").Value;
    this._prs_kostenplaats_key = oRs("prs_kostenplaats_key").Value;
    this._mld_adres_key = oRs("mld_adres_key").Value;
  }
  oRs.close();
}

Gebouw.prototype.alg_gebouw_key = function()
{
  return this._alg_gebouw_key;
}

Gebouw.prototype.naam = function()
{
  return this._naam;
}

Gebouw.prototype.alg_gebouw_code = function()
{
  return this._alg_gebouw_code;
}
Gebouw.prototype.alg_gebouw_omschrijving = function()
{
  return this._alg_gebouw_omschrijving;
}

Gebouw.prototype.kpn_naam = function()
{
  return this._kpn_naam;
}

Gebouw.prototype.prs_kostenplaats_key = function()
{
  return this._prs_kostenplaats_key;
}
Gebouw.prototype.mld_adres_key = function()
{
  return this._mld_adres_key;
}

/************************************************************\
 * Bepaal allerlei gegevens van een Verdieping
 * Input: flrKey (moet bestaan)
 * Result: Verdieping object
\************************************************************/
function Verdieping(flrKey)
{
  var sql = " SELECT v.alg_verdieping_key"
          + ", v.alg_verdieping_omschrijving"
          + ", v.alg_verdieping_code"
          + "   FROM alg_v_aanwezigverdieping v" // Een vervallen verdieping blijft dus verborgen
          + "  WHERE v.alg_verdieping_key = " + flrKey;
  var oRs = Oracle.Execute(sql);

  if (!oRs.eof)
  {
    this._alg_verdieping_key = oRs("alg_verdieping_key").value;
    this._alg_verdieping_omschrijving = oRs("alg_verdieping_omschrijving").value;
    this._alg_verdieping_code = oRs("alg_verdieping_code").value;
  }
  oRs.close();
}

Verdieping.prototype.alg_verdieping_key = function()
{
  return this._alg_verdieping_key;
}

Verdieping.prototype.naam = function()
{
  return this._alg_verdieping_omschrijving;
}

Verdieping.prototype.alg_verdieping_code = function()
{
  return this._alg_verdieping_code;
}

/************************************************************\
 * Bepaal allerlei gegevens van een Ruimte
 * Input: roomKey (moet bestaan)
 * Result: Ruimte object
\************************************************************/
function Ruimte(roomKey)
{
  var sql = " SELECT r.alg_ruimte_key"
          + ", r.alg_ruimte_omschrijving"
          + ", r.alg_ruimte_nr"
          + "   FROM alg_v_aanwezigruimte r" // Een vervallen ruimte blijft dus verborgen
          + "  WHERE r.alg_ruimte_key = " + roomKey;
  var oRs = Oracle.Execute(sql);

  if (!oRs.eof)
  {
    this._alg_ruimte_key = oRs("alg_ruimte_key").value;
    this._alg_ruimte_omschrijving = oRs("alg_ruimte_omschrijving").value;
    this._alg_ruimte_nr = oRs("alg_ruimte_nr").value;
  }

  oRs.close();
}

Ruimte.prototype.alg_ruimte_key = function()
{
  return this._alg_ruimte_key;
}

Ruimte.prototype.naam = function()
{
  return this._alg_ruimte_nr  + ' (' + (this._alg_ruimte_omschrijving||"") + ')';
}

Ruimte.prototype.alg_ruimte_nr = function()
{
  return this._alg_ruimte_nr;
}

/************************************************************\
 * Bepaal allerlei gegevens van een Werkplek
 * Input: wpKey (moet bestaan)
 * Result: Werkplek object
\************************************************************/
function Werkplek(wpKey)
{
  var sql = " SELECT w.prs_werkplek_key"
          + "      , w.alg_locatie_key"
          + "      , w.alg_gebouw_key"
          + "      , w.alg_verdieping_key"
          + "      , w.alg_ruimte_key"
          + "      , w.prs_werkplek_omschrijving naam"
          + "      , w.prs_werkplek_volgnr"
          + "      , w.alg_ruimte_aanduiding"
          + "      , w.prs_werkplek_aanduiding"
          + "      , w.prs_werkplek_virtueel"
          + "      , w.prs_werkplek_type"
          + "      , pw.prs_perslidwerkplek_bezetting"
          + "      , g.alg_gebouw_bez"
          + "   FROM prs_v_werkplek_gegevens w"
          + "      , prs_perslidwerkplek pw"
          + "      , alg_gebouw g"
          + "  WHERE pw.prs_werkplek_key = w.prs_werkplek_key"
          + "    AND w.alg_gebouw_key = g.alg_gebouw_key"
          + "    AND w.prs_werkplek_key = " + wpKey;
  var oRs = Oracle.Execute(sql);

  if (!oRs.eof)
  {
    this._prs_werkplek_key = oRs("prs_werkplek_key").value; // wpKey
    this._alg_locatie_key = oRs("alg_locatie_key").value;
    this._alg_gebouw_key = oRs("alg_gebouw_key").value;
    this._alg_verdieping_key = oRs("alg_verdieping_key").value;
    this._alg_ruimte_key = oRs("alg_ruimte_key").value;
    this._naam = oRs("naam").value;
    this._isVirtueel = oRs("prs_werkplek_virtueel").value=="1";
    this._type = oRs("prs_werkplek_type").value;
    this._prs_werkplek_volgnr = oRs("prs_werkplek_volgnr").value;
    this._alg_ruimte_aanduiding = oRs("alg_ruimte_aanduiding").value;
    this._prs_werkplek_aanduiding = oRs("prs_werkplek_aanduiding").value;
    this._bezetting = oRs("prs_perslidwerkplek_bezetting").value;
    this._alg_gebouw_bezoekbaar = oRs("alg_gebouw_bez").value || 0;
  }
  oRs.close();
}

Werkplek.prototype.prs_werkplek_key = function()
{
  return this._prs_werkplek_key;
}

Werkplek.prototype.alg_locatie_key = function()
{
  return this._alg_locatie_key;
}

Werkplek.prototype.alg_locatie_naam = function()
{
  return (new Locatie(this._alg_locatie_key)).naam();
}

Werkplek.prototype.alg_locatie_string = function()
{
  return (new Locatie(this._alg_locatie_key)).locatie_string();
}

Werkplek.prototype._require_alg_gebouw = function()
{
    if (typeof this._alg_gebouw == "undefined")
    {
        this._alg_gebouw = new Gebouw(this._alg_gebouw_key);
    }
}

Werkplek.prototype.alg_gebouw_key = function()
{

  return this._alg_gebouw_key;
}

Werkplek.prototype.alg_gebouw_naam = function()
{
    this._require_alg_gebouw();
    return this._alg_gebouw.naam();
}

Werkplek.prototype.alg_gebouw_code = function()
{
    this._require_alg_gebouw();
    return this._alg_gebouw.alg_gebouw_code();
}

Werkplek.prototype.prs_kostenplaats_key = function()
{
    this._require_alg_gebouw();
    return this._alg_gebouw.prs_kostenplaats_key();
}

Werkplek.prototype.kpn_naam = function()
{
    this._require_alg_gebouw();
    return this._alg_gebouw.kpn_naam();
}

Werkplek.prototype.isVirtueel = function()
{
    return this._isVirtueel;
}

Werkplek.prototype.alg_verdieping_key = function()
{
  return this._alg_verdieping_key;
}

Werkplek.prototype.alg_verdieping_naam = function()
{
  return (new Verdieping(this._alg_verdieping_key)).naam();
}

Werkplek.prototype.alg_verdieping_code = function()
{
  return (new Verdieping(this._alg_verdieping_key)).alg_verdieping_code();
}

Werkplek.prototype.alg_ruimte_key = function()
{
  return this._alg_ruimte_key;
}

Werkplek.prototype.alg_ruimte_naam = function()
{
  return (new Ruimte(this._alg_ruimte_key)).naam();
}

Werkplek.prototype.deliveryPlace = function()
{
  return this._alg_ruimte_aanduiding;
}

Werkplek.prototype.bezetting = function()
{
  return this._bezetting;
}

Werkplek.prototype.naam = function()
{
  return this._naam;
}

Werkplek.prototype.prs_werkplek_volgnr = function()
{
  return this._prs_werkplek_volgnr;
}

Werkplek.prototype.prs_werkplek_aanduiding = function()
{
  return   (S("prs_werkplek_implicit")==1?this._alg_ruimte_aanduiding:this._prs_werkplek_aanduiding)
         + (this._type==1?L("lcl_flexwp_suffix"):"");
}

Werkplek.prototype.alg_gebouw_bezoekbaar = function()
{

  return this._alg_gebouw_bezoekbaar;
}

%>

