Function Wafer_Counter_Services(@Service, @Params)
/***********************************************************************************************************************

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

    Description :   Handler program for all module related services.

    Notes       :   The generic parameters should contain all the necessary information to process the services. Often
                    this will be information like the data Record and Key ID.

    Parameters  :
        Service         [in] -- Name of the service being requested
        Param1-10   [in/out] -- Additional request parameter holders
        Response       [out] -- Response to be sent back to the Controller (MCP) or requesting procedure

    Metadata    :

    History     :   (Date, Initials, Notes)
        09/26/23    djs     Adapted from FlatFinder_Services.

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

#pragma precomp SRP_PreCompiler

$Insert LOGICAL
$Insert SERVICE_SETUP
$Insert RDS_EQUATES
$Insert WO_LOG_EQUATES
$Insert WM_OUT_EQUATES
$Insert RLIST_EQUATES
$Insert WAFER_COUNTER_EQUATES
$Insert TOOL_EQUATES
$Insert TOOL_LOG_EQUATES
$Insert LOT_OPERATION_EQUATES
$Insert LOT_EQUATES

Equ Tab$       to \09\
Equ CRLF$      to \0D0A\
Equ LF$        to \0A\
Equ Comma$     to ','
* Reduce Modes
Equ new_exist$ To 0 
Equ next_cur$  To 1
Equ add_exist$ to 2

Declare subroutine  Error_Services, Database_Services, Logging_Services, Httpclient_Services, Reduce, SRP_JSON
Declare subroutine Wafer_Counter_Services, Lot_Event_Services
Declare function    Database_Services, Environment_Services, Logging_Services, Httpclient_Services, OConv
Declare function    RTI_CreateGuid, SRP_JSON, WO_Mat_Services, WM_Out_Services, Wafer_Counter_Services, Datetime

LogPath     = Environment_Services('GetApplicationRootPath') : '\LogFiles\WaferCounter'
LogDate     = Oconv(Date(), 'D4/')
LogTime     = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Wafer Counter Import Log.csv'
Headers     = 'Logging DTM':@FM:'ToolID':@FM:'Operation':@FM:'Datetime':@FM:'LotID':@FM:'CassNo':@FM:'Wafer Count':@FM:'Import Result'
objLog      = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$)
LoggingDTM  = LogDate : ' ' : LogTime   ; // Logging DTM

GoToService else
    Error_Services('Set', Service : ' is not a valid service request within the ' : ServiceModule : ' services module.')
end

Return Response else ''

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Service Parameter Options
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Options BOOLEAN     = True$, False$
Options WAFER_SIZES = '6INCH', '8INCH'
Options LOCATIONS   = 'MU', 'QA', 'EPR-EAST', 'EPR-WEST' 


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Services
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//----------------------------------------------------------------------------------------------------------------------
// ImportWaferCounterFiles
//
// Looks for available wafer counter CSV files that are ready to be imported into the RDS table.
//----------------------------------------------------------------------------------------------------------------------
Service ImportWaferCounterFiles()
    
    hSysLists   = Database_Services('GetTableHandle', 'SYSLISTS')
    Lock hSysLists, ServiceKeyID then
        DataPath    = Environment_Services('GetApplicationRootPath') : '\WaferCounter\'
        BackupPath  = Environment_Services('GetApplicationRootPath') : '\WaferCounter\BackupFiles\'
        InitDir DataPath : '*.csv'
        FileList    = DirList()
        For Each File in FileList using @FM
            OSRead WaferCounterData from DataPath : File then
                BackupDate      = Oconv(Date(), 'D4/')
                BackupTime      = Oconv(Time(), 'MTS')
                Convert ':' to '-' in BackupTime
                BackupFileName  = BackupDate[7, 4] : '-' : BackupDate[1, 2] : '-' : BackupDate[4, 2] : '-' : BackupTime : ' ' : File
                If Count(File, '-') LE 1 then
                    OSWrite WaferCounterData to BackupPath : BackupFileName
                end
                Swap CRLF$ with '' in WaferCounterData
                Swap ',' with @FM in WaferCounterData
                ToolID         = Trim(WaferCounterData<2>)
                Operation      = Trim(WaferCounterData<3>)
                Datetime       = IConv(Trim(WaferCounterData<4>), 'DT')
                ReferenceKeyID = Trim(WaferCounterData<5>)
                CassetteNo     = Trim(WaferCounterData<6>)
                WaferCount     = Trim(WaferCounterData<7>)
                
                Result     = False$
                LogData    = LoggingDTM
                LogData<2> = ToolID
                LogData<3> = Operation
                LogData<4> = Trim(WaferCounterData<4>)
                LogData<5> = ReferenceKeyID
                LogData<6> = CassetteNo
                LogData<7> = WaferCount
                
                If ReferenceKeyID[1, 2] EQ '1T' or ReferenceKeyID[1, 1] EQ 'O' then
                    Convert 'O' to '' in ReferenceKeyID
                    Swap '1T' with '' in ReferenceKeyID                      
                    If Index(ReferenceKeyID, '.', 1) then
                        // A dot means this is a WorkOrderNo.Cassette value. Need to create a WM_OUT Key ID.
                        WorkOrderNo = ReferenceKeyID[1, '.']
                        WOStepKeyID = ReferenceKeyID[Col2() + 1, '.']
                        CassetteNo  = ReferenceKeyID[Col2() + 1, '.']
                        WMOutKeyID  = WorkOrderNo : '*' : WOStepKeyID : '*' : CassetteNo
                        WMOutRow    = Database_Services('ReadDataRow', 'WM_OUT', WMOutKeyID)
                        If Error_Services('NoError') then
                            WMOutRow<WM_OUT_WAFER_COUNTER_DTM$> = DateTime
                            WMOutRow<WM_OUT_WAFER_COUNTER_QTY$> = WaferCount
                            Database_Services('WriteDataRow', 'WM_OUT', WMOutKeyID, WMOutRow, True$, False$, True$)
                        end
                    end else
                        // No dot in the reference key means this is an RDS Key ID.
                        Transfer ReferenceKeyID to RDSKeyID
                        If Num(RDSKeyID) then RDSKeyID = RDSKeyID + 0
                        RDSRow      = Database_Services('ReadDataRow', 'RDS', RDSKeyID)
                        If Error_Services('NoError') then
                            RDSRow<RDS_WAFER_COUNTER_DTM$> = DateTime
                            RDSRow<RDS_WAFER_COUNTER_QTY$> = WaferCount
                            Database_Services('WriteDataRow', 'RDS', RDSKeyID, RDSRow, True$, False$, True$)
                        end
                    end
                    If Error_Services('NoError') then
                        Result = 'Success'
                    end else
                        Result = 'Failure: ':Error_Services('GetMessage')
                    end
                end else
                    // Throw error - either invalid barcode scanned or user manually entered data
                    Result = 'Failure: ReferenceKeyID "':ReferenceKeyID:'" is invalid.'
                end
                
                LogData<8> = Result
                Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
                
                OSDelete DataPath : File
            end
        Next File
        
        Unlock hSysLists, ServiceKeyID else Null
    end
    
end service


Service ConvertWaferData(FileData)
    
    ErrorMsg   = ''
    WaferArray = ''
    If FileData NE '' then
        Swap CRLF$ with @FM in FileData
        WaferTotal = FileData<1>
        WaferData  = FileData<2>
        If ( (Len(WaferTotal) EQ 3) and (WaferTotal[1, 1] EQ 'T') and (Len(WaferData) EQ 8 ) and (WaferData[1, 1] EQ 'P') )  then
            Convert 'T' to '' in WaferTotal
            WaferArray = ''
            For CharIndex = 2 to 8
                Val         = IConv(WaferData[CharIndex, 1], 'MX')
                Val         = OConv(Val, 'MB')
                If CharIndex GT 2 then Val = Fmt(Val, 'R(0)#4')
                WaferArray := Val
            Next CharIndex
            
            If (Len(WaferArray) NE 25) then
                ErrorMsg = 'Error in ':Service:' service. Invalid wafer array length.'
            end else
                // Reverse the array so it is in order from slot 1 to 25
                WaferArray = WaferArray[-1, -25]
                // Return @VM delimited array for ease of use in OI BASIC+
                DelimArray = ''
                For CharIndex = 1 to 25
                    DelimArray<0, CharIndex> = WaferArray[CharIndex, 1]
                Next CharIndex
                If (Sum(DelimArray) EQ WaferTotal) then
                    Response = DelimArray
                end else
                    ErrorMsg = 'Error in ':Service:' service. Wafer total does not match array total.'
                end
            end
            
        end else
            ErrorMsg = 'Error in ':Service:' service. Invalid data format passed in FileData variable.'
        end
    end else
        ErrorMsg = 'Error in ':Service:' service. Null FileData passed into service.'
    end
    If ErrorMsg NE '' then
        Error_Services('Add', ErrorMsg)
    end
    
end service


Service GetWaferCounterJSON(WaferSize, ToolLocation, CassID)
    
    If ( (WaferSize NE '') and (ToolLocation NE '') and (CassID NE '') ) then 
        URL      = 'https://oi-metrology-viewer-prod.mes.infineon.com:4438/api/v1/WaferCounter/{waferSize}/last-quantity-and-slot-map/?area={area}&text={cassID}'
        Swap '{waferSize}' with WaferSize in URL
        Swap '{area}' with ToolLocation in URL
        Swap '{cassID}' with CassID in URL
        // Set timeout to 24 seconds. This value was decided upon with Mike Phares to allow time
        // for EAF to receive the new wafer counter file from the tool and serve it up.
        Httpclient_Services('SetTimeoutDuration', 24) 
        Response = Httpclient_Services('SendHTTPRequest', 'GET', URL, '', '', '', '', False$, False$, '')
        If Error_Services('NoError') then
            StatusCode = Httpclient_Services('GetResponseStatusCode')
            If StatusCode NE 200 then
                Begin Case
                    Case Response EQ ''
                        ErrorMsg = 'Unexpected server error.'
                    Case Response EQ 'No files!'
                        ErrorMsg = 'No data. Please re-seat cassette and try again.'
                    Case Otherwise$
                        // Use message in response body to populate error services
                        ErrorMsg = Response
                End Case
                Error_Services('Add', ErrorMsg)
            end
        end
    end
    
end service


Service AddScan(LotID, ScanQty, ScanDtm, ScanTool, ScanUser, ScanLocation, WaferMap)
    
    KeyID                                = RTI_CreateGuid()
    Record                               = ''
    Record<WAFER_COUNTER.LOT_ID$>        = LotID
    Record<WAFER_COUNTER.SCAN_QTY$>      = ScanQty
    If Not(Num(ScanDtm)) then
        ScanYear  = ScanDtm[1, 'F-']
        ScanMonth = ScanDtm[Col2() + 1, 'F-']
        ScanDay   = ScanDtm[Col2() + 1, 'F ']
        ScanTime  = ScanDtm[Col2() + 1, 999]
        Convert ' ' to '' in ScanTime
        ScanDtm   = ScanMonth:'/':ScanDay:'/':ScanYear:' ':ScanTime
        ScanDtm   = IConv(ScanDtm, 'DT')
    end
    Record<WAFER_COUNTER.SCAN_DTM$>       = ScanDtm
    Record<WAFER_COUNTER.SCAN_TOOL$>      = ScanTool
    Record<WAFER_COUNTER.SCAN_USER$>      = ScanUser
    If ScanLocation EQ 'FQA' then ScanLocation = 'QA'
    Record<WAFER_COUNTER.SCAN_LOCATION$>  = ScanLocation
    Record<WAFER_COUNTER.SCAN_WAFER_MAP$> = WaferMap
    Database_Services('WriteDataRow', 'WAFER_COUNTER', KeyID, Record)
    
    Response = KeyId
    
end service


Service GetLastScan(LotID, ScanLocation=LOCATIONS)
    
    ErrorMsg = ''
    WCRec    = ''
    If LotID NE '' then 
        Tablename = "WAFER_COUNTER"
        Flag      = ""
        Done      = False$
        CursorVar = ""
        
        GoSub ClearCursors
        
        SortList     = "#SCAN_DTM"
        ReduceScript = 'WITH {LOT_ID} EQ ':Quote(LotID)
        If ScanLocation NE '' then
            ReduceScript := ' AND WITH {SCAN_LOCATION} EQ ':Quote(ScanLocation)
        end
        Mode         = NEXT_CUR$
        
        Reduce(ReduceScript, SortList, Mode, Tablename, Cursorvar, Flag)
        If Flag then
            Select Tablename By SortList Using Cursorvar then
                Open Tablename To hTable then
                    KeyID = ''
                    Loop
                        ReadNext KeyID Using Cursorvar By AT Else Done = TRUE$
                        If KeyID NE '' then
                            Done = True$
                            Read WCRec from hTable, KeyID then
                                WCRec<WAFER_COUNTER.SCAN_DTM$> = OConv(WCRec<WAFER_COUNTER.SCAN_DTM$>, 'DT/^2H')
                            end else
                                ErrorMsg = 'Error in ':Service:' service. Error reading ':KeyID:' from ':Tablename:' table.'
                            end
                        end
                    Until Done or (KeyID NE '')
                    Repeat
                End Else
                    ErrorMsg = 'Error in ':Service:' service. Error in opening ':Tablename:'.'
                End
            End Else
                ErrorMsg = 'Error in ':Service:' service. Error in selecting ':Tablename:'.'
            end
        End Else
            ErrorMsg = 'Error in ':Service:' service. Error in Reduce call.'
        End
    end else
        ErrorMsg = 'Error in ':Service:' service. Null LotID passed into service.'
    end
    
    If ErrorMsg NE '' then
        Error_Services('Add', ErrorMsg)
    end 
    
    Response = WCRec
    
end service


Service GetProdWaferCounter(WaferSize=WAFER_SIZES, Location=LOCATIONS)
    
    ToolID   = ''
    ErrorMsg = ''
    If ( (WaferSize NE '') and (Location NE '') ) then
        Query   = "SELECT TOOL WITH @ID CONTAINING 'WC":WaferSize:"' AND WITH TOOL_LOC EQ '":Location:"' AND WITH CURR_MODE EQ 'PROD'"
        GoSub ClearCursors
        RList(Query, TARGET_ACTIVELIST$, '', '', '')
        ErrCode = ''
        If Not(Get_Status(ErrCode)) then
            Begin Case
                Case @RecCount EQ 0
                    ErrorMsg = 'Error in ':Service:' service. No production wafer counter found!'
                Case @RecCount EQ 1
                    ReadNext ToolID else
                        ErrorMsg = 'Error in ':Service:' service. Error reading production wafer counter tool ID!'
                    end
                Case @RecCount GT 1
                    ErrorMsg = 'Error in ':Service:' service. More than one production wafer counter found!'
            End Case
            GoSub ClearCursors
        end else
            ErrorMsg = 'Error in ':Service:' service. Error calling RList. Error code: ':ErrCode:'.'
        end
    end else
        ErrorMsg = 'Error in ':Service:' service. Null WaferSize or Location passed into service.'
    end
    If ErrorMsg NE '' then
        Error_Services('Add', ErrorMsg)
    end
    Response = ToolID
    
end service


Service GetWaferCounterToolID(WaferSize=WAFER_SIZES, Location=LOCATIONS)
    
    ToolID   = ''
    ErrorMsg = ''
    If ( (WaferSize NE '') and (Location NE '') ) then
        Query   = "SELECT TOOL WITH @ID CONTAINING 'WC":WaferSize:"' AND WITH TOOL_LOC EQ '":Location:"'"
        GoSub ClearCursors
        RList(Query, TARGET_ACTIVELIST$, '', '', '')
        ErrCode = ''
        If Not(Get_Status(ErrCode)) then
            Begin Case
                Case @RecCount EQ 0
                    ErrorMsg = 'Error in ':Service:' service. No wafer counter tool found for ':WaferSize:' ':Location:'.'
                Case @RecCount EQ 1
                    ReadNext ToolID else
                        ErrorMsg = 'Error in ':Service:' service. Error reading wafer counter tool ID!'
                    end
                Case @RecCount GT 1
                    ErrorMsg = 'Error in ':Service:' service. More than one wafer counter tool found for ':WaferSize:' ':Location:'.'
            End Case
            GoSub ClearCursors
        end else
            ErrorMsg = 'Error in ':Service:' service. Error calling RList. Error code: ':ErrCode:'.'
        end
    end else
        ErrorMsg = 'Error in ':Service:' service. Null WaferSize or Location passed into service.'
    end
    If ErrorMsg NE '' then
        Error_Services('Add', ErrorMsg)
    end
    Response = ToolID
    
end service

//----------------------------------------------------------------------------------------------------------------------
// ProcessCass2DBarcode
//
// Takes in the raw barcode data for a 2D Cassette label. Returns a single field array with 3 field delimited by @VM
// CassId, Expected Qty, and Cass Type
//----------------------------------------------------------------------------------------------------------------------
Service ProcessCass2DBarcode(BarcodeText)
    
    ErrorMessage = ''
    ExpectedSlotWaferMap = ''
    ExpectedQty = ''
    CassId = ''
    CassType = ''
    If BarcodeText NE '' then
        DelimCnt      = DCount(BarcodeText, '|')
        If DelimCnt EQ 8 then
            CassId = Field(BarcodeText, '|', 3)
            If CassId NE '' then
                If CassId[1, 2] EQ '1T' then
                    CassId[1, 2] = ''
                    Begin Case
                        Case CassId[1, 1] EQ 'O'
                            CassId[1, 1] = ''
                            CassType = 'WM_OUT'
                        Case (CassId[1, 1] EQ 'I')
                            CassId[1, 1] = ''
                            CassType = 'WM_IN'
                        Case Otherwise$
                            CassType = 'RDS'
                    End Case
                    Convert '.' to '*' in CassId
                    Begin Case
                        Case RowExists('RDS', CassId)
                            ExpectedQty = Xlate('RDS', CassId, 'WFRS_OUT', 'X')
                        Case RowExists('WM_OUT', CassId)
                            ExpectedQty = Xlate('WM_OUT', CassId, 'WAFER_CNT', 'X')
                    End Case
                end                    
                
            end else
                ErrorMessage = 'Invalid Lot Label Scan. Unable to determine Cass Id'
            end
        end else
            ErrorMessage = 'Invalid Lot Label Scan.'
        end
    end else
        ErrorMessage = 'Scan data was null.'
    end
    
    If ErrorMessage EQ '' then
        Response = CassId : @VM: ExpectedQty : @VM : CassType
    end else
        Error_Services('Add', ErrorMessage) 
    end
    
end service

//----------------------------------------------------------------------------------------------------------------------
// ProcessTool2DBarcode
//
// Takes in the raw barcode data for a wafer counter label, Cassette Id, Cassette Type, and UserId(Optional)
// Returns a key ID for a completed WAFER_COUNTER record.
//----------------------------------------------------------------------------------------------------------------------
Service ProcessTool2DBarcode(BarcodeText, CassId, CassType, UserId)
    
    ErrorMessage = ''
    
    If BarcodeText NE '' then
        DelimCnt      = DCount(BarcodeText, '|')
        If DelimCnt EQ 2 then
            WaferSize   = Field(BarcodeText, '|', 1)
            Area        = Field(BarcodeText, '|', 2)
            If Environment_Services('IsProd') then
                WcJson      = Wafer_Counter_Services('GetWaferCounterJSON', WaferSize, Area, CassID) 
            end else
                WcJson      = Wafer_Counter_Services('GetWaferCounterJSONTestData', WaferSize, Area, CassID) 
            end
            
            If Error_Services('NoError') then
                objJSON = ''
                If SRP_JSON(objJSON, 'Parse', WcJson) EQ '' then
                    ScanDtm          = SRP_JSON(objJSON, 'GetValue', 'dateTimeFormatted')
                    ToolID           = SRP_JSON(objJSON, 'GetValue', 'equipmentId')
                    WaferCount       = SRP_JSON(objJSON, 'GetValue', 'total')
                    SlotMap          = SRP_JSON(objJSON, 'GetValue', 'slotMap')
                    SRP_JSON(objJSON, 'Release')
                    ToolCurrModeKey = Database_Services('ReadDataColumn', 'TOOL', ToolId, TOOL_CURR_MODE_KEY$, True$, 0, False$)
                    ToolCurrMode = Database_Services('ReadDataColumn', 'TOOL_LOG', ToolCurrModeKey, TOOL_LOG_TOOL_MODE$, True$, 0, False$)
                    If ToolCurrMode EQ 'PROD' OR ToolCurrMode EQ 'LIM' then
                        WaferCounterId = Wafer_Counter_Services('AddScan', CassID, WaferCount, ScanDtm, ToolID, UserId, Area, SlotMap)
                        If Error_Services('NoError') then
                            Lot_Event_Services('CreateLotEvent', CassId, ScanDtm, 'WAFER_COUNTER', 'Wafer counter data received for lot. ' : WaferCount : ' wafers found.', ToolId, UserId, True$, CassType)
                        end
                    end else
                        ErrorMessage = 'Wafer counter is currently down and cannot be used to log wafer counts.'
                    end
                end else
                    ErrorMessage = 'Error parsing response from wafer counter.'
                end
            end else
                ErrorMessage = Error_Services('GetMessage')
            end
        end else
            ErrorMessage = 'Invalid tool scan.'    
        end
    end else
        ErrorMessage = 'Scan data was null.' 
    end
    
    If ErrorMessage EQ '' then
        Response = WaferCounterId
    end else
        Error_Services('Add', ErrorMessage) 
    end
    
end service

//----------------------------------------------------------------------------------------------------------------------
// GetWaferCounterJSONTestData
//
// Emulates GetWaferCounterJson service. 
//----------------------------------------------------------------------------------------------------------------------
Service GetWaferCounterJSONTestData(WaferSize, ToolLocation, CassID)
    
    If ( (WaferSize NE '') and (ToolLocation NE '') and (CassID NE '') ) then 
        Response = ''
        objJson = ''
        If SRP_JSON(objJson, 'New', 'Object') then
            SRP_JSON(objJson, 'SetValue', 'dateTimeFormatted', Datetime(), 'String')
            SRP_JSON(objJson, 'SetValue', 'equipmentId', 'WC8INCH1', 'String')
            SRP_JSON(objJson, 'SetValue', 'total', 24, 'Number')
            SRP_JSON(objJson, 'SetValue', 'slotMap', '1111111110111111111111111', 'String') 
            Response = SRP_Json(objJson, 'Stringify', 'Styled')
            SRP_JSON(objJSON, 'Release')
        end
        
        If Error_Services('NoError') then
            StatusCode = 200
            If StatusCode NE 200 then
                Begin Case
                    Case Response EQ ''
                        ErrorMsg = 'Unexpected server error.'
                    Case Response EQ 'No files!'
                        ErrorMsg = 'No data. Please re-seat cassette and try again.'
                    Case Otherwise$
                        // Use message in response body to populate error services
                        ErrorMsg = Response
                End Case
                Error_Services('Add', ErrorMsg)
            end
        end
    end
    
end service

Service ConvertWaferCounterRecToJson(WaferCounterId)
    
    ErrorMessage = ''
    If WaferCounterId NE '' then
        WaferCounterRec = Database_Services('ReadDataRow', 'WAFER_COUNTER', WaferCounterId, True$, 0, False$)
        If Error_Services('NoError') then
            //Fields within wafer counter rec
            CassId = WaferCounterRec<WAFER_COUNTER.LOT_ID$>
            swap '.' with '*' in CassId
            WaferCount = WaferCounterRec<WAFER_COUNTER.SCAN_QTY$>
            ScanDtm = WaferCounterRec<WAFER_COUNTER.SCAN_DTM$>
            ToolID = WaferCounterRec<WAFER_COUNTER.SCAN_TOOL$>
            WaferMapData = WaferCounterRec<WAFER_COUNTER.SCAN_WAFER_MAP$>
            swap 1 with 1:@FM in WaferMapData
            swap 0 with 0:@FM in WaferMapData
            
            ActualWaferArray = ''
            for i = 25 to 1 step -1
                Slot = i
                WaferPresent = WaferMapData<i>
                ActualWaferArray<-1, 1> = Slot : @VM : WaferPresent
            Next i
            //Fields calculated at runtime.
            CassType = ''
            WONo = ''
            CassNo = ''
            ExpectedQty = ''
            Begin Case
                Case RowExists('RDS', CassId)
                    CassType = 'RDS'
                    WONo = XLATE('RDS', CassId, 'WO', 'X')
                    CassNo = XLATE('RDS', CassId, 'CASS_NO', 'X')
                    ExpectedQty = Xlate('RDS', CassId, 'WFRS_OUT', 'X')
                Case RowExists('WM_OUT', CassId) OR RowExists('WM_IN', CassId)
                    CassType = 'WM_OUT'
                    WONo = Field(CassId, '*', 1)
                    CassNo = Field(CassId, '*', 3)
                    ExpectedQty = Xlate('WM_OUT', CassId, 'WAFER_CNT', 'X')
            End Case
            WoMatKey = WONo : '*' : CassNo
            
            ExpectedWaferData = Wo_Mat_Services('GetWaferMap', WoMatKey)
            ExpectedWaferArray = ''
            for i = 25 to 1 step -1
                Slot = i
                WaferPresent = ExpectedWaferData<1, i>
                ExpectedWaferArray<-1, 1> = Slot : @VM : WaferPresent
            Next i
            
            //Constructing the JSON Object
            objJson = ''
            If SRP_Json(objJson, 'New', 'Object') then
                SRP_Json(objJson, 'SetValue', 'WaferCounterId', WaferCounterId, 'String')
                SRP_Json(objJson, 'SetValue', 'CassId', CassId, 'String')
                SRP_Json(objJson, 'SetValue', 'CassType', CassType, 'String')
                SRP_Json(objJson, 'SetValue', 'ExpectedQty', ExpectedQty, 'Number')
                SRP_Json(objJson, 'SetValue', 'ScanDtm', OConv(ScanDtm, 'DT4/'), 'String')
                SRP_Json(objJson, 'SetValue', 'ToolId', ToolId, 'String')
                SRP_Json(objJson, 'SetValue', 'WaferCount', WaferCount, 'Number')
                
                //Wafer Counter Slot Array
                objWaferCounterSlotArray = ''
                IF SRP_Json(objWaferCounterSlotArray, 'New', 'Array') then
                    For each Slot in ActualWaferArray using @FM
                        SlotNo = Slot<1, 1>
                        WaferPresent = Slot<1, 2>
                        //Create the individiual slot object
                        objSlot = ''
                        If SRP_Json(objSlot, 'New', 'Object') then
                            SRP_Json(objSlot, 'SetValue', 'SlotNo', SlotNo, 'Number')
                            SRP_Json(objSlot, 'SetValue', 'WaferPresent', WaferPresent, 'Boolean')
                            SRP_Json(objWaferCounterSlotArray, 'Add', objSlot)
                            SRP_Json(objSlot, 'Release')
                        end
                    Next Slot
                    SRP_Json(objJson, 'Set', 'WaferArray', objWaferCounterSlotArray)
                    SRP_Json(objWaferCounterSlotArray, 'Release')
                end
                
                //OpenInsight Expected Slot Array
                objOISlotArray = ''
                IF SRP_Json(objOISlotArray, 'New', 'Array') then
                    For each Slot in ExpectedWaferArray using @FM
                        SlotNo = Slot<1, 1>
                        WaferPresent = Slot<1, 2>
                        //Create the individiual slot object
                        objSlot = ''
                        If SRP_Json(objSlot, 'New', 'Object') then
                            SRP_Json(objSlot, 'SetValue', 'SlotNo', SlotNo, 'Number')
                            SRP_Json(objSlot, 'SetValue', 'WaferPresent', WaferPresent, 'Boolean')
                            SRP_Json(objOISlotArray, 'Add', objSlot)
                            SRP_Json(objSlot, 'Release')
                        end
                    Next slot
                    SRP_Json(objJson, 'Set', 'ExpectedWaferArray', objOISlotArray)
                    SRP_Json(objWaferCounterSlotArray, 'Release')
                    
                    
                end
                Response = SRP_Json(objJson, 'Stringify', 'Styled')
                SRP_Json(objJson, 'Release')
            end else
                ErrorMessage = 'Error initializing JSON object'
            end
        end else
            ErrorMessage = 'Error reading wafer counter record. ' : Error_Services('GetMessage')
        end
    end else
        ErrorMessage = 'Wafer counter id was null.'
    end
    
    If ErrorMessage NE '' then
        Error_Services('Add', ErrorMessage)
    end
    
end service

Service AssociateWaferCounter(LotOperationId, WaferCounterId, UserId)
    
    ErrorMessage = ''

    If RowExists('LSL_USERS', UserId) then
        If RowExists('LOT_OPERATION', LotOperationId) then
            If RowExists('WAFER_COUNTER', WaferCounterId) then
                WaferCounterRec = Database_Services('ReadDataRow', 'WAFER_COUNTER', WaferCounterId, True$, 0, False$)
                If Error_Services('NoError') then
                    WaferCounterToolId = WaferCounterRec<WAFER_COUNTER.SCAN_TOOL$>
                    ThisLotOpRec = Database_Services('ReadDataRow', 'LOT_OPERATION', LotOperationId, True$, 0, False$)
                    If Error_Services('NoError') then
                        LotId = ThisLotOpRec<LOT_OPERATION_LOT_ID$>
                        If RowExists('LOT', LotId) then
                            ThisWaferCountCassId = WaferCounterRec<WAFER_COUNTER.LOT_ID$>
                            ThisLotId = ThisLotOpRec<LOT_OPERATION_LOT_ID$>
                            LegacyLotType = Xlate('LOT', ThisLotId, LOT_LEGACY_LOT_TYPE$, 'X')
                            LotIdToCompare = ''
                            If LegacyLotType NE '' then
                                LotIdToCompare = Xlate('LOT', ThisLotId, LOT_LEGACY_LOT_ID$, 'X')
                            end else
                                LotIdToCompare = ThisLotId
                            end
                            
                            If ThisWaferCountCassId EQ LotIdToCompare then
                                ThisLotOpRec<LOT_OPERATION_WAFER_COUNTER_ID$> = WaferCounterId
                                Database_Services('WriteDataRow', 'LOT_OPERATION', LotOperationId, ThisLotOpRec)
                                If Error_Services('NoError') then
                                    Lot_Event_Services('CreateLotEvent', LotId, Datetime(), 'LOG_WAFER_COUNT', 'Wafer Count logged.', WaferCounterToolId, UserId)
                                end
                            end else
                                ErrorMessage = 'Lot IDs do not match!'
                            end
                        end else
                            ErrorMessage = 'Lot not found.'
                        end
                    end else
                        ErrorMessage = Error_Services('GetMessage')
                    end 
                end else
                    ErrorMessage = Error_Services('GetMessage')
                end
            end else
                ErrorMessage = 'Wafer counter record not found.'
            end
        end else
            ErrorMessage = 'Lot Operation record not found.'
        end
    end else
        ErrorMessage = 'User ID not found.'
    end
    
    If ErrorMessage NE '' then
        Error_Services('Add', ErrorMessage)
    end
    
end service

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

ClearCursors:
    
    For counter = 0 to 8
        ClearSelect counter
    Next counter
    
return



