Fixed non recursive FlxGroup.SetAll and FlxGroup.CallAll

#rem
	header:This module contains the FlxGroup class
#end
Strict

Import reflection

Import flxextern
Import flxbasic
Import flxobject
Import flxu
Import system.flxarray

#Rem
summary:This is an organizational class that can update and render a bunch of FlxBasics.
[i][b]NOTE:[/b] Although FlxGroup extends [a flxbasic.monkey.html]FlxBasic[/a], it will not automatically add itself to the global collisions quad tree, it will only add its members.[/i]
#End
Class FlxGroup Extends FlxBasic

	Global ClassObject:Object

	#Rem
	summary:See detail.
	Use with [a #Sort]Sort()[/a] to sort in ascending order.
	#End
	Const ASCENDING:Bool = False

	#Rem
	summary:See detail.
	Use with [a #Sort]Sort()[/a] to sort in descending order.
	#End
	Const DESCENDING:Bool = True

Private

	Field _maxSize:Int

	Field _marker:Int

	Field _length:Int

	Field _members:FlxBasic[]

	Field _comparators:StringMap<Comparator>

	Field _comparator:Comparator

	Field _sortDescending:Bool

	Field _enumerator:Enumerator

Public
	#Rem
	summary:Constructor
	Params:
	[list]
	[*]maxSize:Int - the maximum capacity of this group.
	[/list]
	#End
	Method New(maxSize:Int = 0)
		Super.New()
		_maxSize = maxSize
		_marker = 0
		_length = 0
		_cameras = Null
		_comparators = New StringMap<Comparator>()
		_enumerator = New Enumerator(Null)
	End Method

	#Rem
	summary:The number of entries in the members array.
	For performance and safety you should check this variable instead of members.length unless you really know what you're doing!
	#End
	Method Length:Int() Property
		Return _length
	End Method

	#Rem
	summary:See detail.
	Array of all the [a flxbasic.monkey.html]FlxBasic[/a]s that exist in this group.
	#End
	Method Members:FlxBasic[]() Property
		Return _members
	End Method

	#Rem
	summary:Override this function to handle any deleting or "shutdown" type operations you might need,such as removing traditional Monkey/Mojo children like Images objects.
	#End
	Method Destroy:Void()
		Local basic:FlxBasic
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) basic.Destroy()
			i+=1
		Wend

		_length = 0
		_members = _members.Resize(_length)
		_cameras = Null

		If (_comparator <> Null) Then
			_comparator.Clear()
			_comparator = Null
		End If

		_comparators.Clear()
		_comparators = Null

		_enumerator.Destroy()
		_enumerator = Null

		Super.Destroy()
	End Method

	#Rem
	summary:Just making sure we don't increment the active objects count.
	#End
	Method PreUpdate:Void()

	End Method

	#Rem
	summary:Automatically goes through and calls update on everything you added.
	#End
	Method Update:Void()
		Local basic:FlxBasic
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists And basic.active) Then
				basic.PreUpdate()
				basic.Update()
				If (basic.HasTween) basic.UpdateTweens()
				basic.PostUpdate()
			End If
			i+=1
		Wend

		If (HasTween) UpdateTweens()
	End Method

	#Rem
	summary:Automatically goes through and calls render on everything you added.
	#End
	Method Draw:Void()
		If (_cameras <> Null And Not _cameras.Contains(FlxG._CurrentCamera.ID)) Return

		Local basic:FlxBasic
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists And basic.visible) basic.Draw()
			i+=1
		Wend
	End Method

	#Rem
	summary:The maximum capacity of this group.  Default is 0, meaning no max capacity, and the group can just grow.
	#End
	Method MaxSize:Int() Property
		Return _maxSize
	End Method

	Method MaxSize:Void(size:Int) Property
		_maxSize = size

		If (_marker >= _maxSize) _marker = 0
		If (_maxSize = 0 Or _maxSize >= _length) Return

		Local basic:FlxBasic
		Local i:Int = _maxSize
		Local l:Int = _length

		While(i < l)
			basic = _members[i]
			If (basic <> Null) basic.Destroy()
			i+=1
		Wend

		_members = _members.Resize(_maxSize)
		_length = _maxSize
	End Method

	#Rem
	summary:See details.
	Adds a new [a flxbasic.monkey.html]FlxBasic[/a] subclass ([a flxbasic.monkey.html]FlxBasic[/a], [a flxsprite.monkey.html]FlxSprite[/a], Enemy, etc) to the group. FlxGroup will try to replace a null member of the array first. Failing that, FlxGroup will add it to the end of the member array, assuming there is room for it, and doubling the size of the array if necessary.

	[b]WARNING[/b]: If the group has a maxSize that has already been met, the object will NOT be added to the group!

	Params:
	[list]
	[*][a flxbasic.monkey.html]object:FlxBasic[/a] - the object you want to add to the group.
	[/list]
	Return the same [a flxbasic.monkey.html]FlxBasic[/a] object that was passed in.
	#End
	Method Add:FlxBasic(object:FlxBasic)
		If (_IndexOf(object) >= 0) Return object

		Local i:Int = 0

		While (i < _length)
			If (_members[i] = Null) Then
				_members[i] = object
				If (i >= _length) _length = i+1
				Return object
			End If
			i+=1
		Wend

		If (_maxSize > 0) Then
			If (_length = _members.Length()) Then
				If (_length >= _maxSize) Then
					Return object
				ElseIf (_length*2 + 10 <= _maxSize)
					_members = _members.Resize(_length*2 + 10)
				Else
					_members = _members.Resize(_maxSize)
				End If
			End if
		Else
			If (_length = _members.Length()) Then
				_members = _members.Resize(_length*2 + 10)
			End If
		End If

		_members[i] = object
		_length+=1

		Return object
	End Method

	#Rem
	summary:Recycling is designed to help you reuse game objects without always re-allocating or "newing" them.
	If you specified a maximum size for this group (like in [a flxemitter.monkey.html]FlxEmitter[/a],then recycle will employ what we're calling "rotating" recycling. Recycle() will first check to see if the group is at capacity yet. If group is not yet at capacity, Recycle() returns a new object. If the group IS at capacity, then Recycle() just returns the next object in line

	If you did NOT specify a maximum size for this group, then Recycle() will employ what we're calling "grow-style" recycling. Recycle() will return either the first object with exists = false, or, finding none, add a new object to the array, doubling the size of the array if necessary.

	[b]WARNING:[/b] If this function needs to create a new object, and no object class was provided, it will return null instead of a valid object!

	Params:
	[list]
	[*]objectClass:FlxClass - the type objectClass implements FlxClass you want to recycle (e.g. FlxSpriteClass, EvilRobotClass, etc). Do NOT "new" the class in the parameter!
	[/list]
	Return a reference to the object that was created. Don't forget to cast it back to the objectClass you want (e.g. myObject = myObjectClass(myGroup.recycle(myObjectClassClass))).
	#End
	Method Recycle:FlxBasic(objectClass:ClassInfo = null)
		If (_maxSize > 0) Then
			If (_length < _maxSize) Then
				If (objectClass = Null) Return Null
				Return Add(FlxBasic(objectClass.NewInstance()))
			Else
				Local basic:FlxBasic = _members[_marker]
				_marker+=1
				If (_marker >= _maxSize) _marker = 0
				Return basic
			End If
		Else
			Local basic:FlxBasic = GetFirstAvailable(objectClass)
			If (basic <> Null) Return basic
			If (objectClass = Null) Return Null
			Return Add(FlxBasic(objectClass.NewInstance()))
		End If
	End Method

	#Rem
	summary:Removes an object from the group.
	Params:
	[list]
	[*][a flxbasic.monkey.html]object:FlxBasic[/a] - The [a flxbasic.monkey.html]FlxBasic[/a] you want to remove.
	[*]splice:Bool - whether the object should be cut from the array entirely or not.
	[/list]
	Return the removed object.
	#End
	Method Remove:FlxBasic(object:FlxBasic, splice:Bool = False)
		Local index:Int = _IndexOf(object)

		If (index < 0) Return Null

		If (splice) Then
			Local i:Int = index
			Local l:Int = _length

			While(i < _length - 1)
				_members[i] = _members[i+1]
				i+=1
			Wend

			_length-=1
		Else
			_members[index] = Null
		End If

		Return object
	End Method

	#Rem
	summary:Replaces an existing [a flxbasic.monkey.html]FlxBasic[/a] with a new one.
	Params:
	[list]
	[*][a flxbasic.monkey.html]oldObject:FlxBasic[/a] - the object you want to replace.
	[*][a flxbasic.monkey.html]newObject:FlxBasic[/a] - the new object you want to use instead.
	[/list]
	Return the new object.
	#End
	Method Replace:FlxBasic(oldObject:FlxBasic, newObject:FlxBasic)
		Local index:Int  = _IndexOf(oldObject)
		If (index < 0) Return Null

		_members[index] = newObject
		Return newObject
	End Method

	#Rem
	summary:Call this function to sort the group according to a particular value and order.
	For example, to sort game objects for Zelda-style overlaps you might call myGroup.Sort(FlxObject.YComparator, FlxGroup.ASCENDING) at the bottom of your [a flxstate.monkey.html]FlxState.Update()[/a] override. To sort all existing objects after a big explosion or bomb attack, you might call myGroup.Sort(FlxBasic.ExistsComparator, FlxGroup.DESCENDING)
	Params:
	[list]
	[*]comparator:FlxBasicComparator - The FlxBasicComparator you want to sort on. Default value is FlxObject.YComparator.
	[*]order:Bool - A FlxGroup constant that defines the sort order. Possible values are ASCENDING and DESCENDING. Default value is ASCENDING.
	[/list]
	Return the new object.
	#End
	Method Sort:Void(index:String = "y", order:Bool = ASCENDING)
		_comparator = _GetComparator(GetFirstNotNull().GetClassInfo().GetField(index))
		If (_comparator = Null) Return

		_sortDescending = order
		_QSort(0, _length - 1)
	End Method

	Method SetAll:Void(variableName:String, value:Object, recurse:Bool = True)
		Local basic:FlxBasic = GetFirstNotNull()
		If (basic = Null) Return

		Local f:FieldInfo = basic.GetClassInfo().GetField(variableName)

		If (f = Null) Then
			_SetAllProperties(variableName, value, recurse)
			Return
		End If

		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (FlxGroup(basic) <> Null) Then
					If (recurse) FlxGroup(basic).SetAll(variableName, value, recurse)
				Else
					f.SetValue(basic, value)
				End If
			End If
			i+=1
		Wend
	End Method

	Method CallAll:Void(functionName:String, recurse:Bool = True)
		Local basic:FlxBasic = GetFirstNotNull()
		If (basic = Null) Return

		Local m:MethodInfo = basic.GetClassInfo().GetMethod(functionName,[])
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (FlxGroup(basic) <> Null) Then
					If (recurse) FlxGroup(basic).CallAll(functionName, recurse)
				Else
					m.Invoke(basic,[])
				End If
			End If
			i+=1
		Wend
	End Method

	Method GetFirstAvailable:FlxBasic(objectClass:ClassInfo = null)
		Local basic:FlxBasic
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And Not basic.exists And
					(objectClass = Null Or basic.GetClassInfo().ExtendsClass(objectClass))) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method GetFirstNull:Int()
		Local i:Int = 0

		While(i < _length)
			If (_members[i] = Null) Return i
			i+=1
		Wend

		Return -1
	End Method

	Method GetFirstNotNull:FlxBasic()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method GetFirstExtant:FlxBasic()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method GetFirstAlive:FlxBasic()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists And basic.alive) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method GetFirstDead:FlxBasic()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And Not basic.alive) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method CountLiving:Int()
		Local count:Int = -1
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (count < 0) count = 0
				If (basic.exists And basic.alive) count+=1
			End If
			i+=1
		Wend

		Return count
	End Method

	Method CountDead:Int()
		Local count:Int = -1
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (count < 0) count = 0
				If (Not basic.alive) count+=1
			End If
			i+=1
		Wend

		Return count
	End Method

	Method GetRandom:FlxBasic(startIndex:Int = 0, length:Int = 0)
		If (length = 0) length = _length
		Return FlxArray<FlxBasic>.GetSafeRandom(_members, startIndex, length)
	End Method

	Method Clear:Void()
		_length = 0
	End Method

	Method ReviveAll:Void()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And Not basic.exists) basic.Revive()
			i+=1
		Wend

		Super.Revive()
	End Method

	Method Kill:Void()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists) basic.Kill()
			i+=1
		Wend

		Super.Kill()
	End Method

	Method ObjectEnumerator:Enumerator()
		Return _enumerator._Reset(Self)
	End

Private
	Method _IndexOf:Int(object:FlxBasic)
		Local i:Int = 0

		While(i < _length)
			If (_members[i] = object) Return i
			i+=1
		Wend

		Return -1
	End Method

	Method _QSort:Void(left:Int, right:Int)
		If (right > left) Then
			Local pivot:Int = left + (right-left)/2
			Local newPivot:Int = _DoSort(left, right, pivot)

			_QSort(left, newPivot - 1)
			_QSort(newPivot + 1, right)
		End If
	End Method

	Method _DoSort:Int(left:Int, right:Int, pivot:Int)
		Local basic:FlxBasic = _members[pivot]

		_members[pivot] = _members[right]
		_members[right] = basic

		Local store:Int = left
		Local basicToCompare:FlxBasic
		Local i:Int = left

		While (i < right)
			basicToCompare = _members[i]

			If (basicToCompare = Null Or basic = Null) Then
				If (basicToCompare <> Null And basic = Null) Then
					_members[i] = _members[store]
					_members[store] = basicToCompare
					store+=1
				End If

				i += 1
				Continue
			End If

			If (_sortDescending) Then
				If (_comparator.Compare(basicToCompare, basic) >= 0) Then
					_members[i] = _members[store]
					_members[store] = basicToCompare
					store+=1
				End If
			Else
				If (_comparator.Compare(basicToCompare, basic) <= 0) Then
					_members[i] = _members[store]
					_members[store] = basicToCompare
					store+=1
				End If
			End If

			i+=1
		Wend

		basic = _members[store]
		_members[store] = _members[right]
		_members[right] = basic

		Return store
	End Method

	Method _SetAllProperties:Void(variableName:String, value:Object, recurse:Bool = True)
		Local basic:FlxBasic = GetFirstNotNull()
		If (basic = Null) Return

		Local prop:MethodInfo

		prop = basic.GetClassInfo().GetMethod(variableName,[GetClass(value)])
		If (prop = Null) Return

		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (FlxGroup(basic) <> Null) Then
					If (recurse) FlxGroup(basic).SetAll(variableName, value, recurse)
				Else
					prop.Invoke(basic,[value])
				End If
			End If
			i+=1
		Wend
	End Method

	Method _GetComparator:Comparator(sortIndex:FieldInfo)
		If (sortIndex = Null) Return Null

		Local key:String = sortIndex.Type.Name
		Local comparator:Comparator = _comparators.Get(key)

		If (comparator = Null) Then
			Select key
				Case FloatClass().Name
					comparator = New FloatComparator()

				Case IntClass().Name
					comparator = New IntComparator()

				Case BoolClass().Name
					comparator = New BoolComparator()

				Case StringClass().Name
					comparator = New StringComparator()

				Default
					key = FlxU.GetObjectClass().Name
					comparator = _comparators.Get(key)

					If (comparator = Null) comparator = New ObjectComparator()
			End Select

			_comparators.Set(key, comparator)
		End If

		comparator.Clear()

		If (key <> FlxU.GetObjectClass().Name) Then
			comparator.Reset(sortIndex)
		Else
			Local sortMethod:MethodInfo = sortIndex.Type.GetMethod("Compare",[sortIndex.Type])
			If (sortMethod = Null) sortMethod = sortIndex.Type.GetMethod("Compare",[FlxU.GetObjectClass()])

			If (sortMethod <> Null) Then
				comparator.Reset(sortIndex, sortMethod)
			Else
				comparator = Null
			End If
		End If

		Return comparator
	End Method

End Class

Class Enumerator

	Method New(group:FlxGroup)
		_Reset(group)
	End

	Method HasNext:Bool()
		If (_dirty) Then
			_dirty = False
			_hasNext = False

			Repeat
				If (_nextIndex = _group._length) Then
					Return _hasNext
				End If

				_basic = _group._members[_nextIndex]

				_nextIndex += 1
			Until (_basic <> Null)

			_hasNext = True
		End If

		Return _hasNext
	End

	Method NextObject:FlxBasic()
		If (_dirty And Not HasNext()) Return Null

		_dirty = True
		Return _basic
	End

	Method Destroy:Void()
		_Reset(Null)
		_basic = Null
	End Method

Private

	Field _group:FlxGroup

	Field _index:Int

	Field _nextIndex:Int

	Field _hasNext:Bool

	Field _dirty:Bool

	Field _basic:FlxBasic

	Method _Reset:Enumerator(group:FlxGroup)
		_group = group
		_nextIndex = 0
		_hasNext = False
		_dirty = True

		Return Self
	End Method

End

Private

Class Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic) Abstract

	Method Reset:Comparator(sortIndex:FieldInfo, sortMethod:MethodInfo = Null)
		_sortIndex = sortIndex
		_sortMethod = sortMethod

		Return Self
	End Method

	Method Clear:Void()
		_sortIndex = Null
		_sortMethod = Null
	End Method

Private

	Field _sortIndex:FieldInfo

	Field _sortMethod:MethodInfo

End Class

Class BoolComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return Int(UnboxBool(_sortIndex.GetValue(basic1))) - Int(UnboxBool(_sortIndex.GetValue(basic2)))
	End Method

End Class

Class IntComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return UnboxInt(_sortIndex.GetValue(basic1)) - UnboxInt(_sortIndex.GetValue(basic2))
	End Method

End Class

Class FloatComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return UnboxFloat(_sortIndex.GetValue(basic1)) - UnboxFloat(_sortIndex.GetValue(basic2))
	End Method

End Class

Class StringComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return UnboxString(_sortIndex.GetValue(basic1)).Compare(UnboxString(_sortIndex.GetValue(basic2)))
	End Method

End Class

Class ObjectComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return UnboxInt(_sortMethod.Invoke(_sortIndex.GetValue(basic1),[_sortIndex.GetValue(basic2)]))
	End Method

End Class

#Rem
footer:Flixel is an open source game-making library that is completely free for personal or commercial use.
[quote]Copyright: Flixel - 2009-2011 Adam 'Atomic' Saltsman
Copyright: Monkey port - 2011 Arthur 'devolonter' Bikmullin

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

NOTE FROM THE AUTHOR: As far as I know, you only have to include
this license if you are redistributing source code that includes
the Flixel library.  There is no need (or way, afaik) to include
it in your compiled flash games and apps![/quote]
#End

#rem
	header:This module contains the FlxGroup class
#end
Strict

Import reflection

Import flxextern
Import flxbasic
Import flxobject
Import flxu
Import system.flxarray

#Rem
summary:This is an organizational class that can update and render a bunch of FlxBasics.
[i][b]NOTE:[/b] Although FlxGroup extends [a flxbasic.monkey.html]FlxBasic[/a], it will not automatically add itself to the global collisions quad tree, it will only add its members.[/i]
#End
Class FlxGroup Extends FlxBasic

	Global ClassObject:Object

	#Rem
	summary:See detail.
	Use with [a #Sort]Sort()[/a] to sort in ascending order.
	#End
	Const ASCENDING:Bool = False

	#Rem
	summary:See detail.
	Use with [a #Sort]Sort()[/a] to sort in descending order.
	#End
	Const DESCENDING:Bool = True

Private

	Field _maxSize:Int

	Field _marker:Int

	Field _length:Int

	Field _members:FlxBasic[]

	Field _comparators:StringMap<Comparator>

	Field _comparator:Comparator

	Field _sortDescending:Bool

	Field _enumerator:Enumerator

Public
	#Rem
	summary:Constructor
	Params:
	[list]
	[*]maxSize:Int - the maximum capacity of this group.
	[/list]
	#End
	Method New(maxSize:Int = 0)
		Super.New()
		_maxSize = maxSize
		_marker = 0
		_length = 0
		_cameras = Null
		_comparators = New StringMap<Comparator>()
		_enumerator = New Enumerator(Null)
	End Method

	#Rem
	summary:The number of entries in the members array.
	For performance and safety you should check this variable instead of members.length unless you really know what you're doing!
	#End
	Method Length:Int() Property
		Return _length
	End Method

	#Rem
	summary:See detail.
	Array of all the [a flxbasic.monkey.html]FlxBasic[/a]s that exist in this group.
	#End
	Method Members:FlxBasic[]() Property
		Return _members
	End Method

	#Rem
	summary:Override this function to handle any deleting or "shutdown" type operations you might need,such as removing traditional Monkey/Mojo children like Images objects.
	#End
	Method Destroy:Void()
		Local basic:FlxBasic
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) basic.Destroy()
			i+=1
		Wend

		_length = 0
		_members = _members.Resize(_length)
		_cameras = Null

		If (_comparator <> Null) Then
			_comparator.Clear()
			_comparator = Null
		End If

		_comparators.Clear()
		_comparators = Null

		_enumerator.Destroy()
		_enumerator = Null

		Super.Destroy()
	End Method

	#Rem
	summary:Just making sure we don't increment the active objects count.
	#End
	Method PreUpdate:Void()

	End Method

	#Rem
	summary:Automatically goes through and calls update on everything you added.
	#End
	Method Update:Void()
		Local basic:FlxBasic
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists And basic.active) Then
				basic.PreUpdate()
				basic.Update()
				If (basic.HasTween) basic.UpdateTweens()
				basic.PostUpdate()
			End If
			i+=1
		Wend

		If (HasTween) UpdateTweens()
	End Method

	#Rem
	summary:Automatically goes through and calls render on everything you added.
	#End
	Method Draw:Void()
		If (_cameras <> Null And Not _cameras.Contains(FlxG._CurrentCamera.ID)) Return

		Local basic:FlxBasic
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists And basic.visible) basic.Draw()
			i+=1
		Wend
	End Method

	#Rem
	summary:The maximum capacity of this group.  Default is 0, meaning no max capacity, and the group can just grow.
	#End
	Method MaxSize:Int() Property
		Return _maxSize
	End Method

	Method MaxSize:Void(size:Int) Property
		_maxSize = size

		If (_marker >= _maxSize) _marker = 0
		If (_maxSize = 0 Or _maxSize >= _length) Return

		Local basic:FlxBasic
		Local i:Int = _maxSize
		Local l:Int = _length

		While(i < l)
			basic = _members[i]
			If (basic <> Null) basic.Destroy()
			i+=1
		Wend

		_members = _members.Resize(_maxSize)
		_length = _maxSize
	End Method

	#Rem
	summary:See details.
	Adds a new [a flxbasic.monkey.html]FlxBasic[/a] subclass ([a flxbasic.monkey.html]FlxBasic[/a], [a flxsprite.monkey.html]FlxSprite[/a], Enemy, etc) to the group. FlxGroup will try to replace a null member of the array first. Failing that, FlxGroup will add it to the end of the member array, assuming there is room for it, and doubling the size of the array if necessary.

	[b]WARNING[/b]: If the group has a maxSize that has already been met, the object will NOT be added to the group!

	Params:
	[list]
	[*][a flxbasic.monkey.html]object:FlxBasic[/a] - the object you want to add to the group.
	[/list]
	Return the same [a flxbasic.monkey.html]FlxBasic[/a] object that was passed in.
	#End
	Method Add:FlxBasic(object:FlxBasic)
		If (_IndexOf(object) >= 0) Return object

		Local i:Int = 0

		While (i < _length)
			If (_members[i] = Null) Then
				_members[i] = object
				If (i >= _length) _length = i+1
				Return object
			End If
			i+=1
		Wend

		If (_maxSize > 0) Then
			If (_length = _members.Length()) Then
				If (_length >= _maxSize) Then
					Return object
				ElseIf (_length*2 + 10 <= _maxSize)
					_members = _members.Resize(_length*2 + 10)
				Else
					_members = _members.Resize(_maxSize)
				End If
			End if
		Else
			If (_length = _members.Length()) Then
				_members = _members.Resize(_length*2 + 10)
			End If
		End If

		_members[i] = object
		_length+=1

		Return object
	End Method

	#Rem
	summary:Recycling is designed to help you reuse game objects without always re-allocating or "newing" them.
	If you specified a maximum size for this group (like in [a flxemitter.monkey.html]FlxEmitter[/a],then recycle will employ what we're calling "rotating" recycling. Recycle() will first check to see if the group is at capacity yet. If group is not yet at capacity, Recycle() returns a new object. If the group IS at capacity, then Recycle() just returns the next object in line

	If you did NOT specify a maximum size for this group, then Recycle() will employ what we're calling "grow-style" recycling. Recycle() will return either the first object with exists = false, or, finding none, add a new object to the array, doubling the size of the array if necessary.

	[b]WARNING:[/b] If this function needs to create a new object, and no object class was provided, it will return null instead of a valid object!

	Params:
	[list]
	[*]objectClass:FlxClass - the type objectClass implements FlxClass you want to recycle (e.g. FlxSpriteClass, EvilRobotClass, etc). Do NOT "new" the class in the parameter!
	[/list]
	Return a reference to the object that was created. Don't forget to cast it back to the objectClass you want (e.g. myObject = myObjectClass(myGroup.recycle(myObjectClassClass))).
	#End
	Method Recycle:FlxBasic(objectClass:ClassInfo = null)
		If (_maxSize > 0) Then
			If (_length < _maxSize) Then
				If (objectClass = Null) Return Null
				Return Add(FlxBasic(objectClass.NewInstance()))
			Else
				Local basic:FlxBasic = _members[_marker]
				_marker+=1
				If (_marker >= _maxSize) _marker = 0
				Return basic
			End If
		Else
			Local basic:FlxBasic = GetFirstAvailable(objectClass)
			If (basic <> Null) Return basic
			If (objectClass = Null) Return Null
			Return Add(FlxBasic(objectClass.NewInstance()))
		End If
	End Method

	#Rem
	summary:Removes an object from the group.
	Params:
	[list]
	[*][a flxbasic.monkey.html]object:FlxBasic[/a] - The [a flxbasic.monkey.html]FlxBasic[/a] you want to remove.
	[*]splice:Bool - whether the object should be cut from the array entirely or not.
	[/list]
	Return the removed object.
	#End
	Method Remove:FlxBasic(object:FlxBasic, splice:Bool = False)
		Local index:Int = _IndexOf(object)

		If (index < 0) Return Null

		If (splice) Then
			Local i:Int = index
			Local l:Int = _length

			While(i < _length - 1)
				_members[i] = _members[i+1]
				i+=1
			Wend

			_length-=1
		Else
			_members[index] = Null
		End If

		Return object
	End Method

	#Rem
	summary:Replaces an existing [a flxbasic.monkey.html]FlxBasic[/a] with a new one.
	Params:
	[list]
	[*][a flxbasic.monkey.html]oldObject:FlxBasic[/a] - the object you want to replace.
	[*][a flxbasic.monkey.html]newObject:FlxBasic[/a] - the new object you want to use instead.
	[/list]
	Return the new object.
	#End
	Method Replace:FlxBasic(oldObject:FlxBasic, newObject:FlxBasic)
		Local index:Int  = _IndexOf(oldObject)
		If (index < 0) Return Null

		_members[index] = newObject
		Return newObject
	End Method

	#Rem
	summary:Call this function to sort the group according to a particular value and order.
	For example, to sort game objects for Zelda-style overlaps you might call myGroup.Sort(FlxObject.YComparator, FlxGroup.ASCENDING) at the bottom of your [a flxstate.monkey.html]FlxState.Update()[/a] override. To sort all existing objects after a big explosion or bomb attack, you might call myGroup.Sort(FlxBasic.ExistsComparator, FlxGroup.DESCENDING)
	Params:
	[list]
	[*]comparator:FlxBasicComparator - The FlxBasicComparator you want to sort on. Default value is FlxObject.YComparator.
	[*]order:Bool - A FlxGroup constant that defines the sort order. Possible values are ASCENDING and DESCENDING. Default value is ASCENDING.
	[/list]
	Return the new object.
	#End
	Method Sort:Void(index:String = "y", order:Bool = ASCENDING)
		_comparator = _GetComparator(GetFirstNotNull().GetClassInfo().GetField(index))
		If (_comparator = Null) Return

		_sortDescending = order
		_QSort(0, _length - 1)
	End Method

	Method SetAll:Void(variableName:String, value:Object, recurse:Bool = True)
		Local basic:FlxBasic = GetFirstNotNull()
		If (basic = Null) Return

		Local f:FieldInfo = basic.GetClassInfo().GetField(variableName)

		If (f = Null) Then
			_SetAllProperties(variableName, value, recurse)
			Return
		End If

		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (recurse And FlxGroup(basic) <> Null) Then
					FlxGroup(basic).SetAll(variableName, value, recurse)
				Else
					f.SetValue(basic, value)
				End If
			End If
			i+=1
		Wend
	End Method

	Method CallAll:Void(functionName:String, recurse:Bool = True)
		Local basic:FlxBasic = GetFirstNotNull()
		If (basic = Null) Return

		Local m:MethodInfo = basic.GetClassInfo().GetMethod(functionName,[])
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (recurse And FlxGroup(basic) <> Null) Then
					FlxGroup(basic).CallAll(functionName, recurse)
				Else
					m.Invoke(basic,[])
				End If
			End If
			i+=1
		Wend
	End Method

	Method GetFirstAvailable:FlxBasic(objectClass:ClassInfo = null)
		Local basic:FlxBasic
		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And Not basic.exists And
					(objectClass = Null Or basic.GetClassInfo().ExtendsClass(objectClass))) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method GetFirstNull:Int()
		Local i:Int = 0

		While(i < _length)
			If (_members[i] = Null) Return i
			i+=1
		Wend

		Return -1
	End Method

	Method GetFirstNotNull:FlxBasic()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method GetFirstExtant:FlxBasic()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method GetFirstAlive:FlxBasic()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists And basic.alive) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method GetFirstDead:FlxBasic()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And Not basic.alive) Return basic
			i+=1
		Wend

		Return Null
	End Method

	Method CountLiving:Int()
		Local count:Int = -1
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (count < 0) count = 0
				If (basic.exists And basic.alive) count+=1
			End If
			i+=1
		Wend

		Return count
	End Method

	Method CountDead:Int()
		Local count:Int = -1
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (count < 0) count = 0
				If (Not basic.alive) count+=1
			End If
			i+=1
		Wend

		Return count
	End Method

	Method GetRandom:FlxBasic(startIndex:Int = 0, length:Int = 0)
		If (length = 0) length = _length
		Return FlxArray<FlxBasic>.GetSafeRandom(_members, startIndex, length)
	End Method

	Method Clear:Void()
		_length = 0
	End Method

	Method ReviveAll:Void()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And Not basic.exists) basic.Revive()
			i+=1
		Wend

		Super.Revive()
	End Method

	Method Kill:Void()
		Local i:Int = 0
		Local basic:FlxBasic

		While(i < _length)
			basic = _members[i]
			If (basic <> Null And basic.exists) basic.Kill()
			i+=1
		Wend

		Super.Kill()
	End Method

	Method ObjectEnumerator:Enumerator()
		Return _enumerator._Reset(Self)
	End

Private
	Method _IndexOf:Int(object:FlxBasic)
		Local i:Int = 0

		While(i < _length)
			If (_members[i] = object) Return i
			i+=1
		Wend

		Return -1
	End Method

	Method _QSort:Void(left:Int, right:Int)
		If (right > left) Then
			Local pivot:Int = left + (right-left)/2
			Local newPivot:Int = _DoSort(left, right, pivot)

			_QSort(left, newPivot - 1)
			_QSort(newPivot + 1, right)
		End If
	End Method

	Method _DoSort:Int(left:Int, right:Int, pivot:Int)
		Local basic:FlxBasic = _members[pivot]

		_members[pivot] = _members[right]
		_members[right] = basic

		Local store:Int = left
		Local basicToCompare:FlxBasic
		Local i:Int = left

		While (i < right)
			basicToCompare = _members[i]

			If (basicToCompare = Null Or basic = Null) Then
				If (basicToCompare <> Null And basic = Null) Then
					_members[i] = _members[store]
					_members[store] = basicToCompare
					store+=1
				End If

				i += 1
				Continue
			End If

			If (_sortDescending) Then
				If (_comparator.Compare(basicToCompare, basic) >= 0) Then
					_members[i] = _members[store]
					_members[store] = basicToCompare
					store+=1
				End If
			Else
				If (_comparator.Compare(basicToCompare, basic) <= 0) Then
					_members[i] = _members[store]
					_members[store] = basicToCompare
					store+=1
				End If
			End If

			i+=1
		Wend

		basic = _members[store]
		_members[store] = _members[right]
		_members[right] = basic

		Return store
	End Method

	Method _SetAllProperties:Void(variableName:String, value:Object, recurse:Bool = True)
		Local basic:FlxBasic = GetFirstNotNull()
		If (basic = Null) Return

		Local prop:MethodInfo

		prop = basic.GetClassInfo().GetMethod(variableName,[GetClass(value)])
		If (prop = Null) Return

		Local i:Int = 0

		While(i < _length)
			basic = _members[i]
			If (basic <> Null) Then
				If (recurse And FlxGroup(basic) <> Null) Then
					FlxGroup(basic).SetAll(variableName, value, recurse)
				Else
					prop.Invoke(basic,[value])
				End If
			End If
			i+=1
		Wend
	End Method

	Method _GetComparator:Comparator(sortIndex:FieldInfo)
		If (sortIndex = Null) Return Null

		Local key:String = sortIndex.Type.Name
		Local comparator:Comparator = _comparators.Get(key)

		If (comparator = Null) Then
			Select key
				Case FloatClass().Name
					comparator = New FloatComparator()

				Case IntClass().Name
					comparator = New IntComparator()

				Case BoolClass().Name
					comparator = New BoolComparator()

				Case StringClass().Name
					comparator = New StringComparator()

				Default
					key = FlxU.GetObjectClass().Name
					comparator = _comparators.Get(key)

					If (comparator = Null) comparator = New ObjectComparator()
			End Select

			_comparators.Set(key, comparator)
		End If

		comparator.Clear()

		If (key <> FlxU.GetObjectClass().Name) Then
			comparator.Reset(sortIndex)
		Else
			Local sortMethod:MethodInfo = sortIndex.Type.GetMethod("Compare",[sortIndex.Type])
			If (sortMethod = Null) sortMethod = sortIndex.Type.GetMethod("Compare",[FlxU.GetObjectClass()])

			If (sortMethod <> Null) Then
				comparator.Reset(sortIndex, sortMethod)
			Else
				comparator = Null
			End If
		End If

		Return comparator
	End Method

End Class

Class Enumerator

	Method New(group:FlxGroup)
		_Reset(group)
	End

	Method HasNext:Bool()
		If (_dirty) Then
			_dirty = False
			_hasNext = False

			Repeat
				If (_nextIndex = _group._length) Then
					Return _hasNext
				End If

				_basic = _group._members[_nextIndex]

				_nextIndex += 1
			Until (_basic <> Null)

			_hasNext = True
		End If

		Return _hasNext
	End

	Method NextObject:FlxBasic()
		If (_dirty And Not HasNext()) Return Null

		_dirty = True
		Return _basic
	End

	Method Destroy:Void()
		_Reset(Null)
		_basic = Null
	End Method

Private

	Field _group:FlxGroup

	Field _index:Int

	Field _nextIndex:Int

	Field _hasNext:Bool

	Field _dirty:Bool

	Field _basic:FlxBasic

	Method _Reset:Enumerator(group:FlxGroup)
		_group = group
		_nextIndex = 0
		_hasNext = False
		_dirty = True

		Return Self
	End Method

End

Private

Class Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic) Abstract

	Method Reset:Comparator(sortIndex:FieldInfo, sortMethod:MethodInfo = Null)
		_sortIndex = sortIndex
		_sortMethod = sortMethod

		Return Self
	End Method

	Method Clear:Void()
		_sortIndex = Null
		_sortMethod = Null
	End Method

Private

	Field _sortIndex:FieldInfo

	Field _sortMethod:MethodInfo

End Class

Class BoolComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return Int(UnboxBool(_sortIndex.GetValue(basic1))) - Int(UnboxBool(_sortIndex.GetValue(basic2)))
	End Method

End Class

Class IntComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return UnboxInt(_sortIndex.GetValue(basic1)) - UnboxInt(_sortIndex.GetValue(basic2))
	End Method

End Class

Class FloatComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return UnboxFloat(_sortIndex.GetValue(basic1)) - UnboxFloat(_sortIndex.GetValue(basic2))
	End Method

End Class

Class StringComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return UnboxString(_sortIndex.GetValue(basic1)).Compare(UnboxString(_sortIndex.GetValue(basic2)))
	End Method

End Class

Class ObjectComparator Extends Comparator

	Method Compare:Int(basic1:FlxBasic, basic2:FlxBasic)
		Return UnboxInt(_sortMethod.Invoke(_sortIndex.GetValue(basic1),[_sortIndex.GetValue(basic2)]))
	End Method

End Class

#Rem
footer:Flixel is an open source game-making library that is completely free for personal or commercial use.
[quote]Copyright: Flixel - 2009-2011 Adam 'Atomic' Saltsman
Copyright: Monkey port - 2011 Arthur 'devolonter' Bikmullin

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

NOTE FROM THE AUTHOR: As far as I know, you only have to include
this license if you are redistributing source code that includes
the Flixel library.  There is no need (or way, afaik) to include
it in your compiled flash games and apps![/quote]
#End


ToString() don't need to be explicitly called

Strict

Private

Import bono

Public

Class AssertTest Extends TestCase
    Method TestAssertEqualsInt:Void()
        AssertEquals(1, 1)
    End

    Method TestAssertEqualsFloat:Void()
        AssertEquals(2.0, 2.0)
    End

    Method TestAssertEqualsString:Void()
        AssertEquals("foo", "foo")
    End

    Method TestAssertEqualsFailureMessageInt:Void()
        Try
            AssertEquals(1, 2)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two integers are equal", ex)
            AssertStringContains("Expected: 1", ex)
            AssertStringContains("Actual  : 2", ex)
        End
    End

    Method TestAssertEqualsFailureMessageFloat:Void()
        Try
            AssertEquals(1.2, 2.3)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two floats are equal", ex)
            ' Only check to the decimal seperator due to float precision
            AssertStringContains("Expected: 1.", ex)
            AssertStringContains("Actual  : 2.", ex)
        End
    End

    Method TestAssertEqualsFailureMessageString:Void()
        Try
            AssertEquals("foo", "bar")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two strings are equal", ex)
            AssertStringContains("Expected: foo", ex)
            AssertStringContains("Actual  : bar", ex)
        End
    End

    Method TestAssertNotEqualsInt:Void()
        AssertNotEquals(1, 2)
    End

    Method TestAssertNotEqualsFloat:Void()
        AssertNotEquals(2.0, 3.0)
    End

    Method TestAssertNotEqualsString:Void()
        AssertNotEquals("foo", "baz")
    End

    Method TestAssertNotEqualsFailureMessageInt:Void()
        Try
            AssertNotEquals(1, 1)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two integers are NOT equal", ex)
        End
    End

    Method TestAssertNotEqualsFailureMessageFloats:Void()
        Try
            AssertNotEquals(1.2, 1.2)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two floats are NOT equal", ex)
        End
    End

    Method TestAssertNotEqualsFailureMessageStrings:Void()
        Try
            AssertNotEquals("foo", "foo")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two strings are NOT equal", ex)
        End
    End

    Method TestAssertGreaterThanInt:Void()
        AssertGreaterThan(1, 2)
    End

    Method TestAssertGreaterThanFloat:Void()
        AssertGreaterThan(1.0, 1.2)
    End

    Method TestAssertGreaterThanMessageInt:Void()
        Try
            AssertGreaterThan(2, 1)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(1 + " is greater than " + 2, ex)
        End
    End

    Method TestAssertGreaterThanMessageFloat:Void()
        Try
            AssertGreaterThan(2.0, 1.0)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(1.0 + " is greater than " + 2.0, ex)
        End
    End

    Method TestAssertGreaterThanOrEqualInt:Void()
        AssertGreaterThanOrEqual(1, 2)
        AssertGreaterThanOrEqual(1, 1)
    End

    Method TestAssertGreaterThanOrEqualFloat:Void()
        AssertGreaterThanOrEqual(1.0, 1.2)
        AssertGreaterThanOrEqual(1.0, 1.0)
    End

    Method TestAssertGreaterThanOrEqualMessageInt:Void()
        Try
            AssertGreaterThanOrEqual(2, 1)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(1 + " is greater than or equal to " + 2, ex)
        End
    End

    Method TestAssertGreaterThanOrEqualMessageFloat:Void()
        Try
            AssertGreaterThanOrEqual(2.0, 1.0)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(1.0 + " is greater than or equal to " + 2.0, ex)
        End
    End

    Method TestAssertLessThanInt:Void()
        AssertLessThan(2, 1)
    End

    Method TestAssertLessThanFloat:Void()
        AssertLessThan(1.2, 1.0)
    End

    Method TestAssertLessThanOrEqualInt:Void()
        AssertLessThanOrEqual(2, 1)
        AssertLessThanOrEqual(2, 2)
    End

    Method TestAssertLessThanMessageInt:Void()
        Try
            AssertLessThan(1, 2)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(2 + " is less than " + 1, ex)
        End
    End

    Method TestAssertLessThanMessageFloat:Void()
        Try
            AssertLessThan(1.0, 2.0)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(2.0 + " is less than " + 1.0, ex)
        End
    End

    Method TestAssertLessThanOrEqualFloat:Void()
        AssertLessThanOrEqual(1.2, 1.0)
        AssertLessThanOrEqual(1.2, 1.2)
    End

    Method TestAssertLessThanOrEqualMessageInt:Void()
        Try
            AssertLessThanOrEqual(1, 2)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(2 + " is less than or equal to " + 1, ex)
        End
    End

    Method TestAssertLessThanOrEqualMessageFloat:Void()
        Try
            AssertLessThanOrEqual(1.0, 2.0)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(2.0 + " is less than or equal to " + 1.0, ex)
        End
    End

    Method TestAssertStringStartsWith:Void()
        AssertStringStartsWith("foo", "foo...")
    End

    Method TestAssertStringStartsWithMessage:Void()
        Try
            AssertStringStartsWith("foo", "...foo")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string starts with a given prefix", ex)
            AssertStringContains("Expected: foo", ex)
            AssertStringContains("Actual  : ...foo", ex)
        End
    End

    Method TestAssertStringNotStartsWith:Void()
        AssertStringNotStartsWith("foo", "bar")
    End

    Method TestAssertStringNotStartsWithMessage:Void()
        Try
            AssertStringNotStartsWith("foo", "foo...")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string does NOT starts with a given prefix", ex)
            AssertStringContains("Expected: foo", ex)
            AssertStringContains("Actual  : foo...", ex)
        End
    End

    Method TestAssertStringEndsWith:Void()
        AssertStringEndsWith("foo", "...foo")
    End

    Method TestAssertStringEndsWithMessage:Void()
        Try
            AssertStringEndsWith("foo", "foo...")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string ends with a given prefix", ex)
            AssertStringContains("Expected: foo", ex)
            AssertStringContains("Actual  : foo...", ex)
        End
    End

    Method TestAssertStringNotEndsWith:Void()
        AssertStringNotEndsWith("foo", "bar")
    End

    Method TestAssertStringNotEndsWithMessage:Void()
        Try
            AssertStringNotEndsWith("foo", "...foo")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string does NOT ends with a given prefix", ex)
            AssertStringContains("Expected: foo", ex)
            AssertStringContains("Actual  : ...foo", ex)
        End
    End

    Method TestAssertStringContains:Void()
        AssertStringContains("foo", "...foo...")
    End

    Method TestAssertStringContainsMessage:Void()
        Try
            AssertStringContains("foo", "...bar...")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string contains a given sub-string", ex)
            AssertStringContains("Expected: foo", ex)
            AssertStringContains("Actual  : ...bar...", ex)
        End
    End

    Method TestAssertStringNotContains:Void()
        AssertStringNotContains("foo", "...")
    End

    Method TestAssertStringNotContainsMessage:Void()
        Try
            AssertStringNotContains("foo", "...foo...")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string does NOT contains a given sub-string", ex)
            AssertStringContains("Expected: foo", ex)
            AssertStringContains("Actual  : ...foo...", ex)
        End
    End

    Method TestAssertTrue:Void()
        AssertTrue(True)
    End

    Method TestAssertTrueMessage:Void()
        Try
            AssertTrue(False)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("false is true", ex)
        End
    End

    Method TestAssertFalse:Void()
        AssertFalse(False)
    End

    Method TestAssertFalseMessage:Void()
        Try
            AssertFalse(True)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("true is false", ex)
        End
    End

    Method TestAssertNull:Void()
        AssertNull(Null)
    End

    Method TestAssertNullMessage:Void()
        Try
            AssertNull(New Object())
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("some object is null", ex)
        End
    End

    Method TestAssertNotNull:Void()
        AssertNotNull(New Object())
    End

    Method TestAssertNotNullMessage:Void()
        Try
            AssertNotNull(Null)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("some object is NOT null", ex)
        End
    End
End

Strict

Private

Import bono

Public

Class AssertTest Extends TestCase
    Method TestAssertEqualsInt:Void()
        AssertEquals(1, 1)
    End

    Method TestAssertEqualsFloat:Void()
        AssertEquals(2.0, 2.0)
    End

    Method TestAssertEqualsString:Void()
        AssertEquals("foo", "foo")
    End

    Method TestAssertEqualsFailureMessageInt:Void()
        Try
            AssertEquals(1, 2)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two integers are equal", ex.ToString())
            AssertStringContains("Expected: 1", ex.ToString())
            AssertStringContains("Actual  : 2", ex.ToString())
        End
    End

    Method TestAssertEqualsFailureMessageFloat:Void()
        Try
            AssertEquals(1.2, 2.3)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two floats are equal", ex.ToString())
            ' Only check to the decimal seperator due to float precision
            AssertStringContains("Expected: 1.", ex.ToString())
            AssertStringContains("Actual  : 2.", ex.ToString())
        End
    End

    Method TestAssertEqualsFailureMessageString:Void()
        Try
            AssertEquals("foo", "bar")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two strings are equal", ex.ToString())
            AssertStringContains("Expected: foo", ex.ToString())
            AssertStringContains("Actual  : bar", ex.ToString())
        End
    End

    Method TestAssertNotEqualsInt:Void()
        AssertNotEquals(1, 2)
    End

    Method TestAssertNotEqualsFloat:Void()
        AssertNotEquals(2.0, 3.0)
    End

    Method TestAssertNotEqualsString:Void()
        AssertNotEquals("foo", "baz")
    End

    Method TestAssertNotEqualsFailureMessageInt:Void()
        Try
            AssertNotEquals(1, 1)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two integers are NOT equal", ex.ToString())
        End
    End

    Method TestAssertNotEqualsFailureMessageFloats:Void()
        Try
            AssertNotEquals(1.2, 1.2)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two floats are NOT equal", ex.ToString())
        End
    End

    Method TestAssertNotEqualsFailureMessageStrings:Void()
        Try
            AssertNotEquals("foo", "foo")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("two strings are NOT equal", ex.ToString())
        End
    End

    Method TestAssertGreaterThanInt:Void()
        AssertGreaterThan(1, 2)
    End

    Method TestAssertGreaterThanFloat:Void()
        AssertGreaterThan(1.0, 1.2)
    End

    Method TestAssertGreaterThanMessageInt:Void()
        Try
            AssertGreaterThan(2, 1)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(1 + " is greater than " + 2, ex.ToString())
        End
    End

    Method TestAssertGreaterThanMessageFloat:Void()
        Try
            AssertGreaterThan(2.0, 1.0)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(1.0 + " is greater than " + 2.0, ex.ToString())
        End
    End

    Method TestAssertGreaterThanOrEqualInt:Void()
        AssertGreaterThanOrEqual(1, 2)
        AssertGreaterThanOrEqual(1, 1)
    End

    Method TestAssertGreaterThanOrEqualFloat:Void()
        AssertGreaterThanOrEqual(1.0, 1.2)
        AssertGreaterThanOrEqual(1.0, 1.0)
    End

    Method TestAssertGreaterThanOrEqualMessageInt:Void()
        Try
            AssertGreaterThanOrEqual(2, 1)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(1 + " is greater than or equal to " + 2, ex.ToString())
        End
    End

    Method TestAssertGreaterThanOrEqualMessageFloat:Void()
        Try
            AssertGreaterThanOrEqual(2.0, 1.0)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(1.0 + " is greater than or equal to " + 2.0, ex.ToString())
        End
    End

    Method TestAssertLessThanInt:Void()
        AssertLessThan(2, 1)
    End

    Method TestAssertLessThanFloat:Void()
        AssertLessThan(1.2, 1.0)
    End

    Method TestAssertLessThanOrEqualInt:Void()
        AssertLessThanOrEqual(2, 1)
        AssertLessThanOrEqual(2, 2)
    End

    Method TestAssertLessThanMessageInt:Void()
        Try
            AssertLessThan(1, 2)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(2 + " is less than " + 1, ex.ToString())
        End
    End

    Method TestAssertLessThanMessageFloat:Void()
        Try
            AssertLessThan(1.0, 2.0)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(2.0 + " is less than " + 1.0, ex.ToString())
        End
    End

    Method TestAssertLessThanOrEqualFloat:Void()
        AssertLessThanOrEqual(1.2, 1.0)
        AssertLessThanOrEqual(1.2, 1.2)
    End

    Method TestAssertLessThanOrEqualMessageInt:Void()
        Try
            AssertLessThanOrEqual(1, 2)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(2 + " is less than or equal to " + 1, ex.ToString())
        End
    End

    Method TestAssertLessThanOrEqualMessageFloat:Void()
        Try
            AssertLessThanOrEqual(1.0, 2.0)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains(2.0 + " is less than or equal to " + 1.0, ex.ToString())
        End
    End

    Method TestAssertStringStartsWith:Void()
        AssertStringStartsWith("foo", "foo...")
    End

    Method TestAssertStringStartsWithMessage:Void()
        Try
            AssertStringStartsWith("foo", "...foo")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string starts with a given prefix", ex.ToString())
            AssertStringContains("Expected: foo", ex.ToString())
            AssertStringContains("Actual  : ...foo", ex.ToString())
        End
    End

    Method TestAssertStringNotStartsWith:Void()
        AssertStringNotStartsWith("foo", "bar")
    End

    Method TestAssertStringNotStartsWithMessage:Void()
        Try
            AssertStringNotStartsWith("foo", "foo...")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string does NOT starts with a given prefix", ex.ToString())
            AssertStringContains("Expected: foo", ex.ToString())
            AssertStringContains("Actual  : foo...", ex.ToString())
        End
    End

    Method TestAssertStringEndsWith:Void()
        AssertStringEndsWith("foo", "...foo")
    End

    Method TestAssertStringEndsWithMessage:Void()
        Try
            AssertStringEndsWith("foo", "foo...")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string ends with a given prefix", ex.ToString())
            AssertStringContains("Expected: foo", ex.ToString())
            AssertStringContains("Actual  : foo...", ex.ToString())
        End
    End

    Method TestAssertStringNotEndsWith:Void()
        AssertStringNotEndsWith("foo", "bar")
    End

    Method TestAssertStringNotEndsWithMessage:Void()
        Try
            AssertStringNotEndsWith("foo", "...foo")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string does NOT ends with a given prefix", ex.ToString())
            AssertStringContains("Expected: foo", ex.ToString())
            AssertStringContains("Actual  : ...foo", ex.ToString())
        End
    End

    Method TestAssertStringContains:Void()
        AssertStringContains("foo", "...foo...")
    End

    Method TestAssertStringContainsMessage:Void()
        Try
            AssertStringContains("foo", "...bar...")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string contains a given sub-string", ex.ToString())
            AssertStringContains("Expected: foo", ex.ToString())
            AssertStringContains("Actual  : ...bar...", ex.ToString())
        End
    End

    Method TestAssertStringNotContains:Void()
        AssertStringNotContains("foo", "...")
    End

    Method TestAssertStringNotContainsMessage:Void()
        Try
            AssertStringNotContains("foo", "...foo...")
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("a string does NOT contains a given sub-string", ex.ToString())
            AssertStringContains("Expected: foo", ex.ToString())
            AssertStringContains("Actual  : ...foo...", ex.ToString())
        End
    End

    Method TestAssertTrue:Void()
        AssertTrue(True)
    End

    Method TestAssertTrueMessage:Void()
        Try
            AssertTrue(False)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("false is true", ex.ToString())
        End
    End

    Method TestAssertFalse:Void()
        AssertFalse(False)
    End

    Method TestAssertFalseMessage:Void()
        Try
            AssertFalse(True)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("true is false", ex.ToString())
        End
    End

    Method TestAssertNull:Void()
        AssertNull(Null)
    End

    Method TestAssertNullMessage:Void()
        Try
            AssertNull(New Object())
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("some object is null", ex.ToString())
        End
    End

    Method TestAssertNotNull:Void()
        AssertNotNull(New Object())
    End

    Method TestAssertNotNullMessage:Void()
        Try
            AssertNotNull(Null)
            Fail("AssertionFailedException expected")
        Catch ex:AssertionFailedException
            AssertStringContains("some object is NOT null", ex.ToString())
        End
    End
End


Fixed a problem with miscalculations for dynamic cols/rows.

--HG--
extra : convert_revision : svn%3Ae934d3cd-0d57-f34a-94d0-9e8d31ae1c29/trunk%40201

Strict

Import core

Interface ILayoutManager
	Method LayoutMinimum:Point(parent:Component, point:Point=Null)
	Method Layout:Point(parent:Component, point:Point=Null)
End

Interface ILayoutData
End

' Based on SWT GridLayout
Class GridLayout Implements ILayoutManager
Private
' Private Constants
	Const DYNAMIC_MAX:Int = 100

' Private fields

	Field columns:Int
	Field rows:Int
	Field calculatedRows:Int
	Field calculatedColumns:Int

	' cached stuff
	Field compArray:Object[] = []
	Field rowNums:Int[] = []
	Field colNums:Int[] = []
	Field cellTaken:Bool[] = []

Public
' Public constants

	Const FILLTYPE_FILL:Int = 0
	Const FILLTYPE_PREFERRED:Int = 1
	Const FILLTYPE_STATIC:Int = 2

	Const DEFAULT_HORIZONTAL_MARGIN:Int = 5
	Const DEFAULT_VERTICAL_MARGIN:Int = 5
	Const DEFAULT_HORIZONTAL_SPACING:Int = 5
	Const DEFAULT_VERTICAL_SPACING:Int = 5

' Public fields

	Field colWidthTypes:Int[]
	Field rowHeightTypes:Int[]
	Field colWidthValues:Int[]
	Field rowHeightValues:Int[]

	Field leftMargin:Int
	Field rightMargin:Int
	Field topMargin:Int
	Field bottomMargin:Int
	Field horizontalSpacing:Int
	Field verticalSpacing:Int

' Constructors

	Method New(rows:Int=0, columns:Int=1,
			leftMargin:Int=DEFAULT_HORIZONTAL_MARGIN, rightMargin:Int=DEFAULT_HORIZONTAL_MARGIN,
			topMargin:Int=DEFAULT_VERTICAL_MARGIN, bottomMargin:Int=DEFAULT_VERTICAL_MARGIN,
			horizontalSpacing:Int=DEFAULT_HORIZONTAL_SPACING, verticalSpacing:Int=DEFAULT_VERTICAL_SPACING)
		If rows <= 0 And columns <= 0 Then AssertError("Only one of rows/columns may be dynamic.")
		Self.rows = rows
		Self.columns = columns
		Self.leftMargin = leftMargin
		Self.rightMargin = rightMargin
		Self.topMargin = topMargin
		Self.bottomMargin = bottomMargin
		Self.horizontalSpacing = horizontalSpacing
		Self.verticalSpacing = verticalSpacing

		If rows = 0 Then
			rowHeightTypes = New Int[DYNAMIC_MAX]
			rowHeightValues = New Int[DYNAMIC_MAX]
		Else
			rowHeightTypes = New Int[rows]
			rowHeightValues = New Int[rows]
		End

		If columns = 0 Then
			colWidthTypes = New Int[DYNAMIC_MAX]
			colWidthValues = New Int[DYNAMIC_MAX]
		Else
			colWidthTypes = New Int[columns]
			colWidthValues = New Int[columns]
		End

		For Local i:Int = 0 Until rowHeightValues.Length
			rowHeightValues[i] = -1
			rowHeightTypes[i] = FILLTYPE_FILL
		Next

		For Local i:Int = 0 Until colWidthValues.Length
			colWidthValues[i] = -1
			colWidthTypes[i] = FILLTYPE_FILL
		Next
	End

' Implements ILayoutManager

	Method Layout:Point(parent:Component, point:Point=Null)
		Return LayoutDelegate(parent, False, point)
	End

	Method LayoutMinimum:Point(parent:Component, point:Point=Null)
		Return LayoutDelegate(parent, True, point)
	End

Private
' Private methods
	Method LayoutDelegate:Point(parent:Component, calculateMinimum:Bool, point:Point=Null)
		' get the children (reuse the array)
		Local compCount:Int = 0
		If compArray.Length < parent.Children.Size Then
			compArray = parent.Children.ToArray()
			compCount = compArray.Length
		Else
			compCount = parent.Children.FillArray(compArray)
		End

		' create or clear rowNums array
		If rowNums.Length < compCount Then rowNums = New Int[compCount]
		For Local i:Int = 0 Until rowNums.Length
			rowNums[i] = 0
		Next

		' create or clear colNums array
		If colNums.Length < compCount Then colNums = New Int[compCount]
		For Local i:Int = 0 Until colNums.Length
			colNums[i] = 0
		Next

		' create or clear cellTaken array
		Local cellTakenCols:Int = columns
		Local cellTakenRows:Int = rows
		If cellTakenCols = 0 Then cellTakenCols = DYNAMIC_MAX
		If cellTakenRows = 0 Then cellTakenRows = DYNAMIC_MAX
		If cellTaken.Length < cellTakenCols*cellTakenRows Then cellTaken = New Bool[cellTakenCols*cellTakenRows]
		For Local i:Int = 0 Until cellTaken.Length
			cellTaken[i] = False
		Next

		' loop on components
		Local currentRow:Int = 0, currentColumn:Int = 0
		Local maxRow:Int = rows - 1, maxColumn:Int = columns - 1
		Local colSpan:Int = 1, rowSpan:Int = 1
		For Local i:Int = 0 Until compCount
			' get the data object
			Local data:GridData = Null
			If GridData(Component(compArray[i]).LayoutData) <> Null Then
				data = GridData(Component(compArray[i]).LayoutData)
				colSpan = data.colSpan
				rowSpan = data.rowSpan
			Else
				colSpan = 1
				rowSpan = 1
			End

			' reset current row/col to last found spot
			If i > 0 Then
				currentRow = rowNums[i-1]
				currentColumn = colNums[i-1]
			End

			' find the next available spot
			If cellTaken[currentColumn+currentRow*cellTakenCols] Then
				Repeat
					' if columns are dynamic, top to bottom then left to right
					If columns <= 0 Then
						currentRow += 1
						If currentRow >= rows Then
							currentRow = 0
							currentColumn += 1
							maxColumn = Max(maxColumn,currentColumn)
						End
					' if rows are dynamic, or the grid is fixed, left to right then top to bottom
					Else
						currentColumn += 1
						If currentColumn >= columns Then
							currentColumn = 0
							currentRow += 1
							maxRow = Max(maxRow,currentRow)
						End
					End
				Until Not cellTaken[currentColumn+currentRow*cellTakenCols]
			End
			' set the component's location to that
			rowNums[i] = currentRow
			colNums[i] = currentColumn
			If data <> Null Then
				data.startRow = currentRow
				data.startCol = currentColumn
			End

			' fill in the boolean array
			For Local fillCol:Int = currentColumn Until currentColumn + colSpan
				For Local fillRow:Int = currentRow Until currentRow + rowSpan
					cellTaken[fillCol + fillRow*cellTakenCols] = True
				Next
			Next
		Next

		' fix the dynamic one (if there is one)
		If maxRow < 0 Then maxRow = currentRow + rowSpan
		If maxColumn < 0 Then maxColumn = currentColumn + colSpan

		' store last
		calculatedRows = maxRow + 1
		calculatedColumns = maxColumn + 1

		' reset rows and columns marked as preferred
		For Local i:Int = 0 Until calculatedRows
			If rowHeightTypes[i] = FILLTYPE_PREFERRED Then rowHeightValues[i] = 0
		Next
		For Local i:Int = 0 Until calculatedColumns
			If colWidthTypes[i] = FILLTYPE_PREFERRED Then colWidthValues[i] = 0
		Next

		' now set the preferred sizes of each row and column based on component
		For Local i:Int = 0 Until compCount
			' get the data object
			Local data:GridData = Null
			If GridData(Component(compArray[i]).LayoutData) <> Null Then
				data = GridData(Component(compArray[i]).LayoutData)
				colSpan = data.colSpan
				rowSpan = data.rowSpan
			Else
				colSpan = 1
				rowSpan = 1
			End

			' if the row for this component is preferred, store the max of the heights
			If rowHeightTypes[rowNums[i]] = FILLTYPE_PREFERRED Then
				' only continue if the component consumes a single row
				If rowSpan = 1 Then
					Local y:Int = Component(compArray[i]).PreferredHeight
					If y <= 0 Then y = Component(compArray[i]).MinimumHeight
					rowHeightValues[rowNums[i]] = Max(rowHeightValues[rowNums[i]], y)
				End
			End

			' if the column for this component is preferred, store the max of the widths
			If colWidthTypes[colNums[i]] = FILLTYPE_PREFERRED Then
				' only continue if the component consumes a single column
				If colSpan = 1 Then
					Local x:Int = Component(compArray[i]).PreferredWidth
					If x <= 0 Then x = Component(compArray[i]).MinimumWidth
					colWidthValues[colNums[i]] = Max(colWidthValues[colNums[i]], x)
				End
			End
		Next

		' calculate the available fill space
		Local colFillCount:Int = 0
		Local rowFillCount:Int = 0
		Local fillWidth:Int = parent.Width - leftMargin - rightMargin - horizontalSpacing * (calculatedColumns - 1)
		Local fillHeight:Int = parent.Height - topMargin - bottomMargin - verticalSpacing * (calculatedRows - 1)
		For Local i:Int = 0 Until calculatedColumns
			If colWidthTypes[i] = FILLTYPE_FILL Then
				colFillCount += 1
			Else
				fillWidth -= colWidthValues[i]
			End
		Next
		For Local i:Int = 0 Until calculatedRows
			If rowHeightTypes[i] = FILLTYPE_FILL Then
				rowFillCount += 1
			Else
				fillHeight -= rowHeightValues[i]
			End
		Next

		' set the fill sizes
		For Local i:Int = 0 Until calculatedColumns
			If colWidthTypes[i] = FILLTYPE_FILL Then
				If calculateMinimum Then colWidthValues[i] = 0 Else colWidthValues[i] = fillWidth / colFillCount
			End
		Next
		For Local i:Int = 0 Until calculatedRows
			If rowHeightTypes[i] = FILLTYPE_FILL Then
				If calculateMinimum Then rowHeightValues[i] = 0 Else rowHeightValues[i] = fillHeight / rowFillCount
			End
		Next

		' if not getting minimum, do the layout
		If Not calculateMinimum Then
			For Local i:Int = 0 Until compCount
				' get the data object
				Local data:GridData = Null
				If GridData(Component(compArray[i]).LayoutData) <> Null Then
					data = GridData(Component(compArray[i]).LayoutData)
					colSpan = data.colSpan
					rowSpan = data.rowSpan
				Else
					colSpan = 1
					rowSpan = 1
				End

				Local x:Int = leftMargin
				Local y:Int = topMargin
				For Local j:Int = 0 Until colNums[i]
					x += colWidthValues[j] + horizontalSpacing
				Next
				For Local j:Int = 0 Until rowNums[i]
					y += rowHeightValues[j] + verticalSpacing
				Next

				Local width:Int = colWidthValues[colNums[i]]
				Local height:Int = rowHeightValues[rowNums[i]]
				For Local j:Int = 1 Until colSpan
					AssertLessThanInt(i, colNums.Length)
					AssertLessThanInt(colNums[i]+j, colWidthValues.Length)
					width += colWidthValues[colNums[i]+j] + horizontalSpacing
				Next
				For Local j:Int = 1 Until rowSpan
					AssertLessThanInt(i, rowNums.Length)
					AssertLessThanInt(rowNums[i]+j, rowHeightValues.Length)
					height += rowHeightValues[rowNums[i]+j] + verticalSpacing
				Next

				Component(compArray[i]).SetBounds(x, y, width, height)
			Next
		End

		' calculate the total size of the laid-out container
		If point = Null Then point = New Point
		For Local i:Int = 0 Until calculatedColumns
			If i = 0 Then point.x = leftMargin Else point.x += horizontalSpacing
			point.x += colWidthValues[i]
		Next
		point.x += rightMargin

		For Local i:Int = 0 Until calculatedRows
			If i = 0 Then point.y = topMargin Else point.y += verticalSpacing
			point.y += rowHeightValues[i]
		Next
		point.y += bottomMargin

		For Local i:Int = 0 Until compArray.Length
			compArray[i] = Null
		Next

		Return point
	End
End ' Class GridLayout

Class GridData Implements ILayoutData
Public
' Public fields

	Field startRow:Int = -1
	Field startCol:Int = -1
	Field rowSpan:Int = 1
	Field colSpan:Int = 1
	Field topBorder:Int = 0
	Field bottomBorder:Int = 0
	Field leftBorder:Int = 0
	Field rightBorder:Int = 0

' Constructors

	Method New(rowSpan:Int=1,colSpan:Int=1, border:Int=0)
		Self.rowSpan = rowSpan
		Self.colSpan = colSpan
		Self.topBorder = border
		Self.bottomBorder = border
		Self.leftBorder = border
		Self.rightBorder = border
	End
End ' Class GridData

Strict

Import core

Interface ILayoutManager
	Method LayoutMinimum:Point(parent:Component, point:Point=Null)
	Method Layout:Point(parent:Component, point:Point=Null)
End

Interface ILayoutData
End

Class GridLayout Implements ILayoutManager
Private
' Private Constants
	Const DYNAMIC_MAX:Int = 100

' Private fields

	Field columns:Int
	Field rows:Int
	Field calculatedRows:Int
	Field calculatedColumns:Int

	' cached stuff
	Field compArray:Object[] = []
	Field rowNums:Int[] = []
	Field colNums:Int[] = []
	Field cellTaken:Bool[] = []

Public
' Public constants

	Const FILLTYPE_FILL:Int = 0
	Const FILLTYPE_PREFERRED:Int = 1
	Const FILLTYPE_STATIC:Int = 2

	Const DEFAULT_HORIZONTAL_MARGIN:Float = 5
	Const DEFAULT_VERTICAL_MARGIN:Float = 5
	Const DEFAULT_HORIZONTAL_SPACING:Float = 5
	Const DEFAULT_VERTICAL_SPACING:Float = 5

' Public fields

	Field colWidthTypes:Int[]
	Field rowHeightTypes:Int[]
	Field colWidthValues:Float[]
	Field rowHeightValues:Float[]

	Field leftMargin:Float
	Field rightMargin:Float
	Field topMargin:Float
	Field bottomMargin:Float
	Field horizontalSpacing:Float
	Field verticalSpacing:Float

' Constructors

	Method New(rows:Int=0, columns:Int=1,
			leftMargin:Float=DEFAULT_HORIZONTAL_MARGIN, rightMargin:Float=DEFAULT_HORIZONTAL_MARGIN,
			topMargin:Float=DEFAULT_VERTICAL_MARGIN, bottomMargin:Float=DEFAULT_VERTICAL_MARGIN,
			horizontalSpacing:Float=DEFAULT_HORIZONTAL_SPACING, verticalSpacing:Float=DEFAULT_VERTICAL_SPACING)
		If rows <= 0 And columns <= 0 Then Error("Only one of rows/columns may be dynamic.")
		Self.rows = rows
		Self.columns = columns
		Self.leftMargin = leftMargin
		Self.rightMargin = rightMargin
		Self.topMargin = topMargin
		Self.bottomMargin = bottomMargin
		Self.horizontalSpacing = horizontalSpacing
		Self.verticalSpacing = verticalSpacing

		If rows = 0 Then
			rowHeightTypes = New Int[DYNAMIC_MAX]
			rowHeightValues = New Float[DYNAMIC_MAX]
		Else
			rowHeightTypes = New Int[rows]
			rowHeightValues = New Float[rows]
		End

		If columns = 0 Then
			colWidthTypes = New Int[DYNAMIC_MAX]
			colWidthValues = New Float[DYNAMIC_MAX]
		Else
			colWidthTypes = New Int[columns]
			colWidthValues = New Float[columns]
		End

		For Local i:Int = 0 Until rowHeightValues.Length
			rowHeightValues[i] = -1
			rowHeightTypes[i] = FILLTYPE_FILL
		Next

		For Local i:Int = 0 Until colWidthValues.Length
			colWidthValues[i] = -1
			colWidthTypes[i] = FILLTYPE_FILL
		Next
	End

' Implements ILayoutManager

	Method Layout:Point(parent:Component, point:Point=Null)
		Return LayoutDelegate(parent, False, point)
	End

	Method LayoutMinimum:Point(parent:Component, point:Point=Null)
		Return LayoutDelegate(parent, True, point)
	End

Private
' Private methods
	Method LayoutDelegate:Point(parent:Component, calculateMinimum:Bool, point:Point=Null)
		' get the children (reuse the array)
		Local compCount:Int = 0
		If compArray.Length < parent.Children.Size Then
			compArray = parent.Children.ToArray()
			compCount = compArray.Length
		Else
			compCount = parent.Children.FillArray(compArray)
		End

		' create or clear rowNums array
		If rowNums.Length < compCount Then rowNums = New Int[compCount]
		For Local i:Int = 0 Until rowNums.Length
			rowNums[i] = 0
		Next

		' create or clear colNums array
		If colNums.Length < compCount Then colNums = New Int[compCount]
		For Local i:Int = 0 Until colNums.Length
			colNums[i] = 0
		Next

		' create or clear cellTaken array
		Local cellTakenCols:Int = columns
		Local cellTakenRows:Int = rows
		If cellTakenCols = 0 Then cellTakenCols = DYNAMIC_MAX
		If cellTakenRows = 0 Then cellTakenRows = DYNAMIC_MAX
		If cellTaken.Length < cellTakenCols*cellTakenRows Then cellTaken = New Bool[cellTakenCols*cellTakenRows]
		For Local i:Int = 0 Until cellTaken.Length
			cellTaken[i] = False
		Next

		' loop on components
		Local currentRow:Int = 0, currentColumn:Int = 0
		Local maxRow:Int = rows - 1, maxColumn:Int = columns - 1
		Local colSpan:Int = 1, rowSpan:Int = 1
		For Local i:Int = 0 Until compCount
			' get the data object
			Local data:GridData = Null
			If GridData(Component(compArray[i]).LayoutData) <> Null Then
				data = GridData(Component(compArray[i]).LayoutData)
				colSpan = data.colSpan
				rowSpan = data.rowSpan
			Else
				colSpan = 1
				rowSpan = 1
			End

			' reset current row/col to last found spot
			If i > 0 Then
				currentRow = rowNums[i-1]
				currentColumn = colNums[i-1]
			End

			' find the next available spot
			If cellTaken[currentColumn+currentRow*cellTakenCols] Then
				Repeat
					' if columns are dynamic, top to bottom then left to right
					If columns <= 0 Then
						currentRow += 1
						If currentRow >= rows Then
							currentRow = 0
							currentColumn += 1
							maxColumn = currentColumn
						End
					' if rows are dynamic, or the grid is fixed, left to right then top to bottom
					Else
						currentColumn += 1
						If currentColumn >= columns Then
							currentColumn = 0
							currentRow += 1
							maxRow = currentRow
						End
					End
				Until Not cellTaken[currentColumn+currentRow*cellTakenCols]
			End
			' set the component's location to that
			rowNums[i] = currentRow
			colNums[i] = currentColumn
			If data <> Null Then
				data.startRow = currentRow
				data.startCol = currentColumn
			End

			' fill in the boolean array
			For Local fillCol:Int = currentColumn Until currentColumn + colSpan
				For Local fillRow:Int = currentRow Until currentRow + rowSpan
					cellTaken[fillCol + fillRow*cellTakenCols] = True
				Next
			Next
		Next

		' store last
		calculatedRows = maxRow + 1
		calculatedColumns = maxColumn + 1

		' reset rows and columns marked as preferred
		For Local i:Int = 0 Until calculatedRows
			If rowHeightTypes[i] = FILLTYPE_PREFERRED Then rowHeightValues[i] = 0
		Next
		For Local i:Int = 0 Until calculatedColumns
			If colWidthTypes[i] = FILLTYPE_PREFERRED Then colWidthValues[i] = 0
		Next

		' now set the preferred sizes of each row and column based on component
		For Local i:Int = 0 Until compCount
			' get the data object
			Local data:GridData = Null
			If GridData(Component(compArray[i]).LayoutData) <> Null Then
				data = GridData(Component(compArray[i]).LayoutData)
				colSpan = data.colSpan
				rowSpan = data.rowSpan
			Else
				colSpan = 1
				rowSpan = 1
			End

			' if the row for this component is preferred, store the max of the heights
			If rowHeightTypes[rowNums[i]] = FILLTYPE_PREFERRED Then
				' only continue if the component consumes a single row
				If rowSpan = 1 Then
					Local y:Float = Component(compArray[i]).PreferredHeight
					If y <= 0 Then y = Component(compArray[i]).MinimumHeight
					rowHeightValues[rowNums[i]] = Max(rowHeightValues[rowNums[i]], y)
				End
			End

			' if the column for this component is preferred, store the max of the widths
			If colWidthTypes[colNums[i]] = FILLTYPE_PREFERRED Then
				' only continue if the component consumes a single column
				If colSpan = 1 Then
					Local x:Float = Component(compArray[i]).PreferredWidth
					If x <= 0 Then x = Component(compArray[i]).MinimumWidth
					colWidthValues[colNums[i]] = Max(colWidthValues[colNums[i]], x)
				End
			End
		Next

		' calculate the available fill space
		Local colFillCount:Int = 0
		Local rowFillCount:Int = 0
		Local fillWidth:Float = parent.Width - leftMargin - rightMargin - horizontalSpacing * (calculatedColumns - 1)
		Local fillHeight:Float = parent.Height - topMargin - bottomMargin - verticalSpacing * (calculatedRows - 1)
		For Local i:Int = 0 Until calculatedColumns
			If colWidthTypes[i] = FILLTYPE_FILL Then
				colFillCount += 1
			Else
				fillWidth -= colWidthValues[i]
			End
		Next
		For Local i:Int = 0 Until calculatedRows
			If rowHeightTypes[i] = FILLTYPE_FILL Then
				rowFillCount += 1
			Else
				fillHeight -= rowHeightValues[i]
			End
		Next

		' set the fill sizes
		For Local i:Int = 0 Until calculatedColumns
			If colWidthTypes[i] = FILLTYPE_FILL Then
				If calculateMinimum Then colWidthValues[i] = 0 Else colWidthValues[i] = fillWidth / colFillCount
			End
		Next
		For Local i:Int = 0 Until calculatedRows
			If rowHeightTypes[i] = FILLTYPE_FILL Then
				If calculateMinimum Then rowHeightValues[i] = 0 Else rowHeightValues[i] = fillHeight / rowFillCount
			End
		Next

		' if not getting minimum, do the layout
		If Not calculateMinimum Then
			For Local i:Int = 0 Until compCount
				' get the data object
				Local data:GridData = Null
				If GridData(Component(compArray[i]).LayoutData) <> Null Then
					data = GridData(Component(compArray[i]).LayoutData)
					colSpan = data.colSpan
					rowSpan = data.rowSpan
				Else
					colSpan = 1
					rowSpan = 1
				End

				Local x:Float = leftMargin
				Local y:Float = topMargin
				For Local j:Int = 0 Until colNums[i]
					x += colWidthValues[j] + horizontalSpacing
				Next
				For Local j:Int = 0 Until rowNums[i]
					y += rowHeightValues[j] + verticalSpacing
				Next

				Local width:Float = colWidthValues[colNums[i]]
				Local height:Float = rowHeightValues[rowNums[i]]
				For Local j:Int = 1 Until colSpan
					width += colWidthValues[colNums[i]+j] + horizontalSpacing
				Next
				For Local j:Int = 1 Until rowSpan
					height += rowHeightValues[rowNums[i]+j] + verticalSpacing
				Next

				Component(compArray[i]).SetBounds(x, y, width, height)
			Next
		End

		' calculate the total size of the laid-out container
		If point = Null Then point = New Point
		For Local i:Int = 0 Until colWidthValues.Length
			If i = 0 Then point.x = leftMargin Else point.x += horizontalSpacing
			point.x += colWidthValues[i]
		Next
		point.x += rightMargin

		For Local i:Int = 0 Until rowHeightValues.Length
			If i = 0 Then point.y = topMargin Else point.y += verticalSpacing
			point.y += rowHeightValues[i]
		Next
		point.y += bottomMargin

		For Local i:Int = 0 Until compArray.Length
			compArray[i] = Null
		Next

		Return point
	End
End ' Class GridLayout

Class GridData Implements ILayoutData
Public
' Public fields

	Field startRow:Int = -1
	Field startCol:Int = -1
	Field rowSpan:Int = 1
	Field colSpan:Int = 1
	Field topBorder:Int = 0
	Field bottomBorder:Int = 0
	Field leftBorder:Int = 0
	Field rightBorder:Int = 0

' Constructors

	Method New(rowSpan:Int=1,colSpan:Int=1, border:Int=0)
		Self.rowSpan = rowSpan
		Self.colSpan = colSpan
		Self.topBorder = border
		Self.bottomBorder = border
		Self.leftBorder = border
		Self.rightBorder = border
	End
End ' Class GridData


Added getPixel example.

Added getPixel example.


InputController example updated

InputController example updated

Strict

Import mojo.graphics
Import bono

Class Handler Extends Partial
    Private

    Field lastTouchDown:TouchEvent
    Field lastTouchMove:TouchEvent
    Field lastTouchUp:TouchEvent
    Field lastKeyDown:KeyEvent
    Field lastKeyPress:KeyEvent
    Field lastKeyUp:KeyEvent

    Public

    Method OnRender:Void()
        Cls()

        SetColor(255, 0, 0)
        If lastTouchDown Then RenderTouch(lastTouchDown)

        SetColor(0, 255, 0)
        If lastTouchMove Then RenderTouch(lastTouchMove)

        SetColor(0, 0, 255)
        If lastTouchUp Then RenderTouch(lastTouchUp)

        SetColor(255, 255, 255)
        If lastKeyDown Then DrawText("lastKeyDown: " + lastKeyDown.code, 100, 100)
        If lastKeyPress Then DrawText("lastKeyPress: " + lastKeyPress.code, 100, 120)
        If lastKeyUp Then DrawText("lastKeyUp: " + lastKeyUp.code, 100, 140)
    End

    Method OnTouchDown:Void(touch:TouchEvent)
        lastTouchDown = touch
    End

    Method OnTouchMove:Void(touch:TouchEvent)
        lastTouchMove = touch
    End

    Method OnTouchUp:Void(touch:TouchEvent)
        lastTouchUp = touch
    End

    Method OnKeyUp:Void(event:KeyEvent)
        lastKeyUp = event
    End

    Method OnKeyPress:Void(event:KeyEvent)
        lastKeyPress = event
    End

    Method OnKeyDown:Void(event:KeyEvent)
        lastKeyDown = event
    End

    Private

    Method RenderTouch:Void(touch:TouchEvent)
        SetAlpha(0.2)
        For Local pos:Vector2D = EachIn touch.positions
            DrawCircle(pos.x, pos.y, 10)
        End

        SetAlpha(1)
        DrawCircle(touch.pos.x, touch.pos.y, 10)
    End
End

Function Main:Int()
    Local director:Director = New Director(480, 640)
    director.inputController.trackTouch = True
    director.inputController.trackKeys = True
    director.inputController.touchRetainSize = 25
    director.Run(New Handler())

    Return 0
End

Strict

Import mojo.graphics
Import bono

Class Handler Extends Partial
    Private

    Field lastTouchDown:TouchEvent
    Field lastTouchMove:TouchEvent
    Field lastTouchUp:TouchEvent
    Field lastKeyDown:KeyEvent
    Field lastKeyPress:KeyEvent
    Field lastKeyUp:KeyEvent

    Public

    Method OnRender:Void()
        Cls()

        SetColor(255, 0, 0)
        If lastTouchDown Then RenderTouch(lastTouchDown)

        SetColor(0, 255, 0)
        If lastTouchMove Then RenderTouch(lastTouchMove)

        SetColor(0, 0, 255)
        If lastTouchUp Then RenderTouch(lastTouchUp)

        SetColor(255, 255, 255)
        If lastKeyDown Then DrawText("lastKeyDown: " + lastKeyDown.code, 100, 100)
        If lastKeyPress Then DrawText("lastKeyPress: " + lastKeyPress.code, 100, 120)
        If lastKeyUp Then DrawText("lastKeyUp: " + lastKeyUp.code, 100, 140)
    End

    Method OnTouchDown:Void(touch:TouchEvent)
        lastTouchDown = touch
    End

    Method OnTouchMove:Void(touch:TouchEvent)
        lastTouchMove = touch
    End

    Method OnTouchUp:Void(touch:TouchEvent)
        lastTouchUp = touch
    End

    Method OnKeyUp:Void(event:KeyEvent)
        lastKeyUp = event
    End

    Method OnKeyPress:Void(event:KeyEvent)
        lastKeyPress = event
    End

    Method OnKeyDown:Void(event:KeyEvent)
        lastKeyDown = event
    End

    Private

    Method RenderTouch:Void(touch:TouchEvent)
        SetAlpha(0.2)
        For Local pos:Vector2D = EachIn touch.positions
            DrawCircle(pos.x, pos.y, 10)
        End

        SetAlpha(1)
        DrawCircle(touch.pos.x, touch.pos.y, 10)
    End
End

Function Main:Int()
    Local director:Director = New Director(640, 480)
    director.inputController.touchRetainSize = 25
    director.Run(New Handler())

    Return 0
End


Getters fixed

Getters fixed

Strict

Import flixel.flxextern
Import flixel.flxtext

Import flixel.system.flxfont

Class FlxAssetsManager

Private
	Global _Fonts:StringMap<FlxFont>[]
	Global _Images:StringMap<String>
	Global _Sounds:StringMap<String>
	Global _Music:StringMap<String>
	Global _Cursors:StringMap<String>
	Global _Strings:StringMap<String>

Public
	Function Init:Void()
		_Fonts = New StringMap<FlxFont>[FlxText.DRIVER_ANGELFONT+1]

		Local l:Int = _Fonts.Length()
		For Local i:Int = 0 Until l
			_Fonts[i] = New StringMap<FlxFont>()
		Next

		_Images = New StringMap<String>()
		_Sounds = New StringMap<String>()
		_Music = New StringMap<String>()
		_Cursors = New StringMap<String>()
		_Strings = New StringMap<String>()
	End Function

	Function AddFont:FlxFont(name:String, driver:Int = FlxText.DRIVER_NATIVE)
		Local font:FlxFont = _Fonts[driver].Get(name)
		If (font <> Null) Return font

		font = New FlxFont(name)
		_Fonts[driver].Set(name, font)

		Return font
	End Function

	Function RemoveFont:Void(name:String, size:Int, driver:Int = FlxText.DRIVER_NATIVE)
		_Fonts[driver].RemoveFontPath(name, size)
	End Function

	Function GetFonts:StringMap<FlxFont>(driver:Int = FlxText.DRIVER_NATIVE)
		Return _Fonts[driver]
	End Function

	Function GetFont:FlxFont(name:String, driver:Int = FlxText.DRIVER_NATIVE)
		Return _Fonts[driver].Get(name)
	End Function

	Function AddImage:Void(name:String, path:String)
		_Images.Set(name, path)
	End Function

	Function RemoveImage:Void(name:String)
		_Images.Remove(name)
	End Function

	Function GetImagePath:String(name:String)
		Return _Images.Get(name)
	End Function

	Function AllImages:MapKeys<String, String>()
		Return _Images.Keys()
	End Function

	Function AddSound:Void(name:String, path:String)
		_Sounds.Set(name, path)
	End Function

	Function RemoveSound:Void(name:String)
		_Sounds.Remove(name)
	End Function

	Function GetSoundPath:String(name:String)
		Return _Sounds.Get(name)
	End Function

	Function AllSounds:MapKeys<String, String>()
		Return _Sounds.Keys()
	End Function

	Function AddMusic:Void(name:String, path:String)
		_Music.Set(name, path)
	End Function

	Function RemoveMusic:Void(name:String)
		_Music.Remove(name)
	End Function

	Function GetMusicPath:String(name:String)
		Return _Music.Get(name)
	End Function

	Function AllMusic:MapKeys<String, String>()
		Return _Music.Keys()
	End Function

	Function AddCursor:Void(cursor:String, path:String)
		_Cursors.Set(cursor, path)
	End Function

	Function RemoveCursor:Void(cursor:String)
		_Cursors.Remove(cursor)
	End Function

	Function GetCursorPath:String(cursor:String)
		Return _Cursors.Get(cursor)
	End Function

	Function AllCursors:MapKeys<String, String>()
		Return _Cursors.Keys()
	End Function

	Function AddString:Void(string:String, path:String)
		_Strings.Set(string, path)
	End Function

	Function RemoveString:Void(string:String)
		_Strings.Remove(string)
	End Function

	Function GetString:String(string:String)
		Return LoadString(_Strings.Get(string))
	End Function

	Function AllStrings:MapKeys<String, String>()
		Return _Cursors.Keys()
	End Function

End Class

Strict

Import flixel.flxextern
Import flixel.flxtext

Import flixel.system.flxfont

Class FlxAssetsManager

Private
	Global _Fonts:StringMap<FlxFont>[]
	Global _Images:StringMap<String>
	Global _Sounds:StringMap<String>
	Global _Music:StringMap<String>
	Global _Cursors:StringMap<String>
	Global _Strings:StringMap<String>

Public
	Function Init:Void()
		_Fonts = New StringMap<FlxFont>[FlxText.DRIVER_ANGELFONT+1]

		Local l:Int = _Fonts.Length()
		For Local i:Int = 0 Until l
			_Fonts[i] = New StringMap<FlxFont>()
		Next

		_Images = New StringMap<String>()
		_Sounds = New StringMap<String>()
		_Music = New StringMap<String>()
		_Cursors = New StringMap<String>()
		_Strings = New StringMap<String>()
	End Function

	Function AddFont:FlxFont(name:String, driver:Int = FlxText.DRIVER_NATIVE)
		Local font:FlxFont = _Fonts[driver].Get(name)
		If (font <> Null) Return font

		font = New FlxFont(name)
		_Fonts[driver].Set(name, font)

		Return font
	End Function

	Function RemoveFont:Void(name:String, size:Int, driver:Int = FlxText.DRIVER_NATIVE)
		_Fonts[driver].RemoveFontPath(name, size)
	End Function

	Function GetFonts:StringMap<FlxFont>(driver:Int = FlxText.DRIVER_NATIVE)
		Return _Fonts[driver]
	End Function

	Function GetFont:FlxFont(name:String, driver:Int = FlxText.DRIVER_NATIVE)
		Return _Fonts[driver].Get(name)
	End Function

	Function AddImage:Void(name:String, path:String)
		_Images.Set(name, path)
	End Function

	Function RemoveImage:Void(name:String)
		_Images.Remove(name)
	End Function

	Function GetImagePath:String(name:String)
		Return _Images.Get(name)
	End Function

	Function AllImages:MapKeys()
		Return _Images.Keys()
	End Function

	Function AddSound:Void(name:String, path:String)
		_Sounds.Set(name, path)
	End Function

	Function RemoveSound:Void(name:String)
		_Sounds.Remove(name)
	End Function

	Function GetSoundPath:String(name:String)
		Return _Sounds.Get(name)
	End Function

	Function AllSounds:MapKeys()
		Return _Sounds.Keys()
	End Function

	Function AddMusic:Void(name:String, path:String)
		_Music.Set(name, path)
	End Function

	Function RemoveMusic:Void(name:String)
		_Music.Remove(name)
	End Function

	Function GetMusicPath:String(name:String)
		Return _Music.Get(name)
	End Function

	Function AllMusic:MapKeys()
		Return _Music.Keys()
	End Function

	Function AddCursor:Void(cursor:String, path:String)
		_Cursors.Set(cursor, path)
	End Function

	Function RemoveCursor:Void(cursor:String)
		_Cursors.Remove(cursor)
	End Function

	Function GetCursorPath:String(cursor:String)
		Return _Cursors.Get(cursor)
	End Function

	Function AllCursors:MapKeys()
		Return _Cursors.Keys()
	End Function

	Function AddString:Void(string:String, path:String)
		_Strings.Set(string, path)
	End Function

	Function RemoveString:Void(string:String)
		_Strings.Remove(string)
	End Function

	Function GetString:String(string:String)
		Return LoadString(_Strings.Get(string))
	End Function

	Function AllStrings:MapKeys()
		Return _Cursors.Keys()
	End Function

End Class