/* 
 * Copyright (c)2009-2025 DemiVision, LLC. All Rights Reserved. The information 
 * herein is the CONFIDENTIAL and PROPRIETARY information of DemiVision, LLC. 
 */

namespace iStatVball3;

/*
 * Implements the Legacy SmartLocations algorithm for arranging players on court in their most likely physical location
 * rather than strictly rotation order.
 */
public class LegacySmart
{
	/* Constants */
	private const int IndexCount = Lineup.RowEntries;

	// Court location indices
	private const int RightBack   = 0;
	private const int RightFront  = 1;
	private const int MiddleFront = 2;
	private const int LeftFront   = 3;
	private const int LeftBack    = 4;
	private const int MiddleBack  = 5;

	// Front/backrow indices
	private static readonly int[] FrontrowIndices = [ 3, 2, 1 ];
	private static readonly int[] BackrowIndices  = [ 4, 5, 0 ];

	/* Fields */
	private readonly List<LineupEntry> smartEntries;

	// External ref
	private List<LineupEntry> lineupEntries;

	/* Methods */
	public LegacySmart()
	{
		smartEntries = new List<LineupEntry>( Lineup.BaseEntries );
	}

	// Clears results for new algorithm run
	private void Reset()
	{
		smartEntries.Clear();

		// MUST start with empty entries
		for ( int i = 0; i < Lineup.BaseEntries; i++ )
		{
			smartEntries.Add( new LineupEntry() );
		}
	}

	// Returns specified entries in SmartLocation order
	public List<LineupEntry> GetSmartEntries( List<LineupEntry> entries )
	{
		lineupEntries = entries;

		Reset();

		// Frontrow in priority order (Zones 2,4,3)
		smartEntries[ RightFront ] = GetRightFront();
		smartEntries[ LeftFront ] = GetLeftFront();
		smartEntries[ MiddleFront ] = GetMiddleFront();

		FillRow( RecordCourt.Row.Frontrow );

		// Backrow in priority order (Zones 5,1,6)
		smartEntries[ LeftBack ] = GetLeftBack();
		smartEntries[ RightBack ] = GetRightBack();
		smartEntries[ MiddleBack ] = GetMiddleBack();

		FillRow( RecordCourt.Row.Backrow );

		return smartEntries;
	}

	/* Zone Population (1-6) */

	// Right-Back (Zone 1)
	private LineupEntry GetRightBack()
	{
		// Backrow S
		LineupEntry backS = GetBackrow( Lineup.SetterKey );

		if ( backS != null )
		{
			return backS;
		}

		// Backrow OPP
		LineupEntry backOPP = GetBackrow( Lineup.OppositeKey );

		if ( backOPP != null )
		{
			return backOPP;
		}

		// Backrow DS
		LineupEntry backDS = GetBackrow( Lineup.SpecialistKey );
		
		return backDS;
	}

	// Right-Front (Zone 2)
	private LineupEntry GetRightFront()
	{
		// Frontrow S
		LineupEntry frontS = GetFrontrow( Lineup.SetterKey );

		if ( frontS != null )
		{
			return frontS;
		}

		// Frontrow OPP
		LineupEntry frontOPP = GetFrontrow( Lineup.OppositeKey );
		
		return frontOPP;
	}

	// Middle-Front (Zone 3)
	private LineupEntry GetMiddleFront()
	{
		// Frontrow MB
		LineupEntry frontMB = GetFrontrow( Lineup.MiddleKey );
		
		return frontMB;
	}

	// Left-Front (Zone 4)
	private LineupEntry GetLeftFront()
	{
		// Frontrow OH
		LineupEntry frontOH = GetFrontrow( Lineup.OutsideKey );

		if ( frontOH != null )
		{
			return frontOH;
		}

		// Frontrow OPP
		LineupEntry frontOPP = GetFrontrow( Lineup.OppositeKey );
		
		return frontOPP;
	}

	// Left-Back (Zone 5)
	private LineupEntry GetLeftBack()
	{
		if ( Shell.Settings.SmartLibero == Settings.LiberoLBKey )
		{
			// Libero
			LineupEntry backLIB = GetBackrow( Lineup.LiberoKey );

			if ( backLIB != null )
			{
				return backLIB;
			}

			// Backrow MB
			LineupEntry backMB = GetBackrow( Lineup.MiddleKey );

			if ( backMB != null )
			{
				return backMB;
			}
		}

		// Backrow OH
		LineupEntry backOH = GetBackrow( Lineup.OutsideKey );

		if ( backOH != null )
		{
			return backOH;
		}

		// Backrow DS
		LineupEntry backDS = GetBackrow( Lineup.SpecialistKey );
		
		return backDS;
	}

	// Middle-Back (Zone 6)
	private LineupEntry GetMiddleBack()
	{
		// Libero
		if ( Shell.Settings.SmartLibero == Settings.LiberoMBKey )
		{
			LineupEntry backLIB = GetBackrow( Lineup.LiberoKey );

			if ( backLIB != null )
			{
				return backLIB;
			}

			// Backrow MB
			LineupEntry backMB = GetBackrow( Lineup.MiddleKey );

			if ( backMB != null )
			{
				return backMB;
			}
		}

		// Backrow OH
		LineupEntry backOH = GetBackrow( Lineup.OutsideKey );

		if ( backOH != null )
		{
			return backOH;
		}

		// Backrow DS
		LineupEntry backDS = GetBackrow( Lineup.SpecialistKey );
		
		return backDS;
	}

	/* Internal Utils */

	// Returns frontrow player matching specified position
	private LineupEntry GetFrontrow( string position )
	{
		return GetEntry( RecordCourt.Row.Frontrow, position );
	}

	// Returns backrow player matching specified position
	private LineupEntry GetBackrow( string position )
	{
		return GetEntry( RecordCourt.Row.Backrow, position );
	}

	// Returns player in front or back row matching specified position
	private LineupEntry GetEntry( RecordCourt.Row row, string position )
	{
		for ( int i = 0; i < IndexCount; i++ )
		{
			// Scan across front/backrow
			int index = GetIndex( row, i );
			LineupEntry entry = lineupEntries[ index ];

			// Found matching position (not already included)
			if ( (entry.Position == position) && !smartEntries.Contains( entry ) )
			{
				return entry;
			}
		}

		// No match found
		return null;
	}

	// Fills unpopulated entries in front/backrow
	private void FillRow( RecordCourt.Row row )
	{
		for ( int i = 0; i < IndexCount; i++ )
		{
			// Scan across front/backrow
			int index = GetIndex( row, i );

			// If zone empty, fill with unused player
			smartEntries[ index ] ??= GetUnused( row );
		}
	}

	// Finds player in specified row that has not yet been populated
	private LineupEntry GetUnused( RecordCourt.Row row )
	{
		for ( int i = 0; i < IndexCount; i++ )
		{
			// Scan front/backrow
			int index = GetIndex( row, i );
			LineupEntry entry = lineupEntries[ index ];

			// Not yet used
			if ( !smartEntries.Contains( entry ) )
			{
				return entry;
			}
		}

		// Should never happen
		return null;
	}

	// Returns front/backrow array index
	private int GetIndex( RecordCourt.Row row, int index )
	{
		return (row == RecordCourt.Row.Frontrow) ? FrontrowIndices[ index ] : BackrowIndices[ index ];
	}
}

//

