using Foresight.Fleet.Services.Asset;
using Foresight.Fleet.Services.Attachment;
using Foresight.Fleet.Services.JobSite;
using Foresight.Fleet.Services.MapView;
using FU = Foresight.Fleet.Services.User;
using Foresight.ServiceModel;
using IronIntel.Contractor.ExportExcel;
using IronIntel.Contractor.FilterQ;
using IronIntel.Contractor.JobSites;
using IronIntel.Contractor.Machines;
using IronIntel.Contractor.MapView;
using IronIntel.Contractor.Users;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using static IronIntel.Contractor.Site.JobSite.JobSitesBasePage;
using static IronIntel.Contractor.Site.MapView.MapViewHandler;

namespace IronIntel.Contractor.Site.JobSite
{
    public class JobSiteRequirementsBasePage : ContractorBasePage
    {
        protected void ProcessRequest()
        {
            object result = null;
            try
            {
                string methodName = Request.Params["MethodName"];
                if (methodName != null)
                {
                    switch (methodName)
                    {
                        case "GetRequirements":
                            result = GetRequirements();
                            break;
                        case "CreateNewRequirments":
                            result = CreateNewRequirments();
                            break;
                        case "CreateNewRequirment":
                            result = CreateNewRequirment();
                            break;
                        case "DeleteRequirment":
                            result = DeleteRequirment();
                            break;
                        case "GetJobsites":
                            result = GetJobsites();
                            break;
                        case "GetJobsitesAndRegions":
                            result = GetJobsitesAndRegions();
                            break;
                        case "GetAssetTypes":
                            result = GetAssetTypes();
                            break;
                        case "GetAssetGroups":
                            result = GetAssetGroups();
                            break;
                        case "GetAvailableAssets":
                            result = GetAvailableAssets();
                            break;
                        case "GetAvailableAssetsByRequirement":
                            result = GetAvailableAssetsByRequirement();
                            break;
                        case "GetAssetDispatchItems":
                            result = GetAssetDispatchItems();
                            break;
                        case "DeleteDispatch":
                            result = DeleteDispatch();
                            break;
                        case "SendEmails":
                            result = SendEmails();
                            break;
                        case "UpdateDispatchCompleted":
                            result = UpdateDispatchCompleted();
                            break;
                        case "GetDispatchContacts":
                            result = GetDispatchContacts();
                            break;
                        case "AddDispatch":
                            result = AddDispatch();
                            break;
                        case "UpdateDispatch":
                            result = UpdateDispatch();
                            break;
                        case "SetRequirmentsDefault":
                            result = SetRequirmentsDefault();
                            break;
                        case "GetRequirmentsDefault":
                            result = GetRequirmentsDefault();
                            break;
                        case "GetAssetSchedulers":
                            result = GetAssetSchedulers();
                            break;
                        case "GetAssetDispatchsByIds":
                            result = GetAssetDispatchsByIds();
                            break;
                        case "GetMachines":
                            result = GetMachines();
                            break;
                        case "GetRoadMachines":
                            result = GetRoadMachines();
                            break;
                        case "AssignDispatch":
                            result = AssignDispatch();
                            break;
                        case "GetRequirementHistory":
                            result = GetRequirementHistory();
                            break;
                        case "GetAssetDispatchHistory":
                            result = GetAssetDispatchHistory();
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                SystemParams.WriteLog("error", "JobSiteRequirementsBasePage", ex.Message, ex.ToString());
                throw ex;
            }
            string json = JsonConvert.SerializeObject(result);
            Response.Write(json);
            Response.End();
        }
        protected bool CheckRequestonly(string custid)
        {
            var user = GetCurrentUser();
            if (user == null)
                return false;

            if (user.UserType == Users.UserTypes.SupperAdmin || user.UserType == Users.UserTypes.Admin)
                return false;

            if (user.UserType == Users.UserTypes.Common)
            {
                var client = CreateClient<FU.PermissionProvider>();
                Tuple<FU.Feature, FU.Permissions>[] pmss = client.GetUserPermissions(custid, user.IID);
                if (pmss.Length > 0)
                {
                    Tuple<FU.Feature, FU.Permissions> permission = pmss.FirstOrDefault(m => m.Item1.Id == FU.Feature.JOB_SITES_REQUIREMENTS);
                    if (permission != null && permission.Item2 == FU.Permissions.RequestOnly)
                        return true;
                }
            }
            return false;
        }

        private object GetRequirements()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    JobSiteRequirementQueryItem p = JsonConvert.DeserializeObject<JobSiteRequirementQueryItem>(clientdata);
                    DateTime latestStartDate = Helper.DBMinDateTime;
                    if (!DateTime.TryParse(p.LatestStartDate, out latestStartDate))
                        latestStartDate = Helper.DBMinDateTime;

                    JobSiteRequirmentInfo[] reqs = CreateClient<JobSiteDispatchProvider>().GetRequirmentItems(SystemParams.CompanyID, latestStartDate, p.JobSites, p.Regions, p.UnScheduledOnly);
                    if (reqs == null || reqs.Length == 0)
                        return new JobSiteRequirmentItem[0];

                    List<JobSiteRequirmentItem> ls = new List<JobSiteRequirmentItem>();
                    foreach (JobSiteRequirmentInfo re in reqs)
                    {
                        JobSiteRequirmentItem item = new JobSiteRequirmentItem();
                        Helper.CloneProperty(item, re);
                        ls.Add(item);
                    }

                    return ls.OrderBy(r => r.BeginDate).ToArray();

                }
                else
                    return new JobSiteRequirmentItem[0];
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private object GetRequirementHistory()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    string[] p = JsonConvert.DeserializeObject<string[]>(clientdata);
                    var sdatestr = HttpUtility.HtmlDecode(p[0]);
                    var edatestr = HttpUtility.HtmlDecode(p[1]);
                    long[] jobsites = JsonConvert.DeserializeObject<long[]>(p[2]);

                    DateTime beginDate = Helper.DBMinDateTime;
                    DateTime endDate = DateTime.MaxValue;
                    if (!DateTime.TryParse(sdatestr, out beginDate))
                        beginDate = Helper.DBMinDateTime;
                    if (!DateTime.TryParse(edatestr, out endDate))
                        endDate = DateTime.MaxValue;


                    JobSiteRequirmentInfo[] reqs = CreateClient<JobSiteDispatchProvider>().GetRequirmentHistory(SystemParams.CompanyID, beginDate, endDate, jobsites);
                    if (reqs == null || reqs.Length == 0)
                        return new JobSiteRequirmentItem[0];

                    List<JobSiteRequirmentItem> ls = new List<JobSiteRequirmentItem>();
                    foreach (JobSiteRequirmentInfo re in reqs)
                    {
                        JobSiteRequirmentItem item = new JobSiteRequirmentItem();
                        Helper.CloneProperty(item, re);
                        ls.Add(item);
                    }

                    return ls.OrderBy(r => r.BeginDate).ToArray();

                }
                else
                    return new JobSiteRequirmentItem[0];
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private object CreateNewRequirments()
        {
            try
            {
                var user = GetCurrentUser();
                if (user != null)
                {
                    //if (!CanEdit(SystemParams.CompanyID, FU.Feature.JOB_SITES_REQUIREMENTS, FU.Permissions.RequestOnly))
                    //    return "";
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    JobSiteRequirmentInfo[] requires = JsonConvert.DeserializeObject<JobSiteRequirmentInfo[]>(clientdata);

                    List<long> requireids = new List<long>();
                    if (requires != null || requires.Length > 0)
                    {
                        var client = CreateClient<JobSiteDispatchProvider>();
                        foreach (JobSiteRequirmentInfo require in requires)
                        {
                            var req = client.CreateNewRequirments(SystemParams.CompanyID, require);
                            requireids.Add(req.Id);
                        }
                    }

                    return requireids.ToArray();
                }
                else
                {
                    return new string[0];
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private object CreateNewRequirment()
        {
            try
            {
                var user = GetCurrentUser();
                if (user != null)
                {
                    //if (!CanEdit(SystemParams.CompanyID, FU.Feature.JOB_SITES_REQUIREMENTS, FU.Permissions.RequestOnly))
                    //    return "";
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    JobSiteRequirmentInfo require = JsonConvert.DeserializeObject<JobSiteRequirmentInfo>(clientdata);

                    var client = CreateClient<JobSiteDispatchProvider>();
                    var req = client.CreateNewRequirments(SystemParams.CompanyID, require);

                    if (req.Assets != null && req.Assets.Count > 0)
                    {
                        long dispatchid = req.Assets[0].DispatchId;
                        return new string[] { req.Assets[0].DispatchId.ToString(), "OK" };
                    }

                    return "Failed";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private string DeleteRequirment()
        {
            try
            {
                var user = GetCurrentUser();
                if (user != null)
                {
                    //if (!CanEdit(SystemParams.CompanyID, FU.Feature.JOB_SITES_REQUIREMENTS))
                    //    return "";
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    StringKeyValue kv = JsonConvert.DeserializeObject<StringKeyValue>(clientdata);
                    long id = Convert.ToInt64(kv.Key);

                    CreateClient<JobSiteDispatchProvider>().DeleteRequirment(SystemParams.CompanyID, id, kv.Value);
                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private object GetJobsites()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var client = CreateClient<MapViewQueryClient>();
                    MapViewJobSiteInfo[] jss = client.GetAvailableJobSites(SystemParams.CompanyID, session.User.UID, string.Empty, false);
                    List<StringKeyValue> list = new List<StringKeyValue>();
                    foreach (MapViewJobSiteInfo js in jss)
                    {
                        StringKeyValue kv = new StringKeyValue();
                        kv.Key = js.ID.ToString();
                        kv.Value = js.Name;
                        kv.Tag1 = js.StartDate == null ? "" : js.StartDate.Value.ToShortDateString();
                        kv.Tag2 = js.EndDate == null ? "" : js.EndDate.Value.ToShortDateString();
                        list.Add(kv);
                    }
                    return list.OrderBy((m) => m.Value).ToArray();
                }
                else
                    return new StringKeyValue[0];
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private object GetMachines()
        {
            var session = GetCurrentLoginSession();
            MachineItem[] machines = null;
            if (GetCurrentLoginSession() != null)
            {
                //machines = MachineManagement.GetMachines(session.SessionID, session.User.UID, "");

                var items = CreateClient<AssetQueryClient>(SystemParams.CompanyID).GetAssetListItem2ByUser(SystemParams.CompanyID, "", session.User.UID, false, 0);
                return items.Select(i => new
                {
                    i.Id,
                    i.VIN,
                    i.MakeName,
                    i.ModelName,
                    i.TypeName,
                    i.DisplayName,
                    TypeID = i.TypeId
                }).OrderBy(g => g.DisplayName).ToArray();
            }
            else
            {
                machines = new MachineItem[0];
            }
            return machines.Where(m => m.Hide == false).OrderBy(m => m.DisplayName).ToArray();
        }
        private object GetRoadMachines()
        {
            var session = GetCurrentLoginSession();
            MachineItem[] machines = null;
            if (GetCurrentLoginSession() != null)
            {
                var items = CreateClient<AssetQueryClient>(SystemParams.CompanyID).GetAssetListItemsByUser(SystemParams.CompanyID, session.User.UID, "", false, 0, true, null, null, null).Where(m => m.OnRoad).ToArray();
                return items.Select(i => new
                {
                    i.Id,
                    i.VIN,
                    i.MakeName,
                    i.ModelName,
                    i.TypeName,
                    i.OnRoad,
                    EngineHours = Math.Round(i.EngineHours ?? 0, 2),
                    Odometer = Math.Round(i.Odometer ?? 0, 2),
                    DisplayName = GetDisplayName(i)
                }).OrderBy(g => g.DisplayName).ToArray();
            }
            else
            {
                machines = new MachineItem[0];
            }
            return machines.Where(m => m.Hide == false).OrderBy(m => m.DisplayName).ToArray();
        }
        private string GetDisplayName(AssetListItemInfo a)
        {
            //Name取值顺序为Name2,Name,VIN,ID用于前端显示
            string name = a.Name2;
            if (string.IsNullOrWhiteSpace(name))
                name = a.Name;
            if (string.IsNullOrWhiteSpace(name))
                name = a.VIN;
            if (string.IsNullOrWhiteSpace(name))
                name = a.Id.ToString();
            return name;
        }

        private object GetJobsitesAndRegions()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    JobSitesAndRegionsItem item = new JobSitesAndRegionsItem();

                    MapViewJobSiteInfo[] jss = CreateClient<MapViewQueryClient>().GetAvailableJobSites(SystemParams.CompanyID, session.User.UID, string.Empty, false);
                    List<StringKeyValue> list = new List<StringKeyValue>();
                    foreach (MapViewJobSiteInfo js in jss)
                    {
                        StringKeyValue kv = new StringKeyValue();
                        kv.Key = js.ID.ToString();
                        kv.Value = js.Name;
                        kv.Tag1 = js.StartDate == null ? "" : js.StartDate.Value.ToShortDateString();
                        kv.Tag2 = js.EndDate == null ? "" : js.EndDate.Value.ToShortDateString();
                        kv.Tag3 = js.ReginId.ToString();
                        list.Add(kv);
                    }


                    var regions = CreateClient<Foresight.Fleet.Services.Customer.CustomerProvider>().GetRegions(SystemParams.CompanyID);
                    List<StringKeyValue> lsregion = new List<StringKeyValue>();
                    if (regions != null || regions.Length > 0)
                    {
                        foreach (var rs in regions)
                        {
                            if (rs.IsActive)
                            {
                                StringKeyValue kv = new StringKeyValue();
                                kv.Key = rs.Id.ToString();
                                kv.Value = rs.Name;
                                lsregion.Add(kv);
                            }
                        }
                    }

                    item.Jobsites = list.OrderBy((m) => m.Value).ToArray();
                    item.Regions = lsregion.OrderBy((m) => m.Value).ToArray();

                    return item;
                }
                else
                    return new JobSitesAndRegionsItem();
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private object GetAssetTypes()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    MachineTypeItem[] types = JobSitesManagement.GetMachineTypes();
                    List<StringKeyValue> list = new List<StringKeyValue>();
                    foreach (MachineTypeItem type in types)
                    {
                        StringKeyValue kv = new StringKeyValue();
                        kv.Key = type.ID.ToString();
                        kv.Value = type.Name;
                        list.Add(kv);
                    }

                    return list.OrderBy((m) => m.Value).ToArray();
                }
                else
                    return new StringKeyValue[0];
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private object GetAssetGroups()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var groups = MachineManagement.GetMachineGroupsByUser(session.User.UID, null);
                    List<StringKeyValue> list = new List<StringKeyValue>();
                    foreach (var gp in groups)
                    {
                        StringKeyValue kv = new StringKeyValue();
                        kv.Key = gp.GroupID;
                        kv.Value = gp.GroupName;
                        list.Add(kv);
                    }

                    return list.OrderBy((m) => m.Value).ToArray();
                }
                else
                    return new StringKeyValue[0];
            }
            catch (Exception ex)
            {
                AddLog("ERROR", "AlertsBasePage.GetAssetGroups", ex.Message, ex.ToString());
                return ex.Message;
            }
        }

        private object GetAvailableAssets()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    AssetQueryItem q = JsonConvert.DeserializeObject<AssetQueryItem>(clientdata);

                    DateTime begindate = Helper.DBMinDateTime;
                    if (!DateTime.TryParse(q.BeginDate, out begindate))
                        begindate = Helper.DBMinDateTime;

                    DateTime enddate = Helper.DBMinDateTime;
                    if (!DateTime.TryParse(q.EndDate, out enddate))
                        enddate = Helper.DBMinDateTime;

                    DispatchAssetInfo[] infos = CreateClient<JobSiteDispatchProvider>().GetAvailableAssets(SystemParams.CompanyID, q.AssetType, q.JobSiteID, begindate, enddate);

                    if (infos.Count() == 0)
                        return null;
                    var items = DispatchAssetItem.Convert(infos, begindate, enddate)
                        .OrderBy((i) => i.ConflictDays)
                        .ThenBy(i => i.AssetName);

                    var minDate = items.Min(i => i.Schedules.Count == 0 ? DateTime.MaxValue : i.Schedules.Min(ii => ii.BeginDate));
                    var maxDate = items.Max(i => i.Schedules.Count == 0 ? DateTime.MinValue : i.Schedules.Max(ii => ii.EndDate));
                    return new
                    {
                        HasSchedule = minDate != DateTime.MaxValue,
                        BeginDate = minDate,
                        TotalDays = (maxDate - minDate).Days + 1,
                        DispatchAssets = items
                    };
                }
                else
                {
                    return new DispatchAssetItem[0];
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private object GetAvailableAssetsByRequirement()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = HttpUtility.HtmlDecode(Request.Form["ClientData"]);
                    long requireid = Convert.ToInt64(clientdata);

                    DispatchAssetInfo[] infos = CreateClient<JobSiteDispatchProvider>().GetAvailableAssetsByRequirement(SystemParams.CompanyID, requireid);

                    if (infos.Count() == 0)
                        return null;

                    JobSiteRequirmentInfo reqinfo = CreateClient<JobSiteDispatchProvider>().GetRequirementInfo(SystemParams.CompanyID, requireid);
                    var items = DispatchAssetItem.Convert(infos, reqinfo.BeginDate, reqinfo.EndDate)
                        .OrderBy((i) => i.ConflictDays)
                        .ThenBy(i => i.AssetName);
                    if (reqinfo != null && reqinfo.Assets != null && reqinfo.Assets.Count > 0)
                    {
                        foreach (JobSiteAssetDispatchInfo dai in reqinfo.Assets)
                        {
                            DispatchAssetItem ai = items.FirstOrDefault(m => m.AssetId == dai.AssetId);
                            if (ai != null)
                            {
                                ai.Selected = true;
                                ai.Completed = dai.Completed;
                                ai.DispatchId = dai.DispatchId;
                                ai.BeginDate = dai.BeginDate;
                                ai.EndDate = dai.EndDate;
                            }
                        }
                    }

                    var minDate = items.Min(i => i.Schedules.Count == 0 ? DateTime.MaxValue : i.Schedules.Min(ii => ii.BeginDate));
                    var maxDate = items.Max(i => i.Schedules.Count == 0 ? DateTime.MinValue : i.Schedules.Max(ii => ii.EndDate));
                    var selitems = items.Where(i => i.Selected);
                    DateTime selMinDate = DateTime.MaxValue;
                    DateTime selMaxDate = DateTime.MinValue;
                    if (selitems.Count() > 0)
                    {
                        selMinDate = selitems.Min(i => i.Schedules.Count == 0 ? DateTime.MaxValue : i.Schedules.Min(ii => ii.BeginDate));
                        selMaxDate = selitems.Max(i => i.Schedules.Count == 0 ? DateTime.MinValue : i.Schedules.Max(ii => ii.EndDate));
                    }
                    return new
                    {
                        HasAllSchedule = minDate != DateTime.MaxValue,
                        AllBeginDate = minDate,
                        AllTotalDays = (maxDate - minDate).Days + 1,
                        HasSchedule = selMinDate != DateTime.MaxValue,
                        BeginDate = selMinDate,
                        TotalDays = selMinDate != DateTime.MaxValue ? (selMaxDate - selMinDate).Days + 1 : 0,
                        DispatchAssets = items
                    };
                }
                else
                {
                    return "";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private string SetRequirmentsDefault()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    UserParams.SetStringParameter(session.User.UID, "RequirmentsDefault", clientdata);
                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private object GetRequirmentsDefault()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    string value = UserParams.GetStringParameter(session.User.UID, "RequirmentsDefault");

                    RequirementsDefaultItem item = null;
                    if (!string.IsNullOrEmpty(value))
                        item = JsonConvert.DeserializeObject<RequirementsDefaultItem>(value);


                    return item;
                }
                else
                    return null;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private object GetAssetDispatchItems()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    JobSiteRequirementQueryItem p = JsonConvert.DeserializeObject<JobSiteRequirementQueryItem>(clientdata);
                    DateTime latestStartDate = Helper.DBMinDateTime;
                    if (!DateTime.TryParse(p.LatestStartDate, out latestStartDate))
                        latestStartDate = Helper.DBMinDateTime;

                    JobSiteAssetDispatchInfo[] reqs = CreateClient<JobSiteDispatchProvider>().GetAssetDispatchItems(SystemParams.CompanyID, latestStartDate, p.JobSites, p.Regions, p.UnScheduledOnly);
                    if (reqs == null || reqs.Length == 0)
                        return new JobSiteAssetDispatchItem[0];

                    List<JobSiteAssetDispatchItem> ls = new List<JobSiteAssetDispatchItem>();
                    foreach (JobSiteAssetDispatchInfo re in reqs)
                    {
                        JobSiteAssetDispatchItem item = new JobSiteAssetDispatchItem();
                        Helper.CloneProperty(item, re);
                        ls.Add(item);
                    }

                    return ls.ToArray();

                }
                else
                    return new JobSiteAssetDispatchItem[0];
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private object GetAssetDispatchHistory()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    string[] p = JsonConvert.DeserializeObject<string[]>(clientdata);
                    int sendtype = Convert.ToInt32(p[0]);
                    long id = Convert.ToInt64(p[1]);

                    JobSiteAssetDispatchInfo[] reqs = null;
                    if (sendtype == 0)
                        reqs = CreateClient<JobSiteDispatchProvider>().GetAssetDispatchHistoryByRequirementID(SystemParams.CompanyID, id);
                    else if (sendtype == 1)
                        reqs = CreateClient<JobSiteDispatchProvider>().GetAssetDispatchHistoryByID(SystemParams.CompanyID, id);

                    if (reqs == null || reqs.Length == 0)
                        return new JobSiteAssetDispatchItem[0];

                    List<JobSiteAssetDispatchItem> ls = new List<JobSiteAssetDispatchItem>();
                    foreach (JobSiteAssetDispatchInfo re in reqs)
                    {
                        JobSiteAssetDispatchItem item = new JobSiteAssetDispatchItem();
                        Helper.CloneProperty(item, re);
                        ls.Add(item);
                    }

                    return ls.ToArray();

                }
                else
                    return new JobSiteAssetDispatchItem[0];
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }


        private object GetAssetDispatchsByIds()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    long[] ids = JsonConvert.DeserializeObject<long[]>(clientdata);

                    JobSiteAssetDispatchInfo[] reqs = CreateClient<JobSiteDispatchProvider>().GetAssetDispatchsByIds(SystemParams.CompanyID, ids);
                    if (reqs == null || reqs.Length == 0)
                        return new JobSiteAssetDispatchItem[0];

                    List<JobSiteAssetDispatchItem> ls = new List<JobSiteAssetDispatchItem>();
                    foreach (JobSiteAssetDispatchInfo re in reqs)
                    {
                        JobSiteAssetDispatchItem item = new JobSiteAssetDispatchItem();
                        Helper.CloneProperty(item, re);
                        ls.Add(item);
                    }

                    return ls.ToArray();

                }
                else
                    return new JobSiteAssetDispatchItem[0];
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private string AssignDispatch()
        {
            try
            {
                var user = GetCurrentUser();
                if (user != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    DispatchAssignmentItem item = JsonConvert.DeserializeObject<DispatchAssignmentItem>(clientdata);
                    long[] disids;
                    var client = CreateClient<JobSiteDispatchProvider>();
                    if (item.Type == 0)
                    {
                        JobSiteAssetDispatchInfo[] dispatchs = client.GetAssetDispatchsByRequirementIds(SystemParams.CompanyID, item.ObjectIDs);
                        disids = dispatchs.Select(m => m.DispatchId).ToArray();
                    }
                    else
                        disids = item.ObjectIDs;

                    CreateClient<JobSiteDispatchProvider>().AssignDispatch(SystemParams.CompanyID, disids, item.AssetID);
                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private object AddDispatch()
        {
            try
            {
                var user = GetCurrentUser();
                if (user != null)
                {
                    //if (!CanEdit(SystemParams.CompanyID, Foresight.Fleet.Services.User.Feature.JOB_SITES_REQUIREMENTS))
                    //    return "";
                    var clientdata = Request.Form["ClientData"].Split((char)170);
                    var id = HttpUtility.HtmlDecode(clientdata[0]);
                    var data = HttpUtility.HtmlDecode(clientdata[1]);
                    JobSiteAssetDispatchInfo[] assts = JsonConvert.DeserializeObject<JobSiteAssetDispatchInfo[]>(data);

                    long[] dispatchids = CreateClient<JobSiteDispatchProvider>().AddDispatch(SystemParams.CompanyID, Convert.ToInt64(id), assts);

                    return dispatchids;
                }
                else
                {
                    return new long[0];
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private string UpdateDispatch()
        {
            try
            {
                var user = GetCurrentUser();
                if (user != null)
                {
                    //if (!CanEdit(SystemParams.CompanyID, Foresight.Fleet.Services.User.Feature.JOB_SITES_REQUIREMENTS))
                    //    return "";
                    var clientdata = HttpUtility.HtmlDecode(Request.Form["ClientData"]);
                    JobSiteAssetDispatchInfo[] dispatchs = JsonConvert.DeserializeObject<JobSiteAssetDispatchInfo[]>(clientdata);

                    if (dispatchs == null || dispatchs.Length == 0)
                        return "";

                    var client = CreateClient<JobSiteDispatchProvider>();
                    try
                    {
                        foreach (JobSiteAssetDispatchInfo dispatch in dispatchs)
                        {
                            client.UpdateDispatch(SystemParams.CompanyID, dispatch);
                        }
                    }
                    catch (Exception)
                    {
                    }

                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private string DeleteDispatch()
        {
            try
            {
                var user = GetCurrentUser();
                if (user != null)
                {
                    //if (!CanEdit(SystemParams.CompanyID, Foresight.Fleet.Services.User.Feature.JOB_SITES_REQUIREMENTS))
                    //    return "";
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    DispatchItem item = JsonConvert.DeserializeObject<DispatchItem>(clientdata);

                    CreateClient<JobSiteDispatchProvider>().DeleteDispatch(SystemParams.CompanyID, item.DispatchId, item.DeleteNotes);
                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private string SendEmails()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    SendEmailsInfo si = JsonConvert.DeserializeObject<SendEmailsInfo>(clientdata);

                    var client = CreateClient<JobSiteDispatchProvider>();

                    JobSiteAssetDispatchInfo[] items = null;
                    if (si.Type == 0)//create requirement
                    {
                        items = client.GetAssetDispatchsByRequirementIds(SystemParams.CompanyID, si.ObjectIDs);
                    }
                    else//dispatch
                    {
                        items = client.GetAssetDispatchsByIds(SystemParams.CompanyID, si.ObjectIDs);
                    }

                    SendDispatchRequest(items, si);

                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        private void SendDispatchRequest(JobSiteAssetDispatchInfo[] dispatchs, SendEmailsInfo si)
        {
            StringKeyValue[] emailaddress = si.EmailAddress;
            StringKeyValue[] textaddress = si.TextAddress;
            var alllangs = GetUserLanguages(emailaddress, textaddress);

            var useriid = GetCurrentUser().IID;
            var client = CreateClient<AttachmentClient>();
            if (emailaddress != null && emailaddress.Length > 0)
            {
                foreach (var item in emailaddress)
                {
                    string lang = GetUserLanguage(alllangs, item.Key);
                    string Subject = SystemParams.GetTextByKey(lang, "P_JS_DISPATCHREQUESTS", "Dispatch Requests");
                    string Body = GenerateDispatchHtml(lang, dispatchs, si.Description, si.AssignTo);
                    client.SendDispathRequestsEmail(SystemParams.CompanyID, Subject, Body, new string[] { item.Value }, useriid);
                }
            }
            //if (textaddress != null && textaddress.Length > 0)
            //{
            //    string Body = GenerateDispatchHtml(lang, dispatchs, si.Description);
            //    FleetServiceClientHelper.CreateClient<AttachmentClient>().SendDispathRequestsMessage(SystemParams.CompanyID, Subject, Body, emailaddress.ToArray(), useriid);
            //}
        }

        public static string GenerateDispatchHtml(string lang, JobSiteAssetDispatchInfo[] dispatchs, string description, string assignto)
        {
            string StrFormat = "";
            if (!string.IsNullOrEmpty(assignto))
                StrFormat += SystemParams.GetTextByKey(lang, "P_JS_FORASSET_COLON", "For Asset:") + " {2}<br/>";
            StrFormat += "{1}<br/>";
            StrFormat += "<table style=\"border:solid 1px #e1dbdb;border-collapse: collapse;\"><tr>";
            StrFormat += "<tr style=\"height:30px; background-color:#f1f1f1;\">";
            StrFormat += "<td style=\"border:1px solid #e1dbdb;\">" + SystemParams.GetTextByKey(lang, "P_JS_MOVEDATE", "Move Date") + "</td>";
            StrFormat += "<td style=\"border:1px solid #e1dbdb;\">" + SystemParams.GetTextByKey(lang, "P_JS_ASSETNAME", "Asset Name") + "</td>";
            StrFormat += "<td style=\"border:1px solid #e1dbdb;\">" + SystemParams.GetTextByKey(lang, "P_JS_ASSETTYPE", "Asset Type") + "</td>";
            StrFormat += "<td style=\"border:1px solid #e1dbdb;\">" + SystemParams.GetTextByKey(lang, "P_JS_FROMJOBSITE", "From Jobsite") + "</td>";
            StrFormat += "<td style=\"border:1px solid #e1dbdb;\">" + SystemParams.GetTextByKey(lang, "P_JS_TOJOBSITE", "To Jobsite") + "</td>";
            StrFormat += "<td style=\"border:1px solid #e1dbdb;\">" + SystemParams.GetTextByKey(lang, "P_JS_NOTES", "Notes") + "</td>";
            StrFormat += "<td style=\"border:1px solid #e1dbdb;\">" + SystemParams.GetTextByKey(lang, "P_JS_POINTOFCONTACT", "Point Of Contact") + "</td>";
            StrFormat += "</tr>";
            StrFormat += "{0}";
            StrFormat += "</table>";

            if (dispatchs != null)
            {
                string tr_data = string.Empty;
                foreach (JobSiteAssetDispatchInfo item in dispatchs)
                {
                    tr_data += "<tr>";
                    tr_data += "<td style=\"border:1px solid #e1dbdb;\">" + (item.BeginDate == null ? "" : item.BeginDate.Value.ToString("M/d/yyyy")) + "</td>";
                    tr_data += "<td style=\"border:1px solid #e1dbdb;\">" + item.AssetName + "</td>";
                    tr_data += "<td style=\"border:1px solid #e1dbdb;\">" + item.AssetTypeName + "</td>";
                    tr_data += "<td style=\"border:1px solid #e1dbdb;\">" + item.CurrentJobSiteName + "</td>";
                    tr_data += "<td style=\"border:1px solid #e1dbdb;\">" + item.RequiredJobSiteName + "</td>";
                    tr_data += "<td style=\"border:1px solid #e1dbdb;\">" + (item.Notes ?? "").Replace("\n", "<br>") + "</td>";
                    tr_data += "<td style=\"border:1px solid #e1dbdb;\">" + item.PointOfContact + "</td>";
                    tr_data += "</tr>";
                }

                return string.Format(StrFormat, tr_data, HttpUtility.HtmlEncode(description ?? "").Replace("\n", "<br>"), assignto);
            }
            return string.Empty;
        }


        private string UpdateDispatchCompleted()
        {
            try
            {
                var user = GetCurrentUser();
                if (user != null)
                {
                    //if (!CanEdit(SystemParams.CompanyID, Foresight.Fleet.Services.User.Feature.JOB_SITES_DISPATCHREQUESTS))
                    //    return "";
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    StringKeyValue kv = JsonConvert.DeserializeObject<StringKeyValue>(clientdata);
                    long dispatchid = Convert.ToInt64(kv.Key);
                    bool compeleted = Helper.IsTrue(kv.Value);
                    CreateClient<JobSiteDispatchProvider>().UpdateDispatchCompleted(SystemParams.CompanyID, dispatchid, compeleted, user.IID);

                    return "OK";
                }
                else
                {
                    return "Failed";
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private object GetDispatchContacts()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    string clientdata = HttpUtility.HtmlDecode(Request.Form["ClientData"]);
                    long[] ps = JsonConvert.DeserializeObject<long[]>(clientdata);

                    var items = UserManagement.GetUsersByAssets(session.SessionID, ps, SystemParams.CompanyID);
                    return items;
                }
                else
                {
                    return new UserInfo[0];
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private object GetAssetSchedulers()
        {
            try
            {
                var session = GetCurrentLoginSession();
                if (session != null)
                {
                    var clientdata = Request.Form["ClientData"];
                    clientdata = HttpUtility.HtmlDecode(clientdata);
                    string[] ps = JsonConvert.DeserializeObject<string[]>(clientdata);
                    long[] jss = JsonConvert.DeserializeObject<long[]>(ps[0]);
                    string[] regions = JsonConvert.DeserializeObject<string[]>(ps[1]);
                    string[] assetGroups = JsonConvert.DeserializeObject<string[]>(ps[2]);
                    int[] assetTypes = JsonConvert.DeserializeObject<int[]>(ps[3]);
                    string searchtxt = ps[4];

                    DateTime beginDate = Helper.DBMinDateTime;
                    DateTime endDate = DateTime.MaxValue;
                    if (!DateTime.TryParse(ps[5], out beginDate))
                        beginDate = Helper.DBMinDateTime;

                    if (!DateTime.TryParse(ps[6], out endDate))
                        endDate = DateTime.MaxValue;
                    bool unscheduled = ps[7] == "1";

                    DispatchAssetInfo[] infos = CreateClient<JobSiteDispatchProvider>().GetAssetSchedulers(SystemParams.CompanyID, jss, regions, assetGroups, assetTypes, beginDate, endDate, unscheduled, searchtxt);

                    var items = DispatchAssetItem.Convert(infos, beginDate, endDate).OrderBy(m => m.AssetName).ToArray();
                    if (items.Count() == 0)
                        return null;

                    var minDate = items.Min(i => i.Schedules.Count == 0 ? DateTime.MaxValue : i.Schedules.Min(ii => ii.BeginDate));
                    var maxDate = items.Max(i => i.Schedules.Count == 0 ? DateTime.MinValue : i.Schedules.Max(ii => ii.EndDate));
                    List<StringKeyValue> labels = new List<StringKeyValue>();
                    if (minDate != DateTime.MaxValue && maxDate != DateTime.MinValue)
                    {
                        minDate = new DateTime(minDate.Year, minDate.Month, 1);//当前月第一天
                        maxDate = maxDate.AddMonths(2);
                        maxDate = new DateTime(maxDate.Year, maxDate.Month, 1);//第三个月第一天
                        var tempMinDate = minDate;
                        var tempMaxDate = maxDate;
                        DateTime? last = null;
                        while (tempMinDate <= tempMaxDate)
                        {
                            if (last != null)
                            {
                                labels.Add(new StringKeyValue()
                                {
                                    Key = last.Value.ToString("MM/dd/yyyy"),
                                    Value = (tempMinDate - last.Value).Days.ToString()
                                });
                            }
                            last = tempMinDate;
                            tempMinDate = tempMinDate.AddMonths(1);
                        }
                    }
                    return new
                    {
                        HasSchedule = minDate != DateTime.MaxValue,
                        BeginDate = minDate,
                        TotalDays = (maxDate - minDate).Days + 1,
                        Labels = labels,
                        DispatchAssets = items
                    };
                }
                else
                {
                    return new DispatchAssetItem[0];
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private class JobSitesAndRegionsItem
        {
            public StringKeyValue[] Jobsites { get; set; }
            public StringKeyValue[] Regions { get; set; }

        }

        private class JobSiteRequirementQueryItem
        {
            public string LatestStartDate { get; set; }
            public long[] JobSites { get; set; }
            public string[] Regions { get; set; }
            public string SearchText { get; set; }
            public bool UnScheduledOnly { get; set; }
        }
        private class AssetQueryItem
        {
            public int AssetType { get; set; }
            public long JobSiteID { get; set; }
            public string BeginDate { get; set; }
            public string EndDate { get; set; }
            public long RequireId { get; set; }
        }
        public class SendEmailsItem
        {
            public long[] DispatchId { get; set; }
            public string Description { get; set; }
            public string[] EmailAddress { get; set; }
            public string[] TextAddress { get; set; }
        }

        private class JobSiteRequirmentItem : JobSiteRequirmentInfo
        {
            public int Schedule { get { return Assets.Count(); } }
            public string BeginDateStr { get { return BeginDate == null ? "" : BeginDate.ToString("M/d/yyyy"); } }
            public string EndDateStr { get { return EndDate == null ? "" : EndDate.ToString("M/d/yyyy"); } }
            public string DeletedOnStr { get { return DeletedOn == null ? "" : DeletedOn.Value.ToString("M/d/yyyy"); } }
        }
        private class DispatchAssetItem : DispatchAssetInfo
        {
            public List<SchedulePart> ScheduleParts { get; private set; } = new List<SchedulePart>();
            public bool Selected { get; set; }
            public bool Completed { get; set; }
            public long DispatchId { get; set; }
            public int ConflictDays { get; set; }
            public DateTime? BeginDate { get; set; }
            public DateTime? EndDate { get; set; }
            public string BeginDateStr { get { return BeginDate == null ? "" : BeginDate.Value.ToString("M/d/yyyy"); } }
            public string EndDateStr { get { return EndDate == null ? "" : EndDate.Value.ToString("M/d/yyyy"); } }
            public string DistanceStr
            {
                get
                {
                    if (DistanceToDestJobSite != null && DistanceToDestJobSite > 0)
                    {
                        return DistanceToDestJobSite + " " + DistanceUnit + "(s)";
                    }
                    else
                    {
                        return "";
                    }
                }
            }

            public void ComputeSchedules()
            {
                List<DateTime> allDates = new List<DateTime>();
                List<DateTime> beginDates = new List<DateTime>();
                List<DateTime> endDates = new List<DateTime>();
                foreach (var s in Schedules)
                {
                    if (!beginDates.Contains(s.BeginDate))
                        beginDates.Add(s.BeginDate);
                    if (!endDates.Contains(s.EndDate))
                        endDates.Add(s.EndDate.AddDays(1));
                }
                allDates.AddRange(beginDates);
                allDates.AddRange(endDates);
                allDates = allDates.OrderBy(d => d).ToList();

                for (int i = 0; i < allDates.Count - 1; i++)
                {
                    SchedulePart sp = new SchedulePart();
                    sp.BeginDate = allDates[i];
                    sp.EndDate = allDates[i + 1];
                    foreach (var s in Schedules)
                    {
                        //if ((sp.BeginDate == sp.EndDate && s.BeginDate == sp.BeginDate)
                        //    || (s.EndDate > sp.BeginDate && s.BeginDate < sp.EndDate))
                        if (s.EndDate >= sp.BeginDate && s.BeginDate < sp.EndDate)
                            sp.Schedules.Add(s);
                    }
                    if (sp.Schedules.Count > 0)
                        ScheduleParts.Add(sp);
                }
            }

            public static DispatchAssetItem[] Convert(IEnumerable<DispatchAssetInfo> infos, DateTime begindate, DateTime enddate)
            {
                List<DispatchAssetItem> items = new List<DispatchAssetItem>();
                foreach (var i in infos)
                {
                    DispatchAssetItem item = new DispatchAssetItem();
                    Helper.CloneProperty(item, i);
                    if (item.DistanceToDestJobSite != null)
                        item.DistanceToDestJobSite = Math.Round(item.DistanceToDestJobSite.Value, 2);
                    if (begindate > DateTime.Now.AddYears(-5) && enddate < DateTime.Now.AddYears(5))
                        item.ConflictDays = GetConflictDays(i, begindate, enddate);
                    foreach (var s in i.Schedules)
                    {
                        AssetScheduleItem si = new AssetScheduleItem();
                        Helper.CloneProperty(si, s);
                        item.Schedules.Add(si);
                    }
                    item.ComputeSchedules();
                    items.Add(item);
                }

                return items.ToArray();
            }

            private static int GetConflictDays(DispatchAssetInfo info, DateTime begindate, DateTime enddate)
            {
                if (info == null)
                    return 0;
                else if (info.Schedules == null || info.Schedules.Count == 0)
                    return 0;
                else
                {
                    int count = 0;
                    while (begindate <= enddate)
                    {
                        foreach (var s in info.Schedules)
                        {
                            if (s.BeginDate <= begindate && s.EndDate >= begindate)
                            {
                                count++;
                                break;
                            }
                        }
                        begindate = begindate.AddDays(1);
                    }
                    return count;
                }
            }
        }
        private class SchedulePart
        {
            public List<AssetScheduleInfo> Schedules { get; private set; } = new List<AssetScheduleInfo>();
            public DateTime BeginDate { get; set; }
            public DateTime EndDate { get; set; }
            public string BeginDateStr { get { return BeginDate == DateTime.MinValue ? "" : BeginDate.ToString("M/d/yyyy"); } }
            public string EndDateStr { get { return EndDate == DateTime.MinValue ? "" : EndDate.ToString("M/d/yyyy"); } }
        }

        private class AssetScheduleItem : AssetScheduleInfo
        {
            public IIColor ColorV
            {
                get
                {
                    System.Drawing.Color color = Helper.ConvertHtmlColor(Color, System.Drawing.Color.Black);
                    return new IIColor() { Alpha = color.A, Red = color.R, Green = color.G, Blue = color.B };
                }
            }
            public string BeginDateStr { get { return BeginDate == DateTime.MinValue ? "" : BeginDate.ToString("M/d/yyyy"); } }
            public string EndDateStr { get { return EndDate == DateTime.MinValue ? "" : EndDate.ToString("M/d/yyyy"); } }

        }

        public class JobSiteAssetDispatchItem : JobSiteAssetDispatchInfo
        {
            public string MoveDateStr { get { return MoveDate == null ? "" : MoveDate.Value.ToString("M/d/yyyy"); } }
            public string BeginDateStr { get { return BeginDate == null ? "" : BeginDate.Value.ToString("M/d/yyyy"); } }
            public string EndDateStr { get { return EndDate == null ? "" : EndDate.Value.ToString("M/d/yyyy"); } }
            public string AddedOnStr { get { return AddedOn == null ? "" : AddedOn.Value.ToString("M/d/yyyy"); } }
            public string CompletedTimeStr
            {
                get
                {
                    if (Completed)
                        return CompletedTime == null ? "" : CompletedTime.Value.ToString("M/d/yyyy");
                    else
                        return "";
                }
            }
            public string DeletedOnStr
            {
                get
                {
                    if (Deleted)
                        return DeletedOn == null ? "" : DeletedOn.Value.ToString("M/d/yyyy");
                    else
                        return "";
                }
            }
        }

        public class RequirementsDefaultItem
        {
            public string[] Jobsites { get; set; }
            public string[] Regions { get; set; }
        }
        public class DispatchItem
        {
            public long[] DispatchId { get; set; }
            public string DeleteNotes { get; set; }
        }
        class DispatchAssignmentItem
        {
            public int Type { get; set; }//0.requirement;1.dispatch
            public long AssetID { get; set; }
            public long[] ObjectIDs { get; set; }
        }
    }
}