Namespace System
Namespace IO

Class TextReader
	Implements System.IDisposable
Public
	Virtual Sub ~TextReader()
		Dispose(False)
	End Sub

'	Static Null = StreamReader.Null As TextReader

Public
	Sub Close()
		Dispose(True)
	End Sub

	Sub Dispose()
		Dispose(True)
	End Sub

	Virtual Function Peek() As Long
		If pos >= buf.Length Then
			buf.Length = 0
			pos = 0
			If Not Underflow() Then
				Peek = -1
				Exit Function
			End If
		End If
		Peek = buf[pos]
	End Function

	Virtual Function Read() As Long
		Read = Peek()
		pos++
	End Function
	/*
	@date 2008/02/26
	@auther Egtra
	*/
	Virtual Function Read(buffer As *Char, index As Long, count As Long) As Long
		If buffer = 0 Then
			Throw New ArgumentNullException("buffer")
		ElseIf index < 0 Then
			Throw New ArgumentOutOfRangeException("index")
		ElseIf count < 0 Then
			Throw New ArgumentOutOfRangeException("count")
		End If
		Read = ReadImpl(VarPtr(buffer[index]), count)
	End Function

	Static Function Synchronized(reader As TextReader) As TextReader
		Synchronized = New Detail.SynchronizedTextReader(reader)
	End Function

	/*
	@date 2008/02/26
	@auther Egtra
	@retval Nothing EOFに達しているとき
	@retval 有効なStringインスタンス 読み取った1行
	*/
	Virtual Function ReadLine() As String
		If Peek() = -1 Then
			Exit Function
		End If
		Dim sb = New Text.StringBuilder
		Dim isLead = FALSE
		Do
			Dim ch = Read()
			If ch = -1 Then Exit Do
			If isLead = FALSE Then
				If ch = &h0D Then
					If Peek() = &h0A Then
						Read() 'CR LFの場合
					End If
					Exit Do
				End If
				Select Case ch
					Case -1 'EOF
						Exit Do
					Case &h0A 'LF
						Exit Do
					Case &h0B 'VT
						Exit Do
					Case &h0C 'FF
						Exit Do
					Case &h0D 'CR
						Exit Do
#ifdef UNICODE
					Case &h85 'NEL
						Exit Do
					Case &h2028 'LS
						Exit Do
					Case &h2029 'PS
						Exit Do
#endif
				End Select
			End If
			sb.Append(ch As Char)
#ifndef UNICODE
			isLead = IsDBCSLeadByte(ch As Byte)
#endif
		Loop
		ReadLine = sb.ToString()
	End Function

	/*!
	@brief 現在位置からストリームの終わりまで読み込む。
	@date 2008/02/26
	@auther Egtra
	*/
	Virtual Function ReadToEnd() As String
		buf.Remove(0, pos)
		While Underflow()
		Wend
		ReadToEnd = buf.ToString()
		buf.Length = 0
		pos = 0
	End Function

Protected
	Sub TextReader()
		buf = New Text.StringBuilder
		pos = 0
	End Sub

	Virtual Sub Dispose(disposing As Boolean)
	End Sub

	/*!
	@brief バッファが足りなくなったときに呼ばれる。
	@date 2008/12/27
	@auther Egtra
	@retval True まだEOFに達していない場合
	@retval False EOFに達した場合
	*/
	Virtual Function Underflow() As Boolean
		Underflow = False
	End Function

	/*!
	@brief 内部バッファを返す
	@date 2008/12/27
	@auther Egtra
	@return 内部バッファ
	内部バッファの既存の要素は、一切の変更をしないこと。また、空であるという仮定を置かないこと。
	*/
	Function Buffer() As Text.StringBuilder
		Buffer = buf
	End Function

	/*!
	@date 2008/02/26
	@auther Egtra
	*/
	Function ReadImpl(buffer As *Char, count As Long) As Long
		'ToDo 適当なところでバッファの読み取り済みの部分を除去する処理を入れる（現在Peekのみ）。
		Dim p = StrPtr(buf)
		While buf.Length - pos < count
			If Underflow() = False Then Exit While
		Wend
		ReadImpl = Math.Min(buf.Length - pos, count)
		ActiveBasic.Strings.ChrCopy(buffer, VarPtr(p[pos]) As *Char, ReadImpl As SIZE_T)
		pos += ReadImpl
	End Function

Private
	buf As Text.StringBuilder
	pos As Long
End Class

Namespace Detail

Class SynchronizedTextReader
	Inherits TextReader
Public
	Sub SynchronizedTextReader(reader As TextReader)
		cs = New ActiveBasic.Windows.CriticalSection
		base = reader
	End Sub

	Override Function Peek() As Long
'		Using lock = cs.Lock()
			Peek = base.Peek()
'		End Using
	End Function

	Override Function Read() As Long
'		Using lock = cs.Lock()
			Read = base.Read()
'		End Using
	End Function

	Override Function Read(buffer As *Char, index As Long, count As Long) As Long
'		Using lock = cs.Lock()
			Read = base.Read(buffer, index, count)
'		End Using
	End Function

	Override Function ReadToEnd() As String
'		Using lock = cs.Lock
			ReadToEnd = base.ReadToEnd
'		End Using
	End Function

Protected
	Override Sub Dispose(disposing As Boolean)
		Dim s = Nothing As Stream
		SetPointer(VarPtr(s) As *VoidPtr, InterlockedExchangePointer(ByVal VarPtr(base) As *VoidPtr, 0))
		If disposing Then
			If Not ActiveBasic.IsNothing(s) Then
				s.Dispose()
			End If
			cs.Dispose()
		End If
	End Sub

Private
	cs As ActiveBasic.Windows.CriticalSection
	base As TextReader
End Class

End Namespace

End Namespace
End Namespace
