public ActionResult Register(RegistrationViewModel rvm)
		{
			if (ModelState.IsValid)
			{
				using(var db = new TennisOrganizerContext())
				{
					if (!Account.CheckAvailability(rvm.Login))
					{
						ViewData.Add("LoginAvailability", (bool)false);
						return View(rvm);
					}
					else
					{
						Account acc = new Account { Login = rvm.Login, Password = rvm.Password };
						rvm.Player.ImagePath = "default.png";
						Player p = rvm.Player;
						p.TopPosition = db.Players.Count<Player>() + 1;

						Account.CreateAccount(acc, p);

						TempData.Add("RegisteredLogin", rvm.Login);
						TempData.Add("RegisteredName", rvm.Player.FirstName);
						TempData.Add("RegisteredEmail", rvm.Player.Email);
						if (!TempData.ContainsKey("ValidRegistration")) ;
						TempData.Add("ValidRegistration", (bool) true);
						return RedirectToAction("RegisterSuccess");
					}
				}
			}
			else
			{
				return View(rvm);
			}
		}
		public static Duel GetDuelByID(int duelID)
		{
			Duel duel;
			using (var db = new TennisOrganizerContext())
			{
				duel = db.Duels.FirstOrDefault<Duel>(d => d.DuelId == duelID);
			}
			return duel;
		}
		public ActionResult Statistics()
		{
			using (var db = new TennisOrganizerContext())
			{
				int id = (int)Session["LoggedInPlayerId"];
				Player player = db.Players.FirstOrDefault<Player>(p => p.AccountId == id);
				var stats = new PlayerStats(player);
				return View(stats);
			}
		}
		public static List<Trainer> GetTrainersList()
		{
			using(var db = new TennisOrganizerContext())
			{
				var query = (from t in db.Trainers
							 where t is Trainer
							 select t);
				return query.ToList<Trainer>();
			}
		}
		public static bool CheckAvailability(String login)
		{
			using (var db = new TennisOrganizerContext())
			{
				var query = (from a in db.Accounts
							 where a.Login == login
							 select a.Login);
				if (query.Contains<String>(login)) return false;
			}
			return true;
		}
		public static bool CreateAccount(Account acc, Player p)
		{
			if (acc == null || p == null) return false;
			if (CheckAvailability(acc.Login) == false) return false;
			acc.Player = p;
			acc.Password = Encrypter.GetSHA256Hash(acc.Password);
			using (var db = new TennisOrganizerContext())
			{
				db.Accounts.Add(acc);
				db.Players.Add(p);
				db.SaveChanges();

				var query = (from a in db.Accounts
							 where a.Login == acc.Login
							 select a);
				if (query.Count<Account>() != 0) return true;
				else return false;
			}
		}
		public bool UpdatePlayer()
		{
			using(var db = new TennisOrganizerContext())
			{
				var p = db.Players.Find(this.AccountId);
				if (p == null) return false;
				
				p.FirstName = this.FirstName;
				p.LastName = this.LastName;
				p.BirthDate = this.BirthDate;
				p.City = this.City;
				p.Email = this.Email;
				p.PhoneNumber = this.PhoneNumber;
				p.SkillLevel = this.SkillLevel;
				p.ImagePath = this.ImagePath;
				
				db.SaveChanges();
			}
			return true;
		}
		public void TestCelanup()
		{
			db = new TennisOrganizerContext();
			var query = db.Accounts.FirstOrDefault<Account>(a => a.Login == "Account_Test");
			if (query != null)
			{
				var DuelQuery = (from d in db.Duels
								 where d.HomePlayerId == query.AccountId || d.GuestPlayerId == query.AccountId
								 select d);

				foreach (var d in DuelQuery)
				{
					db.Duels.Remove(d);
				}
				db.Players.Remove(query.Player);
				db.Accounts.Remove(query);

			}
			db.SaveChanges();
		}
		public bool UpdateAccount(String oldPassword, String newPassword = "******", String newLogin = "******")
		{
			if (this == null) return false;
			using (var db = new TennisOrganizerContext())
			{
				var query = db.Accounts.FirstOrDefault<Account>(a => a.AccountId == this.AccountId);
				if (query == null) return false;
				else if (query.Password != Encrypter.GetSHA256Hash(oldPassword)) return false;
				else
				{
					if (newLogin != "default" && newLogin != null)
					{
						query.Login = newLogin;
					}
					if (newPassword != "default" && newPassword != null)
					{
						query.Password = Encrypter.GetSHA256Hash(newPassword);
					}
					db.SaveChanges();
					return true;
				}
			}
		}
		public ActionResult Index(Account acc, string ReturnUrl)
		{
			using (var db =  new TennisOrganizerContext())
			{
				var query = db.Accounts.FirstOrDefault<Account>(a => a.Login == acc.Login);
				if (query == null)
				{
					ViewData.Add("LoginNotFound", (bool)true);
					return View(acc);
				}
				else if (Account.CheckPassword(query.Login, acc.Password) == false)
				{
					ViewData.Add("PasswordIncorrect", (bool)true);
					return View(acc);
				}
				else
				{
				//	Session["User"] = acc.Login;
					FormsAuthentication.SetAuthCookie(acc.Login, false);
					if (ReturnUrl != null) return Redirect(ReturnUrl);
					return RedirectToAction("Profile", "Main");
				}
			}
		}
		public Duel[] GetChallengingDuels()
		{
			Duel[] list;
			Player player = Player.GetPlayerById(AccountId);
			using (var Context = new TennisOrganizerContext())
			{
				Context.Players.Attach(player);
				list = (from d in player.Matches
						where
						(d.GuestPlayerId == player.AccountId
						&& d.Accepted == null
						&& DateTime.Compare(d.DateOfPlay, DateTime.Now) > 0)
						select d).ToArray<Duel>();
			}
			return list;
		}
		public Duel[] GetRejectedNotSeenDuels()
		{
			Player player = Player.GetPlayerById(AccountId);
			using (var Context = new TennisOrganizerContext())
			{
				Duel[] duels;
				Context.Players.Attach(player);
				duels = (from d in player.Matches
						 where
						 (d.HomePlayerId == player.AccountId
						 && d.Seen == false
						 && d.Accepted == false
						 && DateTime.Compare(d.DateOfPlay, DateTime.Now) >= 0)
						 select d).ToArray<Duel>();
				return duels;
			}
		}
		public Duel[] GetFinishedNotRatedDuels()
		{
			Player player = Player.GetPlayerById(AccountId);
			using (var Context = new TennisOrganizerContext())
			{
				Duel[] info;
				Context.Players.Attach(player);
				info = (from d in player.Matches
						where
						(d.HomePlayerId == player.AccountId
						&& d.Accepted == true
						&& d.Result == String.Empty
						&& DateTime.Compare(d.DateOfPlay, DateTime.Now) < 0)
						//&& !(d.GuestPlayer is Trainer)
						select d).ToArray<Duel>();
				return info;
			}
		}
		public static Player GetPlayerById(int id)
		{
			using (var db = new TennisOrganizerContext())
			{
				return db.Players.FirstOrDefault<Player>(p => p.Account.AccountId == id);
			}
		}
		private bool CanPlay(DateTime date, TennisOrganizerContext db)
		{
			Player player = db.Players.FirstOrDefault<Player>(p => p.AccountId == AccountId);
			bool hasAnotherMatch = (from m in player.Matches
									where m.DateOfPlay.Year == date.Year && m.DateOfPlay.Month == date.Month && m.DateOfPlay.Day == date.Day
									select m).Any<Duel>();
			return !hasAnotherMatch;
		}
		public static void PlayerClassInitialize(TestContext testContext)
		{
			context = new TennisOrganizerContext();
		}
		public ActionResult Challenge(ChallengeCriteria cc)
		{
			Player player = Player.GetPlayerByLogin(User.Identity.Name);

			
			if (cc.OpponentNumber <= 0)
			{
				if (cc.AgeFrom == null)
					cc.AgeFrom = 0;
				if (cc.AgeTo == null)
					cc.AgeTo = 200;
				if (cc.LevelFrom == null)
					cc.LevelFrom = 0;
				if (cc.LevelTo == null)
					cc.LevelTo = 100;

				if (cc.City == null || cc.City == String.Empty)
					cc.SuitableOpponents = player.GetOpponentsBy(cc.Date, (int)cc.AgeFrom, (int)cc.AgeTo, (float)cc.LevelFrom, (float)cc.LevelTo);
				else
					cc.SuitableOpponents = player.GetOpponentsBy(cc.Date, (int)cc.AgeFrom, (int)cc.AgeTo, (float)cc.LevelFrom, (float)cc.LevelTo, cc.City);

				
				return View(cc);
			}

			// else
			Player opponent = new Player() {  AccountId = cc.OpponentNumber};
			String[] hour = cc.Hour.ToString().Split(':') ;
			DateTime date = (DateTime)cc.Date;
			//dateOfPlay.Hour = hour[0];
			//dateOfPlay.Minute = hour[1];
			DateTime dateOfPlay;
			try
			{
				dateOfPlay = new DateTime(date.Date.Year, date.Date.Month, date.Date.Day, int.Parse(hour[0]), int.Parse(hour[1]), 0);
			}
			catch (IndexOutOfRangeException)
			{
				return View(cc);
			}

			using (var db = new TennisOrganizerContext())
			{
				db.Duels.Add(new Duel() { Accepted = false, GuestPlayerId = opponent.AccountId, HomePlayerId = player.AccountId, Seen = false, DateOfPlay = dateOfPlay });
				db.SaveChanges();

				TempData.Add("opponentName", Player.GetPlayerById(cc.OpponentNumber).ToString());
				TempData.Add("dateOfPlay", cc.Date.ToShortDateString());
				TempData.Add("hourOfPlay", cc.Hour);

				return RedirectToAction("ChallengeSuccess", "Main");
			}
		}
		public int GetMonthlyMatchesCount()
		{
			int count;

			using (var db = new TennisOrganizerContext())
			{
				Player player = db.Players.FirstOrDefault<Player>(p => p.AccountId == AccountId);
				count = player.Matches.Where<Duel>
					(p => p.DateOfPlay.Month == DateTime.Now.Month && p.DateOfPlay.Year == DateTime.Now.Year)
					.Count<Duel>();
			}
			return count;
		}
		public DateTime? GetLastMatchDate()
		{
			DateTime? date;
			using (var db = new TennisOrganizerContext())
			{
				Player player = db.Players.FirstOrDefault<Player>(p => p.AccountId == AccountId);
				var pastMatches = (from p in player.Matches
								   where p.DateOfPlay < DateTime.Now
								   orderby p.DateOfPlay
								   select p);
				if (pastMatches.Count<Duel>() > 0)
					date = pastMatches.FirstOrDefault<Duel>().DateOfPlay.Date;
				else
					date = null;
			}
			return date;
		}
		public static void Initialize(TestContext tc)
		{
			context = new TennisOrganizerContext();
		}
		public static List<PlayerStats> GetPlayersStats()
		{
			using (var db = new TennisOrganizerContext())
			{
				var players = db.Players.ToList();
				List<PlayerStats> stats = new List<PlayerStats>();

				foreach (var p in players)
					stats.Add(new PlayerStats(p));
				return stats;
			}
		}
		public ActionResult Profile()
		{
			if (Session["LoggedInPlayerId"] == null || (int)Session["LoggedInPlayerId"] <= 0)
			{
				String login = User.Identity.Name;
				using (var db = new TennisOrganizerContext())
				{
					var LoggedInPlayer = db.Players.FirstOrDefault<Player>(p => p.Account.Login == login);
					if (LoggedInPlayer == null)
					{
						FormsAuthentication.SignOut();
						return RedirectToAction("Index", "Home");
					}
					LoggedInPlayerId = LoggedInPlayer.AccountId;
					Session.Add("LoggedInPlayerId", (int)LoggedInPlayerId);
					Session.Add("LoggedInPlayer", (string)User.Identity.Name);
					Session.Add("ImagePath", (string)LoggedInPlayer.ImagePath);
				}
			}
			Player player = Player.GetPlayerByLogin(User.Identity.Name);
			return View(player);
		}
		public bool UpdatePlayer(String Password, Player p)
		{
			if (this == null || p == null) return false;
			using (var db = new TennisOrganizerContext())
			{
				var query = db.Accounts.FirstOrDefault<Account>(a => a.AccountId == this.AccountId);
				if (query == null || query.Password != Password) return false;
				else
				{
					var updated = db.Players.FirstOrDefault<Player>(player => player.AccountId == this.AccountId);
					if (updated == null) return false;
					updated.FirstName = p.FirstName;
					updated.LastName = p.LastName;
					updated.BirthDate = p.BirthDate ;
					updated.PhoneNumber = p.PhoneNumber;
					updated.Email = p.Email;
					updated.ImagePath = p.ImagePath;
					updated.City = p.City;

					db.SaveChanges();
					return true;
				}
			}
		}
		public ActionResult Training(TrainingCriteria cc)
		{
			Player player = Player.GetPlayerByLogin(User.Identity.Name);


			if (cc.OpponentNumber <= 0)
			{
				return View(cc);
			}
			Player opponent = Player.GetPlayerById(cc.OpponentNumber);
			String[] hour = cc.Hour.ToString().Split(':');
			DateTime date = (DateTime)cc.Date;
			DateTime dateOfPlay = new DateTime(date.Date.Year, date.Date.Month, date.Date.Day, int.Parse(hour[0]), int.Parse(hour[1]), 0);

			using (var db = new TennisOrganizerContext())
			{
				db.Duels.Add(new Duel() { Accepted = false, GuestPlayerId = opponent.AccountId, HomePlayerId = player.AccountId, Seen = false, DateOfPlay = dateOfPlay });
				db.SaveChanges();
				try
				{
					Mailer.NotifyAboutChallenge(player.ToString(), opponent.Email, opponent.ToString());
				}
				catch(FormatException e)
				{

				}
				TempData.Add("opponentName", Player.GetPlayerById(cc.OpponentNumber).ToString());
				TempData.Add("dateOfPlay", cc.Date.ToShortDateString());
				TempData.Add("hourOfPlay", cc.Hour);

				return RedirectToAction("TrainingSuccess", "Main");
			}
		}
		public List<PlayerDuels> GetFinished()
		{
			List<PlayerDuels> info = new List<PlayerDuels>();

			using (var db = new TennisOrganizerContext())
			{
				Player player = db.Players.FirstOrDefault<Player>(p => p.AccountId == AccountId);
				var duels = (from d in player.Matches
							 where
							 ((d.HomePlayerId == player.AccountId || d.GuestPlayerId == player.AccountId)
							 && DateTime.Compare(d.DateOfPlay, DateTime.Now) < 0)
							 select d);
				foreach (var d in duels)
					info.Add(new PlayerDuels(player, d));
			}
			return info;
		}
		public List<Player> GetOpponentsBy(DateTime gameTime, int ageFrom, int ageTo, float levelFrom, float levelTo, String city)
		{
			List<Player> players;

			using (var Context = new TennisOrganizerContext())
			{
				Player player = Context.Players.FirstOrDefault<Player>(p => p.AccountId == AccountId);
				var playersQuery = from p in Context.Players.AsEnumerable<Player>()
								   where CanPlay(p, gameTime)
								   && p.GetAge() >= ageFrom && p.GetAge() <= ageTo
								   && p.SkillLevel >= levelFrom && p.SkillLevel <= levelTo
								   && p.AccountId != player.AccountId
								   && p.City.ToLower() == city.ToLower()
								   && !(p is Trainer)
								   select p;

				return playersQuery.ToList<Player>();
			}
			return players;
		}
		public Player GetOpponentBy(int duelID)
		{
			Player player;
			using (var db = new TennisOrganizerContext())
			{
				player = (from d in db.Duels
						  where d.DuelId == duelID
						  let p = d.HomePlayerId == AccountId ? d.GuestPlayer : d.HomePlayer
						  select p).Single<Player>();
			}
			return player;
		}
		public static Player GetPlayerByLogin(string login)
		{
			using (var db = new TennisOrganizerContext())
			{
				return db.Players.FirstOrDefault<Player>(p => p.Account.Login == login);
			}
		}
		public int GetRank()
		{
			int rank = 1;
			using (var db = new TennisOrganizerContext())
			{
				var ranking = (from p in db.Players
							   where p.AccountId != AccountId //&& !(p is Trainer)
							   orderby p.SkillLevel descending
							   select p);
				foreach (Player p in ranking)
				{
					if (p.GetWonMatchesCount() - p.GetLostMatchesCount() >= GetWonMatchesCount() - GetLostMatchesCount())
						rank++;
				}
				if (rank < TopPosition && rank != 0)
				{
					TopPosition = rank;
				}
			}
			return rank;
		}
		public static bool CheckPassword(String login, String password)
		{
			password = Encrypter.GetSHA256Hash(password);
			using(var db = new TennisOrganizerContext())
			{
				var query = db.Accounts.FirstOrDefault<Account>(a => a.Login == login);
				if (query == null) return false;
				if (password != query.Password) return false;
				return true;
			}
		}