Compile function Tool_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        :   Tool_Services

    Description :   Handler program for all Tool services.

    Notes       :   Application errors should be logged using the Error Services module. There are a few methodological
                    assumptions built into way errors are managed which are important to understand in order to properly
                    work with Error Services:

    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

    History     :   (Date, Initials, Notes)


***********************************************************************************************************************/
#pragma precomp SRP_PreCompiler

$insert SERVICE_SETUP
$insert APP_INSERTS
$insert TOOL_ESC_EQUATES
$insert TOOL_EQUATES
$insert TOOL_LOG_EQUATES
$insert RLIST_EQUATES

Declare subroutine Database_Services, Set_Status, Error_Services, Logging_Services, Btree.Extract, Update_Index
Declare function   Get_Status, Database_Services, Logging_Services, Datetime, Environment_Services, SRP_Array

LogPath     = Environment_Services('GetApplicationRootPath') : '\LogFiles\Tool'
LogDate     = Oconv(Date(), 'D4/')
LogTime     = Oconv(Time(), 'MTS')
LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' Tool Log.csv'
Headers     = 'Logging DTM' : @FM : 'ToolID' : @FM : 'Notes' : @FM : 'Error'
objLog      = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$)
LoggingDTM  = LogDate : ' ' : LogTime   ; // Logging DTM

GoToService

Return Response or ""

//-----------------------------------------------------------------------------
// SERVICES
//-----------------------------------------------------------------------------

Service UpdateKeysByType()
    
    hSysLists   = Database_Services('GetTableHandle', 'SYSLISTS')
    Lock hSysLists, ServiceKeyID then
        OPEN 'TOOL' TO FileIn THEN
            SELECT "TOOL" BY "TOOL_TYPE" SETTING Cursor ELSE
                Status = Set_FSError()
                ErrorMsg = 'Error performing SELECT_BY agains TOOL table.'
                RETURN
            END
        END ELSE
            ErrorMsg = 'Unable to open table "TOOL" for index lookup'
            RETURN
        END

        ToolIDs = ''
        Done = 0
        LOOP
            READNEXT ToolID USING Cursor ELSE Done = 1
        UNTIL Done
            READ ToolRec FROM FileIn,ToolID THEN
                // Ignore tools that are Out of Service or GaN.
                IF (ToolRec<TOOL_OUT_OF_SERVICE$> NE 1) AND (ToolRec<TOOL_TOOL_PROC$> NE 'G') AND (ToolRec<TOOL_TOOL_TYPE$> NE 'Reactor') AND (ToolRec<TOOL_TOOL_TYPE$> NE 'Bottle Change') THEN
                    ToolIDs := ToolID:@VM
                END
            END
        REPEAT
        
        ToolIds[-1,1] = ''

        Database_Services('WriteDataRow', 'APP_INFO', 'TOOL_KEYS_BY_TYPE', ToolIDs, True$, False$, True$)
        Unlock hSysLists, ServiceKeyID else Null
    end
    
End Service


Service UpdateGaNTools()
    
    hSysLists   = Database_Services('GetTableHandle', 'SYSLISTS')
    Lock hSysLists, ServiceKeyID then
        GaNToolQuery = 'SELECT TOOL WITH TOOL_PROC "G" BY @ID'
        Set_Status(0)
        RList(GaNToolQuery, TARGET_SAVELIST$, 'GAN_TOOL_LIST', 'Current List of GaN Tools', False$)
        GaNToolList = Database_Services('ReadDataRow', 'SYSLISTS', 'GAN_TOOL_LIST')
        // Remove field containing list description
        GaNToolList = Delete(GaNToolList, 1, 0, 0)
        errCode = ''
        If Get_Status(errCode) then
            ErrorMsg = 'Error retrieving GaN tool list from the ':Service:' module. Error code':errCode
            Error_Services('Add', ErrorMsg)       
        end
        
        Database_Services('WriteDataRow', 'APP_INFO', 'GAN_TOOL_LIST', GaNToolList, True$, False$, True$)
        Unlock hSysLists, ServiceKeyID else Null
    end
    
end service


Service GetTools(ToolClass)

    Query = 'SELECT TOOL '
    If ToolClass NE '' then
        Query := 'WITH CLASS EQ ': Quote(ToolClass)
    end
    Query := 'BY CLASS BY TOOL_ID'
    Set_Status(0)
    ClearSelect TARGET_ACTIVELIST$
    RList(Query, TARGET_ACTIVELIST$, '', '', '')
    If Not(Get_Status(ErrCode)) then
        EOF = False$
        Loop
            ReadNext KeyID else EOF = True$
        Until EOF
            Response<-1> = KeyID
        Repeat
    end
    
end service


Service GetAllTools()
    
    AllTools = ''
    AllTools = Database_Services('ReadDataRow', 'APP_INFO', 'TOOL_KEYS_BY_TYPE')
    Response = AllTools
    
end service


Service ChangeToolMode(ToolID, NewMode, NewReason, CurrUser, ForceModeChange)
    
    LogData    = ''
    LogData<1> = OConv(Datetime(), 'DT2/^H')
    LogData<2> = ToolID
    LogData<3> = 'Change Tool Mode Start'
    LogData<4> = 'To Mode: ': NewMode
    Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
    If ForceModeChange NE True$ then ForceModeChange = False$
    
    If ( (ToolID NE '') and (NewMode NE '') and ( (NewReason NE '') or (ForceModeChange EQ True$) ) ) then
        
        LogData     = ''
        LogData<1>  = OConv(Datetime(), 'DT2/^H')
        LogData<2>  = ToolID
        LogData<3>  = 'Tool ID Detected, New Mode Detected'
        LogData<4>  = 'To Mode: ': NewMode
        Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
        NewModeDTM  = ICONV(OCONV(Date(),'D4/'):' ':OCONV(Time(),'MTS'),'DT')
        
        // Close old mode record
        // Don't wait for the indexer. Flush pending index transactions BEFORE reading
        // the Tool CURR_MODE_KEY.
        Update_Index('TOOL_LOG', 'TOOL_CURR_MODE', False$, True$)
        // Get Current Mode - There should only be one key, but we will verify before proceeding.
        CurrModeKeys = Xlate('TOOL', ToolID, TOOL_CURR_MODE_KEY$, 'X')
        // CurrModeKey will be set within the following GoSub
        GoSub VerifyCurrModeIndex
        CurrModeRec = Database_Services('ReadDataRow', 'TOOL_LOG', CurrModeKey)
        If Error_Services('NoError') then
            CurrModeRec<TOOL_LOG_STOP_DTM$>  = NewModeDTM						;* Put stop time in current log
            CurrModeRec<TOOL_LOG_STOP_USER$> = CurrUser
            LogData                          = ''
            LogData<1>                       = OConv(Datetime(), 'DT2/^H')
            LogData<2>                       = ToolID
            LogData<3>                       = 'Current Mode'
            LogData<4>                       = CurrModeRec
            Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
            // Write and close old mode
            Database_Services('WriteDataRow', 'TOOL_LOG', CurrModeKey, CurrModeRec, True$, False$, True$)
            If Error_Services('HasError') then
                // Log the error
                LogData    = ''
                LogData<1> = OConv(Datetime(), 'DT2/^H')
                LogData<2> = ToolID
                LogData<3> = 'Error writing TOOL_LOG record ':CurrModeKey
                LogData<4> = Error_Services('GetMessage')
                Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
            end
            // Create new mode record
            NewLogRecKey                      = ToolID : '*' : NewModeDTM
            NewLogRec                         = ''
            NewLogRec<TOOL_LOG_START_USER$>   = CurrUser
            NewLogRec<TOOL_LOG_START_REASON$> = NewReason
            NewLogRec<TOOL_LOG_TOOL_MODE$>    = NewMode
            LogData                           = ''
            LogData<1>                        = OConv(Datetime(), 'DT2/^H')
            LogData<2>                        = ToolID
            LogData<3>                        = 'Attempting to write new mode'
            LogData<4>                        = NewLogRec
            Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
            // Write new mode record
            Database_Services('WriteDataRow', 'TOOL_LOG', NewLogRecKey, NewLogRec, True$, False$, True$)
            If Error_Services('HasError') then
                LogData    = ''
                LogData<1> = OConv(Datetime(), 'DT2/^H')
                LogData<2> = ToolID
                LogData<3> = 'Error writing TOOL_LOG record ':NewLogRecKey
                LogData<4> = Error_Services('GetMessage')
                Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
            end else
                LogData    = ''
                LogData<1> = OConv(Datetime(), 'DT2/^H')
                LogData<2> = ToolID
                LogData<3> = 'Successfully wrote new mode'
                LogData<4> = NewLogRec
                Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
            end
        end else
            LogData    = ''
            LogData<1> = OConv(Datetime(), 'DT2/^H')
            LogData<2> = ToolID
            LogData<3> = 'Error reading TOOL_LOG record ':CurrModeKey
            LogData<4> = Error_Services('GetMessage')
            Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
        end
    end else
        LogData    = ''
        LogData<1> = OConv(Datetime(), 'DT2/^H')
        LogData<2> = ToolID
        LogData<3> = ''
        LogData<4> = 'Null parameter passed into ':Service:' service.'
        Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
    end
    
end service


Service GetNumPoints(ToolClass, ToolPattern)
    
    ErrorMsg  = ''
    NumPoints = ''
    If ( (ToolClass NE '') and (ToolPattern NE '') ) then
        If RowExists('TOOL_CLASS', ToolClass) then
            ToolPatterns  = Xlate('TOOL_CLASS', ToolClass, 'PATTERN', 'X')
            Locate ToolPattern in ToolPatterns using @VM setting PatternPos then
                NumPoints = Xlate('TOOL_CLASS', ToolClass, 'PATTERN_SIZE', 'X')<0, PatternPos>
            end else
                ErrorMsg = 'Error in ':Service:' service. ToolPattern "':ToolPattern:'" not found in TOOL_CLASS "':ToolClass:'".'
            end
        end else
            ErrorMsg = 'Error in ':Service:' service. ToolClass "':ToolClass:'" does not exist.'
        end
    end else
        ErrorMsg = 'Error in ':Service:' service. Null ToolClass or ToolPattern passed into service.'
    end
    
    If ErrorMsg EQ '' then
        Response = NumPoints
    end else
        Error_Services('Add', ErrorMsg)
    end
    
end service

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

VerifyCurrModeIndex:
    
    NumKeys      = DCount(CurrModeKeys, @VM)
    If NumKeys GT 1 then
        // There should only be one current mode key.
        // It's possible that the relational index is incomplete or that previous
        // mode records (i.e. TOOL_LOG records) were not closed for some reason.
        LogData    = LoggingDTM
        LogData<2> = ToolID
        LogData<3> = 'Multiple CURR_MODE_KEY values found in TOOL record ':ToolID:'.'
        Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
        
        // First let's make sure all previous TOOL_LOG records are closed.
        Open 'DICT.TOOL_LOG' to hDictToolLog then
            SearchString = 'TOOL_ID':@VM:ToolID:@FM
            Option       = ''
            Flag         = ''
            Btree.Extract(SearchString, 'TOOL_LOG', hDictToolLog, AllToolLogKeys, Option, Flag)
            If Not(Get_Status(errCode)) then
                AllToolLogKeys = SRP_Array('SortRows', AllToolLogKeys, 'DN2', 'LIST', @VM, '*', False$)
                NumTotalKeys   = DCount(AllToolLogKeys, @VM)
                Open 'TOOL_LOG' to hToolLog then
                    For KeyIndex = NumTotalKeys to 2 Step -1
                        WriteRec         = False$
                        NextModeKey      = AllToolLogKeys<0, KeyIndex - 1>
                        ThisModeKey      = AllToolLogKeys<0, KeyIndex>
                        ThisToolLogRec   = Database_Services('ReadDataRow', 'TOOL_LOG', ThisModeKey)
                        ThisModeStopDTM  = ThisToolLogRec<TOOL_LOG_STOP_DTM$>
                        If ThisModeStopDTM EQ '' then
                            LogData                            = LoggingDTM
                            LogData<2>                         = ToolID
                            LogData<3>                         = 'TOOL_LOG record ':ThisModeKey:' is missing a STOP_DTM value.'
                            Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
                            NextModeStartDTM                   = Field(NextModeKey, '*', 2)
                            ThisToolLogRec<TOOL_LOG_STOP_DTM$> = NextModeStartDTM
                            WriteRec                           = True$
                        end
                        ThisModeStopUser = ThisToolLogRec<TOOL_LOG_STOP_USER$>
                        If ThisModeStopUser EQ '' then
                            LogData           = LoggingDTM
                            LogData<2>        = ToolID
                            LogData<3>        = 'TOOL_LOG record ':ThisModeKey:' is missing a STOP_USER value.'
                            Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
                            NextModeStartUser = Xlate('TOOL_LOG', NextModeKey, 'START_USER', 'X')
                            If NextModeStartUser NE '' then 
                                ThisToolLogRec<TOOL_LOG_STOP_USER$> = NextModeStartUser
                                WriteRec                            = True$
                            end
                        end
                        If WriteRec then
                            Database_Services('WriteDataRow', 'TOOL_LOG', ThisModeKey, ThisToolLogRec, True$, False$, True$)
                            If Error_Services('HasError') then
                                LogData    = LoggingDTM
                                LogData<2> = ToolID
                                LogData<3> = 'TOOL_LOG record ':ThisModeKey:' failed to write.'
                                Logging_Services('AppendLog', objLog, LogData, @RM, @FM)
                            end
                        end
                    Next KeyIndex
                end
                
            end
        end
        
        // Second, let's read and write the TOOL_LOG records listed in the tool record curr mode key column to trigger
        // SI.MFS to update the index if it is incomplete.
        For each CurrModeKey in CurrModeKeys using @VM setting vPos
            ToolLogRec                     = Database_Services('ReadDataRow', 'TOOL_LOG', CurrModeKey)
            StopDtm                        = ToolLogRec<TOOL_LOG_STOP_DTM$>
            ToolLogRec<TOOL_LOG_STOP_DTM$> = ''
            Database_Services('WriteDataRow', 'TOOL_LOG', CurrModeKey, ToolLogRec, True$, False$, True$)
            Update_Index('TOOL_LOG', 'TOOL_CURR_MODE', False$, True$)
            ToolLogRec<TOOL_LOG_STOP_DTM$> = StopDtm
            Database_Services('WriteDataRow', 'TOOL_LOG', CurrModeKey, ToolLogRec, True$, False$, True$)
            Update_Index('TOOL_LOG', 'TOOL_CURR_MODE', False$, True$)
        Next CurrModeKey
        
        // The index should be healthy now and we should only have one key.
        CurrModeKey = Xlate('TOOL', ToolID, TOOL_CURR_MODE_KEY$, 'X')
    end else
        CurrModeKey = CurrModeKeys
    end
    
return




