Function Scan_API(@API)
/***********************************************************************************************************************

    This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written
    permission from SRP Computer Solutions, Inc.

    Name        :   Scan_API

    Description :   API logic for the Scan resource.

    Notes       :   All web APIs should include the API_SETUP insert. This will provide several useful variables:

                        HTTPMethod              - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.)
                        APIURL                  - The URL for the API entry point (e.g., api.mysite.com/v1).
                        FullEndpointURL         - The URL submitted by the client, including query params.
                        FullEndpointURLNoQuery  - The URL submitted by the client, excluding query params.
                        ParentURL               - The URL path preceeding the current endpoint.
                        CurrentAPI              - The name of this stored procedure.

    Parameters  :
        API             [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]:
                                    - APIPattern must follow this structure Scan[.ID.[<Property>]]
                                    - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc.
                                Examples:
                                    - Scan.POST
                                    - Scan.ID.PUT
                                    - Scan.ID.firstName.GET
        Response       [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API
                                services do not rely upon anything being returned in the response. This is what the
                                various services like SetResponseBody and SetResponseStatus services are for. A response
                                value is only helpful if the developers want to use it for debug purposes.

    History     :   (Date, Initials, Notes)
        07/30/19    xxx     Original programmer.

***********************************************************************************************************************/

#pragma precomp SRP_PreCompiler

$insert APP_INSERTS
$insert API_SETUP
$insert HTTP_INSERTS
$insert SCANS_EQUATES
$insert RDS_EQUATES
$insert SCAN_SETUP

Declare Function   Scan_Services, Database_Services, QA_Services, Datetime, RDS_Services, SRP_Array, SRP_Stopwatch
Declare function   Logging_Services, Environment_Services, GetTickCount
Declare Subroutine Scan_Services, Database_Services, QA_Services, obj_WO_Mat_Log, SRP_Stopwatch
Declare Subroutine Logging_Services, Mona_Services

LogPath      = Environment_Services('GetApplicationRootPath') : '\LogFiles\ScanAPI\APIResponseTime'; //Define the directory where the log will be saved to. This happens the first time of the day that the log is written to.
LogDate      = Oconv(Date(), 'D4/')
LogTime      = Oconv(Time(), 'MTS')
LoggingDTM   = LogDate : ' ' : LogTime   ; // Logging DTM

LogFileName      = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' ScanAPIResponseTimes.csv'; //Define the file name that will get created.
Headers          = 'Logging DTM' : @FM : 'API' : @FM : 'ResponseTime' : @FM : 'ScanID' : @FM : 'ScanData' : @VM : 'StatusCode' ; //Define the column names in the log file, delimited by a Field Mark.
objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$); //Actually creates the log.

IsProd = Environment_Services('IsProd')
If IsProd EQ True$ then
	MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_SCANAPI'
end else
	MonaResource = 'GRP_OPENINSIGHT_MES_OP_FE_DEV_SCANAPI'
end
 
GoToAPI else
    // The specific resource endpoint doesn't have a API handler yet.
    HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.')
end

Return Response OR ''


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Endpoint Handlers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


API scan.POST
	StartTick = GetTickCount()
	MetricName = 'SCAN_POST'
	
    SRP_Stopwatch('Reset')
    SRP_Stopwatch('Start', 'SCAN_POST_RESPONSE_TIME')
    ScanID  = Scan_Services('CreateScansRow')
    If Error_Services('NoError') then
        StatusCode  = 201
        GoSub CreateHALItem
        Mona_Services('SendStatus', MonaResource, MetricName, 'OK')
    end else
        Message = Error_Services('GetMessage')
        HTTP_Services('SetResponseStatus', 500, Message)
        Mona_Services('SendStatus', MonaResource, MetricName, 'CRITICAL')
    end
    
    EndTick = GetTickCount()
    Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
    
    SRP_Stopwatch('Stop', 'SCAN_POST_RESPONSE_TIME')
    TotalPostResponseTime = SRP_Stopwatch('GetData', 'SCAN_POST_RESPONSE_TIME')
    LogData    = ''
    LogData<1> = LoggingDTM;//Defined at entry of subroutine
    LogData<2> = 'SCAN.POST'
    LogData<3> = TotalPostResponseTime
    LogData<4> = ScanID
    LogData<5> = ''
    ResponseStatusCode = ''
    If Assigned(StatusCode) then
        ResponseStatusCode = StatusCode
    end
    LogData<6> = ResponseStatusCode
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end api


API scan.ID.POST
	StartTick = GetTickCount()
	MetricName = 'SCAN_ID_POST'
	
    SRP_Stopwatch('Reset')
    SRP_Stopwatch('Start', 'SCAN_ID_POST_RESPONSE_TIME')
    ScanID      = EndpointSegment
    // The resource will have been put into the POST string.
    Body    = HTTP_Services('GetHTTPPostString')
    If Body NE '' then
        // The POST string will have been encoded so use percent (URL) decoding.
        ScanJSON = HTTP_Services('DecodePercentString', Body)
        Scan_Services('ProcessScanData', ScanID, ScanJSON)
        If Error_Services('NoError') then
            StatusCode = 200
            GoSub CreateHALItem
            Mona_Services('SendStatus', MonaResource, MetricName, 'OK')
        end else
            Message    = Error_Services('GetMessage')
            HTTP_Services('SetResponseStatus', 400, Message)
            Mona_Services('SendStatus', MonaResource, MetricName, 'CRITICAL')
        end
    end else
        HTTP_Services('SetResponseStatus', 400, 'JSON object is missing from the request.')
        Mona_Services('SendStatus', MonaResource, MetricName, 'WARNING')
    end
    
    EndTick = GetTickCount()
    Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
    
    SRP_Stopwatch('Stop', 'SCAN_ID_POST_RESPONSE_TIME')
    TotalPostResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_POST_RESPONSE_TIME')
    LogData    = ''
    LogData<1> = LoggingDTM;//Defined at entry of subroutine
    LogData<2> = 'SCAN.ID.POST'
    LogData<3> = TotalPostResponseTime
    LogData<4> = ScanID
    If Assigned(ScanJson) then
        ThisScanDataToLog = ScanJson
    end else
        ThisScanDataToLog = Body
    end
    LogData<5> = ThisScanDataToLog
    ResponseStatusCode = ''
    If Assigned(StatusCode) then
        ResponseStatusCode = StatusCode
    end
    LogData<6> = ResponseStatusCode
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end api


API scan.ID.HEAD
API scan.ID.GET
	StartTick = GetTickCount()
	MetricName = 'SCAN_ID_GET'
	
    SRP_Stopwatch('Reset')
    SRP_Stopwatch('Start', 'SCAN_ID_GET_RESPONSE_TIME')
    ScanID     = EndpointSegment
    StatusCode = 200
    GoSub CreateHALItem
    Mona_Services('SendStatus', MonaResource, MetricName, 'OK')
    
    EndTick = GetTickCount()
    Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)    
    
    SRP_Stopwatch('Stop', 'SCAN_ID_POST_RESPONSE_TIME')
    TotalGetResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_GET_RESPONSE_TIME')
    LogData    = ''
    LogData<1> = LoggingDTM;//Defined at entry of subroutine
    LogData<2> = 'SCAN.ID.GET'
    LogData<3> = TotalGetResponseTime
    LogData<4> = ScanID
    LogData<5> = ''
    ResponseStatusCode = ''
    If Assigned(StatusCode) then
        ResponseStatusCode = StatusCode
    end
    LogData<6> = ResponseStatusCode
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end api


API scan.ID.DELETE
	StartTick = GetTickCount()
	MetricName = 'SCAN_ID_DELETE'
	
    SRP_Stopwatch('Reset')
    SRP_Stopwatch('Start', 'SCAN_ID_DELETE_RESPONSE_TIME')
    ScanID  = EndpointSegment

    ScanRow = Database_Services('ReadDataRow', 'SCANS', ScanID)
    If Error_Services('NoError') then
        If ScanRow<SCANS.ACCEPTED$> NE True$ then
            Database_Services('DeleteDataRow', 'SCANS', ScanID, True$, False$)
            If Error_Services('NoError') then
                HTTP_Services('SetResponseStatus', 200)
                Mona_Services('SendStatus', MonaResource, MetricName, 'OK')
            end else
                Message = Error_Services('GetMessage')
                HTTP_Services('SetResponseStatus', 500, Message)
                Mona_Services('SendStatus', MonaResource, MetricName, 'CRITICAL')
            end
        end else
            HTTP_Services('SetResponseStatus', 403, 'This scan is already accepted and cannot be deleted.')
            Mona_Services('SendStatus', MonaResource, MetricName, 'OK')
        end
    end else
        Message = Error_Services('GetMessage')
        HTTP_Services('SetResponseStatus', 404, Message)
        Mona_Services('SendStatus', MonaResource, MetricName, 'WARNING')
    end
    
    EndTick = GetTickCount()
    Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
    
    SRP_Stopwatch('Stop', 'SCAN_ID_DELETE_RESPONSE_TIME')
    TotalDeleteResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_DELETE_RESPONSE_TIME')
    LogData    = ''
    LogData<1> = LoggingDTM;//Defined at entry of subroutine
    LogData<2> = 'SCAN.ID.DELETE'
    LogData<3> = TotalDeleteResponseTime
    LogData<4> = ScanID
    LogData<5> = ''
    ResponseStatusCode = ''
    If Assigned(StatusCode) then
        ResponseStatusCode = StatusCode
    end
    LogData<6> = ResponseStatusCode
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end api


API scan.ID.PATCH
	StartTick = GetTickCount()
	MetricName = 'SCAN_ID_PATCH'
	
    // This is where scans are ultimately accepted for final processing. We will need to determine which type
    // of scan this is (i.e. Location, Pre-Epi + Load, or Unload). This will be determined by the data coming in and the
    // current status of the lot. For example a Location scan would only have an RDS, location code, and username. 
    SRP_Stopwatch('Reset')
    SRP_Stopwatch('Start', 'SCAN_ID_PATCH_RESPONSE_TIME')
    
    ScanID  = EndpointSegment
    SRP_Stopwatch('Start', 'IDPatchResponseTime')
    // First confirm that this is a valid Scan ID.
    jsonScan    = Scan_Services('GetScansRow', ScanID, True$)
    If Error_Services('NoError') then
        // Confirm that all required data has been scanned before allowing the "accept" field to be updated.
        ParseResponse   = SRP_JSON(objResource, 'Parse', jsonScan)
        If ParseResponse EQ '' then
            ScanAcceptable  = SRP_JSON(objResource, 'GetValue', 'scan.acceptable', False$)
            If ScanAcceptable EQ True$ then
                // The resource will have been put into the POST string.
                Body    = HTTP_Services('GetHTTPPostString')
                If Body NE '' then
                    // The POST string will have been encoded so use percent (URL) decoding.
                    ScanJSON = HTTP_Services('DecodePercentString', Body)
                    Scan_Services('AcceptScan', ScanID, ScanJSON)
                                            
                    If Error_Services('NoError') then
                        StatusCode  = 200
                        GoSub CreateHALItem
                        Mona_Services('SendStatus', MonaResource, MetricName, 'OK')
                    end else
                        Message = Error_Services('GetMessage')
                        HTTP_Services('SetResponseStatus', 500, Message)
                        Mona_Services('SendStatus', MonaResource, MetricName, 'CRITICAL')
                    end
                    
                    SRP_JSON(hBody, 'Release')               
                end else
                    HTTP_Services('SetResponseStatus', 400, 'JSON object is missing from the request.')
                    Mona_Services('SendStatus', MonaResource, MetricName, 'WARNING')
                end
            end else
                ScanNotAcceptableReason = SRP_JSON(objResource, 'GetValue', 'scan.notAcceptableReason')
                Error_Services('Add', ScanNotAcceptableReason)
            end
            SRP_JSON(objResource, 'Release')
        end else
            Message = 'Unable to parse the JSON scan resource.'
            HTTP_Services('SetResponseStatus', 400, Message)
            Mona_Services('SendStatus', MonaResource, MetricName, 'WARNING')
        end
    end else
        Message = Error_Services('GetMessage')
        HTTP_Services('SetResponseStatus', 404, Message)
        Mona_Services('SendStatus', MonaResource, MetricName, 'WARNING')
    end
    
    EndTick = GetTickCount()
    Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
    
    SRP_Stopwatch('Stop', 'SCAN_ID_PATCH_RESPONSE_TIME')
    TotalPatchResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_PATCH_RESPONSE_TIME')
    LogData    = ''
    LogData<1> = LoggingDTM;//Defined at entry of subroutine
    LogData<2> = 'SCAN.ID.PATCH'
    LogData<3> = TotalPatchResponseTime
    LogData<4> = ScanID
    LogData<5> = ''
    ResponseStatusCode = ''
    If Assigned(StatusCode) then
        ResponseStatusCode = StatusCode
    end
    LogData<6> = ResponseStatusCode
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end api


API scan.ID.PUT
    StartTick = GetTickCount()
    MetricName = 'SCAN_ID_PUT'
    
    SRP_Stopwatch('Reset')
    SRP_Stopwatch('Start', 'SCAN_ID_PUT_RESPONSE_TIME')
    ScanID  = EndpointSegment

    // The resource will have been put into the POST string.
    Body    = HTTP_Services('GetHTTPPostString')
    If Body NE '' then
        // The POST string will have been encoded so use percent (URL) decoding.
        Body            = HTTP_Services('DecodePercentString', Body)
        ParseResponse   = SRP_JSON(hBody, 'PARSE', Body)
        If (ParseResponse EQ '') then
            ScanRow                     = Database_Services('ReadDataRow', 'SCANS', ScanID)
            If Error_Services('NoError') then
                // Existing scan resource is being replaced.
                StatusCode  = 200
            end else
                // Scan resource is being created for the first time.
                StatusCode  = 201
            end
            If ScanRow<SCANS.CREATED_DATE$> EQ '' then ScanRow<SCANS.CREATED_DATE$> = Date()
            If ScanRow<SCANS.CREATED_TIME$> EQ '' then ScanRow<SCANS.CREATED_TIME$> = Time()
            ScanRow<SCANS.EMPLOYEE_ID$>     = SRP_JSON(hBody, 'GetValue', 'employeeID', '')
            ScanRow<SCANS.TOOL_ID$>         = SRP_JSON(hBody, 'GetValue', 'toolID', '')
            ScanRow<SCANS.CASSETTE_IDS$>    = SRP_JSON(hBody, 'GetValue', 'cassetteID', '')
            Accept                          = SRP_JSON(hBody, 'GetValue', 'accept', False$)
            If Accept EQ True$ then
                // Before allowing the accept field to be set to True, verify that all required data has been populated.
                Begin Case
                    Case ScanRow<SCANS.EMPLOYEE_ID$> EQ ''  ; Accept = False$
                    Case ScanRow<SCANS.TOOL_ID$> EQ ''      ; Accept = False$
                    Case ScanRow<SCANS.CASSETTE_IDS$> EQ '' ; Accept = False$
                End Case
            end
            ScanRow<SCANS.ACCEPTED$>    = Accept
            If ScanRow<SCANS.ACCEPTED$> EQ True$ then
                ScanRow<SCANS.ACCEPTED_DATE$>   = Date()
                ScanRow<SCANS.ACCEPTED_TIME$>   = Time()
            end
            Database_Services('WriteDataRow', 'SCANS', ScanID, ScanRow, True$, False$, True$)
            If Error_Services('NoError') then
                GoSub CreateHALItem
                Mona_Services('SendStatus', MonaResource, MetricName, 'OK')
            end else
                Message = Error_Services('GetMessage')
                HTTP_Services('SetResponseStatus', 500, Message)
                Mona_Services('SendStatus', MonaResource, MetricName, 'CRITICAL')
            end
            SRP_JSON(hBody, 'Release')
        end else
            HTTP_Services('SetResponseStatus', 400, 'Unable to parse the scanData JSON.')
            Mona_Services('SendStatus', MonaResource, MetricName, 'WARNING')
        end
    end else
        HTTP_Services('SetResponseStatus', 400, 'JSON object is missing from the request.')
        Mona_Services('SendStatus', MonaResource, MetricName, 'WARNING')
    end
    
    EndTick = GetTickCount()
    Mona_Services('QueueLatencyAndCountMetrics', MonaResource, MetricName, StartTick, EndTick)
    
    SRP_Stopwatch('Stop', 'SCAN_ID_PUT_RESPONSE_TIME')
    TotalPutResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_PUT_RESPONSE_TIME')
    LogData    = ''
    LogData<1> = LoggingDTM;//Defined at entry of subroutine
    LogData<2> = 'SCAN.ID.PUT'
    LogData<3> = TotalPutResponseTime
    LogData<4> = ScanID
    LogData<5> = ''
    ResponseStatusCode = ''
    If Assigned(StatusCode) then
        ResponseStatusCode = StatusCode
    end
    LogData<6> = ResponseStatusCode
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$)
end api


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Internal GoSubs
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//----------------------------------------------------------------------------------------------------------------------
// CreateHALItem
//
// Creates a HAL+JSON object based on the OpenInsight data row representation of the scan.
//----------------------------------------------------------------------------------------------------------------------
CreateHALItem:
    
    jsonScan = Scan_Services('ConvertMVScanToJSON', ScanID, '', FullEndpointURL)

    If Error_Services('NoError') then
        If SRP_JSON(objResource, 'Parse', jsonScan) EQ '' then
            lastModified    = SRP_JSON(objResource, 'GetValue', 'lastModified')
        end else
            lastModified    = ''
        end
        SRP_JSON(objResource, 'Release')
        HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL)
        HTTP_Services('SetResponseHeaderField', 'Last-Modified', lastModified)
        HTTP_Services('SetResponseBody', jsonScan, False$, 'application/hal+json')
        If Assigned(Message) then
            HTTP_Services('SetResponseStatus', StatusCode, Message)
        end else
            HTTP_Services('SetResponseStatus', StatusCode)
        end
    end else
        Message = Error_Services('GetMessage')          
        HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message)
    end

return

