Sub OpenFile()

Dim Ret As Integer
Dim iRow As Long
Dim iCol As Long
Dim cWorkSheetName As String
Dim cEditor As String                                   ' Editor executable to be used for opening the specified filed
Dim cFileName As String
Dim iLineNr As Long
Dim cLineNrOption As String                             ' CLI Argument to be used for the editor to open at a specific line within the file
Dim cLineNrPosition As String                           ' Variable indicating where we need to add the CLI argument for the line option
Dim iLastRow As Long
Dim iLastColumn As Long
Dim iHeaderCount, iColCount, iIndex As Long
Dim aHeader As Variant                                  ' First number represent the number of column headers within
                                                        ' the array called header
Dim aHeaderFound(5 - 1) As Integer                      ' First number represent the number of column headers within
                                                        ' the array called header

Dim aHeaderColumnNrs As Variant                         ' Column numbers for headers we are looking for in an array

Dim iHeaderColCount As Long                             ' Counter for checking the amount of columns we have found
Dim iHeaderRow As Long                                  ' Variable we use to store the row number where we have found our column headers
Dim iHeaderRowcnt As Long                               ' For-Next variable used to loop through from the first row until the row as defined
                                                        ' by iHeaderRowmax while trying to find the row containing all column headers
Dim iHeaderRowmax As Long                               ' Maximum amount of headers we will have a look at while trying to find the header row
                                                        ' containing the column headers
                                                        
Dim folderPath As String                                ' For storing the current path for the Excel sheet we have open
folderPath = Application.ActiveWorkbook.Path            ' Current Path for the Excel sheet we have open

aHeader = Array("Line", "FN", "Text")                   ' Array header assignment (case sensitive!)
aHeaderColumnNrs = Array(0, 0, 0)
iHeaderCount = 3                                        ' Number of columns in header we are interested in
iRow = ActiveCell.Row
cWorkSheetName = ActiveSheet.Name
iLastRow = ActiveCell.SpecialCells(xlLastCell).Row
iLastColumn = ActiveCell.SpecialCells(xlLastCell).Column
cTitle = "Open Captured File"                           ' Define cTitle.

'
' Retrieve the required editor and editor options from OpenFile.ini file
'
Ret = Read_OpenFile_ini(cEditor, cLineNrOption, cLineNrPosition)
' cMessage = MsgBox("Editor set to: " + cEditor, vbCritical)
' cMessage = MsgBox("cLineNrOption set to: " + cLineNrOption, vbCritical)
' cMessage = MsgBox("cLineNrPosition set to: " + cLineNrPosition, vbCritical)

'
' Is the selected editor available for execution??
' If not provide critical error message and exit
'
If Dir(cEditor) = "" Then
        cMessage = MsgBox("Enabled editor " + """" + cEditor + """" + " is not available for opening captured file", vbCritical, cTitle)
        GoTo Finish
End If

iHeaderRow = 2

iHeaderColCount = 0                              ' Initialize the counters for the headers we have found
iHeaderRowmax = 20                               ' Maximum number of rows to check while trying to find the header row
If iLastRow < iHeaderRowmax Then
        iHeaderRowmax = iLastRow
End If
For iHeaderRowcnt = 1 To iHeaderRowmax Step 1
        For iColCount = 1 To iLastColumn Step 1
            cellvalue = Cells(iHeaderRowcnt, iColCount).Value
            '
            ' Only continue if the Cell value is NOT in an error state
            '
            If Not IsError(cellvalue) Then
                For iIndex = 0 To iHeaderCount - 1 Step 1
                    If aHeader(iIndex) = cellvalue Then
                        aHeaderFound(iIndex) = 1
                        aHeaderColumnNrs(iIndex) = iColCount
                        iIndex = iHeaderCount - 1
                        iHeaderColCount = iHeaderColCount + 1
                        If iHeaderColCount = iHeaderCount Then
                            iColCount = iLastColumn
                            iHeaderRow = iHeaderRowcnt
                            iHeaderRowcnt = iHeaderRowmax
                        End If
                    End If
                Next
            End If
        Next
Next

Debug.Print cEditor & "iHeaderRow is located at row " & iHeaderRow & " within worksheet " & cWorkSheetName

If iHeaderColCount <> iHeaderCount Then
        bHeaderNotFound = ""
        For iIndex = 0 To iHeaderCount - 1 Step 1
            If aHeaderFound(iIndex) = 0 Then
                If bHeaderNotFound = "" Then
                    bHeaderNotFound = aHeader(iIndex)
                Else
                    bHeaderNotFound = bHeaderNotFound + "," + aHeader(iIndex)
                End If
            End If
        Next
        cMessage = MsgBox("This macro is not valid in worksheet """ + cWorkSheetName + """", vbInformation)
        GoTo Finish
End If

If iLastRow <= iHeaderRow Then
        Debug.Print cEditor & "There are no data rows within worksheet " & cWorkSheetName
        Cells(iRow, iCol).Select
        GoTo Finish
End If

'
' Let's ask first if the user really wants to open this file and go to the line
'
iCol = aHeaderColumnNrs(0)
cFileName = Cells(iRow, iCol + 1).Value
cFileName = Replace(cFileName, """", "")                          ' Remove double quotes
'
' Various tasks (like tunesys, start of AO) have no detailed task file available so we cannot open these
' If that is the case the cFileName is empty and we can exit immediately since there is nothing we can open
'
If cFileName = "" Then
    cMessage = "No detailed information for this line available"            ' Define message.
    Style = vbOKOnly + vbError + vbDefaultButton1              ' Define buttons.
    Response = MsgBox(cMessage, Style, cTitle)
    GoTo Finish
End If
'
' Just on an offchance we have a file specification...
' with the folderpath already included, why add it. If we
' were to add it we would get a bad file name...
'
If folderPath <> Left(cFileName, Len(folderPath)) Then
    cFileName = folderPath + "\" + cFileName                          ' Add path to excel file we have open right now
End If
'
' Determine if the file exists, no point trying to open the
' editor if the file is not there...
'
If (Dir(cFileName) = "") Then

    cMessage = cFileName + vbNewLine + "was not found!"            ' Define message.
    Style = vbOKOnly + vbError + vbDefaultButton1              ' Define buttons.
    Response = MsgBox(cMessage, Style, cTitle)
    GoTo Finish
End If
'
' See if the user wants to edit the file...
'
iLineNr = Cells(iRow, iCol).Value
cMessage = "Do you want to open the file " + cFileName            ' Define message.
Style = vbYesNo + vbInformational + vbDefaultButton1              ' Define buttons.
Response = MsgBox(cMessage, Style, cTitle)
If Response = vbYes Then                                          ' User chose Yes.

'
' Depending on the editor selected we need to provide the line numbers before or after the filename
'
        Select Case cLineNrPosition
            Case "beforefile"
                ' eg. Notepad++, PSPad and Vim require the line number to be provided before the filename
                ' "C:\Program Files (x86)\Notepad++\notepad++.exe" "-n57" "filename"
                ' "C:\Program Files\PSPad editor\PSPad.exe" "-57" "filename"
                ' "C:\Program Files (x86)\Vim\vim72\vim.exe" "+57" "filename"
                a = """" + cEditor + """" + " " + """" + cLineNrOption + CStr(iLineNr) + """" + " " + """" + cFileName + """"
                TaskID = Shell("""" + cEditor + """" + " " + """" + cLineNrOption + CStr(iLineNr) + """" + " " + """" + cFileName + """", vbNormalFocus)
            Case "afterfile"
                ' no editors known to require this yet but it would look like:
                ' "C:\Program Files (x86)\knotspad\knotspad.exe" "filename" "-n57"
                TaskID = Shell("""" + cEditor + """" + " " + """" + cFileName + """" + " " + """" + cLineNrOption + CStr(iLineNr) + """", vbNormalFocus)
            Case "afterfileattached"
                ' eg. Ultraedit requires the line number to be provided directly after the filename
                ' "C:\Program Files (x86)\IDM Computer Solutions\UltraEdit\Uedit32.exe" "filename/57"
                TaskID = Shell("""" + cEditor + """" + " " + """" + cFileName + cLineNrOption + CStr(iLineNr) + """", vbNormalFocus)
        End Select
End If

Finish:
End Sub

Function Read_OpenFile_ini(ByRef cEditor, ByRef cLineNrOption, ByRef cLineNrPosition)
Dim FileNum As Integer
Dim DataLine As String
Dim inifile As String
Dim iNexhome As String

'
' Define editor defaults if none is specified within the OpenFile.ini file
'
cEditor = "C:\Program Files (x86)\Notepad++\notepad++.exe"
cLineNrOption = "-n"
cLineNrPosition = "beforefile"

iNexhome = Environ("INEX_HOME")
If iNexhome = "" Then
    cMessage = MsgBox("Environment variable INEX_HOME is unavailable, defaulting editor to " + cEditor, vbInformational)
    GoTo Finish
End If

inifile = iNexhome + "\config\OpenFile.ini"

'
' Verify whether the OpenFile.ini file exists
'
If Dir(inifile) <> "" Then
'    cMessage = MsgBox("File " + inifile + " exists", vbInformational)
Else
    cMessage = MsgBox("File " + inifile + " is unavailable, defaulting editor to " + cEditor, vbInformational)
    GoTo Finish
End If

FileNum = FreeFile() ' define a free file handle for the OpenFile.ini file to be opened

' Open OpenFile.ini file
'cMessage = MsgBox("Opening file " + inifile, vbInformational)
Open inifile For Input As #FileNum

'
' Read all lines from the OpenFile.ini file one by one
'
While Not EOF(FileNum)
    Line Input #FileNum, DataLine
    DataLine = Trim(LCase(DataLine))
    '
    ' Parse the line if it is not a comment line
    '
    If Left(DataLine, 1) <> "#" Then
        While InStr(DataLine, vbTab): DataLine = Replace(DataLine, vbTab, " "): Wend ' replace tabs by spaces
        While InStr(DataLine, "  "): DataLine = Replace(DataLine, "  ", " "): Wend ' replace multiple spaces into just one space
        DataLine = Replace(DataLine, " =", "=")
        DataLine = Replace(DataLine, "= ", "=")
        If InStr(DataLine, "editor=") <> 0 Then
            ' Editor line found in OpenFile.ini file
            ' cMessage = MsgBox("Editor line found: " + DataLine, vbCritical)
            cEditor = Mid(DataLine, InStr(DataLine, "editor="), Len(DataLine))
            cEditor = Mid(cEditor, InStr(cEditor, "=") + 1, Len(cEditor))
            If InStr(cEditor, "#") <> 0 Then
                cEditor = Mid(cEditor, 1, InStr(cEditor, "#") - 1)  ' Remove possible comments
            End If
            While InStr(cEditor, """"): cEditor = Replace(cEditor, """", ""): Wend ' remove double quotes
            ' cMessage = MsgBox("Editor set to: " + cEditor, vbCritical)
        ElseIf InStr(DataLine, "linenroption=") <> 0 Then
            ' LineNrOption line found in OpenFile.ini file
            ' cMessage = MsgBox("LineNrOption line found: " + DataLine, vbCritical)
            cLineNrOption = Mid(DataLine, InStr(DataLine, "linenroption="), Len(DataLine))
            cLineNrOption = Mid(cLineNrOption, InStr(cLineNrOption, "=") + 1, Len(cLineNrOption))
            If InStr(cLineNrOption, "#") <> 0 Then
                cLineNrOption = Mid(cLineNrOption, 1, InStr(cLineNrOption, "#") - 1)  ' Remove possible comments
            End If
            While InStr(cLineNrOption, """"): cLineNrOption = Replace(cLineNrOption, """", ""): Wend ' remove double quotes
            ' cMessage = MsgBox("LineNrOption set to: " + cLineNrOption, vbCritical)
        ElseIf InStr(DataLine, "linenrposition=") <> 0 Then
            ' LineNrPosition line found in OpenFile.ini file
            ' cMessage = MsgBox("LineNrPosition line found: " + DataLine, vbCritical)
            cLineNrPosition = Mid(DataLine, InStr(DataLine, "linenrposition="), Len(DataLine))
            cLineNrPosition = Mid(cLineNrPosition, InStr(cLineNrPosition, "=") + 1, Len(cLineNrPosition))
            If InStr(cLineNrPosition, "#") <> 0 Then
                cLineNrPosition = Mid(cLineNrPosition, 1, InStr(cLineNrPosition, "#") - 1)  ' Remove possible comments
            End If
            While InStr(cLineNrPosition, """"): cLineNrPosition = Replace(cLineNrPosition, """", ""): Wend ' remove double quotes
            ' cMessage = MsgBox("LineNrPosition set to: " + cLineNrPosition, vbCritical)
        End If
    End If
Wend

'
' Close the OpenFile.ini file we have been reading
'
Close #FileNum

'
' Verify that cLineNrPosition is set to beforefile, afterfile or afterfileattached else default to afterfileattached (silently)
'
If cLineNrPosition <> "beforefile" And cLineNrPosition <> "afterfile" And cLineNrPosition <> "afterfileattached" Then
    cLineNrPosition = "beforefile"
    ' cMessage = MsgBox("LineNrPosition silently defaulted to: " + cLineNrPosition, vbCritical)
End If

Finish:

End Function