struct NetworkMinigameData
{
	var gridData : array< CellData >;
	var playerBufferSize : Int32;
	var basicAccess : ProgramData;
	var playerPrograms : array< ProgramData >;
	var enemyBufferSize : Int32;
	var enemyLockNetwork : ProgramData;
	var enemyPrograms : array< ProgramData >;
}

struct NewTurnMinigameData
{
	var position : Vector2;
	var doConsume : Bool;
	var nextHighlightMode : HighlightMode;
	var newPlayerBufferContent : array< ElementData >;
	var newEnemyBufferContent : array< ElementData >;
	var doRegenerateGrid : Bool;
	var regeneratedGridData : array< CellData >;
	var basicAccessCompletionState : ProgramProgressData;
	var playerProgramsCompletionState : array< ProgramProgressData >;
	var enemyProgramsCompletionState : array< ProgramProgressData >;
	var playerProgramsChange : Bool;
	var playerProgramsAdded : array< ProgramData >;
	var playerProgramsRemoved : array< ProgramData >;
	var enemyProgramsChange : Bool;
	var enemyprogramsAdded : array< ProgramData >;
	var enemyprogramsRemoved : array< ProgramData >;
}

enum HighlightMode
{
	Row = 0,
	Column = 1,
}

class NetworkMinigameVisualController extends inkLogicController
{
	protected editable var m_gridContainer : inkCompoundRef;
	protected editable var m_middleVideoContainer : inkVideoRef;
	protected editable var m_sidesAnimContainer : inkWidgetRef;
	protected editable var m_sidesLibraryPath : ResRef;
	protected editable var m_introAnimationLibraryName : CName;
	protected editable var m_gridOutroAnimationLibraryName : CName;
	protected editable var m_endScreenIntroAnimationLibraryName : CName;
	protected editable var m_programsContainer : inkWidgetRef;
	protected editable var m_bufferContainer : inkWidgetRef;
	protected editable var m_endScreenContainer : inkWidgetRef;
	protected const editable var m_FluffToHideContainer : array< inkWidgetRef >;
	protected const editable var m_DottedLinesList : array< inkWidgetRef >;
	protected editable var m_basicAccessContainer : inkWidgetRef;
	protected editable var m_animationCallbackContainer : inkWidgetRef;
	protected editable var m_dotMask : inkWidgetRef;
	protected editable var m_linesToGridOffset : Float;
	protected editable var m_linesSeparationDistance : Float;
	protected var m_animationCallback : weak< NetworkMinigameAnimationCallbacksTransmitter >;
	protected var m_grid : weak< NetworkMinigameGridController >;
	private editable var m_gridController : inkWidgetRef;
	private editable var m_programListController : inkWidgetRef;
	private editable var m_bufferController : inkWidgetRef;
	private editable var m_endScreenController : inkWidgetRef;
	protected var m_programList : weak< NetworkMinigameProgramListController >;
	protected var m_buffer : weak< NetworkMinigameBufferController >;
	protected var m_endScreen : weak< NetworkMinigameEndScreenController >;
	protected var m_basicAccess : weak< NetworkMinigameBasicProgramController >;
	protected var m_sidesAnim : weak< inkWidget >;
	private var m_bufferFillCount : Int32;
	private var m_bufferAnimProxy : inkAnimProxy;
	private var m_fillProgress : inkAnimDef;

	protected event OnInitialize()
	{
		m_sidesAnim = SpawnFromExternal( inkWidgetRef.Get( m_sidesAnimContainer ), m_sidesLibraryPath, 'Root' );
		m_grid = ( ( NetworkMinigameGridController )( SpawnFromLocal( inkCompoundRef.Get( m_gridContainer ), 'Grid' ).GetController() ) );
		m_programList = ( ( NetworkMinigameProgramListController )( inkWidgetRef.Get( m_programListController ).GetController() ) );
		m_buffer = ( ( NetworkMinigameBufferController )( inkWidgetRef.Get( m_bufferController ).GetController() ) );
		m_endScreen = ( ( NetworkMinigameEndScreenController )( inkWidgetRef.Get( m_endScreenController ).GetController() ) );
		m_animationCallback = ( ( NetworkMinigameAnimationCallbacksTransmitter )( inkWidgetRef.GetController( m_animationCallbackContainer ) ) );
		m_basicAccess = ( ( NetworkMinigameBasicProgramController )( SpawnFromLocal( inkWidgetRef.Get( m_basicAccessContainer ), 'BasicAccessProgram' ).GetController() ) );
		m_grid.RegisterToCallback( 'OnCellSelected', this, 'OnCellSelectCallback' );
		m_animationCallback.RegisterToCallback( 'OnStartSidesAnimation', this, 'OnStartSidesAnimation' );
		m_animationCallback.RegisterToCallback( 'OnStartMinigameBGIntroAnimation', this, 'OnStartMinigameBGIntroAnimation' );
		m_animationCallback.RegisterToCallback( 'OnIntroAnimationFinished', this, 'OnIntroAnimationFinished' );
		PlaySound( 'MiniGame', 'OnOpen' );
	}

	protected event OnUninitialize()
	{
		PlaySound( 'MiniGame', 'OnClose' );
	}

	public function SetUp( const data : ref< NetworkMinigameData > )
	{
		var startingScale : Vector2;
		startingScale.X = 0.001;
		startingScale.Y = 1.0;
		inkCompoundRef.SetVisible( m_gridContainer, true );
		inkWidgetRef.SetVisible( m_programsContainer, true );
		inkWidgetRef.SetVisible( m_bufferContainer, true );
		inkWidgetRef.SetVisible( m_endScreenContainer, false );
		inkWidgetRef.SetVisible( m_basicAccessContainer, true );
		SetFluffVisibility( true );
		m_sidesAnim.SetVisible( false );
		m_grid.SetUp( data.gridData );
		m_buffer.Spawn( data.playerBufferSize );
		m_programList.Spawn( data.playerPrograms );
		m_basicAccess.Spawn( data.basicAccess );
		StartIntroAnimation();
		inkWidgetRef.SetScale( m_dotMask, startingScale );
		m_bufferFillCount = 0;
		InitializeFluffLines();
	}

	public function SetGridElementPicked( const newData : ref< NewTurnMinigameData > )
	{
		var selectedCell : CellData;
		var oldScale : Vector2;
		var newScale : Vector2;
		var scaleInterpolator : inkAnimScale;
		var basicData : ProgramData;
		if( newData.doConsume )
		{
			selectedCell = m_grid.FindCellData( newData.position );
			selectedCell.assignedCell.Consume();
		}
		if( newData.doRegenerateGrid )
		{
			m_grid.SetGridData( newData.regeneratedGridData );
		}
		m_grid.SetCurrentActivePosition( newData.position, newData.nextHighlightMode == HighlightMode.Row );
		m_buffer.SetEntries( newData.newPlayerBufferContent );
		m_programList.ProcessListModified( newData.playerProgramsChange, newData.playerProgramsAdded, newData.playerProgramsRemoved );
		basicData = m_basicAccess.GetData();
		if( newData.basicAccessCompletionState.isComplete && !( basicData.wasCompleted ) )
		{
			m_basicAccess.ShowCompleted( newData.basicAccessCompletionState.revealLocalizedName );
			m_programList.PlaySideBarAnim();
		}
		m_programList.UpdatePartialCompletionState( newData.playerProgramsCompletionState );
		m_basicAccess.UpdatePartialCompletionState( newData.basicAccessCompletionState );
		m_bufferFillCount += 1;
		newScale.X = 0.18000001 * ( ( Float )( m_bufferFillCount ) );
		newScale.Y = 1.0;
		oldScale = inkWidgetRef.GetScale( m_dotMask );
		m_fillProgress = new inkAnimDef;
		scaleInterpolator = new inkAnimScale;
		scaleInterpolator.SetDuration( 0.2 );
		scaleInterpolator.SetStartScale( oldScale );
		scaleInterpolator.SetEndScale( newScale );
		scaleInterpolator.SetType( inkanimInterpolationType.Linear );
		scaleInterpolator.SetMode( inkanimInterpolationMode.EasyIn );
		m_fillProgress.AddInterpolator( scaleInterpolator );
		m_bufferAnimProxy = inkWidgetRef.PlayAnimation( m_dotMask, m_fillProgress );
	}

	public function SetProgramCompleted( const id : ref< String >, revealLocalizedName : Bool ) {}

	public function ShowEndScreen( const endData : ref< EndScreenData > )
	{
		var animproxy : inkAnimProxy;
		m_endScreen.SetUp( endData );
		animproxy = PlayLibraryAnimation( m_gridOutroAnimationLibraryName );
		animproxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnGridOutroOver' );
	}

	protected event OnGridOutroOver( e : inkAnimProxy )
	{
		var closeButtonRef : inkWidgetRef;
		var closeButton : weak< inkLogicController >;
		PlayLibraryAnimation( m_endScreenIntroAnimationLibraryName );
		inkCompoundRef.SetVisible( m_gridContainer, false );
		inkWidgetRef.SetVisible( m_programsContainer, false );
		inkWidgetRef.SetVisible( m_bufferContainer, false );
		inkWidgetRef.SetVisible( m_basicAccessContainer, false );
		inkWidgetRef.SetVisible( m_endScreenContainer, true );
		SetFluffVisibility( false );
		closeButtonRef = m_endScreen.GetCloseButtonRef();
		closeButton = ( ( inkLogicController )( inkWidgetRef.GetController( closeButtonRef ) ) );
		closeButton.RegisterToCallback( 'OnRelease', this, 'OnCloseClicked' );
	}

	public function GetLastCellSelected() : CellData
	{
		return m_grid.GetLastCellSelected();
	}

	public function Close()
	{
		GetRootWidget().SetVisible( false );
		ClearContainer( ( ( inkCompoundWidget )( inkCompoundRef.Get( m_gridContainer ) ) ) );
		ClearContainer( ( ( inkCompoundWidget )( inkWidgetRef.Get( m_bufferContainer ) ) ) );
		ClearContainer( ( ( inkCompoundWidget )( inkWidgetRef.Get( m_programsContainer ) ) ) );
		ClearContainer( ( ( inkCompoundWidget )( inkWidgetRef.Get( m_endScreenContainer ) ) ) );
		ClearContainer( ( ( inkCompoundWidget )( inkWidgetRef.Get( m_basicAccessContainer ) ) ) );
	}

	private function StartIntroAnimation()
	{
		inkVideoRef.Play( m_middleVideoContainer );
		m_sidesAnim.SetVisible( true );
		PlayLibraryAnimation( m_introAnimationLibraryName );
	}

	protected event OnStartSidesAnimation( e : weak< inkWidget > )
	{
		var controller : weak< NetworkMinigameAnimationCallManager >;
		controller = ( ( NetworkMinigameAnimationCallManager )( m_sidesAnim.GetController() ) );
		controller.StartReveal();
	}

	protected event OnStartMinigameBGIntroAnimation( e : weak< inkWidget > ) {}

	protected event OnIntroAnimationFinished( e : weak< inkWidget > ) {}

	private function InitializeFluffLines()
	{
		var i : Int32;
		var positionalIndex : Float;
		var lineController : weak< inkLinePattern >;
		var gridData : array< CellData >;
		var cellWidget : weak< inkWidget >;
		var cellSize : Vector2;
		var vertexToAdd : Vector2;
		gridData = m_grid.GetGrid();
		cellWidget = gridData[ 0 ].assignedCell.GetRootWidget();
		cellSize = cellWidget.GetSize();
		for( i = 0; i < m_DottedLinesList.Size(); i += 1 )
		{
			lineController = ( ( inkLinePattern )( inkWidgetRef.Get( m_DottedLinesList[ i ] ) ) );
			positionalIndex = ( ( Float )( FloorF( ( ( ( Float )( i ) ) + 1.0 ) / 2.0 ) ) );
			vertexToAdd = Vector2( ( m_linesToGridOffset + ( positionalIndex * cellSize.X ) ) - ( m_linesSeparationDistance * positionalIndex ), -95.0 );
			lineController.AddVertex( vertexToAdd );
		}
	}

	private function SetFluffVisibility( isVisible : Bool )
	{
		var i : Int32;
		for( i = 0; i < m_FluffToHideContainer.Size(); i += 1 )
		{
			inkWidgetRef.SetVisible( m_FluffToHideContainer[ i ], isVisible );
		}
	}

	private function ClearContainer( toClear : inkCompoundWidget )
	{
		toClear = ( ( inkCompoundWidget )( inkCompoundRef.Get( m_gridContainer ) ) );
		toClear.RemoveAllChildren();
	}

	protected event OnCellSelectCallback( e : weak< inkWidget > )
	{
		CallCustomCallback( 'OnCellSelected' );
	}

	protected event OnCloseClicked( e : inkPointerEvent )
	{
		CallCustomCallback( 'OnEndClosed' );
	}

}

class NetworkMinigameAnimationCallManager extends inkLogicController
{

	public function StartReveal()
	{
		PlayLibraryAnimation( 'reveal' );
	}

}

class NetworkMinigameAnimationCallbacksTransmitter extends inkLogicController
{

	protected event OnStartSidesAnimation()
	{
		CallCustomCallback( 'OnStartSidesAnimation' );
	}

	protected event OnStartMinigameBGIntroAnimation()
	{
		CallCustomCallback( 'OnStartMinigameBGIntroAnimation' );
	}

	protected event OnIntroAnimationFinished()
	{
		CallCustomCallback( 'OnIntroAnimationFinished' );
	}

}

