using System.Linq;
using System.Data.Linq;
using System.Collections.Generic;

using DataAccess.Mapping;
using MVCBlogo.NET.BO;
using System;

namespace MVCBlogo.NET.DAL
{

    public static class BlogEntryDB
    {
        private static BlogMapDataContext db = new BlogMapDataContext();

        public static int CountAll(int StartRow, int PageSize)
        {
            return db.blogentries.Count();
        }

        public static int Count(int StartRow, int PageSize)
        {
            return (from blogentry in db.blogentries where blogentry.markprivate == false select blogentry).Count();
        }

        public static int CountTag(int TagID, int StartRow, int PageSize)
        {
            return (from blogtag in db.blog_tags where blogtag.tag_id == TagID && blogtag.blogentries.markprivate == false select blogtag.blogentries).Count();
        }

        public static int CountType(Types type, int StartRow, int PageSize)
        {
            return (from blogentry in db.blogentries where blogentry.type.Equals(type.ToString()) && blogentry.markprivate == false select blogentry).Count();
        }

        public static int CountMonth(int year, int month, int StartRow, int PageSize)
        {
            return (from blogentry in db.blogentries
                    where (blogentry.datepublished.Value.Year== year
                        && blogentry.datepublished.Value.Month == month && blogentry.markprivate == false)
                    select blogentry).Count();
        }

        public static int CountUsedMonths(int StartRow, int PageSize)
        {
            return (from blogentry in db.blogentries where blogentry.markprivate == false select new { blogentry.datepublished.Value.Month, blogentry.datepublished.Value.Year }).Distinct().Count();
        }

        public static List<BlogEntry> GetListAll(int StartRow, int PageSize)
        {
            var query = (from blogentry in db.blogentries orderby blogentry.datepublished descending select blogentry).Skip(StartRow).Take(PageSize);
            List<BlogEntry> result = new List<BlogEntry>();
            foreach (var t in query)
                result.Add(FillRecord(t));
            return result;
        }

        public static List<BlogEntry> GetList(int StartRow, int PageSize)
        {
            var query = (from blogentry in db.blogentries where blogentry.markprivate == false orderby blogentry.datepublished descending select blogentry).Skip(StartRow ).Take(PageSize);
            List<BlogEntry> result = new List<BlogEntry>();
            foreach (var t in query)
                result.Add(FillRecord(t));
            return result;
        }

        public static List<BlogEntry> GetList()
        {
            var query = (from blogentry in db.blogentries 
                         where blogentry.markprivate == false
                         orderby blogentry.datepublished descending select blogentry);

            List<BlogEntry> result = new List<BlogEntry>();
            foreach (var t in query)
                result.Add(FillRecord(t));
            return result;
        }


        public static List<BlogEntry> GetListTag(int TagID, int StartRow, int PageSize)
        {
            var query = (from blogtag in db.blog_tags where blogtag.tag_id == TagID && blogtag.blogentries.markprivate == false orderby blogtag.blogentries.datepublished descending select blogtag.blogentries).Skip(StartRow).Take(PageSize);
            List<BlogEntry> result = new List<BlogEntry>();
            foreach (var t in query)
                result.Add(FillRecord(t));
            return result;
        }

        public static List<BlogEntry> GetListType(Types type, int StartRow, int PageSize)
        {
            var query = (from blogentry in db.blogentries where blogentry.type.Equals(type.ToString()) && blogentry.markprivate == false orderby blogentry.datepublished descending select blogentry).Skip(StartRow).Take(PageSize);
            List<BlogEntry> result = new List<BlogEntry>();
            foreach (var t in query)
                result.Add(FillRecord(t));
            return result;
        }

        /// <summary>
        /// 根据年，月来进行查询
        /// </summary>
        /// <param name="year"></param>
        /// <param name="month"></param>
        /// <param name="StartRow"></param>
        /// <param name="PageSize"></param>
        /// <returns></returns>
        public static List<BlogEntry> GetListMonth(int year, int month, int StartRow, int PageSize)
        {
            //DateTime为值类型，原则上不允许为空。DateTime? :表面的是该DateTime类型可以为空
            var query = (from blogentry in db.blogentries
                         where (blogentry.datepublished.Value.Year == year && blogentry.datepublished.Value.Month == month && blogentry.markprivate == false)
                         orderby blogentry.datepublished descending
                         select blogentry).Skip(StartRow).Take(PageSize);
            List<BlogEntry> result = new List<BlogEntry>();
            foreach (var t in query)
                result.Add(FillRecord(t));
            return result;
        }

        public static List<Month> GetListUsedMonths(int StartRow, int PageSize)
        {
            var query = (from blogentry in db.blogentries where blogentry.markprivate == false select new { blogentry.datepublished.Value.Month, blogentry.datepublished.Value.Year })
                         .Distinct().Skip(StartRow).Take(PageSize).OrderByDescending  (x => x.Year).ThenByDescending (x => x.Month);
            List<Month> result = new List<Month>();
            //增加Month下的记录数 
            Month temp=null;
            foreach (var m in query)
            {
                temp = new Month(m.Year, m.Month);
                temp.number = (from blogentry in db.blogentries
                               where ((blogentry.markprivate == false) && (blogentry.datepublished.Value.Month == temp.month)
                               && (blogentry.datepublished.Value.Year == temp.year))
                               select blogentry).Count();

                result.Add(temp);
            }
            return result;
        }

        public static BlogEntry GetItem(long id)
        {
            blogentries t = (from blogentry in db.blogentries where blogentry.id == id select blogentry).FirstOrDefault();
            return FillRecord(t);
        }

        public static long Save(BlogEntry myBlogEntry)
        {
            blogentries t;
            bool found = false;

            if (myBlogEntry.id == -1)
            {
                // new record
                t = new blogentries();
                t.datecreated = System.DateTime.Now;
                t.datepublished = myBlogEntry.datepublished;
                db.blogentries.InsertOnSubmit(t);
                found = true;
            }
            else
            {
                // existing record
                t = (from blogentry in db.blogentries where blogentry.id == myBlogEntry.id select blogentry).FirstOrDefault();
                if (t != null)
                {
                    found = true;
                    t.id = myBlogEntry.id;
                }
            }

            if (found)
            {

                t.authors = db.authors.Single(c => c.id == myBlogEntry.author.id);
                t.title = myBlogEntry.title;
                t.description = myBlogEntry.description;
                t.type = (myBlogEntry.type.Equals(Types.article) ? Types.article.ToString() : Types.blogentry.ToString());
                t.allowcomments = myBlogEntry.allowcomments;
                t.markprivate = myBlogEntry.markprivate;
                t.body = myBlogEntry.body;
                t.datemodified = System.DateTime.Now;

                try
                {
                    db.SubmitChanges();

                    // delete and recreate blog/tag mappings
                    var tagmaps = (from tagmap in db.blog_tags where tagmap.blog_id == t.id select tagmap);
                    db.blog_tags.DeleteAllOnSubmit(tagmaps);
                    foreach (Tag tag in myBlogEntry.tags)
                    {
                        blog_tags bTag = new blog_tags();
                        bTag.blog_id = t.id;
                        bTag.tag_id = tag.id;
                        db.blog_tags.InsertOnSubmit(bTag);
                    }

                    db.SubmitChanges();

                }
                catch (ChangeConflictException)
                {
                    db.ChangeConflicts.ResolveAll(RefreshMode.OverwriteCurrentValues);
                    db.SubmitChanges();
                }
                return t.id;
            }
            else
                return -1;

        }

        public static bool Delete(long id)
        {
            blogentries t = (from blogentry in db.blogentries where blogentry.id == id select blogentry).FirstOrDefault();
            if (t != null)
            {
                try
                {
                    // delete related comments of blog entry
                    var comments = (from comment in db.comments where comment.blog_id == id select comment);
                    db.comments.DeleteAllOnSubmit(comments);

                    // delete tag mappings of blog entry
                    var tagmaps = (from tagmap in db.blog_tags where tagmap.blog_id == id select tagmap);
                    db.blog_tags.DeleteAllOnSubmit(tagmaps);

                    // delete blog entry
                    db.blogentries.DeleteOnSubmit(t);
                    db.SubmitChanges();
                }
                catch (ChangeConflictException)
                {
                    db.ChangeConflicts.ResolveAll(RefreshMode.OverwriteCurrentValues);
                    db.SubmitChanges();
                }
            }
            return (t != null);
        }

        private static BlogEntry FillRecord(blogentries i)
        {
            BlogEntry result = null;
            if (i != null)
            {
                result = new BlogEntry();
                result.id = i.id;

                if (i.authors != null)
                    result.author = AuthorDB.GetItem(i.authors.id);
                else
                    result.author = null;

                result.title = i.title;
                result.description = i.description;
                result.type = (i.type.Equals(Types.article.ToString()) ? Types.article : Types.blogentry);
                result.allowcomments = (Boolean)i.allowcomments;
                result.markprivate = (Boolean)i.markprivate;
                result.body = i.body;
                result.datecreated =Convert.ToDateTime(i.datecreated);
                result.datepublished =Convert.ToDateTime(i.datepublished);
                result.datemodified = Convert.ToDateTime(i.datemodified);
                result.comments = CommentDB.GetList(i.id);
                result.tags = TagDB.GetList(i.id);
            }
            return result;
        }
    }
}
