#region

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using MvcApplication3.Entities;
using MvcApplication3.Models;
using MvcApplication3.Linq;
using MvcApplication3.ViewModels;
using System.Data;
using System.Linq.Expressions;

#endregion

namespace MvcApplication3.Controllers
{
    public class DepartmentsController : Controller
    {
        [HttpPost]
        public ActionResult GetAll(int skip, int take, int page, int pageSize, 
            List<GridSort> sort = null, GridFilter filter = null)
        {
            var myDatabaseContext = new MyDatabaseContext();

            var departments = myDatabaseContext.Departments.Include("Division").AsQueryable();
            var totalCount = myDatabaseContext.Departments.Include("Division").AsQueryable();

            if (filter != null && (filter.Filters != null && filter.Filters.Count > 0))
            {
                ProcessFilters(filter, ref departments);
                totalCount = departments;
            }

            if (sort != null && sort.Count > 0)
                foreach (var s in sort)
                {
                    departments = departments.OrderBy(s.Field + " " + s.Dir);
                }

            departments = departments.Skip(skip).Take(take);

            List<Department> departmentList = departments.ToList();
          
            return Json(
                new KendoGridModelWrapper<Department>
                    {
                        Items = departmentList,
                        TotalItemCount = totalCount.Count()
                    });
        }

        public static void ProcessFilters(GridFilter filter, ref IQueryable<Department> queryable)
        {
            var whereClause = string.Empty;
            var filters = filter.Filters;
            var parameters = new List<object>();
            for (int i = 0; i < filters.Count; i++)
            {
                var f = filters[i];

                if (f.Filters == null)
                {
                    if (i == 0)
                        whereClause += BuildWhereClause<Department>(f, i, parameters) + " ";
                    if (i != 0)
                        whereClause += ToLinqOperator(filter.Logic) + BuildWhereClause<Department>(f, i, parameters) + " ";
                    if (i == (filters.Count - 1))
                    {
                        CleanUp(ref whereClause);
                        queryable = queryable.Where(whereClause, parameters.ToArray());
                    }
                }
                else
                    ProcessFilters(f, ref queryable);
            }
        }

        public static string CleanUp(ref string whereClause)
        {
            switch (whereClause.Trim().Substring(0, 2).ToLower())
            {
                case "&&":
                    whereClause = whereClause.Trim().Remove(0, 2);
                    break;
                case "||":
                    whereClause = whereClause.Trim().Remove(0, 2);
                    break;
            }

            return whereClause;
        }

        public static string BuildWhereClause<T>(GridFilter filter, int index, List<object> parameters)
        {
            var entityType = (typeof(T));
            var property = entityType.GetProperty(filter.Field);
            var parameterIndex = parameters.Count;

            switch (filter.Operator.ToLower())
            {
                case "eq":
                case "neq":
                case "gte":
                case "gt":
                case "lte":
                case "lt":
                    if (typeof(DateTime).IsAssignableFrom(property.PropertyType))
                    {
                        parameters.Add(DateTime.Parse(filter.Value).Date);
                        return string.Format("EntityFunctions.TruncateTime(" + filter.Field + ")" + ToLinqOperator(filter.Operator) + "@" + parameterIndex);
                    }
                    if (typeof(int).IsAssignableFrom(property.PropertyType))
                    {
                        parameters.Add(int.Parse(filter.Value));
                        return string.Format(filter.Field + ToLinqOperator(filter.Operator) + "@" + parameterIndex);
                    }
                    parameters.Add(filter.Value);
                    return string.Format(filter.Field + ToLinqOperator(filter.Operator) + "@" + parameterIndex);
                case "startswith":
                    parameters.Add(filter.Value);
                    return filter.Field + ".StartsWith(" + "@" + parameterIndex + ")";
                case "endswith":
                    parameters.Add(filter.Value);
                    return filter.Field + ".EndsWith(" + "@" + parameterIndex + ")";
                case "contains":
                    parameters.Add(filter.Value);
                    return filter.Field + ".Contains(" + "@" + parameterIndex + ")";
                default:
                    throw new ArgumentException("This operator is not yet supported for this Grid", filter.Operator);
            }
        }

        public static string ToLinqOperator(string @operator)
        {
            switch (@operator.ToLower())
            {
                case "eq": return " == ";
                case "neq": return " != ";
                case "gte": return " >= ";
                case "gt": return " > ";
                case "lte": return " <= ";
                case "lt": return " < ";
                case "or": return " || ";
                case "and": return " && ";
                default: return null;
            }
        }

        [HttpPost]
        public ActionResult Update(IEnumerable<Department> models)
        {            
            using (var db = new MyDatabaseContext())
            {
                //Iterate all updated products which are posted by the Kendo Grid
                foreach (var dp in models)
                {
                    var department = db.Departments.SingleOrDefault(d => d.Id == dp.Id);
                    // Create a new Product entity and set its properties from productViewModel
                    department.Name = dp.Name;
                    department.Code = dp.Code;
                    department.Active = dp.Active;
                    department.DivisionId = dp.DivisionId;
                }

                // Save all updated products to the database
                db.SaveChanges();

                //Return emtpy result
                return Json(null);
            }
        }

        [HttpPost]
        public ActionResult Create(IEnumerable<Department> models)
        {
            using (var db = new MyDatabaseContext())
            {
                //Iterate all updated products which are posted by the Kendo Grid
                foreach (var dp in models)
                {
                    if (dp.Id <= 0)
                    {
                        var department = new Department
                        {
                            // Create a new Product entity and set its properties from productViewModel
                            Name = dp.Name,
                            Code = dp.Code,
                            Active = dp.Active,
                            DivisionId = dp.DivisionId
                        };
                        db.Departments.Add(department);
                    }
                }

                // Save all updated products to the database
                db.SaveChanges();

                //Return emtpy result
                return Json(null);
            }
        } 
    }
}