Function HTTP_Picture_Services(RemainingURL)
/***********************************************************************************************************************

    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        :   HTTP_Picture_Services

    Description :   Handler program for the HTTP Picture service module.

    Notes       :   All HTTP web services should include the HTTP_SERVICE_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).
                        SelfURL                 - The URL path representing the current service.
                        FullEndPointURL         - The URL submitted by the client. This can be the same or longer than
                                                  the SelfURL.
                        NextSegment             - The URL segment immediately following the SelfURL (if any). This
                                                  could contain the name of the next service or it could contain the
                                                  Item ID for the current service (aka resource).
                        CurrentServiceHandler   - The name of this stored procedure.

    Parameters  :
        RemainingURL    [in] -- The remaining portion of the URL that follows the URL that launched this current
                                service. This information is used in the HTTP_SERVICE_SETUP insert to populate other
                                useful variables (see Notes above).
        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)
        03/27/16    dmb     Original programmer. - [SRPFW-96]
        07/06/17    dmb     Refactor using Enhanced BASIC+ syntax. - [SRPFW-184]

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

#pragma precomp SRP_PreCompiler

$insert APP_INSERTS
$insert HTTP_SERVICE_SETUP
$insert HTTP_INSERTS
$insert CONTACTS_EQUATES

// Assume the current HTTP method is valid until proven otherwise.
ValidMethod     = True$
// Assume the current web service is valid until provent otherwise.
ValidService    = True$
// Assume no HTTP methods are valid until proven otherwise.
AllowedMethods  = ''
// A list of all services able to be called from this URL.
AllowedServices = ''

PictureFolder   = '\WebAppData\ContactPictures\'

// Handle the HTTP request as needed.
Begin Case
    Case RemainingURL _EQC ''
        // This means the URL ends with /contacts/{KeyID}/picture, which means this is the end point.
        AllowedMethods  = 'PUT,GET,OPTIONS'
        Locate HTTPMethod in AllowedMethods using ',' setting MethodPos then
            On MethodPos GoSub Put, Get, Options
        end else
            ValidMethod = False$
        end

    Case Otherwise$
        ValidService    = False$
End Case

// Resolve any invalid conditions with the HTTP request.
Begin Case
    Case Not(ValidService)
        HTTP_Services('SetResponseStatus', 404, NextSegment : ' is not a valid service request within the ' : CurrentServiceHandler : ' module.')

    Case Not(ValidMethod)
        HTTP_Services('SetResponseStatus', 405, HTTPMethod : ' is not valid for this service.')

        GoSub SetAllowedMethods
End Case

Return Response OR ''


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Service Parameter Options
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Options BOOLEAN                     = True$, False$


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Web Services
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//----------------------------------------------------------------------------------------------------------------------
// Put
//
// Attempts to update the picture resource at this URL end point.
//----------------------------------------------------------------------------------------------------------------------
Put:

    NumSegments     = DCount(SelfURL, '/')
    KeyID           = Field(SelfURL, '/', NumSegments - 1, 1)
    TableName       = 'CONTACTS'

    Open TableName to hTable then
        Lock hTable, KeyID then
            ResponseStatus  = 200       ; // Updating an existing resource.
            Read DataRow from hTable, KeyID else
                DataRow         = ''
                ResponseStatus  = 201   ; // Creating a new resource.
            end

            // A URI scheme of the Base64 encoded image will be in the Data variable.
            HTTPPostString  = HTTP_Services('GetHTTPPostString')
            HTTPPostString  = HTTP_Services('DecodePercentString', HTTPPostString)
            Scheme = HTTPPostString[1, 'F:']
            If Scheme _EQC 'data' then
                MediaType   = HTTPPostString[Col2() + 1, 'F;']                  ; // Should be "image/png" or "image/jpg"
                Encoding    = HTTPPostString[Col2() + 1, 'F,']                  ; // Should be "base64"
                EncodedData = HTTPPostString[Col2() + 1, Len(HTTPPostString)]   ; // Should be the actual Base64 encoded content.
                DecodedData = SRP_Decode(EncodedData, 'BASE64')
                FileType    = MediaType[-1, 'B/']
                FileName    = KeyID : '.' : FileType
                FilePath    = Drive() : PictureFolder : FileName
                Status()    = 0
                OSWrite DecodedData to FilePath
                StatusCode = Status()
                If StatusCode then
                    Begin Case
                        Case StatusCode EQ 1    ; Error = 'Bad OS filename. Code: ' : StatusCode
                        Case StatusCode EQ 2    ; Error = 'Access denied by operating system. Code: ' : StatusCode
                        Case StatusCode EQ 3    ; Error = 'Disk or directory full. Code: ' : StatusCode
                        Case StatusCode EQ 4    ; Error = 'File does not exist. Code: ' : StatusCode
                        Case StatusCode EQ 5    ; Error = 'Unknown error. Code: ' : StatusCode
                        Case StatusCode EQ 6    ; Error = 'Attempt to write to read-only file. Code: ' : StatusCode
                        Case Otherwise$         ; Error = 'Unknown error. Code: ' : StatusCode
                    End Case
                    HTTP_Services('SetResponseStatus', '501', Error)
                end else
                    DataRow<CONTACTS_PICTURE$>  = PictureFolder : FileName
                    Write DataRow to hTable, KeyID then
                        HTTP_Services('SetResponseStatus', ResponseStatus)
                        HTTP_Services('SetResponseHeaderField', 'Content-Location', SelfURL)
                    end else
                        HTTP_Services('SetResponseStatus', 500, 'Error writing ' : KeyID : ' to the ' : TableName : ' table.')
                    end
                end
            end else
                HTTP_Services('SetResponseStatus', '415')
            end
            Unlock hTable, KeyID else Null
        end else
            HTTP_Services('SetResponseStatus', 423, KeyID : ' is currently locked.')
        end
    end else
        HTTP_Services('SetResponseStatus', 500, 'Error opening the ' : TableName : ' table.')
    end

return


//----------------------------------------------------------------------------------------------------------------------
// Get
//
// Attempts to return the picture resource from this URL end point.
//----------------------------------------------------------------------------------------------------------------------
Get:

    // Get the picture's physical file path from the CONTACT database row.
    NumSegments     = DCount(SelfURL, '/')
    KeyID           = Field(SelfURL, '/', NumSegments - 1, 1)
    PicturePath     = Drive() : HTTP_Resource_Services('GetColumnValues', 'CONTACTS', 'picture', KeyID)

    If PicturePath NE '' then
        // Verify the picture actually exists.
        If Dir(PicturePath) NE '' then
            // Get the image extension.
            ImageExt    = PicturePath[-1, 'B.']
            If ImageExt _EQC 'jpg' then ImageExt = 'jpeg'
            // Get the best content type that matches the client's and server's ability.
            ContentType = HTTP_Services('GetBestContentNegotiation', 'Accept', 'text/plain' : @FM : 'image/' : ImageExt)
            If ContentType NE '' then
                OSRead PictureBinary from PicturePath then
                    Begin Case
                        Case ContentType _EQC 'text/plain'
                            PictureBody = SRP_Encode(PictureBinary, 'BASE64')
                            PictureBody = 'data:' : 'image/' : ImageExt : ';base64,' : PictureBody
                            HTTP_Services('SetResponseHeaderField', 'Content-Encoding', 'base64')
                            HTTP_Services('SetResponseBody', PictureBody, False$, 'text/plain')

                        Case ContentType[1, 6] _EQC 'image/'
                            HTTP_Services('SetResponseBody', PictureBinary, True$, ContentType)

                    End Case
                end
            end
        end else
            HTTP_Services('SetResponseStatus', '404', 'Picture for contact ' : KeyID : ' does not exist.')
        end
    end else
        HTTP_Services('SetResponseStatus', '404', 'Picture for contact ' : KeyID : ' does not exist.')
    end

return


//----------------------------------------------------------------------------------------------------------------------
// Options
//
// Sets the appropriate response header fields for an OPTIONS request.
//----------------------------------------------------------------------------------------------------------------------
Options:

    GoSub SetCommonOptionResponseHeaders

return


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

//----------------------------------------------------------------------------------------------------------------------
// SetCommonOptionResponseHeaders
//
// Sets the response headers that will be common for all OPTIONS methods.
//----------------------------------------------------------------------------------------------------------------------
SetCommonOptionResponseHeaders:

    HTTP_Services('SetResponseHeaderField', 'Access-Control-Allow-Headers', 'authorization', True$)
    HTTP_Services('SetResponseHeaderField', 'Access-Control-Allow-Headers', 'x-authorization', True$)
    HTTP_Services('SetResponseHeaderField', 'Access-Control-Max-Age', 1728000)

    GoSub SetAllowedMethods

return
//----------------------------------------------------------------------------------------------------------------------
// SetAllowedMethods
//
// Sets the Allow response header field as appropriate for the requested URL.
//----------------------------------------------------------------------------------------------------------------------
SetAllowedMethods:

    If AllowedMethods NE '' then
        For Each Method in AllowedMethods using ','
            HTTP_Services('SetResponseHeaderField', 'Allow', Method, True$)
        Next Method
    end

return
