' *
' * The project site is at: http://sourceforge.jp/projects/fishbornas/
' *
' * First author tiritomato 2012.
' *
' * Distributed under the FishbornArchiveShelf License (See
' *  file "Licenses/License.txt" contained in a project, or the following link.
' *  http://sourceforge.jp/projects/fishbornas/scm/svn/blobs/head/trunk/Licenses/License.txt)
' *
' * 2012.06.07 Initial Revision (tiritomato)
' *

Partial Public Class AppBase

    Partial Class Archive

        Partial Public Class Threading

            Public Const FILECOPY_BUFFERSIZE As Integer = 1024 * 8
            Public Const FILECOPY_LOGINTERVAL As Integer = 128
            Public Const FILECOPY_CANCELINTERVAL As Integer = FILECOPY_LOGINTERVAL * 4

            Public Shared Function BinaryFileCopy(ByVal AppBase As AppBase, ByVal DestPath As Logic.FileSystem.Path, ByVal SrcPath As Logic.FileSystem.Path,
                                                  Optional ByVal IsStopRequested As Logic.Threading.SignalHandler = Nothing,
                                                  Optional ByVal TemporaryPriority As System.Threading.ThreadPriority = System.Threading.ThreadPriority.Highest) As RESULT

                If AppBase Is Nothing Or DestPath Is Nothing Or SrcPath Is Nothing Then Return AppBase.RESULT.NO_OBJECT
                If SrcPath.FileExists = False Then Return AppBase.RESULT.NO_FILE
                If DestPath.Equals(SrcPath) Then Return AppBase.RESULT.FILECOPY_ERR

                BinaryFileCopy = RESULT.OK

                Dim buf(FILECOPY_BUFFERSIZE - 1) As Byte, szFile As Long, szCopyProgress As Long = 0
                Dim hFileSrc As IO.FileStream = Nothing
                Dim iFileSrc As IO.FileInfo = Nothing
                Dim hFileDest As IO.FileStream = Nothing
                Dim iFileDest As IO.FileInfo = Nothing
                Dim ctTryRead As Integer, ctRead As Integer
                Dim ctLogInterval As Integer = 0
                Dim ctCancelInterval As Integer = 0
                Dim RegistedPri As System.Threading.ThreadPriority = System.Threading.Thread.CurrentThread.Priority

                Try
                    AppBase.Echoing.Log.Echo("FileCopySrc " & SrcPath.ToString, AppendLogArgs.LogType.Status)
                    AppBase.Echoing.Log.Echo("FileCopyDest " & DestPath.ToString, AppendLogArgs.LogType.Status)

                    System.Threading.Thread.CurrentThread.Priority = TemporaryPriority

                    ' get file info
                    iFileSrc = New IO.FileInfo(SrcPath.ToString)
                    szFile = iFileSrc.Length
                    iFileSrc = Nothing

                    DestPath.DeleteFile()
                    hFileDest = New IO.FileStream(DestPath.ToString, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.None, 4)
                    hFileSrc = New IO.FileStream(SrcPath.ToString, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.None, 4)
                    Do
                        For ctTryRead = 0 To 7
                            Try
                                ctRead = hFileSrc.Read(buf, 0, buf.Length)
                            Catch ex As IO.IOException
                                ctRead = -1 '              ioerr?(without eof)->retry
                            End Try
                            If 0 <= ctRead Then Exit For ' eof or read succeed
                        Next

                        If ctRead <= 0 Then
                            If ctRead < 0 Then BinaryFileCopy = RESULT.FILECOPY_ERR
                            Exit Do
                        End If

                        hFileDest.Write(buf, 0, ctRead)

                        szCopyProgress = szCopyProgress + ctRead

                        If FILECOPY_LOGINTERVAL <= ctLogInterval Then
                            AppBase.Echoing.Progress.Echo(CInt(Fix(CDbl(szCopyProgress) / CDbl(szFile) * 100.0)), 100)
                            ctLogInterval = 0
                        Else
                            ctLogInterval = ctLogInterval + 1
                        End If

                        If FILECOPY_CANCELINTERVAL <= ctCancelInterval Then

                            ' Sleep
                            System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest
                            System.Threading.Thread.CurrentThread.Join(0)
                            System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest

                            ' Cancel Check
                            If IsStopRequested IsNot Nothing AndAlso IsStopRequested() Then
                                BinaryFileCopy = RESULT.USER_CANCEL
                                Exit Do
                            End If
                            ctCancelInterval = 0

                        Else
                            ctCancelInterval = ctCancelInterval + 1
                        End If
                    Loop

                Catch ex As Exception
                    BinaryFileCopy = RESULT.NO_FILE
                    Throw
                Finally
                    If Not hFileDest Is Nothing Then hFileDest.Close()
                    If Not hFileSrc Is Nothing Then hFileSrc.Close()
                    System.Threading.Thread.CurrentThread.Priority = RegistedPri
                End Try

                If BinaryFileCopy <> RESULT.OK Then
                    DestPath.DeleteFile()
                    Exit Function
                End If

                Try
                    ' apply file info
                    iFileSrc = New IO.FileInfo(SrcPath.ToString)
                    iFileDest = New IO.FileInfo(DestPath.ToString)
                    iFileDest.CreationTime = iFileSrc.CreationTime
                    iFileDest.LastAccessTime = iFileSrc.LastAccessTime
                    iFileDest.LastWriteTime = iFileSrc.LastWriteTime
                    iFileDest.Attributes = iFileSrc.Attributes
                Catch
#If DEBUG Then
                    Throw
#End If
                End Try

            End Function

        End Class ' AppBase.Archive.Threading
    End Class ' AppBase.Archive
End Class ' AppBase
