/**********************************************************
RunUO 2.0 AoV C# script file
Official Age of Valor Script :: www.uovalor.com
Last modified by 
Filepath: scripts\_custom\engines\Event System\events\pvptourney\Match.cs
Lines of code: 291
***********************************************************/


using Server;
using Server.Items;
using Server.Mobiles;
using System;
using System.Collections.Generic;
using Server.Targeting;


namespace Server.EventSystem
{
	public class PvPMatch
	{
		private DateTime startdate;
		private MatchTimer m_Timer;
		private TourneyArena m_Arena;
		private PvpTourneyEventController m_Controller;
		private PvPMatchRegion m_Region;
		private DateTime nextstatuschange;
		public int status=0; //0=available, 1=wall drop, 2=match started, 3=sudden death mode, 4= stopped
		public int matchnum;
		public Dictionary<Mobile,bool> dualers = new Dictionary<Mobile,bool>(); //keeps track of dualers - bool is true if they are still fighting

		
		
		public TourneyArena Arena{get{return m_Arena;}}
		public PvpTourneyEventController Controller{get{return m_Controller;}}		
		public bool IsAvailable {get{return status==0;}}
		
		
		public PvPMatch(TourneyArena parena,PvpTourneyEventController pcontroller)
		{
			m_Arena=parena;
			m_Controller=pcontroller;
			matchnum=pcontroller.GetNextMatchNum();
		}
		
		//used when deserializing
		public PvPMatch()
		{			
		}



		//this function removes deleted/null objects from event arrays.  This is cpu intense so should only be called when really needed.
		private void ArrayDefrag()
		{
			Debugger.Write("pvptourney","{0} Match::ArrayDefrag()",this);
			
			//RegisteredMobs
			//==========================================================================
			List <Mobile> mobstodel = new List<Mobile>();
			
			foreach( KeyValuePair<Mobile, bool> kvp in dualers )
			{				
				if(kvp.Key==null || kvp.Key.Deleted)mobstodel.Add(kvp.Key);			
			}
			
			foreach(Mobile mob in mobstodel)
			{
				dualers.Remove(mob);
			}
			mobstodel.Clear();
			
		}		

		
		
		public void AddDualer(Mobile dualer,int team)
		{
			dualer.Team=team;
			dualers[dualer]=true;
		}
		
		public void DualerDied(Mobile m)
		{
			new BaseEventController.DeathTeleportTimer(Controller,m,Arena.OutLocation,Arena.Map,1,true).Start();
			m.Team=0;
			
			Broadcast("{0} was killed",m.Name);
			
			dualers[m]=false;
		}
		
		
		private void RegisterRegion()
		{
			if(Controller==null)return;
			Debugger.Write("pvptourney","Registering match {0} region",matchnum);
			m_Region=new PvPMatchRegion(this);
			m_Region.Register();
		}
		
		
		public void Broadcast(string format, params object[] args)
		{
			if(Controller==null)return;
			Controller.EventBroadcast(String.Format("Match {0}: {1}",matchnum,String.Format(format,args)),true);
		}
		
		
		public void StartMatch()
		{
			if(Controller==null)return;
			
			//create region
			RegisterRegion();
			
			Debugger.Write("pvptourney","{0} starting match...",m_Controller);
			
			Broadcast("Started");
			
			
			Arena.DivWall(5);
			nextstatuschange=DateTime.Now+TimeSpan.FromSeconds(4);
			status=1;
			
			foreach( KeyValuePair<Mobile, bool> kvp in dualers )
			{
				Mobile m = kvp.Key;
				Debugger.Write("pvptourney","{0} Prepping {1} (team {2})",m_Controller,m,m.Team);
				m.Hidden=false;
				if(m.Target!=null)m.Target.Cancel(m,TargetCancelType.Canceled);
				if(m.Team==1)m.MoveToWorld(Arena.Team1Start,Arena.Map);
				else if(m.Team==2)m.MoveToWorld(Arena.Team2Start,Arena.Map);

				m.Pacify(m,DateTime.Now+TimeSpan.FromSeconds(4));
			}
			
			
			if(m_Timer!=null && m_Timer.Running)m_Timer.Stop();
			m_Timer=new MatchTimer(this);
			m_Timer.Start();		
		}
		
		
		
		
		public void StopMatch(int winteam)
		{
			if(Controller==null)return;
			Debugger.Write("pvptourney","{0} match ended...",m_Controller);			
						
			string winners="";
			bool multiplewinners=false;
			
			foreach( KeyValuePair<Mobile, bool> kvp in dualers )
			{
				Mobile m = kvp.Key;
				Debugger.Write("pvptourney","{0} Teleporting out {1}",m_Controller,m);
				
				bool winner=m.Team==winteam;
				
				if(winner)
				{
					if(winners=="")winners += m.Name;
					else
					{
						winners+=", " + m.Name;
						multiplewinners=true;
					}
				}
				
				Controller.EndMatchTeleport(m,winner,Arena.OutLocation);
			}
			
			
			//ensure nobody (such as summons) are still in arena:
			if(m_Region!=null)
			{
				foreach(Mobile m in m_Region.GetMobiles())
				{
					Controller.EndMatchTeleport(m,false,Arena.OutLocation);				
				}			
			}
			
			Broadcast("Match Ended, winner{0} {1}",(multiplewinners ? "s are" : " is"), winners);
			
			status=4;
			nextstatuschange=DateTime.Now+TimeSpan.FromSeconds(10);
			if(m_Region!=null)m_Region.Unregister();
			
			//we let timer run as there is a small delay before another match is on
		}
		
		

		
		private DateTime NextDisconnectCheck;
		
		public void MatchTick()
		{
			if(Controller==null)return;
			Debugger.Write("pvptourney","{0} MatchTick() {1}",m_Controller,matchnum);
			
			
			//occasionally check if someone is disconnected, if yes, make them loose so they dont hold up the match - specially if everyone DCs for whatever reason
			if(NextDisconnectCheck<DateTime.Now)
			{		
				Debugger.Write("pvptourney","Match {0} Checking if anyone DCed and kicking them out...",matchnum);
			
				List<Mobile> tokill = new List<Mobile>();
				
				foreach( KeyValuePair<Mobile, bool> kvp in dualers )
				{					
					Mobile dualer = kvp.Key;
					if(dualer is PlayerMobile && dualer.NetState==null)
					{
						Broadcast("{0} DCed, killing...",dualer.Name);
						tokill.Add(dualer);
					}
				}
				
				foreach(Mobile m in tokill)
				{
					
					m.Kill();
				}
				
				NextDisconnectCheck=DateTime.Now+TimeSpan.FromSeconds(30);
			}			
			
			
			if(nextstatuschange<DateTime.Now && status!=3)
			{
				status++;
				
				Debugger.Write("pvptourney","{0} Status changing to {1}",m_Controller,status);
				
				
				switch(status)
				{
					case 2:
					{
						nextstatuschange=DateTime.Now+TimeSpan.FromMinutes(5);  //how long till sudden death
					}break;
					case 3:
					{
						Broadcast("Sudden death activated");
					}break;
					case 5: //reset stuff
					{
						status=0;
						dualers.Clear();
						m_Timer.Stop();
						m_Arena.ClearMatch();
					}break;
				}
			}
		}
		
		
		
		//region stuff
		
		public bool RegionOnSkillUse( Mobile m, int Skill )
		{
			if(m.Team==0)return true;
			if(status==1)return false;
			
			return true;
		}
		
		public bool RegionOnBeginSpellCast( Mobile m, ISpell s )
		{
			if(m.Team==0)return true;
			if(status==1)return false;
			
			return true;
		}
					
		
		public bool RegionOnBeforeDeath( Mobile m )
		{
			if(m.Team==0)return false; 
			m.IsFakeDead=true;
			//someone died, figure out who won, or if match should continue
			
			DualerDied(m);
			
			Debugger.Write("pvptourney","{0} was killed in match {1} will now check if match should end or not...",m,matchnum);
			
			//check how many dualers there are left, and if we should end the match

			int t1left=0;
			int t2left=0;
						
			foreach( KeyValuePair<Mobile, bool> kvp in dualers )
			{
				Mobile dualer = kvp.Key;
				if(dualers[dualer]==true)
				{
					if(dualer.Team==1)t1left++;
					else if(dualer.Team==2)t2left++;
				}
				Debugger.Write("pvptourney","Match {0} {1} match status: T1: {2} T2: {3}",matchnum,dualer,t1left,t2left);
			}
			
			if(t1left<=0)StopMatch(2);
			else if(t2left<=0)StopMatch(1);			
			else Debugger.Write("pvptourney","Match {0} continues",matchnum);
			
			
			return false;
		}
		
		public bool RegionOnDamage( Mobile m, ref int Damage )
		{
			if(m.Team==0)return true;
			if(status!=2 && status!=3)return false;
			
			if(status==3)Damage=Damage+Utility.Random(Damage);//do more damage in sudden death mode
		
			return true;
		}		
		
		public bool RegionOnHeal( Mobile m, ref int Heal )
		{
			if(m.Team==0)return true;
			if(status==3)return false;	//cant heal in sudden death mode	
		
			return true;
		}		
		
		public bool RegionOnDoubleClick( Mobile m, object o )
		{
			if(m.Team==0)return true;
			if(status==1)return false;
			
			if(o is BallOfSummoning || o is BraceletOfBinding || o is braceoftravel)return false;
			
			
			return true;
		}		
		

		//end region stuff	
		
		
			public class MatchTimer : Timer
			{
				PvPMatch owner;
				
				public MatchTimer(PvPMatch powner) : base( TimeSpan.FromSeconds( 0 ), TimeSpan.FromSeconds( 1.0 ) )
				{
					Priority = TimerPriority.OneSecond;
					owner=powner;
				}		
				
				protected override void OnTick()
				{
					if(owner==null || owner.Controller==null || owner.Controller.Deleted || owner.Controller.EventStatus!=2)
					{
						Debugger.Write("pvptourney","Stopping MatchTimer as stone has been deleted or event status changed prematurely");
						owner.status=0;
						Stop();
					}
					owner.MatchTick();
				}		
			}
			
			
			
		public void Serialize(GenericWriter writer)
		{
			writer.Write(0); //version
			
			ArrayDefrag();

			writer.WriteDeltaTime(startdate);			
			writer.Write(m_Arena);
			writer.Write(m_Controller);
			writer.WriteDeltaTime(nextstatuschange);
			writer.Write(status);
			writer.Write(matchnum);
			
			writer.Write(dualers.Count);
			
			foreach( KeyValuePair<Mobile, bool> kvp in dualers )
			{
				writer.Write(kvp.Key);
				writer.Write(kvp.Value);			
			}
			
		}
		
		public void Deserialize( GenericReader reader )
		{
			int version = reader.ReadInt();
			
			startdate=reader.ReadDeltaTime();
			m_Arena=(TourneyArena)reader.ReadItem();
			m_Controller=(PvpTourneyEventController)reader.ReadItem();
			nextstatuschange=reader.ReadDeltaTime();
			status=reader.ReadInt();
			matchnum=reader.ReadInt();
			
			int dualerscount=reader.ReadInt();
			
			dualers= new Dictionary<Mobile,bool>();
			
			for(int i=0;i<dualerscount;i++)
			{
				Mobile tamob=reader.ReadMobile();
				bool tabool=reader.ReadBool();
				
				dualers[tamob]=tabool;
			}
			
			if(Controller!=null)
			{			
				m_Timer=new MatchTimer(this);
				m_Timer.Start();
				if(status!=4)RegisterRegion();
			}
		}
	
	
	}
}