context: using System;
  using System.Collections;
  using Server;
  
  namespace Server.Engines.Mahjong
  {
  	public class MahjongPlayers
  	{
  		private MahjongGame m_Game;
  		private Mobile[] m_Players;
  		private bool[] m_InGame;
  		private bool[] m_PublicHand;
  		private int[] m_Scores;
  		private int m_DealerPosition;
  		private ArrayList m_Spectators;
  
  		public MahjongGame Game { get { return m_Game; } }
  		public int Seats { get { return m_Players.Length; } }
  		public Mobile Dealer { get { return m_Players[m_DealerPosition]; } }
  		public int DealerPosition { get { return m_DealerPosition; } }
  
  		public MahjongPlayers( MahjongGame game, int maxPlayers, int baseScore )
  		{
  			m_Game = game;
  			m_Spectators = new ArrayList();
  
  			m_Players = new Mobile[maxPlayers];
  			m_InGame = new bool[maxPlayers];
  			m_PublicHand = new bool[maxPlayers];
  			m_Scores = new int[maxPlayers];
  
  			for ( int i = 0; i < m_Scores.Length; i++ )
  				m_Scores[i] = baseScore;
  		}
  
  		public Mobile GetPlayer( int index )
  		{
  			if ( index < 0 || index >= m_Players.Length )
  				return null;
  			else
  				return m_Players[index];
  		}
  
  		public int GetPlayerIndex( Mobile mobile )
  		{
  			for ( int i = 0; i < m_Players.Length; i++ )
  			{
  				if ( m_Players[i] == mobile )
  					return i;
  			}
  			return -1;
  		}
  
  		public bool IsInGameDealer( Mobile mobile )
  		{
  			if ( Dealer != mobile )
  				return false;
  			else
  				return m_InGame[m_DealerPosition];
  		}
  
  		public bool IsInGamePlayer( int index )
  		{
  			if ( index < 0 || index >= m_Players.Length || m_Players[index] == null )
  				return false;
  			else
  				return m_InGame[index];
  		}
  
  		public bool IsInGamePlayer( Mobile mobile )
  		{
  			int index = GetPlayerIndex( mobile );
  
  			return IsInGamePlayer( index );
  		}
  
  		public bool IsSpectator( Mobile mobile )
  		{
  			return m_Spectators.Contains( mobile );
  		}
  
  		public int GetScore( int index )
  		{
  			if ( index < 0 || index >= m_Scores.Length )
  				return 0;
  			else
  				return m_Scores[index];
  		}
  
  		public bool IsPublic( int index )
  		{
  			if ( index < 0 || index >= m_PublicHand.Length )
  				return false;
  			else
  				return m_PublicHand[index];
  		}
  
  		public void SetPublic( int index, bool value )
  		{
  			if ( index < 0 || index >= m_PublicHand.Length || m_PublicHand[index] == value )
  				return;
  
  			m_PublicHand[index] = value;
  
  			SendTilesPacket( true, !m_Game.SpectatorVision );
  
  			if ( IsInGamePlayer( index ) )
  				m_Players[index].SendLocalizedMessage( value ? 1062775 : 1062776 ); // Your hand is [not] publicly viewable.
  		}
  
  		public ArrayList GetInGameMobiles( bool players, bool spectators )
  		{
  			ArrayList list = new ArrayList();
  
  			if ( players )
  			{
  				for ( int i = 0; i < m_Players.Length; i++ )
  				{
  					if ( IsInGamePlayer( i ) )
  						list.Add( m_Players[i] );
  				}
  			}
  
  			if ( spectators )
  			{
  				list.AddRange( m_Spectators );
  			}
  
  			return list;
  		}
  
  		public void CheckPlayers()
  		{
  			bool removed = false;
  
  			for ( int i = 0; i < m_Players.Length; i++ )
  			{
  				Mobile player = m_Players[i];
  
  				if ( player != null )
  				{
  					if ( player.Deleted )
  					{
  						m_Players[i] = null;
  
  						SendPlayerExitMessage( player );
  						UpdateDealer( true );
  
  						removed = true;
  					}
  					else if ( m_InGame[i] )
  					{
  						if ( player.NetState == null )
  						{
  							m_InGame[i] = false;
  
  							SendPlayerExitMessage( player );
  							UpdateDealer( true );
  
  							removed = true;
  						}
  						else if ( !m_Game.IsAccessibleTo( player ) || player.Map != m_Game.Map || !player.InRange( m_Game.GetWorldLocation(), 5 ) )
  						{
  							m_InGame[i] = false;
  
  							player.Send( new MahjongRelieve( m_Game ) );
  
  							SendPlayerExitMessage( player );
  							UpdateDealer( true );
  
  							removed = true;
  						}
  					}
  				}
  			}
  
  			for ( int i = 0; i < m_Spectators.Count; )
  			{
  				Mobile mobile = (Mobile)m_Spectators[i];
  
  				if ( mobile.NetState == null || mobile.Deleted )
  				{
  					m_Spectators.RemoveAt( i );
  				}
  				else if ( !m_Game.IsAccessibleTo( mobile ) || mobile.Map != m_Game.Map || !mobile.InRange( m_Game.GetWorldLocation(), 5 ) )
  				{
  					m_Spectators.RemoveAt( i );
  
  					mobile.Send( new MahjongRelieve( m_Game ) );
  				}
  				else
  				{
  					i++;
  				}
  			}
  
  			if ( removed && !UpdateSpectators() )
  				SendPlayersPacket( true, true );
  		}
  
  		private void UpdateDealer( bool message )
  		{
  			if ( IsInGamePlayer( m_DealerPosition ) )
  				return;
  
  			for ( int i = m_DealerPosition + 1; i < m_Players.Length; i++ )
  			{
  				if ( IsInGamePlayer( i ) )
  				{
  					m_DealerPosition = i;
  
  					if ( message )
  						SendDealerChangedMessage();
  
  					return;
  				}
  			}
  
  			for ( int i = 0; i < m_DealerPosition; i++ )
  			{
  				if ( IsInGamePlayer( i ) )
  				{
  					m_DealerPosition = i;
  
  					if ( message )
  						SendDealerChangedMessage();
  
  					return;
  				}
  			}
  		}
  
  		private int GetNextSeat()
  		{
  			for ( int i = m_DealerPosition; i < m_Players.Length; i++ )
  			{
  				if ( m_Players[i] == null )
  					return i;
  			}
  
  			for ( int i = 0; i < m_DealerPosition; i++ )
  			{
  				if ( m_Players[i] == null )
  					return i;
  			}
  
  			return -1;
  		}
  
  		private bool UpdateSpectators()
  		{
  			if ( m_Spectators.Count == 0 )
  				return false;
  
  			int nextSeat = GetNextSeat();
  
  			if ( nextSeat >= 0 )
  			{
  				Mobile newPlayer = (Mobile)m_Spectators[0];
  
  				m_Spectators.RemoveAt( 0 );
  
  				AddPlayer( newPlayer, nextSeat, false );
  
  				UpdateSpectators();
  
  				return true;
  			}
  			else
  			{
  				return false;
  			}
  		}
  
  		private void AddPlayer( Mobile player, int index, bool sendJoinGame )
  		{
  			m_Players[index] = player;
  			m_InGame[index] = true;
  
  			UpdateDealer( false );
  
  			if ( sendJoinGame )
  				player.Send( new MahjongJoinGame( m_Game ) );
  
  			SendPlayersPacket( true, true );
  
  			player.Send( new MahjongGeneralInfo( m_Game ) );
  			player.Send( new MahjongTilesInfo( m_Game, player ) );
  
  			if ( m_DealerPosition == index )
  				SendLocalizedMessage( 1062773, player.Name ); // ~1_name~ has entered the game as the dealer.
  			else
  				SendLocalizedMessage( 1062772, player.Name ); // ~1_name~ has entered the game as a player.
  		}
  
  		private void AddSpectator( Mobile mobile )
  		{
  			if ( !IsSpectator( mobile ) )
  			{
  				m_Spectators.Add( mobile );
  			}
  
  			mobile.Send( new MahjongJoinGame( m_Game ) );
  			mobile.Send( new MahjongPlayersInfo( m_Game, mobile ) );
  			mobile.Send( new MahjongGeneralInfo( m_Game ) );
  			mobile.Send( new MahjongTilesInfo( m_Game, mobile ) );
  		}
  
  		public void Join( Mobile mobile )
  		{
  			int index = GetPlayerIndex( mobile );
  
  			if ( index >= 0 )
  			{
  				AddPlayer( mobile, index, true );
  			}
  			else
  			{
  				int nextSeat = GetNextSeat();
  
  				if ( nextSeat >= 0 )
  				{
  					AddPlayer( mobile, nextSeat, true );
  				}
  				else
  				{
  					AddSpectator( mobile );
  				}
  			}
  		}
  
  		public void LeaveGame( Mobile player )
  		{
  			int index = GetPlayerIndex( player );
  			if ( index >= 0 )
  			{
  				m_InGame[index] = false;
  
  				SendPlayerExitMessage( player );
  				UpdateDealer( true );
  
  				SendPlayersPacket( true, true );
  			}
  			else
  			{
  				m_Spectators.Remove( player );
  			}
  		}
  
  		public void ResetScores( int value )
  		{
  			for ( int i = 0; i < m_Scores.Length; i++ )
  			{
  				m_Scores[i] = value;
  			}
  
  			SendPlayersPacket( true, m_Game.ShowScores );
  
  			SendLocalizedMessage( 1062697 ); // The dealer redistributes the score sticks evenly.
  		}
  
  		public void TransferScore( Mobile from, int toPosition, int amount )
  		{
  
gt: 			int fromPosition = GetPlayerIndex( from );