using System;
using System.Collections.Generic;
using FluentNHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Mapping;
using NHibernate.Cfg;
using Rhino.Mocks;
uusing Xunit;

namespace USD259.Test
{
    public class RepositoryBuildUpExample_3
    {
            // SimpleSessionStorage, NHibernateRepository, NHibernateSession
            // and PersistentObject exist in our base library and are based on the
            // S#arp Architecture project.  Including the SharpArch.* libraries
            // should resolve the dependency.
        
        public RepositoryBuildUpExample_3()
        {
         ExampleConfiguration.Init(new SimpleSessionStorage());
        }

        [Fact]
        public void Fetch_A_Report_By_Id()
        {
            IReportRepository stubRepository =
                MockRepository.GenerateStub<IReportRepository>();

            Report stubReport =
                MockRepository.GenerateStub<Report>();

            stubReport.Id = 140;

            stubRepository
                .Expect(x => x.Get(140))
                .Return(stubReport);

            var report = stubRepository.Get(140);

            report.Id.ShouldBeEqualTo(140);
        }

        [Fact]
        public void Fetch_Reports_By_StudentId()
        {
            var stubRepository =
                MockRepository.GenerateStub<IReportRepository>();

            var stubReports =
                MockRepository.GenerateStub<List<Report>>();

            stubReports.Add(new Report() {Id = 1, StudentId = 669710});
            stubReports.Add(new Report() {Id = 2, StudentId = 669710});
            stubReports.Add(new Report() {Id = 3, StudentId = 669710});

            stubRepository
                .Expect(x => x.GetAllByStudentId(140))
                .Return(stubReports);

            var reports = stubRepository.GetAllByStudentId(140);
            
            reports.ForEach(x => x.StudentId.ShouldBeEqualTo(669710));
        }

        [Fact]
        public void Fetch_A_Report_By_Id_From_Database()
        {
            var repository = new ReportRepository();
            var report = repository.Get(140);
            report.Id.ShouldBeEqualTo(140);
        }
        
        [Fact]
        public void Fetch_Reports_By_StudentId_From_Database()
        {
            var reportRepository = new ReportRepository();
            var reports = reportRepository.GetAllByStudentId(669710);
            reports.ForEach(x => x.StudentId.ShouldBeEqualTo(669710));
            reports.ForEach(x => Console.WriteLine("{0}, {1}", x.Quarter, x.EnteredBy));
        }

        [Fact]
        public void Generic_Repository_Returns_Same_Values_As_Explicit_From_Database()
        {
            var reportRepository = new ReportRepository();
            var report = reportRepository.Get(140);

            var genericRepository = new NHibernateRepository<Report>();
            var generic = genericRepository.Get(140);

            report.ShouldBeEqualTo(generic);
        }
    }

    public interface IReportRepository : INHibernateRepository<Report>
    {
        IList<Report> GetAllByStudentId(int studentId);
    }

    public class Report : PersistentObject
    {
        public virtual int StudentId { get; set; }
        public virtual int Year { get; set; }
        public virtual int Quarter { get; set; }
        public virtual DateTime DateEntered { get; set; }
        public virtual string EnteredBy { get; set; }
        public virtual string Comments { get; set; }
    }

    public class ReportMap : ClassMap<Report>
    {
        public ReportMap()
        {
            CreateMap();
        }

        private void CreateMap()
        {
            WithTable("Reports");
            Id(x => x.Id);
            Map(x => x.StudentId);
            Map(x => x.Year);
            Map(x => x.Quarter);
            Map(x => x.DateEntered);
            Map(x => x.EnteredBy);
            Map(x => x.Comments);
        }
    }

    public class ReportRepository : NHibernateRepository<Report>, IReportRepository
    {
        public IList<Report> GetAllByStudentId(int studentId)
        {
            return Session.CreateCriteria(typeof(Report))
                       .Add(RestrictionsHelper<Report>.Eq(x => x.StudentId, studentId))
                       .List<Report>() as List<Report>;
        }
    }

    public static class ExampleConfiguration
    {
        public static Configuration Default
        {
            get { return Production; }
        }

        public static Configuration Production
        {
            get
            {
                var config = new Configuration();

                MsSqlConfiguration.MsSql2005
                    .ConnectionString
                        .Database("DBName")
                        .Server("DBServer")
                        .Username("DBLogin")
                        .Password("DBPassword")
                        .Create
                    .ConfigureProperties(config);
                return config;
            }
        }

        public static void Init(ISessionStorage storage)
        {
            Init(Default, storage);
        }

        public static void Init(Configuration configuration, ISessionStorage storage)
        {
            // Any of the maps will do for the assembly mapping.
            NHibernateSession.Init(typeof(ReportMap).Assembly, configuration, storage);
        }
    }


}