 
/*------------------------------------------------------------------------
   File        : usersHandler
   Purpose     : 
   Syntax      : 
   Description : 
   Author(s)   : walter.riechsteiner
   Created     : Fri Nov 21 11:31:01 CET 2025
   Notes       : 
 ----------------------------------------------------------------------*/


BLOCK-LEVEL ON ERROR UNDO, THROW.

USING Progress.Json.ObjectModel.JsonObject                  FROM PROPATH.
USING Progress.Json.ObjectModel.JsonArray                   FROM PROPATH.
USING utilities.utilitiesHandler                            FROM PROPATH.
USING utilities.selectboxhandler                            FROM PROPATH.
USING Progress.Json.ObjectModel.ObjectModelParser           FROM PROPATH.
USING OpenEdge.DataAdmin.IIndex                             FROM PROPATH.
USING OpenEdge.Web.DataObject.Writer.JsonObjectValueWriter  FROM PROPATH.

CLASS admin.adminprogsHandler FINAL:
    DEFINE VARIABLE oJsonData        AS JsonObject        NO-UNDO.
    DEFINE VARIABLE oJsonArray       AS JsonArray         NO-UNDO.
    DEFINE VARIABLE oParser          AS ObjectModelParser NO-UNDO.
    
    DEFINE VARIABLE cuser_name       AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE ccompany         AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE lcJsonString     AS LONGCHAR          NO-UNDO.
    DEFINE VARIABLE iLanguage_id     AS INTEGER           NO-UNDO.

    DEFINE VARIABLE oRecords         AS JsonArray         NO-UNDO.
    DEFINE VARIABLE oJsonPosition    AS JsonObject        NO-UNDO.
        
    DEFINE VARIABLE cFileName        AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cFunction        AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE lCompany         AS LOGICAL           NO-UNDO.
    DEFINE VARIABLE lActive          AS LOGICAL           NO-UNDO.
    DEFINE VARIABLE lWordindex       AS LOGICAL           NO-UNDO.
    DEFINE VARIABLE cActiveSelection AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cSortField       AS CHARACTER         NO-UNDO INIT ''.
    DEFINE VARIABLE cDirection       AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cFieldReplace    AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cKeyFieldReplace AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cFilterReplace   AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cFileReplace     AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cKeyFields       AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cKeyValues       AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cWhere           AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cString          AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE cMessage         AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE lcMessage        AS LONGCHAR          NO-UNDO.
    DEFINE VARIABLE lcString         AS LONGCHAR          NO-UNDO.
    
    DEFINE VARIABLE iAnzahlRecords   AS INTEGER           NO-UNDO.
    DEFINE VARIABLE iActualPage      AS INTEGER           NO-UNDO.
    DEFINE VARIABLE iMaxRecords      AS INTEGER           NO-UNDO INIT 20.
    DEFINE VARIABLE iStartPage       AS INTEGER           NO-UNDO.
    DEFINE VARIABLE iStartRecord     AS INTEGER           NO-UNDO.
    DEFINE VARIABLE iPageCounter     AS INTEGER           NO-UNDO.
    DEFINE VARIABLE iCurrentPosition AS INTEGER           NO-UNDO.

    DEFINE VARIABLE cPrimaryKey      AS CHARACTER         NO-UNDO.
    DEFINE VARIABLE iIndex           AS INTEGER           NO-UNDO.
    DEFINE VARIABLE iStartIndex      AS INTEGER           NO-UNDO.
    
    DEFINE VARIABLE httTable         AS HANDLE            NO-UNDO.
    DEFINE VARIABLE ttTable          AS HANDLE            NO-UNDO.
    
    DEFINE VARIABLE hQuery           AS HANDLE            NO-UNDO.
    DEFINE VARIABLE hBuffer          AS HANDLE            NO-UNDO.
    
    DEFINE TEMP-TABLE ttKeyFields
        FIELD iIndex     AS INTEGER 
        FIELD cLongName  AS CHARACTER 
        FIELD cFieldName AS CHARACTER 
        FIELD cFileName  AS CHARACTER 
        FIELD cValue     AS CHARACTER 
        FIELD cDataType  AS CHARACTER
        FIELD lKeyfield  AS LOGICAL
        
        INDEX ttKeyFields-k1 IS PRIMARY 
        iIndex
        cFieldName
        .
    DEFINE VARIABLE httKeyFields AS HANDLE NO-UNDO.
    
    DEFINE TEMP-TABLE ttPrimaryIndex
        FIELD iIndex     AS INTEGER 
        FIELD cFieldName AS CHARACTER 
        FIELD cFileName  AS CHARACTER 
        FIELD cValue     AS CHARACTER 
        FIELD cDataType  AS CHARACTER
        
        INDEX ttPrimaryIndex-k1 IS PRIMARY 
        iIndex
        cFieldName
        .
    DEFINE VARIABLE httPrimaryIndex   AS HANDLE           NO-UNDO.

    
    DEFINE VARIABLE outilitiesHandler AS utilitiesHandler NO-UNDO.
    DEFINE VARIABLE oselectboxHandler AS selectboxHandler NO-UNDO.
    
    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC VOID buildWhere(
        INPUT oJsonIdent    AS JsonObject
        ):

        DEFINE VARIABLE ii           AS INTEGER   NO-UNDO.
        DEFINE VARIABLE i1           AS INTEGER   NO-UNDO.
        DEFINE VARIABLE lOK          AS LOGICAL   NO-UNDO.
        DEFINE VARIABLE cValue       AS CHARACTER NO-UNDO.
        DEFINE VARIABLE cString      AS CHARACTER NO-UNDO.
        DEFINE VARIABLE iNumerisch   AS INTEGER   NO-UNDO.
        
        DEFINE VARIABLE cSearchChars AS CHARACTER NO-UNDO INIT ''.
        DEFINE VARIABLE lSearch      AS LOGICAL   NO-UNDO.
        DEFINE VARIABLE cFields      AS CHARACTER NO-UNDO EXTENT.
        DEFINE VARIABLE cField       AS CHARACTER NO-UNDO.
        DEFINE VARIABLE cFieldValue  AS CHARACTER NO-UNDO.
        DEFINE VARIABLE cFilter      AS CHARACTER NO-UNDO.
        DEFINE VARIABLE cDBField     AS CHARACTER NO-UNDO.
        DEFINE VARIABLE cType        AS CHARACTER NO-UNDO.
        
        outilitiesHandler = NEW utilitiesHandler().
        //
        //  Ermitteln des Tabellennamens, ob die Tabelle das Feld "company" und/oder das Feld "active" enthält
        //
        outilitiesHandler:evaluateFile(
            INPUT-OUTPUT oJsonIdent     ,
            OUTPUT       cFileName      ,
            OUTPUT       lCompany       ,
            OUTPUT       lActive        ,
            OUTPUT       lWordindex     ,
            INPUT-OUTPUT httKeyFields   ,
            INPUT-OUTPUT httPrimaryIndex
            ).

        CREATE BUFFER hBuffer FOR TABLE cFileName.
        
        cuser_name  = oJsonIdent:GetCharacter('user_name').
        ccompany    = oJsonIdent:GetCharacter('company').
        cSortField  = ''.
        cDirection  = ''.
        cWhere      = ''.
        iStartPage  = 1.    
        iMaxRecords = 25.
        IF oJsonIdent:HAS('page')  THEN iStartPage  = INTEGER(oJsonIdent:GetCharacter('page'))  NO-ERROR.
        IF oJsonIdent:HAS('limit') THEN iMaxRecords = INTEGER(oJsonIdent:GetCharacter('limit')) NO-ERROR.

        IF oJsonIdent:HAS('search') THEN 
        DO:
            cSearchChars = oJsonIdent:GetCharacter('search').
            cSearchChars = REPLACE(cSearchChars, '+', ' ').
            lSearch      = TRUE.
            iMaxRecords  = 100.
        END.
        iStartRecord = ((iStartPage - 1) * iMaxRecords) + 1.

        cString = 'WHERE'.
        FOR EACH ttKeyFields NO-LOCK:
            IF lSearch THEN 
            DO:
                IF  ttKeyFields.iIndex >  1 AND
                    ttKeyFields.iIndex < 99 THEN NEXT.
            END.
            IF ttKeyFields.cDataType = 'logical' AND ttKeyFields.cValue = '' THEN NEXT.
            CASE ttKeyFields.cDataType:
                WHEN 'integer' THEN 
                    cValue = ttKeyFields.cValue.
                WHEN 'decimal' THEN 
                    cValue = ttKeyFields.cValue.
                WHEN 'date' THEN 
                    cValue = STRING(DATE(ttKeyFields.cValue),'99.99.9999').
                WHEN 'logical' THEN 
                    cValue = STRING(LOGICAL(ttKeyFields.cValue),'true/false').
                WHEN 'character' THEN 
                    cValue = QUOTER(ttKeyFields.cValue).
            END CASE.
            IF ttKeyFields.lKeyfield OR ttKeyFields.cDataType = 'logical' THEN 
                cWhere = cWhere + SUBSTITUTE('&1 &2 = &3 ', cString, ttKeyFields.cFieldName, cValue).
            ELSE 
            DO:
                /*                cFieldValue = STRING(hBuffer:BUFFER-FIELD(ttKeyFields.cFieldName):BUFFER-VALUE).*/
                cWhere      = cWhere + SUBSTITUTE('&1 INDEX(STRING(&2), &3) > 0 ', cString, ttKeyFields.cFieldName, QUOTER(STRING(cValue))).
            END.
            cString = 'AND'.
        END.
        //
        //  Suche aus dem Suchfeld -->  geht dann über Wordindex
        //
        IF lSearch THEN
        DO:
            DO ii = 1 TO NUM-ENTRIES(cSearchChars, ' '):
                cValue     = ENTRY(ii, cSearchChars, ' ').
                iNumerisch = INTEGER(cValue) NO-ERROR.
                IF NOT ERROR-STATUS:ERROR THEN cValue = SUBSTITUTE('&1&2&1', CHR(01), TRIM(STRING(iNumerisch,'>>>>>>>>9-'))).
                cWhere = cWhere + (IF cWhere = '' THEN ' WHERE ' ELSE 'AND ').
                cWhere = cWhere + 'LOOKUP(' + QUOTER(cValue) + ', ' + cFileName + '.wordindex, " ") > 0 '. 
            END.
        END.
        //
        //  hat es Sortierfelder ?
        //
        outilitiesHandler:readSortFields(
            INPUT  oJsonIdent   ,
            INPUT  cFileName    ,
            OUTPUT cSortField   ,
            OUTPUT cDirection
            ).
        IF cSortField <> '' THEN 
        DO:
            IF cDirection BEGINS 'asc' THEN cDirection = ''.
            cWhere = cWhere + SUBSTITUTE(' BY &1 &2', cSortField, cDirection).
        END.
// MESSAGE 'cWhere am Ende von BuildWhere ' cWhere.
        createTempTable(
            INPUT oJsonIdent
            ).
// MESSAGE 'WHERE-Statement nach buildcWhere =' cWhere.
        RETURN.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC LOGICAL createData(
        INPUT  oJsonIdent  AS JsonObject,
        INPUT  oJsonRecord AS jsonObject,
        OUTPUT oJsonReturn AS JsonObject  
        ):
            
        DEFINE VARIABLE oJsonMessage     AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonMessageBox  AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonFieldErrors AS JsonObject NO-UNDO.

        DEFINE VARIABLE lRetVal          AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE lOK              AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE ii               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE i1               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE iIndex           AS INTEGER    NO-UNDO.
        DEFINE VARIABLE cWordIndex       AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cField           AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE hField           AS HANDLE     NO-UNDO.
        DEFINE VARIABLE htField          AS HANDLE     NO-UNDO.
        DEFINE VARIABLE cValue           AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cFieldValue      AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE rBuffer          AS RECID      NO-UNDO.
        DEFINE VARIABLE cUniqueWhere     AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE hUniqueBuffer    AS HANDLE     NO-UNDO.

        DEFINE VARIABLE oJsonSelectBoxes AS JsonObject NO-UNDO.
        
        outilitiesHandler = NEW utilitiesHandler().
        oselectboxHandler = NEW selectboxHandler().
        
        httKeyFields    = TEMP-TABLE ttKeyFields   :DEFAULT-BUFFER-HANDLE.
        httPrimaryIndex = TEMP-TABLE ttPrimaryIndex:DEFAULT-BUFFER-HANDLE.
        //
        //  Ermitteln des Tabellennamens, ob die Tabelle das Feld "company" und/oder das Feld "active" enthält
        //
        outilitiesHandler:evaluateFile(
            INPUT-OUTPUT oJsonIdent     ,
            OUTPUT       cFileName      ,
            OUTPUT       lCompany       ,
            OUTPUT       lActive        ,
            OUTPUT       lWordindex     ,
            INPUT-OUTPUT httKeyFields   ,
            INPUT-OUTPUT httPrimaryIndex
            ).

        cFunction = oJsonIdent:GetCharacter('function').
        CREATE BUFFER hBuffer       FOR TABLE cFileName.
        CREATE BUFFER hUniqueBuffer FOR TABLE cFileName.
        
        createTempTable(
            INPUT oJsonIdent
            ).
            
        httTable:READ-JSON('JsonObject', oJsonRecord) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
        httTable:FIND-FIRST('', NO-LOCK) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).

        CREATE BUFFER hBuffer FOR TABLE cFileName.
        
        /*        CASE cFileName:                                        */
        /*            WHEN 'xxxxxxx' THEN                                */
        /*                httTable::xxxxx_id = NEXT-VALUE(masterdata_id).*/
        /*        END CASE.                                              */
        
        createUniqueWhere(
            INPUT  httTable,
            OUTPUT cUniqueWhere
            ).
        cWhere = cUniqueWhere.

        lRetVal = FALSE.
        REPEAT TRANSACTION ON ERROR UNDO, LEAVE:
            lOK = hBuffer:FIND-UNIQUE(cUniqueWhere, NO-LOCK) NO-ERROR. 
            IF lOK THEN 
            DO:
                outilitiesHandler:createErrorBox(
                    INPUT  oJsonIdent       ,
                    INPUT  '2007'           ,
                    INPUT  ''               ,
                    OUTPUT oJsonMessageBox
                    ).
                oJsonReturn = NEW JsonObject().
                oJsonReturn:ADD('success'     , FALSE          ).
                oJsonReturn:ADD('message', oJsonMessageBox:GetLongchar('text')).
                
                oJsonFieldErrors = NEW JsonObject().
                FOR EACH ttPrimaryIndex NO-LOCK:
                    cField = SUBSTITUTE('&1_&2', ttPrimaryIndex.cFileName, ttPrimaryIndex.cFieldName).
                    oJsonFieldErrors:ADD(cField, 'Doppelt').
                END.
                oJsonReturn:ADD('fieldErrors', oJsonFieldErrors).
                oJsonReturn:ADD('showMessage', oJsonMessageBox ).
                RETURN TRUE.
            END.
            //
            //  Datensatz erstellen / active setzen / wordindex erstellen
            //
            hBuffer:BUFFER-CREATE ().
            DO ii = 1 TO httTable:NUM-FIELDS:
                htField = httTable:BUFFER-FIELD(ii):HANDLE NO-ERROR.
                cField  = htField:NAME.
                hField  = hBuffer:BUFFER-FIELD(cField):HANDLE NO-ERROR.
                IF  ERROR-STATUS:ERROR       OR
                    NOT VALID-HANDLE(hField) THEN NEXT.
                    
                IF hField:EXTENT > 0 THEN 
                DO:
                    cFieldValue = htField:BUFFER-VALUE.
                    DO i1 = 1 TO hField:EXTENT:
                        hField:BUFFER-VALUE(i1) = ENTRY(i1, cFieldValue, CHR(10)) NO-ERROR.
                    END.
                END.
                ELSE 
                DO:
                    IF htField:BUFFER-VALUE = hField:BUFFER-VALUE THEN NEXT.
                    hField:BUFFER-VALUE = htField:BUFFER-VALUE.
                END. 
            END.

            htField = hBuffer:BUFFER-FIELD('active'):HANDLE NO-ERROR.
            IF  NOT ERROR-STATUS:ERROR AND 
                VALID-HANDLE(htField)  THEN htField:BUFFER-VALUE = TRUE.
                
            htField = hBuffer:BUFFER-FIELD('created_at'):HANDLE NO-ERROR.
            IF  NOT ERROR-STATUS:ERROR AND 
                VALID-HANDLE(htField)  THEN htField:BUFFER-VALUE = NOW.
            htField = hBuffer:BUFFER-FIELD('created_by'):HANDLE NO-ERROR.
            IF  NOT ERROR-STATUS:ERROR AND 
                VALID-HANDLE(htField)  THEN htField:BUFFER-VALUE = oJsonIdent:GetCharacter('H_display_name').
            
            htField = hBuffer:BUFFER-FIELD('wordindex'):HANDLE NO-ERROR.
            IF  NOT ERROR-STATUS:ERROR AND 
                VALID-HANDLE(htField)  THEN 
            DO:
                cWordIndex = outilitiesHandler:createWordindex(
                    INPUT hBuffer
                    ).
                htField:BUFFER-VALUE = cWordIndex.
            END.
            rBuffer = hBuffer:RECID.
            oJsonIdent:ADD('rBuffer', INT64(rBuffer)) NO-ERROR.

            hBuffer:BUFFER-RELEASE ().
            
            outilitiesHandler:writeLastRecord(
                INPUT oJsonIdent,
                INPUT cUniqueWhere
                ).
            
            lRetVal = TRUE.
            LEAVE.
        END.
        //
        //  Datensatz anhand der RECID und den letzten Kriterien in der Tabelle finden und Pagination ermitteln
        //
        DO WHILE lRetVal:
            outilitiesHandler:readLastcWhere(
                INPUT  oJsonIdent,
                INPUT  cFileName ,
                OUTPUT cWhere
                ).
            MESSAGE 'LAST cWhere =' cWHere.
            outilitiesHandler:evaluatePageNumber(
                INPUT-OUTPUT oJsonIdent   ,
                INPUT        cWhere       ,
                INPUT        rBuffer
                ).
                
            httTable:EMPTY-TEMP-TABLE ().            
            createTempTable(
                INPUT oJsonIdent
                ).
            
            fillTemptableFromTable(
                INPUT  oJsonIdent   ,
                INPUT  cWhere       ,
                OUTPUT oJsonReturn
                ).
            
            hUniqueBuffer:FIND-UNIQUE (cUniqueWhere, NO-LOCK) NO-ERROR.
            outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
            hField = hUniqueBuffer:BUFFER-FIELD('language_id'):HANDLE NO-ERROR.
            IF  VALID-HANDLE(hField)   AND
                NOT ERROR-STATUS:ERROR THEN oJsonIdent:SET('language_id', hField:BUFFER-VALUE).

            oselectboxHandler:getVariableSelectBoxes(
                INPUT  oJsonIdent      ,
                OUTPUT oJsonSelectBoxes
                ).
            IF VALID-OBJECT(oJsonSelectBoxes) THEN oJsonReturn:ADD('selectOptions', oJsonSelectBoxes).
            
            lRetVal      = TRUE.
            LEAVE.
        END.
        DELETE OBJECT hBuffer       NO-ERROR.
        DELETE OBJECT hUniqueBuffer NO-ERROR.

        IF lRetVal THEN 
        DO:
            outilitiesHandler:createInfoBox(
                INPUT  oJsonIdent       ,
                INPUT  '2008'           ,
                INPUT  ''               ,
                OUTPUT oJsonMessageBox
                ) NO-ERROR.
            oJsonReturn:ADD('showMessage', oJsonMessageBox).
            oJsonReturn:ADD('success',     TRUE           ).
            RETURN lRetVal.
        END.

        IF NOT lRetVal THEN 
        DO:
            oJsonMessage = NEW JsonObject().
            oJsonMessage:ADD('success', FALSE).
            oJsonMessage:ADD('message', lcMessage).
            oJsonMessage:WRITE(lcJsonString, FALSE).
            
            oJsonReturn = oJsonMessage.
        END.
        
        RETURN lRetVal.

        CATCH e AS Progress.Lang.Error:

        END CATCH.

        FINALLY:

        END FINALLY.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC VOID createTempTable(
        INPUT oJsonIdent AS JsonObject
        ):

        DEFINE VARIABLE ii             AS INTEGER   NO-UNDO.
        DEFINE VARIABLE cFunction      AS CHARACTER NO-UNDO.
        DEFINE VARIABLE cSerializeName AS CHARACTER NO-UNDO.
        DEFINE VARIABLE cttName        AS CHARACTER NO-UNDO.        
        
        CREATE TEMP-TABLE ttTable.
        ttTable:ADD-FIELDS-FROM (cFilename, 'wordindex').   /*  Alle Felder aus dem Buffer, ausser wordindex    */
        IF cSortField <> '' THEN 
        DO:
            ttTable:ADD-NEW-INDEX ('ttTable-k1', FALSE, TRUE).     /*  UNIQUE, PRIMARY */
            IF cDirection BEGINS 'des' THEN ttTable:ADD-INDEX-FIELD ('ttTable-k1', cSortField, 'desc').
            ELSE                            ttTable:ADD-INDEX-FIELD ('ttTable-k1', cSortField).
        END.
        
        cFunction = oJsonIdent:GetCharacter('function').

        CASE cFunction:
            WHEN 'delete' THEN 
                cttName = 'record'.
            WHEN 'update' THEN 
                cttName = 'record'.
            WHEN 'change' THEN 
                cttName = 'record'.
            WHEN 'create' THEN 
                cttName = 'record'.
            WHEN 'loaddataunique' THEN 
                cttName = 'record'.
            OTHERWISE 
            cttName = 'records'.
        END CASE.
        ttTable:TEMP-TABLE-PREPARE (cttName).
        httTable = ttTable:DEFAULT-BUFFER-HANDLE.
        //
        //  Den Feldnamen wird für das Front-End der Tabellenname vorhergestellt (Serialize-Name)
        //
        DO ii = 1 TO httTable:NUM-FIELDS:
            CASE httTable:BUFFER-FIELD(ii):NAME:
                WHEN 'active' THEN 
                    cSerializeName = 'active'.
                OTHERWISE 
                cSerializeName = cFileName + '_' + httTable:BUFFER-FIELD(ii):NAME.
            END CASE.
            httTable:BUFFER-FIELD(ii):SERIALIZE-NAME = cSerializeName NO-ERROR.
        END.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC VOID createUniqueWhere(
        INPUT  hBuffer      AS HANDLE,
        OUTPUT cUniqueWhere AS CHARACTER 
        ):
            
        DEFINE VARIABLE hField AS HANDLE NO-UNDO.
        
        cUniqueWhere  = ''.
        cString       = 'WHERE'.
        FOR EACH ttPrimaryIndex NO-LOCK:
            hField = httTable:BUFFER-FIELD(ttPrimaryIndex.cFieldName):HANDLE.    
            CASE ttPrimaryIndex.cDataType:
                WHEN 'character' THEN 
                    cValue = QUOTER(hField:BUFFER-VALUE).
                WHEN 'logical'   THEN 
                    cValue = STRING(hField:BUFFER-VALUE,"true/false").
                WHEN 'date'      THEN 
                    cValue = STRING(DATE(hField:BUFFER-VALUE)).
                OTHERWISE             
                cValue = hField:BUFFER-VALUE. 
            END CASE.
            cUniqueWhere = cUniqueWhere + cString
                + SUBSTITUTE(' &1.&2 = &3 ', ttPrimaryIndex.cFileName, ttPrimaryIndex.cFieldName, cValue).
            cString = 'AND'.
        END.
        
        RETURN.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC LOGICAL deleteData(
        INPUT  oJsonIdent  AS JsonObject,
        INPUT  oJsonRecord AS jsonObject,
        OUTPUT oJsonReturn AS JsonObject  
        ):

        DEFINE VARIABLE oJsonMessage     AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonMessageBox  AS JsonObject NO-UNDO.

        DEFINE VARIABLE lRetVal          AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE lOK              AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE ii               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE hField           AS HANDLE     NO-UNDO.
        DEFINE VARIABLE htField          AS HANDLE     NO-UNDO.
        DEFINE VARIABLE cValue           AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE rBuffer          AS RECID      NO-UNDO.
        DEFINE VARIABLE cQueryWhere      AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE iAnzRecords      AS INTEGER    NO-UNDO.
        DEFINE VARIABLE oRecord          AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonSelectBoxes AS JsonObject NO-UNDO. 
        
        outilitiesHandler = NEW utilitiesHandler().
        oselectboxHandler = NEW selectboxHandler().
        
        httKeyFields    = TEMP-TABLE ttKeyFields   :DEFAULT-BUFFER-HANDLE.
        httPrimaryIndex = TEMP-TABLE ttPrimaryIndex:DEFAULT-BUFFER-HANDLE.
        //
        //  Ermitteln des Tabellennamens, ob die Tabelle das Feld "company" und/oder das Feld "active" enthält
        //
        outilitiesHandler:evaluateFile(
            INPUT-OUTPUT oJsonIdent     ,
            OUTPUT       cFileName      ,
            OUTPUT       lCompany       ,
            OUTPUT       lActive        ,
            OUTPUT       lWordindex     ,
            INPUT-OUTPUT httKeyFields   ,
            INPUT-OUTPUT httPrimaryIndex
            ).
            
        cFunction = oJsonIdent:GetCharacter('function').
        CREATE BUFFER hBuffer FOR TABLE cFileName.
        
        createTempTable(
            INPUT oJsonIdent
            ).
            
        httTable:READ-JSON('JsonObject', oJsonRecord) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
        httTable:FIND-FIRST('', NO-LOCK) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).

        CREATE BUFFER hBuffer FOR TABLE cFileName.
        //
        //  Erzeugen von Where-Statement für UNIQUE-Find
        //
        createUniqueWhere(
            INPUT  httTable,
            OUTPUT cWhere
            ).

        lRetVal = FALSE.
        REPEAT TRANSACTION ON ERROR UNDO, LEAVE:
            lOK = hBuffer:FIND-UNIQUE(cWhere, NO-LOCK) NO-ERROR.
            IF NOT lOK THEN 
            DO:
                outilitiesHandler:createErrorBox(
                    INPUT  oJsonIdent       ,
                    INPUT  '2000'           ,
                    INPUT  ''               ,
                    OUTPUT oJsonMessageBox
                    ).
                oJsonReturn = NEW JsonObject().
                oJsonReturn:ADD('success'     , FALSE          ).
                oJsonReturn:ADD('showMessage' , oJsonMessageBox).
                RETURN TRUE.
            END.
            rBuffer = hBuffer:RECID.
            hBuffer:BUFFER-RELEASE ().

            iStartPage = INTEGER(oJsonIdent:GetCharacter('page'))  NO-ERROR.
            iIndex     = INTEGER(oJsonIdent:GetCharacter('index')) NO-ERROR.

            lOK = hBuffer:FIND-UNIQUE(cWhere, EXCLUSIVE-LOCK, NO-WAIT) NO-ERROR.
            IF hBuffer:LOCKED THEN 
            DO:
                outilitiesHandler:createLockMessage(
                    INPUT  oJsonIdent,
                    INPUT  rBuffer  ,
                    OUTPUT oJsonMessageBox
                    ).
                lcMessage = oJsonMessageBox:GetLongchar('message').
                LEAVE.
            END.
                
            DO WHILE lActive :
                hField = hBuffer:BUFFER-FIELD('active'):HANDLE NO-ERROR.
                IF  ERROR-STATUS:ERROR        OR
                    NOT VALID-HANDLE(hField) THEN LEAVE.
                hField:BUFFER-VALUE = FALSE NO-ERROR.

                hField = hBuffer:BUFFER-FIELD('updated_at'):HANDLE NO-ERROR.
                IF  NOT ERROR-STATUS:ERROR AND
                    VALID-HANDLE(hField)   THEN hField:BUFFER-VALUE = NOW.
                hField = hBuffer:BUFFER-FIELD('updated_by'):HANDLE NO-ERROR.
                IF  NOT ERROR-STATUS:ERROR AND
                    VALID-HANDLE(hField)   THEN hField:BUFFER-VALUE = oJsonIdent:GetCharacter('H_display_name').

                httTable:BUFFER-COPY(hBuffer).
                
                hBuffer:BUFFER-RELEASE ().

                lRetVal = TRUE.
                LEAVE.                
            END.
            
            DO WHILE NOT lRetVal:
                lRetVal = hBuffer:BUFFER-DELETE ().
                hBuffer:BUFFER-RELEASE ().
                
                LEAVE.
            END.
            //
            //  Letzte Abfrage wiederholen und Temp-Tabelle füllen
            //
            outilitiesHandler:readLastcWhere(
                INPUT  oJsonIdent,
                INPUT  cFileName,
                OUTPUT cQueryWhere) NO-ERROR.
            outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
            
            httTable:EMPTY-TEMP-TABLE ().            
            createTempTable(
                INPUT oJsonIdent
                ).
            
            fillTemptableFromTable(
                INPUT  oJsonIdent   ,
                INPUT  cQueryWhere  ,
                OUTPUT oJsonReturn
                ).
 
            oRecords = NEW JsonArray().
            oRecords = oJsonReturn:GetJsonArray('records').
            oRecord  = NEW JsonObject().
            oRecord  = oRecords:GetJsonObject(iIndex + 1). 
            
            oselectboxHandler:getVariableSelectBoxes(
                INPUT  oJsonIdent,
                OUTPUT oJsonSelectBoxes
                ).
            IF VALID-OBJECT(oJsonSelectBoxes) THEN oJsonReturn:ADD('selectOptions', oJsonSelectBoxes).
            LEAVE.
        END.
                
        IF lRetVal THEN 
        DO:             
            oJsonReturn:ADD('success', TRUE).
            RETURN lRetVal.
        END.

        IF NOT lRetVal THEN 
        DO:
            oJsonMessage = NEW JsonObject().
            oJsonMessage:ADD('success', FALSE).
            oJsonMessage:ADD('message', lcMessage).
            
            oJsonMessage:WRITE(lcJsonString, FALSE).
            
            oJsonReturn = oJsonMessage.
        END.
        
        RETURN lRetVal.
        
        CATCH e AS Progress.Lang.Error:
        
        END CATCH.
        
        FINALLY:
            DELETE OBJECT oJsonArray    NO-ERROR.
            DELETE OBJECT oJsonData     NO-ERROR.
        END FINALLY.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC LOGICAL fillTemptableFromTable(
        INPUT  oJsonIdent   AS JsonObject,
        INPUT  cWhere       AS CHARACTER,
        OUTPUT oJsonReturn  AS JsonObject 
        ):
        
        DEFINE VARIABLE lRetVal       AS LOGICAL   NO-UNDO INIT FALSE.
        DEFINE VARIABLE i1            AS INTEGER   NO-UNDO.
        DEFINE VARIABLE hQuery        AS HANDLE    NO-UNDO.
        DEFINE VARIABLE hBuffer       AS HANDLE    NO-UNDO.
        DEFINE VARIABLE iTotalRecords AS INTEGER   NO-UNDO.
        DEFINE VARIABLE cAddress      AS CHARACTER NO-UNDO.
        DEFINE VARIABLE hFeld         AS HANDLE    NO-UNDO.
        DEFINE VARIABLE cUniqueWHere  AS CHARACTER NO-UNDO.
        DEFINE VARIABLE rBuffer       AS RECID     NO-UNDO.
        
        DEFINE VARIABLE oRecords      AS JsonArray NO-UNDO.
        
        outilitiesHandler = NEW utilitiesHandler().
        oselectboxHandler = NEW selectboxHandler().
        
        iStartPage  = 1.
        iMaxRecords = 25.
        iIndex      = 0.
        cFileName   = oJsonIdent:GetCharacter('file_name').
        rBuffer     = (IF oJsonIdent:HAS('rBuffer') THEN oJsonIdent:GetInt64('rBuffer') ELSE ?).
        //
        //  Manchmal kommen die Werte als Integer, manchmal als character
        //
        IF oJsonIdent:HAS('limit') THEN 
        DO:
            iMaxRecords = (IF oJsonIdent:getType('limit') = 1 THEN INTEGER(oJsonIdent:GetCharacter('limit')) ELSE oJsonIdent:GetInteger('limit')).
        END. 
        IF oJsonIdent:HAS('page')  THEN 
        DO:
            iStartPage = (IF oJsonIdent:getType('page')   = 1 THEN INTEGER(oJsonIdent:GetCharacter('page')) ELSE oJsonIdent:GetInteger('page')).
        END. 
        IF oJsonIdent:HAS('index') THEN 
        DO:
            iIndex     = (IF oJsonIdent:getType('index')  = 1 THEN INTEGER(oJsonIdent:GetCharacter('index')) ELSE oJsonIdent:GetInteger('index')).
        END.
        iStartRecord = ((iStartPage - 1) * iMaxRecords) + 1.
        //
        //  Für das Dynamische Query wird PRESELECT verwendet für die Pagination
        //
        cWhere = REPLACE(cWhere, 'FOR', 'PRESELECT').
        CREATE QUERY  hQuery.
        CREATE BUFFER hBuffer FOR TABLE cFileName.
        hQuery:SET-BUFFERS (hBuffer) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
        hQuery:QUERY-PREPARE (cWhere) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
        hQuery:QUERY-OPEN ().

        iTotalRecords = hQuery:NUM-RESULTS.
        hQuery:REPOSITION-FORWARD(iStartRecord - 1) NO-ERROR.
        hQuery:GET-NEXT ().
        iCurrentPosition = 0.
        iAnzahlRecords   = 0.

        DO WHILE NOT hQuery:QUERY-OFF-END:
            IF iCurrentPosition = 0 THEN iCurrentPosition = iStartRecord.
            iAnzahlRecords = iAnzahlRecords + 1.
            httTable:BUFFER-CREATE().
            httTable:BUFFER-COPY(hBuffer, 'address').
            
            hFeld = hBuffer:BUFFER-FIELD('address'):HANDLE NO-ERROR.
            IF  VALID-HANDLE(hFeld)    AND 
                NOT ERROR-STATUS:ERROR THEN 
            DO:
                cAddress = ''.
                DO i1 = 1 TO hFeld:EXTENT:
                    cAddress = cAddress + (IF i1 > 1 THEN CHR(10)  ELSE '') + hFeld:BUFFER-VALUE(i1). 
                END.
                httTable:BUFFER-FIELD('address'):BUFFER-VALUE = cAddress.
            END. 
            IF rBuffer <> ? AND hBuffer:RECID = rBuffer THEN iIndex = iAnzahlRecords - 1.
            IF iAnzahlRecords >= iMaxRecords THEN LEAVE.
            hQuery:GET-NEXT ().
        END.
        hQuery:QUERY-CLOSE ().
        DELETE OBJECT hQuery  NO-ERROR.
        DELETE OBJECT hBuffer NO-ERROR.

        oRecords = NEW JsonArray().
        httTable:WRITE-JSON('JsonArray', oRecords).
        
        iPageCounter = iTotalRecords / iMaxRecords.
        IF (iPageCounter * iMaxRecords) < iTotalRecords THEN iPageCounter = iPageCounter + 1.  

        oJsonReturn = NEW JsonObject().
        oJsonReturn:ADD('records'     , oRecords      ).
        oJsonReturn:ADD('currentPage' , iStartPage    ).
        oJsonReturn:ADD('maxRecords'  , iTotalRecords ).
        oJsonReturn:ADD('pageCount'   , iPageCounter  ).
        oJsonReturn:ADD('recordCount' , iAnzahlRecords).
        oJsonReturn:ADD('currentIndex', iIndex        ).
        
        IF  iAnzahlRecords > 0 AND
            rBuffer        = ? THEN 
        DO:
            httTable:FIND-FIRST('', NO-LOCK) NO-ERROR.
            createUniqueWhere(
                INPUT  httTable    ,
                OUTPUT cUniqueWhere
                ).
            outilitiesHandler:writeLastRecord(
                INPUT oJsonIdent,
                INPUT cUniqueWhere
                ). 
        END.
        
// oJsonReturn:WriteFile(SUBSTITUTE('C:\TEMP\adminprogs_fillTemptablefrom_table_&1.json', ETIME), TRUE).
        
        lRetVal = (IF iAnzahlRecords = 0 THEN FALSE ELSE TRUE).        
        RETURN lRetVal.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC LOGICAL getChanges(
        INPUT  oJsonIdent  AS JsonObject,
        INPUT  oJsonData   AS JsonObject,
        OUTPUT oJsonResult AS JsonObject
        ):
            
        DEFINE VARIABLE oJsonMessage    AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonMessageBox AS JsonObject NO-UNDO.

        DEFINE VARIABLE lRetVal         AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE lOK             AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE ii              AS INTEGER    NO-UNDO.
        DEFINE VARIABLE hField          AS HANDLE     NO-UNDO.
        DEFINE VARIABLE htField         AS HANDLE     NO-UNDO.
        DEFINE VARIABLE cField          AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cBufferField    AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cValue          AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE iValue          AS INTEGER    NO-UNDO.
        DEFINE VARIABLE lValue          AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE cWordIndex      AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE rBuffer         AS RECID      NO-UNDO.
        DEFINE VARIABLE cFieldNames     AS CHARACTER  NO-UNDO EXTENT.
        DEFINE VARIABLE cReplace        AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE lNew            AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE iType           AS INTEGER    NO-UNDO.
        DEFINE VARIABLE cUniqueWhere    AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cChangeAction   AS CHARACTER  NO-UNDO.
        
        DEFINE VARIABLE cFunction       AS CHARACTER  NO-UNDO.

        DEFINE VARIABLE oJsonReturn     AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonRecord     AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonArray      AS JsonArray  NO-UNDO.
        
        outilitiesHandler = NEW utilitiesHandler().

        httKeyFields    = TEMP-TABLE ttKeyFields   :DEFAULT-BUFFER-HANDLE.
        httPrimaryIndex = TEMP-TABLE ttPrimaryIndex:DEFAULT-BUFFER-HANDLE.
        //
        //  Ermitteln des Tabellennamens, ob die Tabelle das Feld "company" und/oder das Feld "active" enthält
        //
        outilitiesHandler:evaluateFile(
            INPUT-OUTPUT oJsonIdent     ,
            OUTPUT       cFileName      ,
            OUTPUT       lCompany       ,
            OUTPUT       lActive        ,
            OUTPUT       lWordindex     ,
            INPUT-OUTPUT httKeyFields   ,
            INPUT-OUTPUT httPrimaryIndex
            ).

        cFunction = oJsonIdent:GetCharacter('function').
        CREATE BUFFER hBuffer FOR TABLE cFileName.

        createTempTable(
            INPUT oJsonIdent
            ).
            
        oJsonRecord = NEW JsonObject().
        oJsonRecord = oJsonData:GetJsonObject('record').

        httTable:BUFFER-CREATE().
        cReplace    = SUBSTITUTE('&1_', cFileName).
        cFieldNames = oJsonRecord:GetNames().
        DO ii = 1 TO EXTENT(cFieldNames):
            cField       = cFieldNames[ii].
            IF NOT cField BEGINS cFileName THEN NEXT.
            cBufferField = REPLACE(cField, cReplace, '').
            hField       = httTable:BUFFER-FIELD(cBufferField):HANDLE NO-ERROR.
            IF ERROR-STATUS:ERROR        THEN NEXT.
            IF NOT VALID-HANDLE (hField) THEN NEXT.
            IF hField:DATA-TYPE = 'date' THEN cValue = outilitiesHandler:iso2date(INPUT cValue). 
                         
            iType = oJsonRecord:getType(cField). 
            CASE iType:
                WHEN 2 THEN 
                    DO:
                        iValue = oJsonRecord:GetInteger(cField).
                        hField:BUFFER-VALUE = iValue NO-ERROR.
                    END.
                WHEN 3 THEN 
                    DO:
                        lValue = oJsonRecord:GetLogical(cField).
                        hField:BUFFER-VALUE = lValue NO-ERROR.
                    END.
                OTHERWISE 
                DO:
                    cValue = oJsonRecord:GetCharacter(cField).
                    IF hField:DATA-TYPE = 'character' THEN hField:BUFFER-VALUE = cValue NO-ERROR.
                    IF hField:DATA-TYPE = 'date'      THEN hField:BUFFER-VALUE = DATE(outilitiesHandler:iso2date(cValue)).
                END.
            END CASE.
            lOk = outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
            IF lOk THEN NEXT.
        END.
// httTable:WRITE-JSON ('FILE', 'C:\TEMP\ttTable_Inhalt.json', TRUE).
        //
        //  Erzeugen von Where-Statement für UNIQUE-Find
        //
        httTable:FIND-FIRST('', NO-LOCK) NO-ERROR.
        createUniqueWhere(
            INPUT  httTable,
            OUTPUT cUniqueWhere
            ).
        cWhere = cUniqueWhere.
        
        lOK = hBuffer:FIND-UNIQUE(cUniqueWhere, NO-LOCK) NO-ERROR.
        IF NOT lOK THEN lNew = TRUE.
        
        oJsonReturn = NEW JsonObject().
        oJsonReturn:ADD('success', TRUE).
        
        cChangeAction = oJsonIdent:GetCharacter('changeAction').

        DO WHILE NOT lNew:
            cField = oJsonData:GetCharacter('changedField').
            cValue = oJsonData:GetCharacter('changedValue').
            CASE cField:
                WHEN 'users_firstname' THEN 
                    DO:
                        ASSIGN  
                            httTable::display_name = httTable::firstname + ' ' + httTable::lastname.
                        IF httTable::ladmin THEN httTable::display_name = httTable::display_name + ' (Admin)'.
                    END.  
                WHEN 'users_lastname' THEN 
                    DO:
                        ASSIGN  
                            httTable::display_name = httTable::firstname + ' ' + httTable::lastname  
                            httTable::initials     = SUBSTRING(httTable::firstname,01,02) + SUBSTRING(httTable::lastname,01,02).  
                        IF httTable::ladmin THEN httTable::display_name = httTable::display_name + ' (Admin)'.
                    END.
            END CASE.
            LEAVE.
        END. 
        
        oJsonRecord = NEW JsonObject().
        oJsonArray  = NEW JsonArray ().
        
        httTable:WRITE-JSON('JsonObject', oJsonRecord).
        oJsonArray  = oJsonRecord:GetJsonArray('record').
        oJsonRecord = oJsonArray:GetJsonObject(1). 
        oJsonReturn:ADD('record', oJsonRecord).
        
        oJsonResult = oJsonReturn.
        
        lRetVal = TRUE.
        RETURN lRetVal.
            
    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC LOGICAL getData(
        INPUT  oJsonIdent  AS JsonObject,
        OUTPUT oJsonReturn AS JsonObject  
        ):
        
        DEFINE VARIABLE ii               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE i1               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE iAnzRec          AS INTEGER    NO-UNDO.
        DEFINE VARIABLE lRetVal          AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE lOK              AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE cAddress         AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE hFeld            AS HANDLE     NO-UNDO.
        DEFINE VARIABLE cFormId          AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cFormUser        AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cFieldName       AS CHARACTER  NO-UNDO.
        
        DEFINE VARIABLE oRecords         AS JsonArray  NO-UNDO.
        DEFINE VARIABLE oJsonEditable    AS JsonArray  NO-UNDO.
        DEFINE VARIABLE oJsonBox         AS JsonArray  NO-UNDO.
        DEFINE VARIABLE oJsonSelectBoxes AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonMessageBox  AS JsonObject NO-UNDO.

        outilitiesHandler = NEW utilitiesHandler().
        oselectboxHandler = NEW selectboxHandler().
        
        cFunction = oJsonIdent:GetCharacter('function').
        cCompany  = oJsonIdent:GetCharacter('company').
        cFileName = oJsonIdent:GetCharacter('file_name').

        httKeyFields    = TEMP-TABLE ttKeyFields   :DEFAULT-BUFFER-HANDLE.
        httPrimaryIndex = TEMP-TABLE ttPrimaryIndex:DEFAULT-BUFFER-HANDLE.
// oJsonIdent:WriteFile('C:\Temp\adminprogs_getdata_jsoniden.json', TRUE).
        iIndex = 0.        
        buildWhere(
            INPUT  oJsonIdent 
            ).

        ii      = 0.
        iAnzRec = 0.
        ttTable:EMPTY-TEMP-TABLE ().
        CREATE QUERY hQuery.
        cWhere = SUBSTITUTE('FOR EACH &1 NO-LOCK &2 ', cFileName, cWhere) NO-ERROR.
// MESSAGE 'cWhere loaddate for adminprogs ' cWhere.
// oJsonIdent:WriteFile('C:\TEMP\adminprogs_getData_oJsonIdent.json', TRUE ).
        IF NOT oJsonIdent:HAS('search') THEN 
        DO:
            outilitiesHandler:writeLastcWhere(
                INPUT  oJsonIdent ,
                INPUT  cFileName  ,
                INPUT  cWhere
                ).
        END.
        //
        //  Für das Dynamische Query wird PRESELECT verwendet für die Pagination
        //
        lRetVal = fillTemptableFromTable(
            INPUT  oJsonIdent   ,
            INPUT  cWhere       ,
            OUTPUT oJsonReturn
            ).
            
        IF NOT lRetVal THEN 
        DO:
            outilitiesHandler:createInfoBox(
                INPUT  oJsonIdent   ,
                INPUT  '2009'       ,
                INPUT  ''           ,
                OUTPUT oJsonMessageBox
                ).
            oJsonReturn:ADD('success', FALSE).
            oJsonReturn:ADD('showMessage', oJsonMessageBox).
            RETURN lRetVal.
        END.
             
        lRetVal = httTable:FIND-FIRST('', NO-LOCK).
        hFeld   = httTable:BUFFER-FIELD('language_id'):HANDLE NO-ERROR.
        IF  VALID-HANDLE(hFeld)    AND
            NOT ERROR-STATUS:ERROR THEN oJsonIdent:SET('language_id', hFeld:BUFFER-VALUE).
        oselectboxHandler:getVariableSelectBoxes(
            INPUT  oJsonIdent      ,
            OUTPUT oJsonSelectBoxes
            ).
        IF VALID-OBJECT(oJsonSelectBoxes) THEN oJsonReturn:ADD('selectOptions', oJsonSelectBoxes).

        outilitiesHandler:writePosition(
            INPUT  oJsonIdent       ,
            INPUT  cFileName        ,
            INPUT  iCurrentPosition ,
            INPUT  iStartPage       ,
            INPUT  iMaxRecords
            ).
// oJsonReturn:WriteFile('C:\TEMP\addresses_getData_messages.json', TRUE).
        
        lRetVal = TRUE.        
        RETURN lRetVal.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC LOGICAL rebuildData(
        INPUT  oJsonIdent  AS JsonObject,
        OUTPUT oJsonReturn AS JsonObject  
        ):
        
        DEFINE VARIABLE ii               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE i1               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE lRetVal          AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE cValue           AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE lOK              AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE rBuffer          AS RECID      NO-UNDO.
        DEFINE VARIABLE iTotalRecords    AS INTEGER    NO-UNDO.
        DEFINE VARIABLE hFeld            AS HANDLE     NO-UNDO.
        DEFINE VARIABLE cAddress         AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cUniqueWhere     AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE hUniqueBuffer    AS HANDLE     NO-UNDO.
        
        DEFINE VARIABLE oJsonSelectBoxes AS JsonObject NO-UNDO.
        
        outilitiesHandler = NEW utilitiesHandler().
        oselectboxHandler = NEW selectboxHandler().
        
        cFileName = oJsonIdent:GetCharacter('file_name').
        outilitiesHandler:readLastRecord(
            INPUT  oJsonIdent ,
            OUTPUT cUniqueWhere
            ).
// MESSAGE 'cUniqueWhere fuer UNIQE-FIND' cUniqueWhere.
        CREATE BUFFER hUniqueBuffer FOR TABLE cFileName.
        hUniqueBuffer:FIND-UNIQUE (cUniqueWhere, NO-LOCK).
        rBuffer = hUniqueBuffer:RECID.
        oJsonIdent:ADD('rBuffer', INT64(rBuffer)).
// MESSAGE hUniqueBuffer::address_id '-' rBuffer.
        outilitiesHandler:readLastcWhere(
            INPUT  oJsonIdent,
            INPUT  cFileName ,
            OUTPUT cWhere
            ).
        outilitiesHandler:evaluatePageNumber(
            INPUT-OUTPUT oJsonIdent   ,
            INPUT        cWhere       ,
            INPUT        rBuffer
            ).            
// oJsonIdent:WriteFile('C:\TEMP\adminprog_rebuildData_JsonIdent.json', TRUE).        
// MESSAGE 'LAST-WHERE' cWhere.            
       
        createTempTable(
            INPUT oJsonIdent
            ).
            
        fillTemptableFromTable(
            INPUT  oJsonIdent   ,
            INPUT  cWhere       ,
            OUTPUT oJsonReturn
            ).
            
        hUniqueBuffer:FIND-UNIQUE (cUniqueWhere, NO-LOCK) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
        oJsonIdent:SET('language_id', hUniqueBuffer::language_id).

        oselectboxHandler:getVariableSelectBoxes(
            INPUT  oJsonIdent      ,
            OUTPUT oJsonSelectBoxes
            ).
        IF VALID-OBJECT(oJsonSelectBoxes) THEN oJsonReturn:ADD('selectOptions', oJsonSelectBoxes).

        lRetVal = TRUE.
        RETURN lRetVal.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC LOGICAL recordChange(
        INPUT  oJsonIdent   AS JsonObject   ,
        INPUT  oJsonData    AS JsonObject   ,
        OUTPUT oJsonReturn  AS JsonObject
        ):
            
        DEFINE VARIABLE cReplace         AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cFieldName       AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cField           AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cBufferField     AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cValue           AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE ii               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE lOK              AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE cCompany         AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cFormId          AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cFormUser        AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cUniqueWhere     AS CHARACTER  NO-UNDO.
            
        DEFINE VARIABLE hField           AS HANDLE     NO-UNDO.
        
        DEFINE VARIABLE oJsonRecord      AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonBox         AS JsonArray  NO-UNDO.
        DEFINE VARIABLE oJsonSelectBoxes AS JsonObject NO-UNDO.
        
        outilitiesHandler = NEW utilitiesHandler().
        oselectboxHandler = NEW selectboxHandler().

        httKeyFields    = TEMP-TABLE ttKeyFields   :DEFAULT-BUFFER-HANDLE.
        httPrimaryIndex = TEMP-TABLE ttPrimaryIndex:DEFAULT-BUFFER-HANDLE.
        //
        //  Ermitteln des Tabellennamens, ob die Tabelle das Feld "company" und/oder das Feld "active" enthält
        //
        outilitiesHandler:evaluateFile(
            INPUT-OUTPUT oJsonIdent     ,
            OUTPUT       cFileName      ,
            OUTPUT       lCompany       ,
            OUTPUT       lActive        ,
            OUTPUT       lWordindex     ,
            INPUT-OUTPUT httKeyFields   ,
            INPUT-OUTPUT httPrimaryIndex
            ).
            
        cFunction = oJsonIdent:GetCharacter('function').
        cCompany  = oJsonIdent:GetCharacter('company').
        cFormId   = oJsonIdent:GetCharacter('formId').
        cFormUser = oJsonIdent:GetCharacter('formUser').
        
        CREATE BUFFER hBuffer FOR TABLE cFileName.
        createTempTable(
            INPUT oJsonIdent
            ).

        oJsonRecord = NEW JsonObject().
        oJsonRecord = oJsonData:GetJsonObject('record').
// oJsonRecord:WriteFile('C:\Temp\oJsonRecord.json', TRUE).

        httTable:READ-JSON('JsonObject', oJsonRecord) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
        
// httTable:WRITE-JSON ('FILE', 'C:\TEMP\ttTable_RecordChange_Inhalt.json', TRUE).
        //
        //  den ersten Datensatz in der TEMP-TABLE lesen
        //
        httTable:FIND-FIRST('', NO-LOCK) NO-ERROR.
        hField = httTable:BUFFER-FIELD('language_id'):HANDLE NO-ERROR.
        IF  VALID-HANDLE(hField)   AND
            NOT ERROR-STATUS:ERROR THEN oJsonIdent:SET('language_id', httTable::language_id).
        //
        //  Erzeugen von Where-Statement für UNIQUE-Find
        //
        createUniqueWhere(
            INPUT  httTable,
            OUTPUT cUniqueWhere
            ).
// MESSAGE 'Where-Statement von Primary-Index =' cUniqueWhere.
        outilitiesHandler:writeLastRecord(
            INPUT  oJsonIdent   ,
            INPUT  cUniqueWhere       
            ).            

        outilitiesHandler:readLastcWhere(
            INPUT  oJsonIdent,
            INPUT  cFileName ,
            OUTPUT cWhere   ).
// MESSAGE 'Filename =' cFileName 'Aktuelle Adress_Id =' httTable::address_id 'Last Where =' cWhere.
        oJsonIdent:WRITE(lcString, TRUE).
// MESSAGE 'oJsonIdent = ' STRING(lcString).
        oselectboxHandler:getVariableSelectBoxes(
            INPUT  oJsonIdent      ,
            OUTPUT oJsonSelectBoxes
            ).
        lOk = TRUE.    
        oJsonReturn = NEW JsonObject().
        oJsonReturn:ADD('success', lOK        ).
        oJsonReturn:ADD('record' , oJsonRecord).
        IF VALID-OBJECT(oJsonSelectBoxes) THEN oJsonReturn:ADD('selectOptions', oJsonSelectBoxes).
        
// oJsonReturn:WriteFile('C:\Temp\RecordChange_return.json', TRUE).
        
        RETURN lOK.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC LOGICAL updateBegin(
        INPUT  oJsonIdent    AS JsonObject   ,
        INPUT  oJsonData     AS JsonObject   ,
        OUTPUT oJsonReturn   AS JsonObject
        ):

        DEFINE VARIABLE lRetVal     AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE lAddressFix AS LOGICAL    NO-UNDO.
        
        DEFINE VARIABLE oJsonAction AS JsonArray  NO-UNDO.
        DEFINE VARIABLE oJsonRecord AS JsonObject NO-UNDO.
        
        /*        oJsonRecord = NEW JsonObject().                                        */
        /*        oJsonRecord = oJsonData:GetJsonObject('record').                       */
        /*                                                                               */
        /*        lAddressFix = LOGICAL(oJsonRecord:GetLogical('addresses_address_fix')).*/
        /*        oJsonAction = NEW JsonArray().                                         */
        /*        oJsonAction:ADD('addresses_address').                                  */
        /*        oJsonReturn = NEW JsonObject().                                        */
        /*        oJsonReturn:ADD('success', TRUE).                                      */
        /*        IF lAddressFix THEN oJsonReturn:ADD('editableFields', oJsonAction).    */
        /*        ELSE                oJsonReturn:ADD('disabledFields', oJsonAction).    */

        oJsonReturn = NEW JsonObject().
        oJsonReturn:ADD('success', TRUE).
        
        lRetVal = TRUE.
        RETURN lRetVal.

    END METHOD.

    /*------------------------------------------------------------------------------
     Purpose:
     Notes:
    ------------------------------------------------------------------------------*/

    METHOD PUBLIC LOGICAL updateData(
        INPUT  oJsonIdent  AS JsonObject,
        INPUT  oJsonData   AS jsonObject,
        OUTPUT oJsonReturn AS JsonObject  
        ):
    
        DEFINE VARIABLE oJsonMessage     AS JsonObject NO-UNDO.
        DEFINE VARIABLE oJsonMessageBox  AS JsonObject NO-UNDO.

        DEFINE VARIABLE lRetVal          AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE lOK              AS LOGICAL    NO-UNDO.
        DEFINE VARIABLE ii               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE i1               AS INTEGER    NO-UNDO.
        DEFINE VARIABLE hField           AS HANDLE     NO-UNDO.
        DEFINE VARIABLE htField          AS HANDLE     NO-UNDO.
        DEFINE VARIABLE CField           AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cValue           AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cWordIndex       AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE rBuffer          AS RECID      NO-UNDO.
        DEFINE VARIABLE cUniqueWhere     AS CHARACTER  NO-UNDO.
        DEFINE VARIABLE cFieldValue      AS CHARACTER  NO-UNDO.
        
        DEFINE VARIABLE oJsonRecord      AS JsonObject NO-UNDO.
        DEFINE VARIABLE oMasterKeyFields AS JsonObject NO-UNDO.
        
        DEFINE VARIABLE cFunction        AS CHARACTER  NO-UNDO.

        outilitiesHandler = NEW utilitiesHandler().
        
        httKeyFields    = TEMP-TABLE ttKeyFields   :DEFAULT-BUFFER-HANDLE.
        httPrimaryIndex = TEMP-TABLE ttPrimaryIndex:DEFAULT-BUFFER-HANDLE.
        //
        //  Ermitteln des Tabellennamens, ob die Tabelle das Feld "company" und/oder das Feld "active" enthält
        //
        outilitiesHandler:evaluateFile(
            INPUT-OUTPUT oJsonIdent     ,
            OUTPUT       cFileName      ,
            OUTPUT       lCompany       ,
            OUTPUT       lActive        ,
            OUTPUT       lWordindex     ,
            INPUT-OUTPUT httKeyFields   ,
            INPUT-OUTPUT httPrimaryIndex
            ).
            
        oJsonRecord = NEW JsonObject().
        oJsonRecord = oJsonData:GetJsonObject('record') NO-ERROR.
        
        oMasterKeyFields = NEW JsonObject().
        oMasterKeyFields = oJsonData:GetJsonObject('masterKeyFields') NO-ERROR.
            
        cFunction = oJsonIdent:GetCharacter('function').
        CREATE BUFFER hBuffer FOR TABLE cFileName.

        createTempTable(
            INPUT oJsonIdent
            ).
            
        httTable:READ-JSON('JsonObject', oJsonRecord) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
        httTable:FIND-FIRST('', NO-LOCK) NO-ERROR.
        outilitiesHandler:evaluateErrorStatus(ERROR-STATUS:HANDLE).
        //
        //  Erzeugen von Where-Statement für UNIQUE-Find
        //
        createUniqueWhere(
            INPUT  httTable,
            OUTPUT cUniqueWhere
            ).

        lRetVal = FALSE.
        REPEAT TRANSACTION ON ERROR UNDO, LEAVE:
            lOK = hBuffer:FIND-UNIQUE(cUniqueWhere, EXCLUSIVE-LOCK, NO-WAIT) NO-ERROR. 
            IF hBuffer:LOCKED THEN 
            DO:
                hBuffer:FIND-UNIQUE(cUniqueWhere, NO-LOCK) NO-ERROR.
                rBuffer = hBuffer:RECID. 
                outilitiesHandler:createLockMessage(
                    INPUT  oJsonIdent,
                    INPUT  rBuffer  ,
                    OUTPUT oJsonMessageBox
                    ).
                oJsonReturn = NEW JsonObject().
                oJsonReturn:ADD('success'     , FALSE          ).
                oJsonReturn:ADD('showMessage', oJsonMessageBox).
                RETURN TRUE.
            END.
            IF NOT hBuffer:AVAILABLE THEN 
            DO:
                outilitiesHandler:createErrorBox(
                    INPUT  oJsonIdent       ,
                    INPUT  '2000'           ,
                    INPUT  ''               ,
                    OUTPUT oJsonMessageBox
                    ).
                oJsonReturn = NEW JsonObject().
                oJsonReturn:ADD('success'     , FALSE          ).
                oJsonReturn:ADD('showMessage' , oJsonMessageBox).
                RETURN TRUE.
            END.

            DO WHILE lActive :
                hField = hBuffer:BUFFER-FIELD('active') NO-ERROR.
                IF NOT VALID-HANDLE(hField) THEN LEAVE.
                IF hField:BUFFER-VALUE = TRUE THEN LEAVE.
                
                htField = httTable:BUFFER-FIELD('active') NO-ERROR.
                IF NOT VALID-HANDLE(htField) THEN LEAVE.

                IF hField:BUFFER-VALUE = FALSE AND htField:BUFFER-VALUE = TRUE THEN LEAVE.

                outilitiesHandler:createQuestionBox(
                    INPUT  oJsonIdent       ,
                    INPUT  '2000'           ,
                    INPUT  ''               ,
                    INPUT  'active'         ,
                    INPUT  'true'           ,
                    INPUT  hBuffer          ,
                    OUTPUT oJsonMessageBox
                    ) NO-ERROR.
                
                oJsonReturn = NEW JsonObject().
                oJsonReturn:ADD('success'     , TRUE                                ).
                oJsonReturn:ADD('record'      , oJsonRecord:GetJsonObject('record') ).
                oJsonReturn:ADD('askQuestion' , oJsonMessageBox                     ).
                RETURN TRUE.
            END.

            DO ii = 1 TO httTable:NUM-FIELDS:
                htField = httTable:BUFFER-FIELD(ii):HANDLE NO-ERROR.
                cField  = htField:NAME.
                hField  = hBuffer:BUFFER-FIELD(cField):HANDLE NO-ERROR.
 
                IF  ERROR-STATUS:ERROR       OR
                    NOT VALID-HANDLE(hField) THEN NEXT.
                IF hField:EXTENT > 0 THEN 
                DO:
                    cFieldValue = htField:BUFFER-VALUE.
                    DO i1 = 1 TO hField:EXTENT:
                        hField:BUFFER-VALUE(i1) = ENTRY(i1, cFieldValue, CHR(10)) NO-ERROR.
                    END.
                END.
                ELSE 
                DO:
                    IF COMPARE(htField:BUFFER-VALUE, '=', hField:BUFFER-VALUE, 'CASE-SENSITIVE') THEN NEXT.
                    hField:BUFFER-VALUE = htField:BUFFER-VALUE.
                END. 
            END.

            hField = hBuffer:BUFFER-FIELD('updated_at'):HANDLE NO-ERROR.
            IF  NOT ERROR-STATUS:ERROR AND
                VALID-HANDLE(hField)   THEN hField:BUFFER-VALUE = NOW.
            hField = hBuffer:BUFFER-FIELD('updated_by'):HANDLE NO-ERROR.
            IF  NOT ERROR-STATUS:ERROR AND
                VALID-HANDLE(hField)   THEN hField:BUFFER-VALUE = oJsonIdent:GetCharacter('H_display_name').
            
            hField = hBuffer:BUFFER-FIELD('wordindex'):HANDLE NO-ERROR.
            IF  NOT ERROR-STATUS:ERROR AND
                VALID-HANDLE(hField)   THEN 
            DO:
                cWordIndex = outilitiesHandler:createWordindex(
                    INPUT hBuffer
                    ).
                hField:BUFFER-VALUE = cWordIndex.
            END.
            
            oJsonData   = NEW JsonObject().
            oJsonArray  = NEW JsonArray ().
            httTable:BUFFER-COPY(hBuffer).
            httTable:WRITE-JSON('JsonObject', oJsonData).
    
            oJsonArray = oJsonData:GetJsonArray('record').
            oJsonData  = oJsonArray:GetJsonObject(1).
            
            hBuffer:BUFFER-RELEASE ().
            
            lRetVal = TRUE.
            LEAVE.
        END.

        IF lRetVal THEN 
        DO:             
            oJsonReturn = NEW JsonObject().
            oJsonReturn:ADD('success', TRUE     ).
            oJsonReturn:ADD('record' , oJsonData).
        
            outilitiesHandler:createInfoBox(
                INPUT  oJsonIdent       ,
                INPUT  '2003'           ,
                INPUT  ''               ,
                OUTPUT oJsonMessageBox
                ) NO-ERROR.
            oJsonReturn:ADD('showMessage' , oJsonMessageBox).
        END.

        IF NOT lRetVal THEN 
        DO:
            oJsonMessage = NEW JsonObject().
            oJsonMessage:ADD('success', FALSE).
            oJsonMessage:ADD('message', lcMessage).
            oJsonMessage:WRITE(lcJsonString, FALSE).
            
            oJsonReturn = oJsonMessage.
        END.
        
        RETURN lRetVal.

        CATCH e AS Progress.Lang.Error:

        END CATCH.

        FINALLY:

        END FINALLY.

    END METHOD.

    DESTRUCTOR PUBLIC adminprogsHandler ( ):

    END DESTRUCTOR.

END CLASS.