UnitTest updated

UnitTest updated

'This is a not module
Strict

Import unittest
Import flixel
Import reflection

#REFLECTION_FILTER="main*|flixel*"

Function Main:Int()
	Local classObject:GlobalInfo

	For Local classInfo:ClassInfo = EachIn GetClasses()
		classObject = classInfo.GetGlobal("ClassObject", False)
		If (classObject = Null) classObject = classInfo.GetGlobal("ClassInfo", False)

		If (classObject <> Null) Then
			classObject.SetValue(classInfo)
		End If
	Next

	New FlixelUnitTest()
	Return 0
End Function

'#Region FlxPoint tests bundle

Class FlxPointUnitTestBase Implements IUnitTest Abstract

	Field x:Float = 10, y:Float = 100
	Field p1:FlxPoint, p2:FlxPoint

	Method New()
		p1 = New FlxPoint(x, y)
		p2 = New FlxPoint()
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

private
	Method _AssertPoint:Bool()
		Return (UnitTest.AssertEqualsF(x, p1.x) And UnitTest.AssertEqualsF(y, p1.y))
	End Method

	Method _AssertPoints:Bool()
		Return (UnitTest.AssertEqualsF(p2.x, p1.x) And UnitTest.AssertEqualsF(p2.y, p1.y))
	End Method

End Class

Class FlxPointNewUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		Return _AssertPoint()
	End Method

	Method GetName:String()
		Return "FlxPoint.New"
	End Method

End Class

Class FlxPointMakeUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p1 = New FlxPoint()
		p1 = p1.Make(x, y)
		Return _AssertPoint()
	End Method

	Method GetName:String()
		Return "FlxPoint.Make"
	End Method

End Class

Class FlxPointCopyToUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p1.CopyTo(p2)
		Return _AssertPoints()
	End Method

	Method GetName:String()
		Return "FlxPoint.CopyTo"
	End Method

End Class

Class FlxPointCopyFromUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p2.CopyFrom(p1)
		Return _AssertPoints()
	End Method

	Method GetName:String()
		Return "FlxPoint.CopyFrom"
	End Method

End Class

'#End Region

'#Region FlxRect tests bundle

Class FlxRectUnitTestBase Implements IUnitTest Abstract

	Field x:Float = 10, y:Float = 100
	Field width:Float = 110, height:Float = 1000
	Field r1:FlxRect, r2:FlxRect

	Method New()
		r1 = New FlxRect(x, y, width, height)
		r2 = New FlxRect()
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

Private
	Method _AssertRect:Bool()
		Return (UnitTest.AssertEqualsF(x, r1.x) And UnitTest.AssertEqualsF(y, r1.y) And
			UnitTest.AssertEqualsF(width, r1.width) And UnitTest.AssertEqualsF(height, r1.height))
	End Method

	Method _AssertRects:Bool()
		Return (UnitTest.AssertEqualsF(r2.x, r1.x) And UnitTest.AssertEqualsF(r2.y, r1.y) And
			UnitTest.AssertEqualsF(r2.width, r1.width) And UnitTest.AssertEqualsF(r2.height, r1.height))
	End Method

End Class

Class FlxRectNewUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return _AssertRect()
	End Method

	Method GetName:String()
		Return "FlxRect.New"
	End Method

End Class

Class FlxRectMakeUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r1 = New FlxRect()
		r1 = r1.Make(x, y, width, height)
		Return _AssertRect()
	End Method

	Method GetName:String()
		Return "FlxRect.Make"
	End Method

End Class

Class FlxRectLeftUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(x, r1.Left)
	End Method

	Method GetName:String()
		Return "FlxRect.Left"
	End Method

End Class

Class FlxRectRightUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(x + width, r1.Right)
	End Method

	Method GetName:String()
		Return "FlxRect.Right"
	End Method

End Class

Class FlxRectTopUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(y, r1.Top)
	End Method

	Method GetName:String()
		Return "FlxRect.Top"
	End Method

End Class

Class FlxRectBottomUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(y + height, r1.Bottom)
	End Method

	Method GetName:String()
		Return "FlxRect.Bottom"
	End Method

End Class

Class FlxRectCopyToUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r1.CopyTo(r2)
		Return _AssertRects()
	End Method

	Method GetName:String()
		Return "FlxRect.CopyTo"
	End Method

End Class

Class FlxRectCopyFromUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r2.CopyFrom(r1)
		Return _AssertRects()
	End Method

	Method GetName:String()
		Return "FlxRect.CopyFrom"
	End Method

End Class

'#End Region

'#Region FlxGroup tests bundle

Class FlxGroupUnitTestBase Implements IUnitTest Abstract

	Field countObjects:Int = 10
	Field objects:FlxBasic[]
	Field group:FlxGroup

	Method New()
		objects = new FlxBasic[countObjects]

		For Local i:Int = 0 To countObjects - 1
			objects[i] = New FlxBasic()
			objects[i].ID = i
		Next
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

End Class

Class FlxGroupAddUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.Length)) Return False

		Local maxSize:Int = 5
		group = New FlxGroup(maxSize)
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		Return UnitTest.AssertEqualsI(i, maxSize)
	End Method

	Method GetName:String()
		Return "FlxGroup.Add"
	End Method

End Class

Class FlxGroupRecycleUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup(10)

		Local recycled:FlxBasic
		For Local i:Int = 0 To group.MaxSize - 1
			recycled = group.Recycle(ClassInfo(FlxBasic.ClassObject))
			If (Not UnitTest.AssertNotNull(recycled)) Return False
			recycled.ID = i
		Next

		For Local basic:FlxBasic = EachIn objects
			recycled = group.Recycle()
			If (Not UnitTest.AssertNotNull(recycled)) Return False
			If (Not UnitTest.AssertEqualsI(basic.ID, recycled.ID)) Return False
		Next

		group = New FlxGroup()

		For Local i:Int = 0 To 9
			recycled = group.Recycle(ClassInfo(FlxBasic.ClassObject))
			If (Not UnitTest.AssertNotNull(recycled)) Return False
			recycled.ID = i
		Next

		recycled = group.Recycle(ClassInfo(FlxBasic.ClassObject))
		If (Not UnitTest.AssertNotNull(recycled)) Return False
		If (Not UnitTest.AssertEqualsI(-1, recycled.ID)) Return False

		group.Members[5].Kill()
		recycled = group.Recycle(ClassInfo(FlxBasic.ClassObject))
		If (Not UnitTest.AssertNotNull(recycled)) Return False
		If (Not UnitTest.AssertEqualsI(5, recycled.ID)) Return False

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.Recycle"
	End Method

End Class

Class FlxGroupRemoveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		For Local basic:FlxBasic = EachIn objects
			If (Not UnitTest.AssertNotNull(group.Remove(basic))) Return False
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.Length)) Return False

		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		For Local basic:FlxBasic = EachIn objects
			If (Not UnitTest.AssertNotNull(group.Remove(basic, True))) Return False
		Next

		Return UnitTest.AssertEqualsI(0, group.Length)
	End Method

	Method GetName:String()
		Return "FlxGroup.Remove"
	End Method

End Class

Class FlxGroupAddRemoveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic)
			i+=1
		Next

		Local newBasic:FlxBasic = new FlxBasic()
		newBasic.ID = 10
		group.Add(newBasic)

		If (Not UnitTest.AssertEqualsI(group.Members[5].ID, newBasic.ID)) Return False

		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic, True)
			i+=1
		Next

		group.Add(newBasic)
		If (Not UnitTest.AssertEqualsI(group.Members[8].ID, newBasic.ID)) Return False

		group = New FlxGroup(6)

		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic)
			i+=1
		Next

		group.Add(newBasic)
		If (Not UnitTest.AssertEqualsI(group.Members[5].ID, newBasic.ID)) Return False

		group = New FlxGroup(6)

		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic, True)
			i+=1
		Next

		group.Add(newBasic)
		Return (UnitTest.AssertEqualsI(group.Members[5].ID, newBasic.ID))
	End Method

	Method GetName:String()
		Return "FlxGroup.Add/Remove"
	End Method

End Class

Class FlxGroupMaxSizeUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.MaxSize = 15

		If (Not UnitTest.AssertEqualsI(objects.Length, group.Length)) Return False

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		group.MaxSize = 6
		If (Not UnitTest.AssertEqualsI(group.MaxSize, group.Length)) Return False
		i = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.MaxSize"
	End Method

End Class

Class FlxGroupReplaceUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Replace(objects[0], objects[countObjects - 1])
		Return UnitTest.AssertEqualsI(countObjects - 1, group.Members[0].ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.Replace"
	End Method

End Class

Class FlxGroupSortUnitTest Extends FlxGroupUnitTestBase Implements FlxBasicComparator

	Method Run:Bool()
		group = New FlxGroup()
		Local i:Int = countObjects - 1
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
			basic.ID = i
			i-=1
		Next

		group.Sort(Self)

		i = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(i, basic.ID)) Return False
			i+=1
		Next

		group.Sort(Self, FlxGroup.DESCENDING)

		i = countObjects - 1
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(i, basic.ID)) Return False
			i-=1
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.Sort"
	End Method

	Method Compare:Int(lhs:FlxBasic,rhs:FlxBasic)
		Return lhs.ID - rhs.ID
	End Method

End Class

Class FlxGroupSetAllUnitTest Extends FlxGroupUnitTestBase Implements FlxBasicSetter

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local group2:FlxGroup = New FlxGroup(5)
		For Local basic:FlxBasic = EachIn objects
			group2.Add(basic)
		Next
		group.Add(group2)

		group.SetAll(Self, IntObject(100), False)

		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(100, basic.ID)) Return False
		Next

		group.SetAll(Self, IntObject(50), False)

		For Local basic:FlxBasic = EachIn group
			If (FlxGroup(basic) <> Null) Then
				For Local innerBasic:FlxBasic = EachIn FlxGroup(basic).Members
					If (Not UnitTest.AssertEqualsI(50, innerBasic.ID)) Return False
				Next
			Else
				If (Not UnitTest.AssertEqualsI(50, basic.ID)) Return False
			End If
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.SetAll"
	End Method

	Method Set:Void(basic:FlxBasic, value:Object)
		basic.ID = IntObject(value)
	End Method

End Class

Class FlxGroupCallAllUnitTest Extends FlxGroupUnitTestBase Implements FlxBasicInvoker

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local group2:FlxGroup = New FlxGroup(5)
		For Local basic:FlxBasic = EachIn objects
			group2.Add(basic)
		Next
		group.Add(group2)

		group.CallAll(Self, False)

		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertFalse(basic.exists)) Return False
			basic.Revive()
		Next

		group.CallAll(Self)

		For Local basic:FlxBasic = EachIn group
			If (FlxGroup(basic) <> Null) Then
				For Local innerBasic:FlxBasic = EachIn FlxGroup(basic).Members
					If (Not UnitTest.AssertFalse(innerBasic.exists)) Return False
				Next
			Else
				If (Not UnitTest.AssertFalse(basic.exists)) Return False
			End If
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.CallAll"
	End Method

	Method Invoke:Void(basic:FlxBasic)
		basic.Kill()
	End Method

End Class

Class FlxGroupGetFirstAvailableUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		Local i:Int = 0
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
			If (i > 4 And i < 7) Then basic.Kill()
			i+=1
		Next

		Local basic:FlxBasic = group.GetFirstAvailable(ClassInfo(FlxBasic.ClassObject))

		If (UnitTest.AssertNotNull(basic) And UnitTest.AssertEqualsI(5, basic.ID)) Then
			basic = group.GetFirstAvailable()

			If (Not UnitTest.AssertNotNull(basic) Or
				Not UnitTest.AssertEqualsI(5, basic.ID)) Then
				Return False
			End If

			Local object:FlxObject = FlxObject(group.Add(new FlxObject()))
			object.ID = 10

			object = FlxObject(group.Add(new FlxObject()))
			object.ID = 11
			object.Kill()

			object = FlxObject(group.GetFirstAvailable(ClassInfo(FlxObject.ClassObject)))
			Return (UnitTest.AssertNotNull(object) And UnitTest.AssertEqualsI(11, object.ID))
		End If

		Return False
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstAvailable"
	End Method

End Class

Class FlxGroupGetFirstNullUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(-1, group.GetFirstNull())) Return False
		group.Remove(objects[5])

		Return UnitTest.AssertEqualsI(5, group.GetFirstNull())
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstNull"
	End Method

End Class

Class FlxGroupGetFirstExtantUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(0, group.GetFirstExtant().ID)) Return False
		group.Members[0].Kill()
		group.Members[1].Kill()
		group.Members[2].Kill()

		Return UnitTest.AssertEqualsI(3, group.GetFirstExtant().ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstExtant"
	End Method

End Class

Class FlxGroupGetFirstAliveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(0, group.GetFirstAlive().ID)) Return False
		group.Members[0].Kill()
		group.Members[1].Kill()
		group.Members[2].Kill()
		group.Members[2].exists = True

		Return UnitTest.AssertEqualsI(3, group.GetFirstAlive().ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstAlive"
	End Method

End Class

Class FlxGroupGetFirstDeadUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertNull(group.GetFirstDead())) Return False
		group.Members[0].Kill()
		group.Members[0].alive = True
		group.Members[1].Kill()
		group.Members[1].alive = True
		group.Members[2].Kill()

		Return UnitTest.AssertEqualsI(2, group.GetFirstDead().ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstDead"
	End Method

End Class

Class FlxGroupCountLivingUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.CountLiving())) Return False
		group.Members[0].Kill()
		group.Members[0].alive = True
		group.Members[1].Kill()
		group.Members[2].Kill()

		Return UnitTest.AssertEqualsI(countObjects - 3, group.CountLiving())
	End Method

	Method GetName:String()
		Return "FlxGroup.CountLiving"
	End Method

End Class

Class FlxGroupCountDeadUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(0, group.CountDead())) Return False
		group.Members[0].Kill()
		group.Members[0].alive = True
		group.Members[1].Kill()
		group.Members[2].Kill()

		Return UnitTest.AssertEqualsI(2, group.CountDead())
	End Method

	Method GetName:String()
		Return "FlxGroup.CountDead"
	End Method

End Class

Class FlxGroupClearUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Clear()

		If (Not UnitTest.AssertEqualsI(-1, group.CountDead())) Return False
		If (Not UnitTest.AssertEqualsI(-1, group.CountLiving())) Return False

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group
			i+=1
		Next

		If (Not UnitTest.AssertEqualsI(0, i)) Return False

		Return UnitTest.AssertTrue(group.Members[0].alive)
	End Method

	Method GetName:String()
		Return "FlxGroup.Clear"
	End Method

End Class

Class FlxGroupKillUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Kill()

		If (Not UnitTest.AssertEqualsI(countObjects, group.CountDead())) Return False
		If (Not UnitTest.AssertEqualsI(0, group.CountLiving())) Return False

		Return UnitTest.AssertFalse(group.alive)
	End Method

	Method GetName:String()
		Return "FlxGroup.Kill"
	End Method

End Class

Class FlxGroupDestroyUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Destroy()

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group
			i+=1
		Next

		If (Not UnitTest.AssertEqualsI(0, i)) Return False

		Return UnitTest.AssertEqualsI(0, group.Members.Length())
	End Method

	Method GetName:String()
		Return "FlxGroup.Destroy"
	End Method

End Class

Class FlxGroupFinalUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()

		group.Update()
		group.Draw()
		group.DrawDebug()
		group.GetRandom()
		group.ToString()

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup final"
	End Method

End Class

'#End Region

'#Region FlxG tests bundle

Class FlxGAddPluginUnitTest Implements IUnitTest

	Method Run:Bool()
		Local oldL:Int = FlxG.Plugins.Length()
		FlxG.AddPlugin(New TimerManager())
		FlxG.AddPlugin(New TimerManager())
		Return UnitTest.AssertEqualsI(oldL, FlxG.Plugins.Length())
	End Method

	Method GetName:String()
		Return "FlxG.AddPlugin"
	End Method

End Class

Class FlxGGetPluginUnitTest Implements IUnitTest

	Method Run:Bool()
		Return UnitTest.AssertNotNull(TimerManager(FlxG.GetPlugin(ClassInfo(TimerManager.ClassObject))))
	End Method

	Method GetName:String()
		Return "FlxG.GetPlugin"
	End Method

End Class

Class FlxGRemovePluginUnitTest Implements IUnitTest

	Method Run:Bool()
		Local oldL:Int = FlxG.Plugins.Length()
		FlxG.RemovePlugin(FlxG.GetPlugin(ClassInfo(TimerManager.ClassObject)))
		If (Not UnitTest.AssertEqualsI(oldL - 1, FlxG.Plugins.Length())) Return False
		FlxG.Init(Null, 0, 0, 0)
		Return True
	End Method

	Method GetName:String()
		Return "FlxG.RemovePlugin"
	End Method

End Class

Class FlxGRemovePluginTypeUnitTest Implements IUnitTest

	Method Run:Bool()
		Local oldL:Int = FlxG.Plugins.Length()
		FlxG.RemovePluginType(ClassInfo(TimerManager.ClassObject))
		If (Not UnitTest.AssertEqualsI(oldL -  1, FlxG.Plugins.Length())) Return False
		FlxG.Init(Null, 0, 0, 0)
		Return True
	End Method

	Method GetName:String()
		Return "FlxG.RemovePluginType"
	End Method

End Class

'#End Region

'#Region TimeManager tests bundle
Class TimeManagerUnitTest Implements IUnitTest

	Method Run:Bool()
		Local timeManager:TimerManager = TimerManager(FlxG.GetPlugin(ClassInfo(TimerManager.ClassObject)))
		Local timer:FlxTimer = New FlxTimer()

		timeManager.Add(New FlxTimer())
		timeManager.Add(timer)
		timeManager.Update()
		timeManager.Remove(timer)
		timeManager.Clear()
		timeManager.Destroy()
		timeManager = Null
		timer = Null

		Return True
	End Method

	Method GetName:String()
		Return "TimeManager full"
	End Method

End Class

Class FlixelUnitTest Extends UnitTestApp

	Method Setup:Void()
		FlxG.Init(Null, 0, 0, 0)

		'#Region add FlxPoint tests bundle

		AddTest(New FlxPointNewUnitTest())
		AddTest(New FlxPointMakeUnitTest())
		AddTest(New FlxPointCopyToUnitTest())
		AddTest(New FlxPointCopyFromUnitTest())

		'#End Region

		'#Region add FlxRect tests bundle

		AddTest(New FlxRectNewUnitTest())
		AddTest(New FlxRectMakeUnitTest())
		AddTest(New FlxRectLeftUnitTest())
		AddTest(New FlxRectRightUnitTest())
		AddTest(New FlxRectTopUnitTest())
		AddTest(New FlxRectBottomUnitTest())
		AddTest(New FlxRectCopyToUnitTest())
		AddTest(New FlxRectCopyFromUnitTest())

		'#End Region

		'#Region add FlxGroup tests bundle

		AddTest(New FlxGroupAddUnitTest())
		AddTest(New FlxGroupRecycleUnitTest())
		AddTest(New FlxGroupRemoveUnitTest())
		AddTest(New FlxGroupAddRemoveUnitTest())
		AddTest(New FlxGroupMaxSizeUnitTest())
		AddTest(New FlxGroupReplaceUnitTest())
		AddTest(New FlxGroupSortUnitTest())
		AddTest(New FlxGroupSetAllUnitTest())
		AddTest(New FlxGroupCallAllUnitTest())
		AddTest(New FlxGroupGetFirstAvailableUnitTest())
		AddTest(New FlxGroupGetFirstNullUnitTest())
		AddTest(New FlxGroupGetFirstExtantUnitTest())
		AddTest(New FlxGroupGetFirstAliveUnitTest())
		AddTest(New FlxGroupGetFirstDeadUnitTest())
		AddTest(New FlxGroupCountLivingUnitTest())
		AddTest(New FlxGroupCountDeadUnitTest())
		AddTest(New FlxGroupClearUnitTest())
		AddTest(New FlxGroupKillUnitTest())
		AddTest(New FlxGroupDestroyUnitTest())
		AddTest(New FlxGroupFinalUnitTest())

		'#End Region

		'#Region add FlxG tests bundle

		AddTest(New FlxGAddPluginUnitTest())
		AddTest(New FlxGGetPluginUnitTest())
		AddTest(New FlxGRemovePluginUnitTest())
		AddTest(New FlxGRemovePluginTypeUnitTest())

		'#End Region

		'#Region add TimeManager tests bundle

		AddTest(New TimeManagerUnitTest())

		'#End Region

	End Method

	Method GetName:String()
		Return "Flixel library"
	End Method

End Class

'This is a not module
Strict

Import unittest
Import flixel

Function Main:Int()
	New FlixelUnitTest()
	Return 0
End Function

'#Region FlxPoint tests bundle

Class FlxPointUnitTestBase Implements IUnitTest Abstract

	Field x:Float = 10, y:Float = 100
	Field p1:FlxPoint, p2:FlxPoint

	Method New()
		p1 = New FlxPoint(x, y)
		p2 = New FlxPoint()
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

private
	Method _AssertPoint:Bool()
		Return (UnitTest.AssertEqualsF(x, p1.x) And UnitTest.AssertEqualsF(y, p1.y))
	End Method

	Method _AssertPoints:Bool()
		Return (UnitTest.AssertEqualsF(p2.x, p1.x) And UnitTest.AssertEqualsF(p2.y, p1.y))
	End Method

End Class

Class FlxPointNewUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		Return _AssertPoint()
	End Method

	Method GetName:String()
		Return "FlxPoint.New"
	End Method

End Class

Class FlxPointMakeUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p1 = New FlxPoint()
		p1 = p1.Make(x, y)
		Return _AssertPoint()
	End Method

	Method GetName:String()
		Return "FlxPoint.Make"
	End Method

End Class

Class FlxPointCopyToUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p1.CopyTo(p2)
		Return _AssertPoints()
	End Method

	Method GetName:String()
		Return "FlxPoint.CopyTo"
	End Method

End Class

Class FlxPointCopyFromUnitTest Extends FlxPointUnitTestBase

	Method Run:Bool()
		p2.CopyFrom(p1)
		Return _AssertPoints()
	End Method

	Method GetName:String()
		Return "FlxPoint.CopyFrom"
	End Method

End Class

'#End Region

'#Region FlxRect tests bundle

Class FlxRectUnitTestBase Implements IUnitTest Abstract

	Field x:Float = 10, y:Float = 100
	Field width:Float = 110, height:Float = 1000
	Field r1:FlxRect, r2:FlxRect

	Method New()
		r1 = New FlxRect(x, y, width, height)
		r2 = New FlxRect()
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

Private
	Method _AssertRect:Bool()
		Return (UnitTest.AssertEqualsF(x, r1.x) And UnitTest.AssertEqualsF(y, r1.y) And
			UnitTest.AssertEqualsF(width, r1.width) And UnitTest.AssertEqualsF(height, r1.height))
	End Method

	Method _AssertRects:Bool()
		Return (UnitTest.AssertEqualsF(r2.x, r1.x) And UnitTest.AssertEqualsF(r2.y, r1.y) And
			UnitTest.AssertEqualsF(r2.width, r1.width) And UnitTest.AssertEqualsF(r2.height, r1.height))
	End Method

End Class

Class FlxRectNewUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return _AssertRect()
	End Method

	Method GetName:String()
		Return "FlxRect.New"
	End Method

End Class

Class FlxRectMakeUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r1 = New FlxRect()
		r1 = r1.Make(x, y, width, height)
		Return _AssertRect()
	End Method

	Method GetName:String()
		Return "FlxRect.Make"
	End Method

End Class

Class FlxRectLeftUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(x, r1.Left)
	End Method

	Method GetName:String()
		Return "FlxRect.Left"
	End Method

End Class

Class FlxRectRightUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(x + width, r1.Right)
	End Method

	Method GetName:String()
		Return "FlxRect.Right"
	End Method

End Class

Class FlxRectTopUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(y, r1.Top)
	End Method

	Method GetName:String()
		Return "FlxRect.Top"
	End Method

End Class

Class FlxRectBottomUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		Return UnitTest.AssertEqualsF(y + height, r1.Bottom)
	End Method

	Method GetName:String()
		Return "FlxRect.Bottom"
	End Method

End Class

Class FlxRectCopyToUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r1.CopyTo(r2)
		Return _AssertRects()
	End Method

	Method GetName:String()
		Return "FlxRect.CopyTo"
	End Method

End Class

Class FlxRectCopyFromUnitTest Extends FlxRectUnitTestBase

	Method Run:Bool()
		r2.CopyFrom(r1)
		Return _AssertRects()
	End Method

	Method GetName:String()
		Return "FlxRect.CopyFrom"
	End Method

End Class

'#End Region

'#Region FlxGroup tests bundle

Class FlxGroupUnitTestBase Implements IUnitTest Abstract

	Field countObjects:Int = 10
	Field objects:FlxBasic[]
	Field group:FlxGroup

	Method New()
		objects = new FlxBasic[countObjects]

		For Local i:Int = 0 To countObjects - 1
			objects[i] = New FlxBasic()
			objects[i].ID = i
		Next
	End Method

	Method Run:Bool() Abstract

	Method GetName:String() Abstract

End Class

Class FlxGroupAddUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.Length)) Return False

		Local maxSize:Int = 5
		group = New FlxGroup(maxSize)
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		Return UnitTest.AssertEqualsI(i, maxSize)
	End Method

	Method GetName:String()
		Return "FlxGroup.Add"
	End Method

End Class

Class FlxGroupRecycleUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup(10)

		Local recycled:FlxBasic
		For Local i:Int = 0 To group.MaxSize - 1
			recycled = group.Recycle(FlxBasic.ClassObject)
			If (Not UnitTest.AssertNotNull(recycled)) Return False
			recycled.ID = i
		Next

		For Local basic:FlxBasic = EachIn objects
			recycled = group.Recycle()
			If (Not UnitTest.AssertNotNull(recycled)) Return False
			If (Not UnitTest.AssertEqualsI(basic.ID, recycled.ID)) Return False
		Next

		group = New FlxGroup()

		For Local i:Int = 0 To 9
			recycled = group.Recycle(FlxBasic.ClassObject)
			If (Not UnitTest.AssertNotNull(recycled)) Return False
			recycled.ID = i
		Next

		recycled = group.Recycle(FlxBasic.ClassObject)
		If (Not UnitTest.AssertNotNull(recycled)) Return False
		If (Not UnitTest.AssertEqualsI(-1, recycled.ID)) Return False

		group.Members[5].Kill()
		recycled = group.Recycle(FlxBasic.ClassObject)
		If (Not UnitTest.AssertNotNull(recycled)) Return False
		If (Not UnitTest.AssertEqualsI(5, recycled.ID)) Return False

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.Recycle"
	End Method

End Class

Class FlxGroupRemoveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		For Local basic:FlxBasic = EachIn objects
			If (Not UnitTest.AssertNotNull(group.Remove(basic))) Return False
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.Length)) Return False

		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		For Local basic:FlxBasic = EachIn objects
			If (Not UnitTest.AssertNotNull(group.Remove(basic, True))) Return False
		Next

		Return UnitTest.AssertEqualsI(0, group.Length)
	End Method

	Method GetName:String()
		Return "FlxGroup.Remove"
	End Method

End Class

Class FlxGroupAddRemoveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic)
			i+=1
		Next

		Local newBasic:FlxBasic = new FlxBasic()
		newBasic.ID = 10
		group.Add(newBasic)

		If (Not UnitTest.AssertEqualsI(group.Members[5].ID, newBasic.ID)) Return False

		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic, True)
			i+=1
		Next

		group.Add(newBasic)
		If (Not UnitTest.AssertEqualsI(group.Members[8].ID, newBasic.ID)) Return False

		group = New FlxGroup(6)

		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic)
			i+=1
		Next

		group.Add(newBasic)
		If (Not UnitTest.AssertEqualsI(group.Members[5].ID, newBasic.ID)) Return False

		group = New FlxGroup(6)

		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		i = 0
		For Local basic:FlxBasic = EachIn objects
			If (i > 4 And i < 7) group.Remove(basic, True)
			i+=1
		Next

		group.Add(newBasic)
		Return (UnitTest.AssertEqualsI(group.Members[5].ID, newBasic.ID))
	End Method

	Method GetName:String()
		Return "FlxGroup.Add/Remove"
	End Method

End Class

Class FlxGroupMaxSizeUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.MaxSize = 15

		If (Not UnitTest.AssertEqualsI(objects.Length, group.Length)) Return False

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		group.MaxSize = 6
		If (Not UnitTest.AssertEqualsI(group.MaxSize, group.Length)) Return False
		i = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(basic.ID, objects[i].ID)) Return False
			i+=1
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.MaxSize"
	End Method

End Class

Class FlxGroupReplaceUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Replace(objects[0], objects[countObjects - 1])
		Return UnitTest.AssertEqualsI(countObjects - 1, group.Members[0].ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.Replace"
	End Method

End Class

Class FlxGroupSortUnitTest Extends FlxGroupUnitTestBase Implements FlxBasicComparator

	Method Run:Bool()
		group = New FlxGroup()
		Local i:Int = countObjects - 1
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
			basic.ID = i
			i-=1
		Next

		group.Sort(Self)

		i = 0
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(i, basic.ID)) Return False
			i+=1
		Next

		group.Sort(Self, FlxGroup.DESCENDING)

		i = countObjects - 1
		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(i, basic.ID)) Return False
			i-=1
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.Sort"
	End Method

	Method Compare:Int(lhs:FlxBasic,rhs:FlxBasic)
		Return lhs.ID - rhs.ID
	End Method

End Class

Class FlxGroupSetAllUnitTest Extends FlxGroupUnitTestBase Implements FlxBasicSetter

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local group2:FlxGroup = New FlxGroup(5)
		For Local basic:FlxBasic = EachIn objects
			group2.Add(basic)
		Next
		group.Add(group2)

		group.SetAll(Self, IntObject(100), False)

		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertEqualsI(100, basic.ID)) Return False
		Next

		group.SetAll(Self, IntObject(50), False)

		For Local basic:FlxBasic = EachIn group
			If (FlxGroup(basic) <> Null) Then
				For Local innerBasic:FlxBasic = EachIn FlxGroup(basic).Members
					If (Not UnitTest.AssertEqualsI(50, innerBasic.ID)) Return False
				Next
			Else
				If (Not UnitTest.AssertEqualsI(50, basic.ID)) Return False
			End If
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.SetAll"
	End Method

	Method Set:Void(basic:FlxBasic, value:Object)
		basic.ID = IntObject(value)
	End Method

End Class

Class FlxGroupCallAllUnitTest Extends FlxGroupUnitTestBase Implements FlxBasicInvoker

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		Local group2:FlxGroup = New FlxGroup(5)
		For Local basic:FlxBasic = EachIn objects
			group2.Add(basic)
		Next
		group.Add(group2)

		group.CallAll(Self, False)

		For Local basic:FlxBasic = EachIn group
			If (Not UnitTest.AssertFalse(basic.exists)) Return False
			basic.Revive()
		Next

		group.CallAll(Self)

		For Local basic:FlxBasic = EachIn group
			If (FlxGroup(basic) <> Null) Then
				For Local innerBasic:FlxBasic = EachIn FlxGroup(basic).Members
					If (Not UnitTest.AssertFalse(innerBasic.exists)) Return False
				Next
			Else
				If (Not UnitTest.AssertFalse(basic.exists)) Return False
			End If
		Next

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup.CallAll"
	End Method

	Method Invoke:Void(basic:FlxBasic)
		basic.Kill()
	End Method

End Class

Class FlxGroupGetFirstAvailableUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		Local i:Int = 0
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
			If (i > 4 And i < 7) Then basic.Kill()
			i+=1
		Next

		Local basic:FlxBasic = group.GetFirstAvailable(FlxBasic.ClassObject)

		If (UnitTest.AssertNotNull(basic) And UnitTest.AssertEqualsI(5, basic.ID)) Then
			basic = group.GetFirstAvailable()

			If (Not UnitTest.AssertNotNull(basic) Or
				Not UnitTest.AssertEqualsI(5, basic.ID)) Then
				Return False
			End If

			Local object:FlxObject = FlxObject(group.Add(new FlxObject()))
			object.ID = 10

			object = FlxObject(group.Add(new FlxObject()))
			object.ID = 11
			object.Kill()

			object = FlxObject(group.GetFirstAvailable(FlxObject.ClassObject))
			Return (UnitTest.AssertNotNull(object) And UnitTest.AssertEqualsI(11, object.ID))
		End If

		Return False
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstAvailable"
	End Method

End Class

Class FlxGroupGetFirstNullUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(-1, group.GetFirstNull())) Return False
		group.Remove(objects[5])

		Return UnitTest.AssertEqualsI(5, group.GetFirstNull())
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstNull"
	End Method

End Class

Class FlxGroupGetFirstExtantUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(0, group.GetFirstExtant().ID)) Return False
		group.Members[0].Kill()
		group.Members[1].Kill()
		group.Members[2].Kill()

		Return UnitTest.AssertEqualsI(3, group.GetFirstExtant().ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstExtant"
	End Method

End Class

Class FlxGroupGetFirstAliveUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(0, group.GetFirstAlive().ID)) Return False
		group.Members[0].Kill()
		group.Members[1].Kill()
		group.Members[2].Kill()
		group.Members[2].exists = True

		Return UnitTest.AssertEqualsI(3, group.GetFirstAlive().ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstAlive"
	End Method

End Class

Class FlxGroupGetFirstDeadUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertNull(group.GetFirstDead())) Return False
		group.Members[0].Kill()
		group.Members[0].alive = True
		group.Members[1].Kill()
		group.Members[1].alive = True
		group.Members[2].Kill()

		Return UnitTest.AssertEqualsI(2, group.GetFirstDead().ID)
	End Method

	Method GetName:String()
		Return "FlxGroup.GetFirstDead"
	End Method

End Class

Class FlxGroupCountLivingUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(countObjects, group.CountLiving())) Return False
		group.Members[0].Kill()
		group.Members[0].alive = True
		group.Members[1].Kill()
		group.Members[2].Kill()

		Return UnitTest.AssertEqualsI(countObjects - 3, group.CountLiving())
	End Method

	Method GetName:String()
		Return "FlxGroup.CountLiving"
	End Method

End Class

Class FlxGroupCountDeadUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		If (Not UnitTest.AssertEqualsI(0, group.CountDead())) Return False
		group.Members[0].Kill()
		group.Members[0].alive = True
		group.Members[1].Kill()
		group.Members[2].Kill()

		Return UnitTest.AssertEqualsI(2, group.CountDead())
	End Method

	Method GetName:String()
		Return "FlxGroup.CountDead"
	End Method

End Class

Class FlxGroupClearUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Clear()

		If (Not UnitTest.AssertEqualsI(-1, group.CountDead())) Return False
		If (Not UnitTest.AssertEqualsI(-1, group.CountLiving())) Return False

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group
			i+=1
		Next

		If (Not UnitTest.AssertEqualsI(0, i)) Return False

		Return UnitTest.AssertTrue(group.Members[0].alive)
	End Method

	Method GetName:String()
		Return "FlxGroup.Clear"
	End Method

End Class

Class FlxGroupKillUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Kill()

		If (Not UnitTest.AssertEqualsI(countObjects, group.CountDead())) Return False
		If (Not UnitTest.AssertEqualsI(0, group.CountLiving())) Return False

		Return UnitTest.AssertFalse(group.alive)
	End Method

	Method GetName:String()
		Return "FlxGroup.Kill"
	End Method

End Class

Class FlxGroupDestroyUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()
		For Local basic:FlxBasic = EachIn objects
			group.Add(basic)
		Next

		group.Destroy()

		Local i:Int = 0
		For Local basic:FlxBasic = EachIn group
			i+=1
		Next

		If (Not UnitTest.AssertEqualsI(0, i)) Return False

		Return UnitTest.AssertEqualsI(0, group.Members.Length())
	End Method

	Method GetName:String()
		Return "FlxGroup.Destroy"
	End Method

End Class

Class FlxGroupFinalUnitTest Extends FlxGroupUnitTestBase

	Method Run:Bool()
		group = New FlxGroup()

		group.Update()
		group.Draw()
		group.DrawDebug()
		group.GetRandom()
		group.ToString()

		Return True
	End Method

	Method GetName:String()
		Return "FlxGroup final"
	End Method

End Class

'#End Region

'#Region FlxG tests bundle

Class FlxGAddPluginUnitTest Implements IUnitTest

	Method Run:Bool()
		Local oldL:Int = FlxG.Plugins.Length()
		FlxG.AddPlugin(New TimerManager())
		FlxG.AddPlugin(New TimerManager())
		Return UnitTest.AssertEqualsI(oldL, FlxG.Plugins.Length())
	End Method

	Method GetName:String()
		Return "FlxG.AddPlugin"
	End Method

End Class

Class FlxGGetPluginUnitTest Implements IUnitTest

	Method Run:Bool()
		Return UnitTest.AssertNotNull(TimerManager(FlxG.GetPlugin(TimerManager.ClassObject)))
	End Method

	Method GetName:String()
		Return "FlxG.GetPlugin"
	End Method

End Class

Class FlxGRemovePluginUnitTest Implements IUnitTest

	Method Run:Bool()
		Local oldL:Int = FlxG.Plugins.Length()
		FlxG.RemovePlugin(FlxG.GetPlugin(TimerManager.ClassObject))
		If (Not UnitTest.AssertEqualsI(oldL - 1, FlxG.Plugins.Length())) Return False
		FlxG.Init(Null, 0, 0, 0)
		Return True
	End Method

	Method GetName:String()
		Return "FlxG.RemovePlugin"
	End Method

End Class

Class FlxGRemovePluginTypeUnitTest Implements IUnitTest

	Method Run:Bool()
		Local oldL:Int = FlxG.Plugins.Length()
		FlxG.RemovePluginType(TimerManager.ClassObject)
		If (Not UnitTest.AssertEqualsI(oldL -  1, FlxG.Plugins.Length())) Return False
		FlxG.Init(Null, 0, 0, 0)
		Return True
	End Method

	Method GetName:String()
		Return "FlxG.RemovePluginType"
	End Method

End Class

'#End Region

'#Region TimeManager tests bundle
Class TimeManagerUnitTest Implements IUnitTest

	Method Run:Bool()
		Local timeManager:TimerManager = TimerManager(FlxG.GetPlugin(TimerManager.ClassObject))
		Local timer:FlxTimer = New FlxTimer()

		timeManager.Add(New FlxTimer())
		timeManager.Add(timer)
		timeManager.Update()
		timeManager.Remove(timer)
		timeManager.Clear()
		timeManager.Destroy()
		timeManager = Null
		timer = Null

		Return True
	End Method

	Method GetName:String()
		Return "TimeManager full"
	End Method

End Class

Class FlixelUnitTest Extends UnitTestApp

	Method Setup:Void()
		FlxG.Init(Null, 0, 0, 0)

		'#Region add FlxPoint tests bundle

		AddTest(New FlxPointNewUnitTest())
		AddTest(New FlxPointMakeUnitTest())
		AddTest(New FlxPointCopyToUnitTest())
		AddTest(New FlxPointCopyFromUnitTest())

		'#End Region

		'#Region add FlxRect tests bundle

		AddTest(New FlxRectNewUnitTest())
		AddTest(New FlxRectMakeUnitTest())
		AddTest(New FlxRectLeftUnitTest())
		AddTest(New FlxRectRightUnitTest())
		AddTest(New FlxRectTopUnitTest())
		AddTest(New FlxRectBottomUnitTest())
		AddTest(New FlxRectCopyToUnitTest())
		AddTest(New FlxRectCopyFromUnitTest())

		'#End Region

		'#Region add FlxGroup tests bundle

		AddTest(New FlxGroupAddUnitTest())
		AddTest(New FlxGroupRecycleUnitTest())
		AddTest(New FlxGroupRemoveUnitTest())
		AddTest(New FlxGroupAddRemoveUnitTest())
		AddTest(New FlxGroupMaxSizeUnitTest())
		AddTest(New FlxGroupReplaceUnitTest())
		AddTest(New FlxGroupSortUnitTest())
		AddTest(New FlxGroupSetAllUnitTest())
		AddTest(New FlxGroupCallAllUnitTest())
		AddTest(New FlxGroupGetFirstAvailableUnitTest())
		AddTest(New FlxGroupGetFirstNullUnitTest())
		AddTest(New FlxGroupGetFirstExtantUnitTest())
		AddTest(New FlxGroupGetFirstAliveUnitTest())
		AddTest(New FlxGroupGetFirstDeadUnitTest())
		AddTest(New FlxGroupCountLivingUnitTest())
		AddTest(New FlxGroupCountDeadUnitTest())
		AddTest(New FlxGroupClearUnitTest())
		AddTest(New FlxGroupKillUnitTest())
		AddTest(New FlxGroupDestroyUnitTest())
		AddTest(New FlxGroupFinalUnitTest())

		'#End Region

		'#Region add FlxG tests bundle

		AddTest(New FlxGAddPluginUnitTest())
		AddTest(New FlxGGetPluginUnitTest())
		AddTest(New FlxGRemovePluginUnitTest())
		AddTest(New FlxGRemovePluginTypeUnitTest())

		'#End Region

		'#Region add TimeManager tests bundle

		AddTest(New TimeManagerUnitTest())

		'#End Region

	End Method

	Method GetName:String()
		Return "Flixel library"
	End Method

End Class


Added quick overloads for 'SetArray'.

Added quick overloads for 'SetArray'.

Strict

Public

#Rem
	TODO:
		* Replace uses of 'Int' and 'Float' with 'Long' and 'Double'.
			('LongArrayView', 'DoubleArrayView', etc)
#End

' Preprocessor related:
#REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS = True

'#If CONFIG = "debug"
	'#REGAL_UTIL_BUFFERS_SAFE = True
'#End

' Imports (Public):
Import brl.databuffer

' Imports (Private):
Private

Import memory

Import regal.sizeof
Import regal.typetool

Import monkey.math

Public

' Interfaces:
Interface BufferView
	' Methods:
	' Nothing so far.

	' Properties:
	Method Data:DataBuffer() Property
	Method Offset:UInt() Property ' Int
End

' Classes:
Class ArrayView<ValueType> Implements BufferView Abstract
	' Global variable(s):
	Global NIL:ValueType

	' Constructor(s):
	Method New(ElementSize:UInt, Count:UInt, __Direct:Bool=False)
		Self.ElementSize = ElementSize
		Self.Data = New DataBuffer(CountInBytes(Count), __Direct)
	End

	Method New(ElementSize:UInt, Data:DataBuffer, OffsetInBytes:UInt=0)
		Self.Offset = OffsetInBytes
		Self.ElementSize = ElementSize
		Self.Data = Data
	End

	' The 'ExtraOffset' argument is used to offset from the 'View' object's offset.
	Method New(ElementSize:UInt, View:BufferView, ExtraOffset:UInt=0)
		Self.ElementSize = ElementSize
		Self.Offset = (View.Offset + ExtraOffset)
		Self.Data = View.Data
	End

	' Methods (Public):

	' If overridden, these methods must respect the 'Offset' property:
	Method Get:ValueType(Index:UInt)
		Return GetRaw(Offset + IndexToAddress(Index))
	End

	Method Set:Void(Index:UInt, Value:ValueType)
		SetRaw(Offset + IndexToAddress(Index), Value)

		Return
	End

	Method GetArray:Bool(Index:UInt, Output:ValueType[], Count:UInt, OutputOffset:UInt=0)
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		If (ByteBounds > Size) Then
			Return False
		Endif

		Local OutputPosition:= OutputOffset

		Local Address:= OffsetIndexToAddress(Index)

		While (Address < ByteBounds)
			Output[OutputPosition] = GetRaw(Address)

			OutputPosition += 1

			Address += ElementSize
		Wend

		' Return the default response.
		Return True
	End

	Method GetArray:ValueType[](Index:UInt, Count:UInt, _ArrOff:UInt=0)
		Local Output:= New ValueType[_ArrOff + Count]

		If (Not GetArray(Index, Output, Count, _ArrOff)) Then
			Return []
		Endif

		Return Output
	End

	Method SetArray:Bool(Index:UInt, Input:ValueType[], Count:UInt, InputOffset:UInt=0)
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		If (ByteBounds > Size) Then
			Return False
		Endif

		Local InputPosition:= InputOffset

		Local Address:= OffsetIndexToAddress(Index)

		While (Address < ByteBounds)
			SetRaw(Address, Input[InputPosition])

			InputPosition += 1

			Address += ElementSize
		Wend

		' Return the default response.
		Return True
	End

	Method SetArray:Bool(Index:UInt, Input:ValueType[])
		Return SetArray(Index, Input, Input.Length)
	End

	' TODO: Optimize this overload to bypass index conversion.
	Method SetArray:Bool(Input:ValueType[])
		Return SetArray(0, Input)
	End

	Method Add:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) + Value)

		Set(Index, Result)

		Return Result
	End

	Method Subtract:ValueType(Index:UInt, Value:ValueType)
		Return Add(Index, -Value)
	End

	' This supplies the raw size of 'Count' elements in bytes.
	Method CountInBytes:UInt(Count:Int)
		Return IndexToAddress(Count) ' (Count * ElementSize)
	End

	' This converts an index to a raw address for use with the internal buffer.
	Method IndexToAddress:UInt(Index:UInt)
		#If REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Index
			Endif
		#End

		Return (Index * ElementSize)
	End

	' This converts a raw address to an index.
	Method AddressToIndex:UInt(Address:UInt)
		#If REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Address
			Endif
		#End

		Return (Address / ElementSize)
	End

	#Rem
		The result of this method is a non-convertible raw address.
		By definition, this address may not be used with commands like
		'AddressToIndex', as the value would be skewed.

		To fix this address for such commands, subtract a stored result gathered
		from the 'Offset' property at the time this method was called.

		Because the value of 'Offset' can be changed, you must always ensure that
		the offset you apply to restore the appropriate value corresponds with the
		original value associated with this object's 'Offset' property.

		This type of address manipulation is not recommended,
		and should be avoided wherever possible.
	#End

	Method OffsetIndexToAddress:UInt(Index:UInt) Final
		Return (IndexToAddress(Index) + Offset)
	End

	' This method is an extension, which should only be used when converting
	' a value from a real address to a convertible address.
	' This command is not recommended, and is subject to deletion.
	Method __OffsetAddressToIndex:UInt(_Address:UInt) Final
		Return AddressToIndex(_Address - Offset)
	End

	' Methods (Protected):
	Protected

	' Abstract:

	' These two methods operate on raw addresses.
	' This means the input should not be an index,
	' nor should it be a non-offset address.
	' The i
	Method GetRaw:ValueType(Address:UInt) Abstract
	Method SetRaw:Void(Address:UInt, Value:ValueType) Abstract

	Public

	' Properties (Public):

	' This provides the number of elements in this view.
	Method Length:UInt() Property
		#If REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Size
			Endif
		#End

		Return (Size / ElementSize)
	End

	' This provides the raw size of the internal buffer (In bytes).
	Method Size:UInt() Property
		Return UInt(Data.Length)
	End

	' This specifies the size of an element.
	Method ElementSize:UInt() Property
		Return Self._ElementSize
	End

	' This provides access to the internal buffer offset.
	Method Offset:UInt() Property ' Int
		Return Self._Offset
	End

	Method Offset:Void(Value:UInt) Property
		Self._Offset = Value

		#If REGAL_UTIL_BUFFERS_SAFE
			' Nothing so far.
		#End

		Return
	End

	' This provides access to the internal buffer.
	Method Data:DataBuffer() Property ' Final
		Return Self._Data
	End

	Method Data:Void(Value:DataBuffer) Property
		Self._Data = Value

		Return
	End

	' Properties (Protected):
	Protected

	Method ElementSize:Void(Value:UInt) Property
		Self._ElementSize = Value

		Return
	End

	Public

	' Fields (Protected):
	Protected

	Field _ElementSize:UInt ' Int
	Field _Offset:UInt ' Int
	Field _Data:DataBuffer

	Public
End

' This is an intermediate class which defines mathematical routines for both integral and floating-point types.
Class MathArrayView<ValueType> Extends ArrayView<ValueType> Abstract
	' Constructor(s):
	Method New(ElementSize:UInt, Count:UInt, __Direct:Bool=False)
		Super.New(ElementSize, Count, __Direct)
	End

	Method New(ElementSize:UInt, Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(ElementSize, Data, OffsetInBytes)
	End

	Method New(ElementSize:UInt, View:BufferView, ExtraOffset:UInt=0)
		Super.New(ElementSize, View, ExtraOffset)
	End

	' Methods:

	' This increments the value located at 'Index' by one.
	Method Increment:ValueType(Index:UInt)
		Return Add(Index, ValueType(1))
	End

	' This decrements the value located at 'Index' by one.
	Method Decrement:ValueType(Index:UInt)
		Return Subtract(Index, ValueType(1))
	End

	' This multiplies the value located at 'Index' using the value specified.
	' The result is written into memory, then returned.
	Method Multiply:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) * Value)

		Set(Index, Result)

		Return Result
	End

	' This divides the value located at 'Index' using the value specified.
	' The result is written into memory, then returned.
	Method Divide:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) / Value)

		Set(Index, Result)

		Return Result
	End

	' This squares the value located at 'Index'.
	' The result is both returned by the method, and
	' written into memory at the specified location.
	Method Sq:ValueType(Index:UInt) ' Square
		Local Value:= Get(Index)
		Local Result:= (Value * Value)

		Set(Index, Result)

		Return Result
	End

	' This calculates the square-root of the value located at 'Index'.
	' The result is both returned by this method, and
	' written into memory at the specified location.
	Method Sqrt:ValueType(Index:UInt) ' SquareRoot
		Local Result:= Sqrt(Get(Index))

		Set(Index, Result)

		Return Result
	End
End

Class IntArrayView Extends MathArrayView<Int> ' ArrayView<Long> ' Int ' LongArrayView
	' Constant variable(s):
	Const Type_Size:= SizeOf_Integer ' 4

	' Constructor(s) (Public):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	' Constructor(s) (Protected):
	Protected

	Method New(Type_Size:UInt, Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Type_Size:UInt, Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(Type_Size:UInt, View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	Public

	' Methods (Public):
	Method GetUnsigned:Int(Index:UInt)
		Return (Get(Index) & $FFFFFFFF)
	End

	' Methods (Protected):
	Protected

	Method GetRaw:Int(Address:UInt) ' Final
		Return Data.PeekInt(Address)
	End

	Method SetRaw:Void(Address:UInt, Value:Int) ' Final
		Data.PokeInt(Address, Value)

		Return
	End

	Public
End

Class ShortArrayView Extends IntArrayView ' ArrayView<Int> ' Short
	' Constant variable(s):
	Const Type_Size:= SizeOf_Short

	' Constructor(s) (Public):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	' Constructor(s) (Protected):
	Protected

	Method New(Type_Size:UInt, Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Type_Size:UInt, Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(Type_Size:UInt, View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	Public

	' Methods (Public):
	Method GetUnsigned:Int(Index:UInt) ' Short
		Return (Get(Index) & $FFFF)
	End

	' Methods (Protected):
	Protected

	Method GetRaw:Int(Address:UInt) ' Final ' Short
		Return Data.PeekShort(Address)
	End

	Method SetRaw:Void(Address:UInt, Value:Int) ' Final ' Short
		Data.PokeShort(Address, Value)

		Return
	End

	Public
End

Class ByteArrayView Extends ShortArrayView ' ArrayView<Int> ' Byte
	' Constant variable(s):
	Const Type_Size:= SizeOf_Byte

	' Constructor(s):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	' Methods (Public):
	#If REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS
		' These two methods follow the integrity rules of 'Offset':
		Method Get:Int(Address:UInt) ' Byte
			Return GetRaw(Offset + Address)
		End

		Method Set:Void(Address:UInt, Value:Int) ' Byte
			SetRaw(Offset + Address, Value)

			Return
		End

		#Rem
			Method IndexToAddress:UInt(Address:UInt) ' Index:UInt
				Return Address
			End

			Method AddressToIndex:UInt(Address:UInt)
				Return Address
			End
		#End
	#End

	Method GetUnsigned:Int(Address:UInt) ' Byte
		Return (Get(Address) & $FF)
	End

	' Methods (Protected):
	Protected

	Method GetRaw:Int(Address:UInt) ' Final ' Byte
		Return Data.PeekByte(Address)
	End

	Method SetRaw:Void(Address:UInt, Value:Int) ' Final ' Byte
		Data.PokeByte(Address, Value)

		Return
	End

	Public
End

Class FloatArrayView Extends MathArrayView<Float> ' DoubleArrayView
	' Constant variable(s):
	Const Type_Size:= SizeOf_Float ' 4 ' 8

	' Constructor(s):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	' Methods (Protected):
	Protected

	Method GetRaw:Float(Address:UInt) ' Final ' Double
		Return Data.PeekFloat(Address)
	End

	Method SetRaw:Void(Address:UInt, Value:Float) ' Final ' Double
		Data.PokeFloat(Address, Value)

		Return
	End

	Public
End

Strict

Public

#Rem
	TODO:
		* Replace uses of 'Int' and 'Float' with 'Long' and 'Double'.
			('LongArrayView', 'DoubleArrayView', etc)
#End

' Preprocessor related:
#REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS = True

'#If CONFIG = "debug"
	'#REGAL_UTIL_BUFFERS_SAFE = True
'#End

' Imports (Public):
Import brl.databuffer

' Imports (Private):
Private

Import memory

Import regal.sizeof
Import regal.typetool

Import monkey.math

Public

' Interfaces:
Interface BufferView
	' Methods:
	' Nothing so far.

	' Properties:
	Method Data:DataBuffer() Property
	Method Offset:UInt() Property ' Int
End

' Classes:
Class ArrayView<ValueType> Implements BufferView Abstract
	' Global variable(s):
	Global NIL:ValueType

	' Constructor(s):
	Method New(ElementSize:UInt, Count:UInt, __Direct:Bool=False)
		Self.ElementSize = ElementSize
		Self.Data = New DataBuffer(CountInBytes(Count), __Direct)
	End

	Method New(ElementSize:UInt, Data:DataBuffer, OffsetInBytes:UInt=0)
		Self.Offset = OffsetInBytes
		Self.ElementSize = ElementSize
		Self.Data = Data
	End

	' The 'ExtraOffset' argument is used to offset from the 'View' object's offset.
	Method New(ElementSize:UInt, View:BufferView, ExtraOffset:UInt=0)
		Self.ElementSize = ElementSize
		Self.Offset = (View.Offset + ExtraOffset)
		Self.Data = View.Data
	End

	' Methods (Public):

	' If overridden, these methods must respect the 'Offset' property:
	Method Get:ValueType(Index:UInt)
		Return GetRaw(Offset + IndexToAddress(Index))
	End

	Method Set:Void(Index:UInt, Value:ValueType)
		SetRaw(Offset + IndexToAddress(Index), Value)

		Return
	End

	Method GetArray:Bool(Index:UInt, Output:ValueType[], Count:UInt, OutputOffset:UInt=0)
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		If (ByteBounds > Size) Then
			Return False
		Endif

		Local OutputPosition:= OutputOffset

		Local Address:= OffsetIndexToAddress(Index)

		While (Address < ByteBounds)
			Output[OutputPosition] = GetRaw(Address)

			OutputPosition += 1

			Address += ElementSize
		Wend

		' Return the default response.
		Return True
	End

	Method GetArray:ValueType[](Index:UInt, Count:UInt, _ArrOff:UInt=0)
		Local Output:= New ValueType[_ArrOff + Count]

		If (Not GetArray(Index, Output, Count, _ArrOff)) Then
			Return []
		Endif

		Return Output
	End

	Method SetArray:Bool(Index:UInt, Input:ValueType[], Count:UInt, InputOffset:UInt=0)
		Local ByteBounds:= OffsetIndexToAddress(Index+Count)

		If (ByteBounds > Size) Then
			Return False
		Endif

		Local InputPosition:= InputOffset

		Local Address:= OffsetIndexToAddress(Index)

		While (Address < ByteBounds)
			SetRaw(Address, Input[InputPosition])

			InputPosition += 1

			Address += ElementSize
		Wend

		' Return the default response.
		Return True
	End

	Method Add:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) + Value)

		Set(Index, Result)

		Return Result
	End

	Method Subtract:ValueType(Index:UInt, Value:ValueType)
		Return Add(Index, -Value)
	End

	' This supplies the raw size of 'Count' elements in bytes.
	Method CountInBytes:UInt(Count:Int)
		Return IndexToAddress(Count) ' (Count * ElementSize)
	End

	' This converts an index to a raw address for use with the internal buffer.
	Method IndexToAddress:UInt(Index:UInt)
		#If REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Index
			Endif
		#End

		Return (Index * ElementSize)
	End

	' This converts a raw address to an index.
	Method AddressToIndex:UInt(Address:UInt)
		#If REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Address
			Endif
		#End

		Return (Address / ElementSize)
	End

	#Rem
		The result of this method is a non-convertible raw address.
		By definition, this address may not be used with commands like
		'AddressToIndex', as the value would be skewed.

		To fix this address for such commands, subtract a stored result gathered
		from the 'Offset' property at the time this method was called.

		Because the value of 'Offset' can be changed, you must always ensure that
		the offset you apply to restore the appropriate value corresponds with the
		original value associated with this object's 'Offset' property.

		This type of address manipulation is not recommended,
		and should be avoided wherever possible.
	#End

	Method OffsetIndexToAddress:UInt(Index:UInt) Final
		Return (IndexToAddress(Index) + Offset)
	End

	' This method is an extension, which should only be used when converting
	' a value from a real address to a convertible address.
	' This command is not recommended, and is subject to deletion.
	Method __OffsetAddressToIndex:UInt(_Address:UInt) Final
		Return AddressToIndex(_Address - Offset)
	End

	' Methods (Protected):
	Protected

	' Abstract:

	' These two methods operate on raw addresses.
	' This means the input should not be an index,
	' nor should it be a non-offset address.
	' The i
	Method GetRaw:ValueType(Address:UInt) Abstract
	Method SetRaw:Void(Address:UInt, Value:ValueType) Abstract

	Public

	' Properties (Public):

	' This provides the number of elements in this view.
	Method Length:UInt() Property
		#If REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS
			If (ElementSize = 1) Then
				Return Size
			Endif
		#End

		Return (Size / ElementSize)
	End

	' This provides the raw size of the internal buffer (In bytes).
	Method Size:UInt() Property
		Return UInt(Data.Length)
	End

	' This specifies the size of an element.
	Method ElementSize:UInt() Property
		Return Self._ElementSize
	End

	' This provides access to the internal buffer offset.
	Method Offset:UInt() Property ' Int
		Return Self._Offset
	End

	Method Offset:Void(Value:UInt) Property
		Self._Offset = Value

		#If REGAL_UTIL_BUFFERS_SAFE
			' Nothing so far.
		#End

		Return
	End

	' This provides access to the internal buffer.
	Method Data:DataBuffer() Property ' Final
		Return Self._Data
	End

	Method Data:Void(Value:DataBuffer) Property
		Self._Data = Value

		Return
	End

	' Properties (Protected):
	Protected

	Method ElementSize:Void(Value:UInt) Property
		Self._ElementSize = Value

		Return
	End

	Public

	' Fields (Protected):
	Protected

	Field _ElementSize:UInt ' Int
	Field _Offset:UInt ' Int
	Field _Data:DataBuffer

	Public
End

' This is an intermediate class which defines mathematical routines for both integral and floating-point types.
Class MathArrayView<ValueType> Extends ArrayView<ValueType> Abstract
	' Constructor(s):
	Method New(ElementSize:UInt, Count:UInt, __Direct:Bool=False)
		Super.New(ElementSize, Count, __Direct)
	End

	Method New(ElementSize:UInt, Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(ElementSize, Data, OffsetInBytes)
	End

	Method New(ElementSize:UInt, View:BufferView, ExtraOffset:UInt=0)
		Super.New(ElementSize, View, ExtraOffset)
	End

	' Methods:

	' This increments the value located at 'Index' by one.
	Method Increment:ValueType(Index:UInt)
		Return Add(Index, ValueType(1))
	End

	' This decrements the value located at 'Index' by one.
	Method Decrement:ValueType(Index:UInt)
		Return Subtract(Index, ValueType(1))
	End

	' This multiplies the value located at 'Index' using the value specified.
	' The result is written into memory, then returned.
	Method Multiply:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) * Value)

		Set(Index, Result)

		Return Result
	End

	' This divides the value located at 'Index' using the value specified.
	' The result is written into memory, then returned.
	Method Divide:ValueType(Index:UInt, Value:ValueType)
		Local Result:= (Get(Index) / Value)

		Set(Index, Result)

		Return Result
	End

	' This squares the value located at 'Index'.
	' The result is both returned by the method, and
	' written into memory at the specified location.
	Method Sq:ValueType(Index:UInt) ' Square
		Local Value:= Get(Index)
		Local Result:= (Value * Value)

		Set(Index, Result)

		Return Result
	End

	' This calculates the square-root of the value located at 'Index'.
	' The result is both returned by this method, and
	' written into memory at the specified location.
	Method Sqrt:ValueType(Index:UInt) ' SquareRoot
		Local Result:= Sqrt(Get(Index))

		Set(Index, Result)

		Return Result
	End
End

Class IntArrayView Extends MathArrayView<Int> ' ArrayView<Long> ' Int ' LongArrayView
	' Constant variable(s):
	Const Type_Size:= SizeOf_Integer ' 4

	' Constructor(s) (Public):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	' Constructor(s) (Protected):
	Protected

	Method New(Type_Size:UInt, Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Type_Size:UInt, Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(Type_Size:UInt, View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	Public

	' Methods (Public):
	Method GetUnsigned:Int(Index:UInt)
		Return (Get(Index) & $FFFFFFFF)
	End

	' Methods (Protected):
	Protected

	Method GetRaw:Int(Address:UInt) ' Final
		Return Data.PeekInt(Address)
	End

	Method SetRaw:Void(Address:UInt, Value:Int) ' Final
		Data.PokeInt(Address, Value)

		Return
	End

	Public
End

Class ShortArrayView Extends IntArrayView ' ArrayView<Int> ' Short
	' Constant variable(s):
	Const Type_Size:= SizeOf_Short

	' Constructor(s) (Public):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	' Constructor(s) (Protected):
	Protected

	Method New(Type_Size:UInt, Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Type_Size:UInt, Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(Type_Size:UInt, View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	Public

	' Methods (Public):
	Method GetUnsigned:Int(Index:UInt) ' Short
		Return (Get(Index) & $FFFF)
	End

	' Methods (Protected):
	Protected

	Method GetRaw:Int(Address:UInt) ' Final ' Short
		Return Data.PeekShort(Address)
	End

	Method SetRaw:Void(Address:UInt, Value:Int) ' Final ' Short
		Data.PokeShort(Address, Value)

		Return
	End

	Public
End

Class ByteArrayView Extends ShortArrayView ' ArrayView<Int> ' Byte
	' Constant variable(s):
	Const Type_Size:= SizeOf_Byte

	' Constructor(s):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	' Methods (Public):
	#If REGAL_UTIL_BUFFERS_BYTE_OPTIMIZATIONS
		' These two methods follow the integrity rules of 'Offset':
		Method Get:Int(Address:UInt) ' Byte
			Return GetRaw(Offset + Address)
		End

		Method Set:Void(Address:UInt, Value:Int) ' Byte
			SetRaw(Offset + Address, Value)

			Return
		End

		#Rem
			Method IndexToAddress:UInt(Address:UInt) ' Index:UInt
				Return Address
			End

			Method AddressToIndex:UInt(Address:UInt)
				Return Address
			End
		#End
	#End

	Method GetUnsigned:Int(Address:UInt) ' Byte
		Return (Get(Address) & $FF)
	End

	' Methods (Protected):
	Protected

	Method GetRaw:Int(Address:UInt) ' Final ' Byte
		Return Data.PeekByte(Address)
	End

	Method SetRaw:Void(Address:UInt, Value:Int) ' Final ' Byte
		Data.PokeByte(Address, Value)

		Return
	End

	Public
End

Class FloatArrayView Extends MathArrayView<Float> ' DoubleArrayView
	' Constant variable(s):
	Const Type_Size:= SizeOf_Float ' 4 ' 8

	' Constructor(s):
	Method New(Count:UInt, __Direct:Bool=False)
		Super.New(Type_Size, Count, __Direct)
	End

	Method New(Data:DataBuffer, OffsetInBytes:UInt=0)
		Super.New(Type_Size, Data, OffsetInBytes)
	End

	Method New(View:BufferView, ExtraOffset:UInt=0)
		Super.New(Type_Size, View, ExtraOffset)
	End

	' Methods (Protected):
	Protected

	Method GetRaw:Float(Address:UInt) ' Final ' Double
		Return Data.PeekFloat(Address)
	End

	Method SetRaw:Void(Address:UInt, Value:Float) ' Final ' Double
		Data.PokeFloat(Address, Value)

		Return
	End

	Public
End


Some fixes for substates

Some fixes for substates

Strict

Import flxgroup

Class FlxState Extends FlxGroup Abstract

	Field persistantUpdate:Bool = False

	Field persistantDraw:Bool = True

	Method Create:Void() Abstract

	Method Destroy:Void()
		Super.Destroy()

		If (_subState <> Null And _subState._initialized) Then
			_subState.Destroy()
		End If
	End Method

	Method OnBack:Bool()
		Return True
	End Method

	Method OnClose:Bool()
		Return True
	End Method

	Method SetSubState:Void(subState:FlxSubState)
		If (_subState = subState) Return

		If (_subState <> Null) Then
			If ( Not _subState.OnClose()) Then
				_subState.PreventDefault()
				_subState.StopPropagation()
				Return
			End If

			_subState._parent = Null
		End If

		_subState = subState

		If (_subState <> Null) Then
			If ( Not _subState._initialized) Then
				_subState.Create()
				_subState._initialized = True
			End If
		End If
	End Method

	Method CloseSubState:Void()
		If (_subState = Null) Return
		SetSubState(Null)
	End Method

	Method DoUpdate:Void()
		If (_subState = Null) Then
			Update()
			Return
		End If

		If (persistantUpdate) Then
			Update()
		End If

		_subState.Update()
	End Method

	Method DoDraw:Void()
		If (_subState = Null) Then
			Draw()
			Return
		End If

		If (persistantDraw) Then
			Draw()
		End If

		_subState.Draw()
	End Method

	Method DoBack:Bool()
		If (_subState = Null) Then
			Return OnBack()
		End If

		_subState.Close()

		If ( Not _subState._stopPropagation) Then
			If ( Not _subState._preventDefault) Then
				Return OnBack()
			End If

			OnBack()
		End If

		Return Not _subState._preventDefault
	End Method

	Method DoClose:Bool()
		If (_subState = Null) Then
			Return OnClose()
		End If

		_subState.Close()

		If ( Not _subState._stopPropagation) Then
			If ( Not _subState._preventDefault) Then
				Return OnClose()
			End If

			OnClose()
		End If

		Return Not _subState._preventDefault
	End Method

	Private

	Field _subState:FlxSubState

End Class

Class FlxSubState Extends FlxGroup Abstract

	Method Create:Void() Abstract

	Method Destroy:Void()
		Super.Destroy()
		_parent = Null
		_initialized = False
	End Method

	Method Close:Void()
		If (_parent = Null) Return
		_preventDefault = False
		_stopPropagation = False
		_parent.CloseSubState()
	End Method

	Method GetParent:FlxState()
		Return _parent
	End Method

	Method OnClose:Bool()
		Destroy()
		Return True
	End Method

	Method StopPropagation:Void()
		_stopPropagation = True
	End Method

	Method PreventDefault:Void()
		_preventDefault = True
	End Method

	Private

	Field _parent:FlxState

	Field _initialized:Bool

	Field _preventDefault:Bool

	Field _stopPropagation:Bool

End Class

Strict

Import flxgroup

Class FlxState Extends FlxGroup Abstract

	Field persistantUpdate:Bool = False

	Field persistantDraw:Bool = True

	Method Create:Void() Abstract

	Method OnBack:Bool()
		Return True
	End Method

	Method OnClose:Bool()
		Return True
	End Method

	Method SetSubState:Void(subState:FlxSubState)
		If (_subState = subState) Return

		If (_subState <> Null) Then
			If ( Not _subState.OnClose()) Then
				_subState.PreventDefault()
				_subState.StopPropagation()
				Return
			End If

			_subState._parent = Null
		End If

		_subState = subState

		If (_subState <> Null) Then
			If ( Not _subState._initialized) Then
				_subState.Create()
				_subState._initialized = True
			End If
		End If
	End Method

	Method CloseSubState:Void()
		If (_subState = Null) Return
		SetSubState(Null)
	End Method

	Method DoUpdate:Void()
		If (_subState = Null) Then
			Update()
			Return
		End If

		If (persistantUpdate) Then
			Update()
		End If

		_subState.Update()
	End Method

	Method DoDraw:Void()
		If (_subState = Null) Then
			Draw()
			Return
		End If

		If (persistantDraw) Then
			Draw()
		End If

		_subState.Draw()
	End Method

	Method DoBack:Bool()
		If (_subState = Null) Then
			Return OnBack()
		End If

		_subState.Close()

		If ( Not _subState._stopPropagation) Then
			If ( Not _subState._preventDefault) Then
				Return OnBack()
			End If

			OnBack()
		End If

		Return Not _subState._preventDefault
	End Method

	Method DoClose:Bool()
		If (_subState = Null) Then
			Return OnClose()
		End If

		_subState.Close()

		If ( Not _subState._stopPropagation) Then
			If ( Not _subState._preventDefault) Then
				Return OnClose()
			End If

			OnClose()
		End If

		Return Not _subState._preventDefault
	End Method

	Private

	Field _subState:FlxSubState

End Class

Class FlxSubState Extends FlxGroup Abstract

	Method Create:Void() Abstract

	Method Destroy:Void()
		Super.Destroy()
		_parent = Null
		_initialized = False
	End Method

	Method Close:Void()
		If (_parent = Null) Return
		_preventDefault = False
		_stopPropagation = False
		_parent.CloseSubState()
	End Method

	Method OnClose:Bool()
		Destroy()
		Return True
	End Method

	Method StopPropagation:Void()
		_stopPropagation = True
	End Method

	Method PreventDefault:Void()
		_preventDefault = True
	End Method

	Private

	Field _parent:FlxState

	Field _initialized:Bool

	Field _preventDefault:Bool

	Field _stopPropagation:Bool

End Class


Fixed up the 'CopyArray' command in the 'GenericUtilities' class. I also added support for offsets.

Strict

Public

' Preprocessor related:
#Rem
#If TARGET = "glfw" Or TARGET = "sexy"
	#GLFW_TARGET = True
#End
#End

#If CONFIG = "debug"
	#DEBUG_PRINT = True
#Else
	#DEBUG_PRINT = False
#End

#DEBUG_PRINT_QUOTES = False

' Imports (Public):
Import byteorder
Import imagedimensions
Import retrostrings
Import stringutil
Import vector

#If CONSOLE_IMPLEMENTED
	Import console
#End

Import sizeof
Import time

#If Not BRL_GAMETARGET_IMPLEMENTED
	Import mojoemulator
#End

Import publicdatastream

' Imports (Private):
Private

' Official:

' BRL:
Import brl.databuffer
Import brl.stream
Import brl.filepath

' Unofficial:

' ImmutableOctet:
Import autostream

Public

' Constant variable(s):

' Used mainly for external code where '-9999...' isn't ever going to be valid.
' You should stick to 'Null' in most cases; try not to use this.
Const NOVAR:Int = -999999

Const ErrorTemplate:String = "[ERROR] {Debug}: " ' + Space
Const LogTemplate:String = "[Info] {Debug}: " ' + Space

' Global variable(s) (Public):
#If CONSOLE_IMPLEMENTED
	Global DebugConsole:Console = Null
#End

' Global variable(s) (Private):
Private

' Nothing so far.

Public

' Functions:
Function FLAG:Int(ID:Int)
	Return Pow(2, ID)
End

' This command is little-endian only:
Function AsByte:Int(I:Int)
	Return ((I Shl 24) Shr 24)
End

' This command treats data as 8-bit (Turns something like $F7, into $FFFFFFF7)
' This is only applied on little-endian systems,
' please use this command for hex values (Monkey converts hex on compile-time).
Function PaddedHex:Int(I:Int)
	If (Not BigEndian()) Then
		Return AsByte(I)
	Endif

	Return I
End

Function Transfer:Bool(InputStream:Stream, OutputStream:Stream, DataSize:Int)
	' Check for errors:
	If (DataSize = 0) Then Return False
	If (InputStream = Null Or InputStream.Eof()) Then Return False
	If (OutputStream = Null) Then Return False

	' Local variable(s):
	#If FLAG_TEMP_BUFFERS
		Local Data:DataBuffer = New DataBuffer(DataSize)
		Local DataLength:= DataSize ' Data.Length()

		' Read from the input-stream, then write to the output-stream:
		InputStream.Read(Data, 0, DataLength)
		OutputStream.Write(Data, 0, DataLength)

		Data.Discard()
	#Else
		'Local Data:Int[DataSize]

		For Local I:Int = 1 To DataSize ' Data.Length()
			OutputStream.WriteByte(InputStream.ReadByte())
		Next
	#End

	' Return the default response.
	Return True
End

Function Sq:Float(Input:Float)
	Return Pow(Input, 2.0) ' Input * Input
End

Function Sq:Int(Input:Int)
	Return Pow(Input, 2)
End

Function WrapAngle:Float(A:Float)
	While (A < 0.0)
		A += 360.0
	Wend

	While (A > 360.0)
		A -= 360.0
	Wend

	Return A
End

Function WrapColor:Float(C:Float)
	#Rem
	While (C < 0.0)
		C += 255.0
	Wend

	While (C > 255.0)
		C -= 255.0
	Wend
	#End

	Return C Mod 256.0
End

#If CONSOLE_IMPLEMENTED
	Function DebugBind:Bool(C:Console)
		If (C = Null) Then Return False

		DebugConsole = C

		' Return the default response.
		Return True
	End
#End

Function DebugError:Void(Msg:String, StopExecution:Bool=True)
	#If DEBUG_PRINT
		' Local variable(s):
		Local TempMsg:String

		If (StopExecution) Then
			TempMsg = ErrorTemplate
		Else
			TempMsg = LogTemplate
		Endif

		#If DEBUG_PRINT_QUOTES
			Msg = Tempmsg + Quote + Msg + Quote
		#Else
			Msg = TempMsg + Msg
		#End

		#If CONSOLE_IMPLEMENTED
			If (DebugConsole <> Null) Then
				DebugConsole.WriteLine(Msg, True)
			Else
		#End

		Print(Msg)

		#If CONSOLE_IMPLEMENTED
			Endif
		#End
	#Else
		' This may change later:
		If (StopExecution) Then
			Msg = ErrorTemplate + Msg
		Endif
	#End

	If (StopExecution) Then
		#If CONFIG = "debug"
			#If DEBUG_PRINT
				DebugStop()
			#Else
				Error(Msg)
			#End
		#Else
			#If DEBUG_PRINT
				Local FinalStr:String = (ErrorTemplate + Quote + "Attempt to stop execution failed. (Reason: Release-mode)" + Quote)

				#If CONSOLE_IMPLEMENTED
					If (DebugConsole <> Null) Then
						DebugConsole.WriteLine(FinalStr, True)
					Else
				#End

				Print(FinalStr)

				#If CONSOLE_IMPLEMENTED
					Endif
				#End
			#Else
				Error(Msg)
			#End
		#End
	Endif

	#If CONFIG = "debug"
		' Nothing so far.
	#Else
		' Nothing so far.
	#End

	Return
End

Function DebugPrint:Void(Str:String, StopExecution:Bool=False)
	DebugError(Str, StopExecution)

	Return
End

' Classes:
Class GenericUtilities<T>
	' Global variable(s):
	Global NIL:T

	' Functions:
	Function IndexOfList:T(L:List<T>, Index:Int=0)
		' Local variable(s):
		Local Response:T
		Local Data:list.Node<T> = L.FirstNode()

		For Local I:= 0 Until Index
			Data = Data.NextNode()

			' Not my favorite method, but it works:
			If (Data = Null) Then
				Return Response
			Endif
		Next

		Response = Data.Value()

		' Return the value of the assessed node.
		Return Response
	End

	Function CopyArray:T[](Source:T[], Destination:T[]=[], SourceOffset:Int=0, DestinationOffset:Int=0)
		If (Destination.Length() = 0) Then
			Destination = New T[Source.Length()]
		Endif

		Local MinLength:Int = Min(Source.Length(), Destination.Length())

		For Local Index:Int = 0 Until MinLength
			' Local variable(s):
			Local DestinationIndex:= Index+DestinationOffset
			Local SourceIndex:= Index+SourceOffset

			' Check if we can perform the current operation:
			If (DestinationIndex >= Destination.Length() Or SourceIndex >= Source.Length()) Then
				Exit
			Endif

			Destination[DestinationIndex] = Source[SourceIndex]
		Next

		Return Destination
	End

	Function CloneArray:T[](Source:T[], Destination:T[]=[])
		Return CopyArray(Source, Destination)
	End

	Function Read:T(S:Stream)
		Return Read(S, NIL)
	End

	Function Read:T[](S:Stream, DataArray:T[], Size:Int=-1)
		If (Size = -1) Then Size = S.ReadInt()

		If (Size > 0) Then
			If (DataArray.Length() = 0) Then
				DataArray = New T[Size]
			Endif
		Endif

		' Local variable(s):
		Local DLength:Int = Min(DataArray.Length, Size)

		For Local Index:= 0 Until DLength
			DataArray[Index] = Read(S, NIL)
		Next

		Return DataArray
	End

	Function Write:Void(S:Stream, DataArray:T[], WriteLength:Bool=True)
		' Local variable(s):
		Local DLength:= DataArray.Length()

		If (WriteLength) Then S.WriteInt(DLength)

		For Local Index:= 0 Until DLength
			Write(S, DataArray[Index])
		Next

		Return
	End

	Function Read:Int(S:Stream, Indentifier:Int, Size:Int=4)
		' Local variable(s):
		Local Data:Int = 0

		If (Size > 1) Then
			If (Size < 4) Then
				Data = S.ReadShort()
			Else
				If (Size > 4) Then
					S.ReadInt()
				Endif

				Data = S.ReadInt()
			Endif
		Else
			Data = S.ReadByte()
		Endif

		Return Data
	End

	Function Write:Void(S:Stream, Data:Int, Size:Int=4)
		Size = IntSize(Size)

		If (Size > 1) Then
			If (Size < 4) Then
				S.WriteShort(Data)
			Else
				If (Size > 4) Then
					S.WriteInt(0)
				Endif

				S.WriteInt(Data)
			Endif
		Else
			S.WriteByte(Data)
		Endif

		Return
	End

	#Rem
	Function Read:Bool(S:Stream, Identifier:Bool)
		Return Read(S, Int(Identifier), 1)
	End

	Function Write:Void(S:Stream, B:Bool)
		Write(S, Int(B), 1)

		Return
	End
	#End

	Function Read:Float(S:Stream, Identifier:Float)
		Return S.ReadFloat()
	End

	Function Write:Void(S:Stream, Data:Float)
		S.WriteFloat(Data)

		Return
	End

	Function Read:String(S:Stream, Data:String, Encoding:String="utf8", Size:Int=-1)
		If (Size = -1) Then Size = S.ReadInt()

		Data = S.ReadString(Size, Encoding)

		' Return the newly read string.
		Return Data
	End

	Function Write:Void(S:Stream, Data:String, Encoding:String="utf8", WriteSize:Bool=True)
		If (WriteSize) Then S.WriteInt(Data.Length())
		S.WriteString(Data, Encoding)

		Return
	End
End

Strict

Public

' Preprocessor related:
#Rem
#If TARGET = "glfw" Or TARGET = "sexy"
	#GLFW_TARGET = True
#End
#End

#If CONFIG = "debug"
	#DEBUG_PRINT = True
#Else
	#DEBUG_PRINT = False
#End

#DEBUG_PRINT_QUOTES = False

' Imports (Public):
Import byteorder
Import imagedimensions
Import retrostrings
Import stringutil
Import vector

#If CONSOLE_IMPLEMENTED
	Import console
#End

Import sizeof
Import time

#If Not BRL_GAMETARGET_IMPLEMENTED
	Import mojoemulator
#End

Import publicdatastream

' Imports (Private):
Private

' Official:

' BRL:
Import brl.databuffer
Import brl.stream
Import brl.filepath

' Unofficial:

' ImmutableOctet:
Import autostream

Public

' Constant variable(s):

' Used mainly for external code where '-9999...' isn't ever going to be valid.
' You should stick to 'Null' in most cases; try not to use this.
Const NOVAR:Int = -999999

Const ErrorTemplate:String = "[ERROR] {Debug}: " ' + Space
Const LogTemplate:String = "[Info] {Debug}: " ' + Space

' Global variable(s) (Public):
#If CONSOLE_IMPLEMENTED
	Global DebugConsole:Console = Null
#End

' Global variable(s) (Private):
Private

' Nothing so far.

Public

' Functions:
Function FLAG:Int(ID:Int)
	Return Pow(2, ID)
End

' This command is little-endian only:
Function AsByte:Int(I:Int)
	Return ((I Shl 24) Shr 24)
End

' This command treats data as 8-bit (Turns something like $F7, into $FFFFFFF7)
' This is only applied on little-endian systems,
' please use this command for hex values (Monkey converts hex on compile-time).
Function PaddedHex:Int(I:Int)
	If (Not BigEndian()) Then
		Return AsByte(I)
	Endif

	Return I
End

Function Transfer:Bool(InputStream:Stream, OutputStream:Stream, DataSize:Int)
	' Check for errors:
	If (DataSize = 0) Then Return False
	If (InputStream = Null Or InputStream.Eof()) Then Return False
	If (OutputStream = Null) Then Return False

	' Local variable(s):
	#If FLAG_TEMP_BUFFERS
		Local Data:DataBuffer = New DataBuffer(DataSize)
		Local DataLength:= DataSize ' Data.Length()

		' Read from the input-stream, then write to the output-stream:
		InputStream.Read(Data, 0, DataLength)
		OutputStream.Write(Data, 0, DataLength)

		Data.Discard()
	#Else
		'Local Data:Int[DataSize]

		For Local I:Int = 1 To DataSize ' Data.Length()
			OutputStream.WriteByte(InputStream.ReadByte())
		Next
	#End

	' Return the default response.
	Return True
End

Function Sq:Float(Input:Float)
	Return Pow(Input, 2.0) ' Input * Input
End

Function Sq:Int(Input:Int)
	Return Pow(Input, 2)
End

Function WrapAngle:Float(A:Float)
	While (A < 0.0)
		A += 360.0
	Wend

	While (A > 360.0)
		A -= 360.0
	Wend

	Return A
End

Function WrapColor:Float(C:Float)
	#Rem
	While (C < 0.0)
		C += 255.0
	Wend

	While (C > 255.0)
		C -= 255.0
	Wend
	#End

	Return C Mod 256.0
End

#If CONSOLE_IMPLEMENTED
	Function DebugBind:Bool(C:Console)
		If (C = Null) Then Return False

		DebugConsole = C

		' Return the default response.
		Return True
	End
#End

Function DebugError:Void(Msg:String, StopExecution:Bool=True)
	#If DEBUG_PRINT
		' Local variable(s):
		Local TempMsg:String

		If (StopExecution) Then
			TempMsg = ErrorTemplate
		Else
			TempMsg = LogTemplate
		Endif

		#If DEBUG_PRINT_QUOTES
			Msg = Tempmsg + Quote + Msg + Quote
		#Else
			Msg = TempMsg + Msg
		#End

		#If CONSOLE_IMPLEMENTED
			If (DebugConsole <> Null) Then
				DebugConsole.WriteLine(Msg, True)
			Else
		#End

		Print(Msg)

		#If CONSOLE_IMPLEMENTED
			Endif
		#End
	#Else
		' This may change later:
		If (StopExecution) Then
			Msg = ErrorTemplate + Msg
		Endif
	#End

	If (StopExecution) Then
		#If CONFIG = "debug"
			#If DEBUG_PRINT
				DebugStop()
			#Else
				Error(Msg)
			#End
		#Else
			#If DEBUG_PRINT
				Local FinalStr:String = (ErrorTemplate + Quote + "Attempt to stop execution failed. (Reason: Release-mode)" + Quote)

				#If CONSOLE_IMPLEMENTED
					If (DebugConsole <> Null) Then
						DebugConsole.WriteLine(FinalStr, True)
					Else
				#End

				Print(FinalStr)

				#If CONSOLE_IMPLEMENTED
					Endif
				#End
			#Else
				Error(Msg)
			#End
		#End
	Endif

	#If CONFIG = "debug"
		' Nothing so far.
	#Else
		' Nothing so far.
	#End

	Return
End

Function DebugPrint:Void(Str:String, StopExecution:Bool=False)
	DebugError(Str, StopExecution)

	Return
End

' Classes:
Class GenericUtilities<T>
	' Global variable(s):
	Global NIL:T

	' Functions:
	Function IndexOfList:T(L:List<T>, Index:Int=0)
		' Local variable(s):
		Local Response:T
		Local Data:list.Node<T> = L.FirstNode()

		For Local I:= 0 Until Index
			Data = Data.NextNode()

			' Not my favorite method, but it works:
			If (Data = Null) Then
				Return Response
			Endif
		Next

		Response = Data.Value()

		' Return the value of the assessed node.
		Return Response
	End

	Function CopyArray:T[](Source:T[], Destination:T[])
		Local MinLength:Int = Min(Source.Length(), Destination.Length())

		For Local Index:Int = 0 Until MinLength
			Destination[Index] = Source[Index]
		Next

		Return Destination
	End

	Function CloneArray:T[](Source:T[], Destination:T[]=[])
		If (Destination.Length() = 0) Then
			Destination = New T[Source.Length()]
		Endif

		Return CopyArray(Source, Destination)
	End

	Function Read:T(S:Stream)
		Return Read(S, NIL)
	End

	Function Read:T[](S:Stream, DataArray:T[], Size:Int=-1)
		If (Size = -1) Then Size = S.ReadInt()

		If (Size > 0) Then
			If (DataArray.Length() = 0) Then
				DataArray = New T[Size]
			Endif
		Endif

		' Local variable(s):
		Local DLength:Int = Min(DataArray.Length, Size)

		For Local Index:= 0 Until DLength
			DataArray[Index] = Read(S, NIL)
		Next

		Return DataArray
	End

	Function Write:Void(S:Stream, DataArray:T[], WriteLength:Bool=True)
		' Local variable(s):
		Local DLength:= DataArray.Length()

		If (WriteLength) Then S.WriteInt(DLength)

		For Local Index:= 0 Until DLength
			Write(S, DataArray[Index])
		Next

		Return
	End

	Function Read:Int(S:Stream, Indentifier:Int, Size:Int=4)
		' Local variable(s):
		Local Data:Int = 0

		If (Size > 1) Then
			If (Size < 4) Then
				Data = S.ReadShort()
			Else
				If (Size > 4) Then
					S.ReadInt()
				Endif

				Data = S.ReadInt()
			Endif
		Else
			Data = S.ReadByte()
		Endif

		Return Data
	End

	Function Write:Void(S:Stream, Data:Int, Size:Int=4)
		Size = IntSize(Size)

		If (Size > 1) Then
			If (Size < 4) Then
				S.WriteShort(Data)
			Else
				If (Size > 4) Then
					S.WriteInt(0)
				Endif

				S.WriteInt(Data)
			Endif
		Else
			S.WriteByte(Data)
		Endif

		Return
	End

	#Rem
	Function Read:Bool(S:Stream, Identifier:Bool)
		Return Read(S, Int(Identifier), 1)
	End

	Function Write:Void(S:Stream, B:Bool)
		Write(S, Int(B), 1)

		Return
	End
	#End

	Function Read:Float(S:Stream, Identifier:Float)
		Return S.ReadFloat()
	End

	Function Write:Void(S:Stream, Data:Float)
		S.WriteFloat(Data)

		Return
	End

	Function Read:String(S:Stream, Data:String, Encoding:String="utf8", Size:Int=-1)
		If (Size = -1) Then Size = S.ReadInt()

		Data = S.ReadString(Size, Encoding)

		' Return the newly read string.
		Return Data
	End

	Function Write:Void(S:Stream, Data:String, Encoding:String="utf8", WriteSize:Bool=True)
		If (WriteSize) Then S.WriteInt(Data.Length())
		S.WriteString(Data, Encoding)

		Return
	End
End


Restore previous scissor in CarouselRendererSimple

SetScissor() is not bound to the current matrix and therefore we need to
restore the previous scissor.

Strict

Private

Import bono.kernel
Import bono.graphics
Import bono.utils
Import carousel
Import carouselhandler
Import carouselrenderer
Import mojo

Public

Class CarouselRendererSimple Implements CarouselRenderer, TouchObserver
    Private

    Field touched:Bool
    Field offset:Vector2D = New Vector2D()
    Field carousel:Carousel
    Field lastItemPixelX:Float
    Field momentumX:Float
    Field offsetMaxX:Float

    Public

    Field padding:Vector2D = New Vector2D()
    Field maxMoveDistanceForClicks:Float = 3
    Field frictionCoefficient:Float = 0.9

    Method SetCarousel:Void(carousel:Carousel)
        Self.carousel = carousel
    End

    Method Recalculate:Void()
        Local nextPos:Vector2D = carousel.GetPosition().Copy()
        nextPos.Add(padding)

        For Local item:BaseDisplayObject = EachIn carousel.GetItems()
            Local oldHeight:Float = item.GetSize().y
            item.GetSize().y = carousel.GetSize().y - (padding.y * 2)

            Local heightScaleFactor:Float = item.GetSize().y / oldHeight
            item.GetSize().x = item.GetSize().x * heightScaleFactor

            item.SetPosition(nextPos.Copy())
            nextPos.x += item.GetSize().x
            nextPos.x += padding.x
        End

        lastItemPixelX = carousel.GetItems().Last().GetPosition().x
        lastItemPixelX += carousel.GetItems().Last().GetSize().x

        offsetMaxX = carousel.GetPosition().x + carousel.GetSize().x
        offsetMaxX -= lastItemPixelX
        offsetMaxX -= padding.x
    End

    Method GetCurrentIndex:Void()
    End

    Method OnRender:Void()
        ApplyMomentum()

        Local pos:Vector2D = carousel.GetPosition()
        Local size:Vector2D = carousel.GetSize()

        Local oldScissor:Float[] = GetScissor()
        SetScissor(pos.x, pos.y, size.x, size.y)

        PushMatrix()
            Translate(offset.x, offset.y)

            For Local item:BaseDisplayObject = EachIn carousel.GetItems()
                Local itemPosX:Float = item.GetPosition().x
                itemPosX += offset.x

                If itemPosX > pos.x + size.x Then Continue
                If itemPosX + item.GetSize().x < pos.x Then Continue
                item.OnRender()
            End
        PopMatrix()

        SetScissor(oldScissor[0], oldScissor[1], oldScissor[2], oldScissor[3])
    End

    Method OnTouchDown:Void(event:TouchEvent)
        touched = True
        momentumX = 0
    End

    Method OnTouchMove:Void(event:TouchEvent)
        If Not touched Then Return
        offset.x += event.prevDelta.x
        CheckOffsetBoundaries()
    End

    Method OnTouchUp:Void(event:TouchEvent)
        If Not touched Then Return
        touched = False

        If event.startDelta.Length() < maxMoveDistanceForClicks
            Local item:BaseDisplayObject = GetTouchedItem(event)
            If Not item Then Return

            Local handler:CarouselHandler = CarouselHandler(item)
            If Not handler Then Return

            handler.OnCarouselSelect()
        Else
            momentumX = event.prevDelta.x
        End
    End

    Private

    Method ApplyMomentum:Void()
        If Abs(momentumX) = 0 Then Return

        offset.x += momentumX
        CheckOffsetBoundaries()

        momentumX *= frictionCoefficient
        If Abs(momentumX) <= 0.05 Then momentumX = 0
    End

    Method CheckOffsetBoundaries:Void()
        offset.x = Min(0.0, offset.x)
        offset.x = Max(offsetMaxX, offset.x)
    End

    Method GetTouchedItem:BaseDisplayObject(event:TouchEvent)
        Local result:BaseDisplayObject
        ' Offset is negative and we need to use Sub() here instead of Add()
        Local checkPos:Vector2D = event.pos.Copy().Sub(offset)

        For Local item:BaseDisplayObject = EachIn carousel.GetItems()
            If item.Collide(checkPos) Then Return item
        End

        Return Null
    End
End

Strict

Private

Import bono.kernel
Import bono.graphics
Import bono.utils
Import carousel
Import carouselhandler
Import carouselrenderer
Import mojo

Public

Class CarouselRendererSimple Implements CarouselRenderer, TouchObserver
    Private

    Field touched:Bool
    Field offset:Vector2D = New Vector2D()
    Field carousel:Carousel
    Field lastItemPixelX:Float
    Field momentumX:Float
    Field offsetMaxX:Float

    Public

    Field padding:Vector2D = New Vector2D()
    Field maxMoveDistanceForClicks:Float = 3
    Field frictionCoefficient:Float = 0.9

    Method SetCarousel:Void(carousel:Carousel)
        Self.carousel = carousel
    End

    Method Recalculate:Void()
        Local nextPos:Vector2D = carousel.GetPosition().Copy()
        nextPos.Add(padding)

        For Local item:BaseDisplayObject = EachIn carousel.GetItems()
            Local oldHeight:Float = item.GetSize().y
            item.GetSize().y = carousel.GetSize().y - (padding.y * 2)

            Local heightScaleFactor:Float = item.GetSize().y / oldHeight
            item.GetSize().x = item.GetSize().x * heightScaleFactor

            item.SetPosition(nextPos.Copy())
            nextPos.x += item.GetSize().x
            nextPos.x += padding.x
        End

        lastItemPixelX = carousel.GetItems().Last().GetPosition().x
        lastItemPixelX += carousel.GetItems().Last().GetSize().x

        offsetMaxX = carousel.GetPosition().x + carousel.GetSize().x
        offsetMaxX -= lastItemPixelX
        offsetMaxX -= padding.x
    End

    Method GetCurrentIndex:Void()
    End

    Method OnRender:Void()
        ApplyMomentum()

        Local pos:Vector2D = carousel.GetPosition()
        Local size:Vector2D = carousel.GetSize()
        PushMatrix()
            SetScissor(pos.x, pos.y, size.x, size.y)
            Translate(offset.x, offset.y)

            For Local item:BaseDisplayObject = EachIn carousel.GetItems()
                Local itemPosX:Float = item.GetPosition().x
                itemPosX += offset.x

                If itemPosX > pos.x + size.x Then Continue
                If itemPosX + item.GetSize().x < pos.x Then Continue
                item.OnRender()
            End
        PopMatrix()
    End

    Method OnTouchDown:Void(event:TouchEvent)
        touched = True
        momentumX = 0
    End

    Method OnTouchMove:Void(event:TouchEvent)
        If Not touched Then Return
        offset.x += event.prevDelta.x
        CheckOffsetBoundaries()
    End

    Method OnTouchUp:Void(event:TouchEvent)
        If Not touched Then Return
        touched = False

        If event.startDelta.Length() < maxMoveDistanceForClicks
            Local item:BaseDisplayObject = GetTouchedItem(event)
            If Not item Then Return

            Local handler:CarouselHandler = CarouselHandler(item)
            If Not handler Then Return

            handler.OnCarouselSelect()
        Else
            momentumX = event.prevDelta.x
        End
    End

    Private

    Method ApplyMomentum:Void()
        If Abs(momentumX) = 0 Then Return

        offset.x += momentumX
        CheckOffsetBoundaries()

        momentumX *= frictionCoefficient
        If Abs(momentumX) <= 0.05 Then momentumX = 0
    End

    Method CheckOffsetBoundaries:Void()
        offset.x = Min(0.0, offset.x)
        offset.x = Max(offsetMaxX, offset.x)
    End

    Method GetTouchedItem:BaseDisplayObject(event:TouchEvent)
        Local result:BaseDisplayObject
        ' Offset is negative and we need to use Sub() here instead of Add()
        Local checkPos:Vector2D = event.pos.Copy().Sub(offset)

        For Local item:BaseDisplayObject = EachIn carousel.GetItems()
            If item.Collide(checkPos) Then Return item
        End

        Return Null
    End
End


New method Color.Reset()

New method Color.Reset()