'Option Strict On
Imports System
Imports WinSCP
Imports System.IO
Imports System.Globalization
Imports System.Threading
Imports Microsoft.Win32
Imports System.Math


Friend Class Example
    Public Shared logger As log4net.ILog
    Const yes As String = "yes"
    Const no As String = "no"
    Shared NewFolder As String = Nothing
    Public Shared session As Session
    Public Shared transferOptions As TransferOptions
    Public Shared FileType As String
    Public Shared MaxTimeFileName As String
    Public Shared MaxDirName As String

    Public Shared MaxDirDate As Date
    Public Shared MaxFileTime As Date

    Public Shared Delete As Boolean = False

    Public Shared provider As CultureInfo
    Public Shared remoteDir As String

    Public Shared ConsolePrint As Boolean


    Public Shared Function Main() As Integer
        Dim timeFormat As String = "H_mm_ss"
        logger = log4net.LogManager.GetLogger("PutFiles")

        Dim ConfigFile As String
        Dim SyncFile As String

        Dim remoteDir As String
        Dim localDir As String

        Dim strPath As String = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly.Location)

        'object created to read Config.ini
        Dim ReadINIFile As INIFile

        'object created to read Sync.ini
        Dim SyncINIFile As INIFile

        ConfigFile = strPath & "\files\Config.ini"
        SyncFile = strPath & "\files\Sync.ini"

        If (File.Exists(ConfigFile)) Then
            ReadINIFile = New INIFile(ConfigFile)
        Else
            logger.Error("Config.ini file does not exists at " & strPath & "\files\")
            Return 1
        End If


        If (File.Exists(SyncFile)) Then
            syncINIFile = New INIFile(SyncFile)
        Else
            logger.Error("Sync.ini file does not exists at " & strPath & "\files\")
            Return 1
        End If


        Dim ProtocolType As String = ReadINIFile.GetString("Session", "File Transfer Protocol", "")

        Dim ProtocolNumber As Integer
        If (ProtocolType = "") Then
            logger.Error("Enter the value of 'File Transfer Protocol' in Config.ini file")
            Return 1
        ElseIf (ProtocolType = "SFTP") Then
            ProtocolNumber = 0
        ElseIf (ProtocolType = "SCP") Then
            ProtocolNumber = 1
        ElseIf (ProtocolType = "FTP") Then
            ProtocolNumber = 2
        End If

        Dim DefaultPortNumber As Integer

        If (ProtocolType.Equals("FTP")) Then
            DefaultPortNumber = 21
        Else
            DefaultPortNumber = 22
        End If


        Dim HostName As String = ReadINIFile.GetString("Session", "Host Name", "")
        Dim PortNumber As Integer = ReadINIFile.GetInteger("Session", "Port Number", DefaultPortNumber)

        Dim UserName As String = ReadINIFile.GetString("Session", "User Name", "")
        Dim password As String = ReadINIFile.GetString("Session", "Password", "")

        FileType = ReadINIFile.GetString("Session", "File Type", "")

        Dim DeleteStr As String = ReadINIFile.GetString("Session", "Delete", "")
        Dim CompressStr As String = ReadINIFile.GetString("Session", "Compress", "")

        Dim HostKey As String = ReadINIFile.GetString("Session", "Host Key", "")

        Dim LogLevel As String = ReadINIFile.GetString("General", "Log Level", "")

        Dim ConsolePrintStr As String = ReadINIFile.GetString("General", "Console Print", "")

        Dim Compress As Boolean = False
        If (DeleteStr.Equals(yes)) Then
            Delete = True
        Else
            Delete = False
        End If

        If (CompressStr.Equals(yes)) Then
            Compress = True
        Else
            Compress = False
        End If

        If (ConsolePrintStr.Equals(yes)) Then
            ConsolePrint = True
        Else
            ConsolePrint = False
        End If

        If (HostName = "") Then
            logger.Error("Enter value of 'Host Name' in Config.ini file")
            Return 1
        End If

        If (UserName = "") Then
            logger.Error("Enter value of 'User Name' in Config.ini file")
            Return 1
        End If

        If (password = "") Then
            logger.Error("Enter value of 'Password' in Config.ini file")
            Return 1
        End If

        If (FileType = "") Then
            logger.Error("Enter value of 'File Type' in Config.ini file")
            Return 1
        End If

        If (HostKey = "") Then
            logger.Error("Enter value of 'Host Key' in Config.ini file")
            Return 1
        End If

        If (LogLevel = "") Then
            logger.Error("Enter value of 'Log Level' in Config.ini file")
            Return 1
        End If

        SetLogingLevel(LogLevel)

        NewFolder = strPath & "\New Folder"

        Dim dirInfo As DirectoryInfo
        Dim dirInfoArr() As DirectoryInfo

        If Not Directory.Exists(NewFolder) Then

            'create blank folder
            Directory.CreateDirectory(NewFolder)
            logger.Debug("created New Folder in " & strPath)

        Else

            'Already exists
            dirInfo = New DirectoryInfo(NewFolder)
            dirInfoArr = dirInfo.GetDirectories
            Dim fileInfos As FileInfo() = dirInfo.GetFiles()

            If (fileInfos.Length > 0 Or dirInfoArr.Length > 0) Then

                Directory.Delete(NewFolder, True)
                logger.Debug("Deleted New Folder")

                Directory.CreateDirectory(NewFolder)
                logger.Debug("created New Folder in " & strPath)

            Else
                logger.Debug("New Folder already exists at " & strPath)
            End If

        End If


        logger.Info("File Protocol = " & ProtocolNumber)

        logger.Info("HostName = " & HostName)
        logger.Info("Port Number = " & PortNumber)

        logger.Info("UserName = " & UserName)

        logger.Info("Password = " & password)
        logger.Info("FileType = " & FileType)
        logger.Info("Delete = " & Delete)
        logger.Info("Compress = " & Compress)


        'convert System date format
        Thread.CurrentThread.CurrentCulture = New CultureInfo("en-GB", False)
        Microsoft.Win32.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\International", "sShortDate", "dd/MM/yyyy")

        logger.Info(DateTime.Now.ToString())
        If (HostName = "" Or UserName = "" Or password = "" Or FileType = "") Then
            logger.Error("Incomplete entry in Config.INI File")
            Return 0
        Else
            Try
                'Setup session options

                Dim sessionOptions As New SessionOptions
                With sessionOptions
                    .Protocol = ProtocolNumber
                    .HostName = HostName
                    .UserName = UserName
                    .Password = password
                    .PortNumber = PortNumber
                    .SshHostKey = HostKey

                    If (Compress) Then
                        .AddRawSettings("Compression", 1)
                    End If
                    '.AddRawSettings("AgentFwd", "1")
                End With

                Dim dateFormat As String
                provider = CultureInfo.CurrentCulture

                dateFormat = "dd-MM-yyyy"

                Using session = New Session

                    'Connect()                    
                    logger.Info("---------------------session started------------------------- ")
                    session.Open(sessionOptions)

                    'Upload(files)
                    transferOptions = New TransferOptions
                    transferOptions.TransferMode = TransferMode.Binary

                    Dim sectionConfig As String() = ReadINIFile.ReadSections()
                    Dim sectionSync As String() = SyncINIFile.ReadSections()

                    For Each section As String In sectionConfig
                        'it takes extra section "" into the array     

                        If ((section <> "General") And (section <> "Session") And (section <> "")) Then
                            MaxTimeFileName = Nothing
                            MaxDirName = Nothing
                            MaxDirDate = Nothing
                            MaxFileTime = Nothing

                            'Check whether file is synchronized before or not
                            'There are two files Config.ini and Sync.ini file
                            'Using Configuration tool Config.ini file is edited.
                            'and first time when directory is to be synchronized its details i.e 'LocalDirectory'' and 'RemoteDirectory'
                            'is fetched from Config.ini and after synchronizing the directory, the details of last read file is written in Sync.ini
                            'and then from next time; details i.e 'LocalDirectory'' and 'RemoteDirectory' are Sync.ini file

                            'so here it check whether section is present in Sync.ini; if no then synchronizing is happening first time
                            If (sectionSync.Contains(section)) Then
                                Dim LastSyncDirStr As String
                                LastSyncDirStr = Nothing
                                Try
                                    'read from Sync.ini file
                                    remoteDir = SyncINIFile.GetString(section, "RemoteDirectory", "")
                                    localDir = SyncINIFile.GetString(section, "LocalDirectory", "")

                                    Dim configLocalDir As String = ReadINIFile.GetString(section, "LocalDirectory", "")

                                    logger.Info("Remote Dir = " + remoteDir)
                                    logger.Info("Local Dir = " + localDir)

                                    Dim fileName As String
                                    Dim LastSyncFileTime As DateTime

                                    'check the last file/directory copied   
                                    If (localDir.Contains(".")) Then
                                        fileName = Path.GetFileName(localDir)
                                        fileName = fileName.Substring(0, fileName.IndexOf("."))
                                        LastSyncFileTime = DateTime.ParseExact(fileName, timeFormat, provider)
                                        LastSyncFileTime = LastSyncFileTime.ToLongTimeString
                                    Else
                                        MaxDirName = localDir
                                        LastSyncFileTime = Nothing
                                    End If

                                    MaxDirName = Directory.GetParent(localDir).FullName
                                    'MaxDirName =E:\InfoFile1\11-12-2012

                                    logger.Debug("Sub Dir" & MaxDirName)

                                    Dim LastSyncSubDir = Directory.GetParent(localDir).Name
                                    ' LastSyncSubDir= "01-12-2012"

                                    logger.Debug("Sub Dir Name " & LastSyncSubDir)

                                    'Dim MainDir As String = subDir.Substring(0, lastIndexOfSubDir)
                                    Dim MainDir As String = Directory.GetParent(localDir).Parent.FullName
                                    ' MainDir=E:\Infofile2

                                    logger.Debug("Main Dir " & MainDir)

                                    Dim LastSyncDirDate As Date
                                    LastSyncDirStr = LastSyncSubDir.Replace("-", "/")
                                    LastSyncDirDate = CDate(LastSyncDirStr)
                                    MaxDirDate = LastSyncDirDate

                                    TransferFile(session, remoteDir, MainDir, False, LastSyncDirDate, LastSyncFileTime)
                                    'TransferFile(remoteDir, MainDir, False, LastSyncDirDate)
                                    If (MaxTimeFileName = Nothing) Then                                        
                                        If (MaxDirName <> Nothing) Then
                                            If (MaxDirName.Substring(MaxDirName.Length - 1).Equals("\")) Then
                                                SyncINIFile.WriteString(section, "LocalDirectory", MaxDirName)
                                                logger.Debug("set Local Directory to " & MaxDirName)
                                            Else
                                                SyncINIFile.WriteString(section, "LocalDirectory", MaxDirName & "\")
                                                logger.Debug("Last File Read :" & MaxDirName & "\")
                                            End If
                                        End If
                                    Else
                                        SyncINIFile.WriteString(section, "LocalDirectory", MaxTimeFileName)
                                        logger.Info("Last File Read = " & MaxTimeFileName)
                                    End If
                                Catch e As System.FormatException
                                    logger.Error("File = " & LastSyncDirStr)
                                Catch e As InvalidCastException                                    
                                    logger.Error("Error : Directory = " & LastSyncDirStr & " not in a proper format ")
                                End Try
                            Else
                                'when reading file first time

                                'read from Config.ini file  when synchronizing file first time
                                remoteDir = ReadINIFile.GetString(section, "RemoteDirectory", "")
                                localDir = ReadINIFile.GetString(section, "LocalDirectory", "")

                                logger.Info("Remote Dir = " + remoteDir)
                                logger.Info("Local Dir = " + localDir)

                                logger.Debug("First Time")


                                ' create directory on server side
                                Dim createDir As String
                                Dim createDir1 As String
                                Dim createDir2 As String
                                Dim createDir3 As String
                                Dim index As Integer = 0
                                Dim index1 As Integer
                                Dim index2 As Integer
                                createDir = remoteDir
                                createDir3 = remoteDir

                                While (createDir3.LastIndexOf("/") <> 0)
                                    index1 = createDir3.IndexOf("/")
                                    logger.Debug("Index1 " & index1)
                                    index1 = index1 + 1
                                    createDir1 = createDir3.Substring(index1)
                                    logger.Debug("createDir1 " & createDir1)

                                    index2 = createDir1.IndexOf("/")
                                    logger.Debug("Index2 " & index2)

                                    index = index + index2 + index1
                                    logger.Debug("Index " & index)
                                    createDir2 = createDir.Substring(0, index)
                                    logger.Debug("createDir2 " & createDir2)

                                    CreateNewDir(session, createDir2)
                                    createDir3 = createDir.Substring(index)
                                End While

                                TransferFile(session, remoteDir, localDir, True, Nothing, Nothing)

                                'Write path of the last directory/file transfered into Sync.ini file
                                If (MaxTimeFileName = Nothing) Then
                                    If (MaxDirName <> Nothing) Then
                                        SyncINIFile.WriteString(section, "LocalDirectory", MaxDirName & "\")
                                        logger.Info("Last Read Directory = " & MaxDirName & "\")
                                        SyncINIFile.WriteString(section, "RemoteDirectory", remoteDir)
                                        logger.Debug("set Remote Directory to " & remoteDir)
                                    End If
                                Else
                                    SyncINIFile.WriteString(section, "LocalDirectory", MaxTimeFileName)
                                    logger.Info("Last Read File = " & MaxTimeFileName)
                                    SyncINIFile.WriteString(section, "RemoteDirectory", remoteDir)
                                    logger.Debug("set Remote Directory to " & remoteDir)
                                End If
                            End If
                        End If
                    Next
                End Using
                logger.Info("---------------------session ended------------------------- ")
                Return 0
            Catch e As TimeoutException
                ConsolePrintf("Error: " & e.ToString)                
                logger.Error("Error : " & e.ToString)
                Return 1
            Catch e As InvalidOperationException
                ConsolePrintf("Error: " & e.ToString)
                logger.Error("Error : " & e.ToString)
                Return 1
            Catch e As SessionRemoteException
                logger.Error("Error : " & e.ToString)
                logger.Error("Error reported by remote server")
                Return 1
            Catch e As SessionLocalException
                ConsolePrintf("Error: " & e.ToString)                
                logger.Error("Error : " & e.ToString)
                logger.Error("Error in communicating with WinSCP.com")
                Return 1
            Catch e As ArgumentOutOfRangeException
                ConsolePrintf("Error: " & e.ToString)                
                logger.Error("Error : " & e.ToString)
                Return 1
            Catch e As ArgumentException
                ConsolePrintf("Error: " & e.ToString)                
                logger.Error("Error : " & e.ToString)
                Return 1
            Catch e As Exception
                ConsolePrintf("Error: " & e.ToString)
                logger.Error("Error : " & e.ToString)
                Return 1
            End Try
        End If

    End Function


    Private Shared Sub SetLogingLevel(ByVal strLogLevel As String)

        Const strChecker As String = "WARN_INFO_DEBUG_ERROR_FATAL"

        If (strLogLevel = Nothing Or Not strChecker.Contains(strLogLevel)) Then
            'Throw New Exception(" The strLogLevel should be set to WARN , INFO , DEBUG ,")
        End If

        Dim repositories As log4net.Repository.ILoggerRepository()
        repositories = log4net.LogManager.GetAllRepositories()

        'Configure all loggers to be at the debug level.
        For Each repository As log4net.Repository.ILoggerRepository In repositories

            repository.Threshold = repository.LevelMap(strLogLevel)
            Dim hier As log4net.Repository.Hierarchy.Hierarchy
            hier = CType(repository, log4net.Repository.Hierarchy.Hierarchy)

            Dim loggers As log4net.Core.ILogger()
            loggers = hier.GetCurrentLoggers()
            For Each logger As log4net.Core.ILogger In loggers

                Dim logger1 As log4net.Repository.Hierarchy.Logger
                logger1 = CType(logger, log4net.Repository.Hierarchy.Logger)
                logger1.Level = hier.LevelMap(strLogLevel)

            Next
        Next

        Dim h As log4net.Repository.Hierarchy.Hierarchy
        Dim Ilogger As log4net.Repository.ILoggerRepository
        Ilogger = log4net.LogManager.GetRepository()
        h = CType(Ilogger, log4net.Repository.Hierarchy.Hierarchy)
        Dim rootLogger As log4net.Repository.Hierarchy.Logger
        rootLogger = h.Root
        rootLogger.Level = h.LevelMap(strLogLevel)
    End Sub
    Private Shared Sub CreateNewDir(ByVal session As Session, ByVal remoteSubDir As String)
        Dim transferResult As TransferOperationResult
        If (Not session.FileExists(remoteSubDir)) Then
            ''if not deleting the files after transfer

            transferResult = session.PutFiles(NewFolder, remoteSubDir, False, transferOptions)
            logger.Debug("Created new folder " & remoteSubDir)
            '' Throw on any error
            transferResult.Check()

            '' Print results            
            For Each transfer1 In transferResult.Transfers
                'Console.WriteLine("Upload of {0} succeeded", transfer1.FileName)
                logger.Info("Upload of " & transfer1.FileName & " succeeded")
            Next
        End If
    End Sub
    Private Shared Sub TransferFile(ByVal session As Session, ByVal remoteDir As String, ByVal MainDir As String, ByVal first As Boolean, ByVal lastsyncdirdate As DateTime, ByVal lastsyncfiletime As DateTime)
        Dim fileName As String
        Dim dirInfo As DirectoryInfo
        Dim dirFileTime As Date
        Dim FileExtension As String        
        Dim timeFormat As String = "H_mm_ss"
        Dim dirEntries As String()
        dirEntries = Nothing
        If (Directory.Exists(MainDir)) Then
            dirEntries = Directory.GetDirectories(MainDir)
        Else
            logger.Error("Directory :" & MainDir & " does not exists")
        End If
        If (dirEntries(0) = Nothing) Then
            logger.Error("No directory exist in " & MainDir)
        Else
            For Each dirIndex As String In dirEntries

                'dirIndex = "E:\Infofile2\30-11-2012"
                logger.Debug("Dir Name " & dirIndex)

                Dim subDirName1 As String = Path.GetFileName(dirIndex)
                'subDirName1 = "30-11-2012"

                logger.Debug("Only Dir Name " & subDirName1)

                Dim SubDirDate As Date

                Dim SubDirDateStr As String

                SubDirDateStr = subDirName1.Replace("-", "/")
                Try
                    SubDirDate = CDate(SubDirDateStr)

                    If (first = False And lastsyncdirdate > SubDirDate) Then
                        Continue For
                    End If
                    If (MaxDirDate = Nothing) Then
                        MaxDirDate = SubDirDate
                        MaxDirName = dirIndex

                        MaxFileTime = Nothing
                        MaxTimeFileName = Nothing
                    ElseIf (MaxDirDate < SubDirDate) Then
                        MaxDirDate = SubDirDate
                        MaxDirName = dirIndex
                        MaxFileTime = Nothing
                        MaxTimeFileName = Nothing
                    End If
                    Dim remoteSubDir As String
                    remoteSubDir = remoteDir & subDirName1
                    logger.Debug("REmote dir " & remoteSubDir)
                    CreateNewDir(session, remoteSubDir)

                    logger.Debug("Now Sub directory path " & dirIndex)
                    'now copy files

                    dirInfo = New DirectoryInfo(dirIndex)
                    Dim file1 As FileInfo() = dirInfo.GetFiles()

                    Dim i As Integer
                    i = 0
                    Dim fileEntries As String() = Directory.GetFiles(dirIndex)
                    For Each fileNameIndex As String In fileEntries
                        Try
                            FileExtension = Path.GetExtension(fileNameIndex)
                            If (FileExtension = "." & FileType) Then
                                fileName = Path.GetFileName(fileNameIndex)
                                fileName = fileName.Substring(0, fileName.IndexOf("."))
                                dirFileTime = Date.ParseExact(fileName, timeFormat, provider)
                                dirFileTime = dirFileTime.ToLongTimeString
                                If (first = False And lastsyncdirdate = SubDirDate) Then
                                    If (lastsyncfiletime <> Nothing And dirFileTime <= lastsyncfiletime) Then
                                        Continue For
                                    End If
                                End If
                                If (MaxDirName = dirIndex) Then
                                    If (MaxFileTime = Nothing) Then
                                        MaxFileTime = dirFileTime
                                        MaxTimeFileName = fileNameIndex
                                    ElseIf (dirFileTime > MaxFileTime) Then
                                        MaxFileTime = dirFileTime
                                        MaxTimeFileName = fileNameIndex
                                    End If
                                End If
                                logger.Debug("Copying file " & dirFileTime)
                                Dim transferResult As TransferOperationResult

                                Dim FileLength As Long
                                Dim diff As Long
                                FileLength = file1(i).Length
                                'put one by on file in for loop

                                logger.Info("Transfering File = " & fileNameIndex & " of size = " & file1(i).Length & " Bytes")
                                ConsolePrintf("Transfering File = " & fileNameIndex & " of size = " & file1(i).Length & " Bytes")

                                Dim sw = Stopwatch.StartNew
                                Dim start = sw.ElapsedMilliseconds
                                Dim speed As Double
                                Try
                                    'if not deleting the files after transfer
                                    transferResult = session.PutFiles(fileNameIndex, remoteSubDir & "/", Delete, transferOptions)
                                    Dim sample = sw.ElapsedMilliseconds
                                    diff = sample - start

                                    If (FileLength > diff) Then
                                        speed = Round((FileLength / diff), 2)
                                    End If

                                    logger.Info(" Time required :- " & diff & " sec and Speed = " & speed & " Bytes/sec")
                                    ConsolePrintf("Time required :- " & diff & " sec and Speed = " & speed & " Bytes/sec")
                                    'session.ExecuteCommand()

                                    ''Throw on any error
                                    transferResult.Check()

                                    ''Print(results)
                                    Dim transfer As TransferEventArgs
                                    For Each transfer In transferResult.Transfers
                                        ConsolePrintf("Upload of " & transfer.FileName & " succeeded")
                                        logger.Info("Upload of " & transfer.FileName & " succeeded")
                                    Next
                                Catch e As TimeoutException
                                    logger.Error("Error : " & e.ToString)
                                Catch e As InvalidOperationException
                                    logger.Error("Error : " & e.ToString)
                                Catch e As SessionRemoteException
                                    logger.Error("Error : " & e.ToString)
                                    logger.Error("Error reported by remote server")
                                Catch e As SessionLocalException
                                    logger.Error("Error : " & e.ToString)
                                    logger.Error("Error in communicating with WinSCP.com")
                                Catch e As ArgumentOutOfRangeException
                                    logger.Error("Error : " & e.ToString)
                                Catch e As ArgumentException
                                    logger.Error("Error : " & e.ToString)
                                End Try
                            End If
                        Catch e As System.FormatException
                            logger.Error("Error : " & subDirName1 & " not in a Date format ")
                        End Try
                        i = i + 1
                    Next
                Catch e As InvalidCastException
                    logger.Error("Error : Directory = " & SubDirDateStr & " not in a Date format ")
                End Try
            Next
        End If
    End Sub
    Private Shared Sub ConsolePrintf(ByVal str As String)
        If (ConsolePrint) Then
            Console.WriteLine(str)
        End If
    End Sub
End Class
