using System;
using System.Linq;

using BLToolkit.Data.DataProvider;
using BLToolkit.Data.Linq;
using BLToolkit.DataAccess;
using BLToolkit.Mapping;

using NUnit.Framework;

namespace Data.Linq
{
	using Model;

	[TestFixture]
	public class JoinTest : TestBase
	{
		[Test]
		public void InnerJoin1()
		{
			TestJohn(db =>
				from p1 in db.Person
					join p2 in db.Person on p1.ID equals p2.ID
				where p1.ID == 1
				select new Person { ID = p1.ID, FirstName = p2.FirstName });
		}

		[Test]
		public void InnerJoin2()
		{
			TestJohn(db =>
				from p1 in db.Person
					join p2 in db.Person on new { p1.ID, p1.FirstName } equals new { p2.ID, p2.FirstName }
				where p1.ID == 1
				select new Person { ID = p1.ID, FirstName = p2.FirstName });
		}

		[Test]
		public void InnerJoin3()
		{
			TestJohn(db =>
				from p1 in db.Person
					join p2 in
						from p2 in db.Person join p3 in db.Person on new { p2.ID, p2.LastName } equals new { p3.ID, p3.LastName } select new { p2, p3 }
					on new { p1.ID, p1.FirstName } equals new { p2.p2.ID, p2.p2.FirstName }
				where p1.ID == 1
				select new Person { ID = p1.ID, FirstName = p2.p2.FirstName, LastName = p2.p3.LastName });
		}

		[Test]
		public void InnerJoin4()
		{
			TestJohn(db =>
				from p1 in db.Person
					join p2 in db.Person on new { p1.ID, p1.FirstName } equals new { p2.ID, p2.FirstName }
						join p3 in db.Person on new { p2.ID, p2.LastName } equals new { p3.ID, p3.LastName }
				where p1.ID == 1
				select new Person { ID = p1.ID, FirstName = p2.FirstName, LastName = p3.LastName });
		}

		[Test]
		public void InnerJoin5()
		{
			TestJohn(db =>
				from p1 in db.Person
				join p2 in db.Person on new { p1.ID, p1.FirstName } equals new { p2.ID, p2.FirstName }
				join p3 in db.Person on new { p1.ID, p2.LastName  } equals new { p3.ID, p3.LastName  }
				where p1.ID == 1
				select new Person { ID = p1.ID, FirstName = p2.FirstName, LastName = p3.LastName });
		}

		[Test]
		public void InnerJoin6()
		{
			TestJohn(db =>
				from p1 in db.Person
					join p2 in from p3 in db.Person select new { ID = p3.ID + 1, p3.FirstName } on p1.ID equals p2.ID - 1
				where p1.ID == 1
				select new Person { ID = p1.ID, FirstName = p2.FirstName });
		}

		[Test]
		public void InnerJoin7()
		{
			var expected =
				from t in
					from ch in Child
						join p in Parent on ch.ParentID equals p.ParentID
					select ch.ParentID + p.ParentID
				where t > 2
				select t;

			ForEachProvider(db => AreEqual(expected,
				from t in
					from ch in db.Child
						join p in db.Parent on ch.ParentID equals p.ParentID
					select ch.ParentID + p.ParentID
				where t > 2
				select t));
		}

		[Test]
		public void InnerJoin8()
		{
			ForEachProvider(db => AreEqual(
				from t in
					from ch in Child
						join p in Parent on ch.ParentID equals p.ParentID
					select new { ID = ch.ParentID + p.ParentID }
				where t.ID > 2
				select t,
				from t in
					from ch in db.Child
						join p in db.Parent on ch.ParentID equals p.ParentID
					select new { ID = ch.ParentID + p.ParentID }
				where t.ID > 2
				select t));
		}

		[Test]
		public void InnerJoin9()
		{
			ForEachProvider(new[] { ProviderName.Access }, db => AreEqual(
				from g in GrandChild
				join p in Parent4 on g.Child.ParentID equals p.ParentID
				where g.ParentID < 10 && p.Value1 == TypeValue.Value3
				select g,
				from g in db.GrandChild
				join p in db.Parent4 on g.Child.ParentID equals p.ParentID
				where g.ParentID < 10 && p.Value1 == TypeValue.Value3
				select g));
		}

		[Test]
		public void InnerJoin10()
		{
			ForEachProvider(db => AreEqual(
				from p in    Parent
				join g in    GrandChild on p.ParentID equals g.ParentID into q
				from q1 in q
				select new { p.ParentID, q1.GrandChildID },
				from p in db.Parent
				join g in db.GrandChild on p.ParentID equals g.ParentID into q
				from q1 in q
				select new { p.ParentID, q1.GrandChildID }));
		}

		[Test]
		public void GroupJoin1()
		{
			ForEachProvider(db => AreEqual(
				from p in Parent
					join ch in Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select p,
				from p in db.Parent
					join ch in db.Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select p));
		}

		[Test]
		public void GroupJoin2()
		{
			ForEachProvider(db =>
			{
				var q = 
					from p in db.Parent
						join c in db.Child on p.ParentID equals c.ParentID into lj
					where p.ParentID == 1
					select new { p, lj };

				var list = q.ToList();

				Assert.AreEqual(1, list.Count);
				Assert.AreEqual(1, list[0].p.ParentID);
				Assert.AreEqual(1, list[0].lj.Count());

				var ch = list[0].lj.ToList();

				Assert.AreEqual( 1, ch[0].ParentID);
				Assert.AreEqual(11, ch[0].ChildID);
			});
		}

		[Test]
		public void GroupJoin3()
		{
			var q1 = Parent
				.GroupJoin(
					Child,
					p  => p.ParentID,
					ch => ch.ParentID,
					(p, lj1) => new { p, lj1 = new { lj1 } }
				)
				.Where (t => t.p.ParentID == 2)
				.Select(t => new { t.p, t.lj1 });

			var list1 = q1.ToList();

			ForEachProvider(db =>
			{
				var q2 = db.Parent
					.GroupJoin(
						db.Child,
						p  => p.ParentID,
						ch => ch.ParentID,
						(p, lj1) => new { p, lj1 = new { lj1 } }
					)
					.Where (t => t.p.ParentID == 2)
					.Select(t => new { t.p, t.lj1 });

				var list2 = q2.ToList();

				Assert.AreEqual(list1.Count,              list2.Count);
				Assert.AreEqual(list1[0].p.ParentID,      list2[0].p.ParentID);
				Assert.AreEqual(list1[0].lj1.lj1.Count(), list2[0].lj1.lj1.Count());
			});
		}

		[Test]
		public void GroupJoin4()
		{
			var q1 =
				from p in Parent
					join ch in
						from c in Child select new { c.ParentID, c.ChildID }
					on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 3
				select new { p, lj1 };

			var list1 = q1.ToList();

			ForEachProvider(db =>
			{
				var q2 =
					from p in db.Parent
						join ch in
							from c in db.Child select new { c.ParentID, c.ChildID }
						on p.ParentID equals ch.ParentID into lj1
					where p.ParentID == 3
					select new { p, lj1 };

				var list2 = q2.ToList();

				Assert.AreEqual(list1.Count,          list2.Count);
				Assert.AreEqual(list1[0].p.ParentID,  list2[0].p.ParentID);
				Assert.AreEqual(list1[0].lj1.Count(), list2[0].lj1.Count());
			});
		}

		[Test]
		public void GroupJoin5()
		{
			ForEachProvider(db => AreEqual(
				from p in Parent
					join ch in Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select lj1.First(),
				from p in db.Parent
					join ch in db.Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select lj1.First()));
		}

		[Test]
		public void GroupJoin51()
		{
			var expected =
			(
				from p in Parent
					join ch in Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select new { p1 = lj1, p2 = lj1.First() }
			).ToList();

			ForEachProvider(db =>
			{
				var result =
				(
					from p in db.Parent
						join ch in db.Child on p.ParentID equals ch.ParentID into lj1
					where p.ParentID == 1
					select new { p1 = lj1, p2 = lj1.First() }
				).ToList();

				Assert.AreEqual(expected.Count, result.Count);
				AreEqual(expected[0].p1, result[0].p1);
			});
		}

		[Test]
		public void GroupJoin52()
		{
			ForEachProvider(db => AreEqual(
				from p in Parent
					join ch in Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select lj1.First().ParentID,
				from p in db.Parent
					join ch in db.Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select lj1.First().ParentID));
		}

		[Test]
		public void GroupJoin53()
		{
			ForEachProvider(db => AreEqual(
				from p in Parent
					join ch in Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select lj1.Select(_ => _.ParentID).First(),
				from p in db.Parent
					join ch in db.Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select lj1.Select(_ => _.ParentID).First()));
		}

		[Test]
		public void GroupJoin54()
		{
			ForEachProvider(db => AreEqual(
				from p in Parent
					join ch in Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select new { p1 = lj1.Count(), p2 = lj1.First() },
				from p in db.Parent
					join ch in db.Child on p.ParentID equals ch.ParentID into lj1
				where p.ParentID == 1
				select new { p1 = lj1.Count(), p2 = lj1.First() }));
		}

		[Test]
		public void GroupJoin6()
		{
			var n = 1;

			var q1 =
				from p in Parent
					join c in Child on p.ParentID + n equals c.ParentID into lj
				where p.ParentID == 1
				select new { p, lj };

			var list1 = q1.ToList();
			var ch1   = list1[0].lj.ToList();

			ForEachProvider(db =>
			{
				var q2 =
					from p in db.Parent
						join c in db.Child on p.ParentID + n equals c.ParentID into lj
					where p.ParentID == 1
					select new { p, lj };

				var list2 = q2.ToList();

				Assert.AreEqual(list1.Count,         list2.Count);
				Assert.AreEqual(list1[0].p.ParentID, list2[0].p.ParentID);
				Assert.AreEqual(list1[0].lj.Count(), list2[0].lj.Count());

				var ch2 = list2[0].lj.ToList();

				Assert.AreEqual(ch1[0].ParentID, ch2[0].ParentID);
				Assert.AreEqual(ch1[0].ChildID,  ch2[0].ChildID);
			});
		}

		[Test]
		public void GroupJoin7()
		{
			var n = 1;

			var q1 = 
				from p in Parent
					join c in Child on new { id = p.ParentID } equals new { id = c.ParentID - n } into j
				where p.ParentID == 1
				select new { p, j };

			var list1 = q1.ToList();
			var ch1   = list1[0].j.ToList();

			ForEachProvider(
				new[] { ProviderName.Firebird },
				db =>
				{
					var q2 = 
						from p in db.Parent
							join c in db.Child on new { id = p.ParentID } equals new { id = c.ParentID - n } into j
						where p.ParentID == 1
						select new { p, j };

					var list2 = q2.ToList();

					Assert.AreEqual(list1.Count,         list2.Count);
					Assert.AreEqual(list1[0].p.ParentID, list2[0].p.ParentID);
					Assert.AreEqual(list1[0].j.Count(),  list2[0].j.Count());

					var ch2 = list2[0].j.ToList();

					Assert.AreEqual(ch1[0].ParentID, ch2[0].ParentID);
					Assert.AreEqual(ch1[0].ChildID,  ch2[0].ChildID);
				});
		}

		[Test]
		public void GroupJoin8()
		{
			ForEachProvider(db => AreEqual(
				from p in Parent
				join c in Child on p.ParentID equals c.ParentID into g
				select new
				{
					Child = g.FirstOrDefault()
				},
				from p in db.Parent
				join c in db.Child on p.ParentID equals c.ParentID into g
				select new
				{
					Child = g.FirstOrDefault()
				}
				));
		}

		[Test]
		public void GroupJoin9()
		{
			ForEachProvider(db => AreEqual(
				Parent
					.GroupJoin(
						Parent,
						x => new { Id = x.ParentID },
						y => new { Id = y.ParentID },
						(xid, yid) => new { xid, yid }
					)
					.SelectMany(
						y => y.yid.DefaultIfEmpty(),
						(x1, y) => new { x1.xid, y }
					)
					.GroupJoin(
						Parent,
						x => new { Id = x.xid.ParentID },
						y => new { Id = y.ParentID     },
						(x2, y) => new { x2.xid, x2.y, h = y }
					)
					.SelectMany(
						a => a.h.DefaultIfEmpty(),
						(x3, a) => new { x3.xid, x3.y, a }
					)
					.GroupJoin(
						Parent,
						x => new { Id = x.xid.ParentID },
						y => new { Id = y.ParentID     },
						(x4, y) => new { x4.xid, x4.y, x4.a, p = y }
					)
					.SelectMany(
						z => z.p.DefaultIfEmpty(),
						(x5, z) => new { x5.xid, z, x5.y, x5.a }
					)
					.GroupJoin(
						Parent,
						x => new { Id = x.xid.ParentID },
						y => new { Id = y.Value1 ?? 1 },
						(x6, y) => new { x6.xid, xy = x6.y, x6.a, x6.z, y }
					)
					.SelectMany(
						z => z.y.DefaultIfEmpty(),
						(x7, z) => new { x7.xid, z, x7.xy, x7.a, xz = x7.z }
					)
					.GroupJoin(
						Parent,
						x => new { Id = x.xid.ParentID },
						y => new { Id = y.ParentID     },
						(x8, y) => new { x8.xid, x8.z, x8.xy, x8.a, x8.xz, y }
					)
					.SelectMany(
						a => a.y.DefaultIfEmpty(),
						(x9, a) => new { x9.xid, x9.z, x9.xy, xa = x9.a, x9.xz, a }
					),
				db.Parent
					.GroupJoin(
						db.Parent,
						x => new { Id = x.ParentID },
						y => new { Id = y.ParentID },
						(xid, yid) => new { xid, yid }
					)
					.SelectMany(
						y => y.yid.DefaultIfEmpty(),
						(x1, y) => new { x1.xid, y }
					)
					.GroupJoin(
						db.Parent,
						x => new { Id = x.xid.ParentID },
						y => new { Id = y.ParentID     },
						(x2, y) => new { x2.xid, x2.y, h = y }
					)
					.SelectMany(
						a => a.h.DefaultIfEmpty(),
						(x3, a) => new { x3.xid, x3.y, a }
					)
					.GroupJoin(
						db.Parent,
						x => new { Id = x.xid.ParentID },
						y => new { Id = y.ParentID     },
						(x4, y) => new { x4.xid, x4.y, x4.a, p = y }
					)
					.SelectMany(
						z => z.p.DefaultIfEmpty(),
						(x5, z) => new { x5.xid, z, x5.y, x5.a }
					)
					.GroupJoin(
						db.Parent,
						x => new { Id = x.xid.ParentID },
						y => new { Id = y.Value1 ?? 1 },
						(x6, y) => new { x6.xid, xy = x6.y, x6.a, x6.z, y }
					)
					.SelectMany(
						z => z.y.DefaultIfEmpty(),
						(x7, z) => new { x7.xid, z, x7.xy, x7.a, xz = x7.z }
					)
					.GroupJoin(
						db.Parent,
						x => new { Id = x.xid.ParentID },
						y => new { Id = y.ParentID     },
						(x8, y) => new { x8.xid, x8.z, x8.xy, x8.a, x8.xz, y }
					)
					.SelectMany(
						a => a.y.DefaultIfEmpty(),
						(x9, a) => new { x9.xid, x9.z, x9.xy, xa = x9.a, x9.xz, a }
					)));
		}

		[Test]
		public void LeftJoin1()
		{
			var expected =
				from p in Parent
					join ch in Child on p.ParentID equals ch.ParentID into lj1
					from ch in lj1.DefaultIfEmpty()
				where p.ParentID >= 4
				select new { p, ch };

			ForEachProvider(db => AreEqual(expected,
				from p in db.Parent
					join ch in db.Child on p.ParentID equals ch.ParentID into lj1
					from ch in lj1.DefaultIfEmpty()
				where p.ParentID >= 4
				select new { p, ch }));
		}

		[Test]
		public void LeftJoin2()
		{
			ForEachProvider(db => AreEqual(
				from p in Parent
					join ch in Child on p.ParentID equals ch.ParentID into lj1
					from ch in lj1.DefaultIfEmpty()
				select new { p, ch },
				from p in db.Parent
					join ch in db.Child on p.ParentID equals ch.ParentID into lj1
					from ch in lj1.DefaultIfEmpty()
				select new { p, ch }));
		}

		[Test]
		public void LeftJoin3()
		{
			ForEachProvider(db => AreEqual(
				from c in    Child select c.Parent,
				from c in db.Child select c.Parent));
		}

		[Test]
		public void LeftJoin4()
		{
			ForEachProvider(db => AreEqual(
				Parent
					.GroupJoin(Child,
						x => new { x.ParentID, x.Value1 },
						y => new { y.ParentID, Value1 = (int?)y.ParentID },
						(x, y) => new { Parent = x, Child = y })
					.SelectMany(
						y => y.Child.DefaultIfEmpty(),
						(x, y) => new { x.Parent, Child = x.Child.FirstOrDefault() })
					.Where(x => x.Parent.ParentID == 1 && x.Parent.Value1 != null)
					.OrderBy(x => x.Parent.ParentID),
				db.Parent
					.GroupJoin(db.Child,
						x => new { x.ParentID, x.Value1 },
						y => new { y.ParentID, Value1 = (int?)y.ParentID },
						(x, y) => new { Parent = x, Child = y })
					.SelectMany(
						y => y.Child.DefaultIfEmpty(),
						(x, y) => new { x.Parent, Child = x.Child.FirstOrDefault() })
					.Where(x => x.Parent.ParentID == 1 && x.Parent.Value1 != null)
					.OrderBy(x => x.Parent.ParentID)));
		}

		public enum EnumInt
		{
			[MapValue(1)] One
		}

		[TableName("Child")]
		public class EnumChild
		{
			public int     ParentID;
			public EnumInt ChildID;
		}

		[Test]
		public void LeftJoin5()
		{
			ForEachProvider(db =>
			{
				var q =
					from p in db.Parent
						join ch in new Table<EnumChild>(db) on p.ParentID equals ch.ParentID into lj1
						from ch in lj1.DefaultIfEmpty()
					where ch == null
					select new { p, ch };

				var list = q.ToList();
				list.ToString();
			});
		}

		[Test]
		public void SubQueryJoin()
		{
			var expected =
				from p in Parent
					join ch in 
						from c in Child
						where c.ParentID > 0
						select new { c.ParentID, c.ChildID }
					on p.ParentID equals ch.ParentID into lj1
					from ch in lj1.DefaultIfEmpty()
				select p;

			ForEachProvider(db => AreEqual(expected,
				from p in db.Parent
					join ch in 
						from c in db.Child
						where c.ParentID > 0
						select new { c.ParentID, c.ChildID }
					on p.ParentID equals ch.ParentID into lj1
					from ch in lj1.DefaultIfEmpty()
				select p));
		}

		[Test]
		public void ReferenceJoin1()
		{
			ForEachProvider(new[] { ProviderName.Access }, db => AreEqual(
				from c in    Child join g in    GrandChild on c equals g.Child select new { c.ParentID, g.GrandChildID },
				from c in db.Child join g in db.GrandChild on c equals g.Child select new { c.ParentID, g.GrandChildID }));
		}

		[Test]
		public void ReferenceJoin2()
		{
			ForEachProvider(new[] { ProviderName.Access }, db => AreEqual(
				from g in    GrandChild
					join c in    Child on g.Child equals c
				select new { c.ParentID, g.GrandChildID },
				from g in db.GrandChild
					join c in db.Child on g.Child equals c
				select new { c.ParentID, g.GrandChildID }));
		}

		[Test]
		public void JoinByAnonymousTest()
		{
			ForEachProvider(new[] { ProviderName.Access }, db => AreEqual(
				from p in    Parent
				join c in    Child on new { Parent = p, p.ParentID } equals new { c.Parent, c.ParentID }
				select new { p.ParentID, c.ChildID },
				from p in db.Parent
				join c in db.Child on new { Parent = p, p.ParentID } equals new { c.Parent, c.ParentID }
				select new { p.ParentID, c.ChildID }));
		}

		[Test]
		public void FourTableJoin()
		{
			ForEachProvider(db => AreEqual(
				from p in Parent
				join c1 in Child      on p.ParentID  equals c1.ParentID
				join c2 in GrandChild on c1.ParentID equals c2.ParentID
				join c3 in GrandChild on c2.ParentID equals c3.ParentID
				select new { p, c1Key = c1.ChildID, c2Key = c2.GrandChildID, c3Key = c3.GrandChildID },
				from p in db.Parent
				join c1 in db.Child      on p.ParentID  equals c1.ParentID
				join c2 in db.GrandChild on c1.ParentID equals c2.ParentID
				join c3 in db.GrandChild on c2.ParentID equals c3.ParentID
				select new { p, c1Key = c1.ChildID, c2Key = c2.GrandChildID, c3Key = c3.GrandChildID }));
		}

		[Test]
		public void ProjectionTest1()
		{
			ForEachProvider(db => AreEqual(
				from p1 in Person
				join p2 in Person on p1.ID equals p2.ID
				select new { ID1 = new { Value = p1.ID }, FirstName2 = p2.FirstName, } into p1
				select p1.ID1.Value,
				from p1 in db.Person
				join p2 in db.Person on p1.ID equals p2.ID
				select new { ID1 = new { Value = p1.ID }, FirstName2 = p2.FirstName, } into p1
				select p1.ID1.Value));
		}

		[Test]
		public void LeftJoinTest()
		{
			// Reproduces the problem described here: http://rsdn.ru/forum/prj.rfd/4221837.flat.aspx
			ForEachProvider(
				//Providers.Select(p => p.Name).Except(new[] { ProviderName.SQLite }).ToArray(),
				db =>
				{
					var q = 
						from p1 in db.Person
						join p2 in db.Person on p1.ID equals p2.ID into g
						from p2 in g.DefaultIfEmpty() // yes I know the join will always succeed and it'll never be null, but just for test's sake :)
						select new { p1, p2 };

					var list = q.ToList(); // NotImplementedException? :(
					Assert.That(list, Is.Not.Empty);
				});
		}

		[Test]
		public void LeftJoinTest2()
		{
			// THIS TEST MUST BE RUN IN RELEASE CONFIGURATION (BECAUSE IT PASSES UNDER DEBUG CONFIGURATION)
			// Reproduces the problem described here: http://rsdn.ru/forum/prj.rfd/4221837.flat.aspx

			ForEachProvider(
				Providers.Select(p => p.Name).Except(new[] { ProviderName.SQLite }).ToArray(),
				db =>
				{
					var q =
						from p1 in db.Patient
						join p2 in db.Patient on p1.Diagnosis equals p2.Diagnosis into g
						from p2 in g.DefaultIfEmpty() // yes I know the join will always succeed and it'll never be null, but just for test's sake :)
						join p3 in db.Person on p2.PersonID equals p3.ID
						select new { p1, p2, p3 };

					var arr = q.ToArray(); // NotImplementedException? :(
					Assert.That(arr, Is.Not.Empty);
				});
		}

		[Test]
		public void StackOverflow([IncludeDataContexts("Sql2008", "Sql2012")] string context)
		{
			using (var db = new TestDbManager(context))
			{
				var q =
					from c in db.Child
					join p in db.Parent on c.ParentID equals p.ParentID
					select new { p, c };

				for (var i = 0; i < 100; i++)
				{
					q =
						from c in q
						join p in db.Parent on c.p.ParentID equals p.ParentID
						select new { p, c.c };
				}

				var list = q.ToList();
			}
		}

		[Test]
		public void ApplyJoin([IncludeDataContexts("Sql2008")] string context)
		{
			using (var db = new TestDbManager(context))
			{
				var q =
					from ch in db.Child
					from p in new Model.Functions(db).GetParentByID(ch.Parent.ParentID)
					select p;

				q.ToList();
			}
		}

		[Test]
		public void Issue257([DataContexts] string context)
		{
			using (var db = GetDataContext(context))
			{
				var q =
					from m in db.Types
						join p in db.Parent on m.ID equals p.ParentID
					group m by new
					{
						m.DateTimeValue.Date
					}
					into b
					select new
					{
						QualiStatusByDate = b.Key,
						Count             = b.Count()
					};

				q.ToList();
			}
		}
	}
}
