class ChangeCasinoTableStateEvent extends Event
{
	editable inlined var m_slotUser : EntityReference;
	editable var m_slot : CasinoTableSlot;
	editable var m_state : CasinoTableState;
	editable var m_betData : BetData;
}

enum CasinoTableSlot
{
	Slot1 = 0,
	Slot2 = 1,
	Slot3 = 2,
	Slot4 = 3,
	Slot5 = 4,
}

enum CasinoTableState
{
	Idle = 0,
	Game = 1,
}

enum CasinoTableBet
{
	none = 0,
	on_0 = 1,
	on_00 = 2,
	on_1 = 3,
	on_2 = 4,
	on_3 = 5,
	on_4 = 6,
	on_5 = 7,
	on_6 = 8,
	on_7 = 9,
	on_8 = 10,
	on_9 = 11,
	on_10 = 12,
	on_11 = 13,
	on_12 = 14,
	on_13 = 15,
	on_14 = 16,
	on_15 = 17,
	on_16 = 18,
	on_17 = 19,
	on_18 = 20,
	on_19 = 21,
	on_20 = 22,
	on_21 = 23,
	on_22 = 24,
	on_23 = 25,
	on_24 = 26,
	on_25 = 27,
	on_26 = 28,
	on_27 = 29,
	on_28 = 30,
	on_29 = 31,
	on_30 = 32,
	on_31 = 33,
	on_32 = 34,
	on_33 = 35,
	on_34 = 36,
	on_35 = 37,
	on_36 = 38,
	on_manque_1_18 = 39,
	on_passe_19_36 = 40,
	on_red = 41,
	on_black = 42,
	on_impair_odd = 43,
	on_pair_even = 44,
	on_1st_12 = 45,
	on_2st_12 = 46,
	on_3st_12 = 47,
}

struct CasinoTableSlotData
{
	editable var m_widget : inkWidgetRef;
	var m_controller : weak< CasinoTableSlotLogicController >;
	var m_casinoChipsListener : weak< InventoryScriptListener >;
	var m_slotUser : weak< GameObject >;
}

struct BetData
{
	editable var m_chipsAmount : Uint32;
	editable var m_betAmount : Uint32;
	editable var m_betOn : CasinoTableBet;
}

class CasinoChipsInventoryCallback extends InventoryScriptCallback
{
	var m_casinoTableGameController : weak< CasinoTableGameController >;
	var m_slot : CasinoTableSlot;

	public export override function OnItemQuantityChanged( item : ItemID, diff : Int32, total : Uint32, flaggedAsSilent : Bool )
	{
		m_casinoTableGameController.SetItemQuantity( m_slot, item, total );
	}

}

class CasinoTableGameController extends inkGameController
{
	[ customEditor = "TweakDBGroupInheritance;Items.money;Items.QuestItem" ]
	editable var m_casinoChipTDBID : TweakDBID;
	default m_casinoChipTDBID = T"Items.q303_casino_chip";
	editable var m_multiplier : Uint32;
	default m_multiplier = 1000;
	editable var m_slots : CasinoTableSlotData[ 5 ];
	var m_casinoChipID : ItemID;
	var m_player : weak< GameObject >;
	var m_transactionSystem : TransactionSystem;

	public function SetItemQuantity( slot : CasinoTableSlot, item : ItemID, total : Uint32 )
	{
		if( ItemID.IsOfTDBID( item, m_casinoChipTDBID ) )
		{
			m_slots[ ( ( Int32 )( slot ) ) ].m_controller.UpdateChipsAmount( total * m_multiplier );
		}
	}

	protected event OnInitialize()
	{
		var playbackOptions : inkAnimOptions;
		var i, count : Int32;
		var controller : weak< CasinoTableSlotLogicController >;
		m_casinoChipID = ItemID.FromTDBID( m_casinoChipTDBID );
		m_player = GetPlayerControlledObject();
		m_transactionSystem = GameInstance.GetTransactionSystem( m_player.GetGame() );
		playbackOptions.loopType = inkanimLoopType.Cycle;
		playbackOptions.loopInfinite = true;
		PlayLibraryAnimation( 'do_not_delete', playbackOptions );
		count = m_slots.Size();
		for( i = 0; i < count; i = i + 1 )
		{
			controller = ( ( CasinoTableSlotLogicController )( inkWidgetRef.GetController( m_slots[ i ].m_widget ) ) );
			controller.InitState();
			m_slots[ i ].m_controller = controller;
		}
	}

	protected event OnUninitialize()
	{
		var i, count : Int32;
		count = m_slots.Size();
		for( i = 0; i < count; i = i + 1 )
		{
			UnregisterInventoryListener( m_slots[ i ] );
		}
	}

	protected event OnChangeCasinoTableState( evt : ChangeCasinoTableStateEvent )
	{
		ChangeCasinoTableState( m_slots[ ( ( Int32 )( evt.m_slot ) ) ], evt );
	}

	public function ChangeCasinoTableState( slotData : ref< CasinoTableSlotData >, evt : ChangeCasinoTableStateEvent )
	{
		var slotUser : weak< GameObject >;
		var casinoChipsCallback : CasinoChipsInventoryCallback;
		if( GetGameObjectFromEntityReference( evt.m_slotUser, m_player.GetGame(), slotUser ) )
		{
			if( slotData.m_slotUser != slotUser )
			{
				UnregisterInventoryListener( slotData );
				casinoChipsCallback = new CasinoChipsInventoryCallback;
				casinoChipsCallback.m_casinoTableGameController = this;
				casinoChipsCallback.m_slot = evt.m_slot;
				slotData.m_slotUser = slotUser;
				slotData.m_casinoChipsListener = m_transactionSystem.RegisterInventoryListener( slotData.m_slotUser, casinoChipsCallback );
			}
			evt.m_betData.m_chipsAmount = ( ( Uint32 )( m_transactionSystem.GetItemQuantity( slotData.m_slotUser, m_casinoChipID ) ) ) * m_multiplier;
		}
		else
		{
			UnregisterInventoryListener( slotData );
		}
		slotData.m_controller.GotoState( evt.m_state, evt.m_betData );
	}

	public function UnregisterInventoryListener( slotData : ref< CasinoTableSlotData > )
	{
		m_transactionSystem.UnregisterInventoryListener( slotData.m_slotUser, slotData.m_casinoChipsListener );
		slotData.m_slotUser = NULL;
		slotData.m_casinoChipsListener = NULL;
	}

}

class CasinoTableSlotLogicController extends inkLogicController
{
	var m_state : CasinoTableState;
	var m_betData : BetData;
	var m_spawnRequest : weak< inkAsyncSpawnRequest >;
	var m_page : weak< inkWidget >;

	public function InitState()
	{
		GotoStateInternal( CasinoTableState.Idle, true );
	}

	public function GotoState( state : CasinoTableState, betData : BetData )
	{
		m_betData = betData;
		if( m_state == state )
		{
			PlaceBet();
		}
		else
		{
			GotoStateInternal( state );
		}
	}

	public function PlaceBet()
	{
		var controller : weak< CasinoTableGamePageLogicController >;
		if( m_state == CasinoTableState.Game )
		{
			controller = ( ( CasinoTableGamePageLogicController )( m_page.GetController() ) );
			controller.PlaceBet( m_betData );
		}
	}

	public function UpdateChipsAmount( chipsAmount : Uint32 )
	{
		var controller : weak< CasinoTableGamePageLogicController >;
		if( m_state == CasinoTableState.Game )
		{
			controller = ( ( CasinoTableGamePageLogicController )( m_page.GetController() ) );
			controller.UpdateChipsAmount( chipsAmount );
		}
	}

	public function GotoStateInternal( state : CasinoTableState, optional force : Bool )
	{
		var libraryID : CName;
		if( !( force ) && m_state == state )
		{
			return;
		}
		m_state = state;
		if( m_spawnRequest != NULL )
		{
			m_spawnRequest.Cancel();
		}
		switch( state )
		{
			case CasinoTableState.Idle:
				libraryID = 'table_screen_idle';
			break;
			case CasinoTableState.Game:
				libraryID = 'table_screen_active';
			break;
		}
		if( libraryID == '' )
		{
			OnStateChanged( NULL, NULL );
			return;
		}
		m_spawnRequest = AsyncSpawnFromLocal( GetRootCompoundWidget(), libraryID, this, 'OnStateChanged' );
	}

	protected event OnStateChanged( widget : inkWidget, userData : IScriptable )
	{
		m_spawnRequest = NULL;
		if( m_page )
		{
			GetRootCompoundWidget().RemoveChild( m_page );
		}
		m_page = widget;
		PlaceBet();
	}

}

class CasinoTableIdlePageLogicController extends inkLogicController
{

	protected event OnInitialize()
	{
		var playbackOptions : inkAnimOptions;
		playbackOptions.loopType = inkanimLoopType.Cycle;
		playbackOptions.loopInfinite = true;
		PlayLibraryAnimation( 'idle_loop', playbackOptions );
	}

}

struct BetOnMark
{
	editable var m_betOn : CasinoTableBet;
	editable var m_mark : inkWidgetRef;
}

class CasinoTableGamePageLogicController extends inkLogicController
{
	editable var m_cash : inkTextRef;
	editable var m_bet : inkTextRef;
	const editable var m_marks : array< BetOnMark >;

	public function PlaceBet( betData : BetData )
	{
		var i, count : Int32;
		var targets : inkWidgetsSet;
		inkTextRef.SetText( m_cash, IntToString( ( ( Int32 )( betData.m_chipsAmount ) ) ) );
		inkTextRef.SetText( m_bet, IntToString( ( ( Int32 )( betData.m_betAmount ) ) ) );
		count = m_marks.Size();
		for( i = 0; i < count; i = i + 1 )
		{
			inkWidgetRef.SetOpacity( m_marks[ i ].m_mark, 0.0 );
			if( m_marks[ i ].m_betOn == betData.m_betOn )
			{
				targets = new inkWidgetsSet;
				targets.Select( inkWidgetRef.Get( m_marks[ i ].m_mark ) );
				PlayLibraryAnimationOnTargets( 'active_selection_proxy', targets );
			}
		}
	}

	public function UpdateChipsAmount( chipsAmount : Uint32 )
	{
		inkTextRef.SetText( m_cash, IntToString( ( ( Int32 )( chipsAmount ) ) ) );
	}

}

class CasinoTableObject extends GameObject
{

	protected event OnChangeCasinoTableState( evt : ChangeCasinoTableStateEvent )
	{
		GameInstance.GetUISystem( GetGame() ).QueueEvent( evt );
	}

}

