Namespace British
Public Class Cup(Of T)
Private _Random As Random
Private _Timer As Timer
Private _ReheatingTime As TimeSpan
Private _ReheatingStopwatch As Stopwatch
Private _IsReheating As Boolean
Protected Contents As Stack(Of T)
''' <summary>
''' Creates a new Cup(Of T) of the specified size.
''' </summary>
''' <param name="size">How much T your Cup(Of T) can hold without overflowing.</param>
Public Sub New(size As Integer)
If size <= 0 Then
Throw New ArgumentOutOfRangeException("size", "Such a small cup does not exist!")
End If
_Size = size
_Random = New Random()
Me.Contents = New Stack(Of T)()
Me.Temperature = 0
_Timer = New Timer()
_Timer.Interval = 500
AddHandler _Timer.Tick, AddressOf Timer_Tick
End Sub
''' <summary>
''' Creates a new Cup(Of T) of the specified size.
''' </summary>
''' <param name="size">How much T your Cup(Of T) can hold without overflowing.</param>
''' <param name="contents">The initial contents of your Cup(Of T)</param>
Public Sub New(size As Integer, contents As IEnumerable(Of T))
Me.New(size)
For Each content As T In contents
Me.Push(content)
Next
Me.Temperature = 100
End Sub
#Region " Properties "
Private _Temperature As Integer
''' <summary>
''' Gets the current temperature of your Cup(Of T). Be careful when drinking hot fluids!
''' </summary>
''' <returns>The current temperature of your Cup(Of T).</returns>
Public Property Temperature() As Integer
Get
Return _Temperature
End Get
Private Set(ByVal value As Integer)
If _Temperature <> value Then
_Temperature = value
Me.OnTemperatureChanged(EventArgs.Empty)
End If
End Set
End Property
Private _Size As Integer
''' <summary>
''' Gets the size of your cup. Be careful not to overflow it!
''' </summary>
''' <returns>The size of your cup.</returns>
Public ReadOnly Property Size() As Integer
Get
Return _Size
End Get
End Property
#End Region
#Region " Methods "
Private Sub Push(content As T)
Me.Contents.Push(content)
If Me.Contents.Count > Me.Size Then
Throw New OverflowException("Your cup is too full and has overflown. Look at the mess you made!")
End If
End Sub
Private Sub CanDrink()
If Me.Contents.Count = 0 Then
Throw New EmptyCupException("You cannot drink from an empty cup. Try calling Refill() first.")
End If
If Me.Temperature <= 0 Then
Throw New TemperatureException("Your T has frozen. Try calling Reheat() first.")
End If
If Me.Temperature >= 40 Then
Throw New TemperatureException("You burned your tongue. Try waiting some more or calling Blow() first.")
End If
End Sub
''' <summary>
''' If you can currently drink the T, you will take a small sip.
''' </summary>
Public Sub Sip()
Me.CanDrink()
Me.Contents.Pop()
End Sub
''' <summary>
''' If you can currently drink the T, you will drink about a quarter of the T.
''' </summary>
Public Sub Drink()
Me.CanDrink()
Dim amount As Integer = _Random.Next(CInt(Me.Contents.Count * (1 / 8)), CInt(Me.Contents.Count * (3 / 8)))
For i As Integer = 0 To amount - 1
Me.Contents.Pop()
Next
End Sub
''' <summary>
''' Stir around the contents of the T.
''' </summary>
Public Sub Stir()
Dim oldContents = Me.Contents.ToList()
Dim newContents = From c As T In oldContents Order By _Random.NextDouble() Select c
Me.Contents.Clear()
For Each content In newContents
Me.Push(content)
Next
End Sub
''' <summary>
''' Add some extra T to your cup. Note that the temperature will change!
''' </summary>
Public Sub Refill(contents As IEnumerable(Of T))
Dim amount = Me.Contents.Count
For Each content As T In contents
Me.Push(content)
Next
Dim ratio = amount / Me.Contents.Count
Me.Temperature = CInt(Me.Temperature * ratio + 100 * (ratio - 1))
End Sub
''' <summary>
''' Reheats your T for the specified time.
''' </summary>
''' <param name="time">The time to reheat your T for. Be careful not to make it too hot!</param>
Public Sub Reheat(time As TimeSpan)
_IsReheating = True
_ReheatingTime = time
_ReheatingStopwatch = New Stopwatch
_ReheatingStopwatch.Start()
End Sub
''' <summary>
''' Blows in your Cup(Of T) to cool it down.
''' </summary>
Public Sub Blow()
Me.Temperature -= 10
End Sub
''' <summary>
''' If the temperature is too high some T will evaporate!
''' </summary>
Private Sub Evaporate()
For i As Integer = 0 To _Random.Next(0, 5)
If Me.Contents.Count > 0 Then Me.Contents.Pop()
Next
End Sub
Private Sub Timer_Tick(sender As Object, e As EventArgs)
If _IsReheating Then
If _ReheatingStopwatch.Elapsed >= _ReheatingTime Then
_ReheatingStopwatch.Stop()
_IsReheating = False
End If
Me.Temperature += _Random.Next(10, 20)
Else
Me.Temperature -= _Random.Next(0, 5)
End If
If Me.Temperature >= 100 Then
Me.Evaporate()
End If
End Sub
#End Region
#Region " Events "
Public Event TemperatureChanged As EventHandler
Protected Overridable Sub OnTemperatureChanged(e As EventArgs)
RaiseEvent TemperatureChanged(Me, e)
End Sub
#End Region
#Region " Nested classes "
Public Class OverflowException
Inherits System.Exception
Public Sub New(msg As String)
MyBase.New(msg)
End Sub
End Class
Public Class EmptyCupException
Inherits System.Exception
Public Sub New(msg As String)
MyBase.New(msg)
End Sub
End Class
Public Class TemperatureException
Inherits System.Exception
Public Sub New(msg As String)
MyBase.New(msg)
End Sub
End Class
#End Region
End Class
End Namespace