using Foresight.Data;
using Foresight.Fleet.Services.Asset;
using Foresight.Fleet.Services.AssetHealth;
using Foresight.Fleet.Services.User;
using IronIntel.Contractor.Machines;
using IronIntel.Services;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IronIntel.Contractor.Maintenance
{
    public class MaintenanceManagement
    {

        #region PM SCHEDULES

        /// <summary>
        /// 根据PM类型、PMId获取PM计划列表
        /// </summary>
        /// <returns></returns>
        public static PmScheduleInfo[] GetPmSchedule(string sessionid, string pmtype, string pmid, string filter)
        {
            var items = FleetServiceClientHelper.CreateClient<PMClient>(sessionid).GetPMScheduleItems(SystemParams.CompanyID, pmtype, filter, true);
            if (items == null || items.Length == 0)
                return new PmScheduleInfo[0];
            if (!string.IsNullOrEmpty(pmid))
                items = items.Where(m => m.Id == pmid).ToArray();
            List<PmScheduleInfo> list = new List<PmScheduleInfo>();
            foreach (var item in items)
            {
                PmScheduleInfo pm = new PmScheduleInfo();
                pm.PmScheduleID = item.Id;
                pm.PmScheduleName = item.Name;
                pm.PmScheduleUom = item.UOM;
                pm.PmScheduleType = item.ScheduleType;
                pm.Notes = item.Notes;
                if (item.Intervals != null || item.Intervals.Count > 0)
                {
                    List<PmIntervalItem> lsinterval = new List<PmIntervalItem>();
                    foreach (var pi in item.Intervals)
                    {
                        PmIntervalItem piclient = new PmIntervalItem();
                        Helper.CloneProperty(piclient, pi);
                        piclient.PmIntervalID = pi.Id;
                        lsinterval.Add(piclient);
                    }
                    pm.Intervals = lsinterval.ToArray();

                    if (pm.PmScheduleType == "HM" || pm.PmScheduleType == "RDM" || pm.PmScheduleType == "TBM")
                        pm.AllIntervals = GetAllIntervals(item);
                }
                else
                    pm.Intervals = new PmIntervalItem[0];
                list.Add(pm);
            }
            return list.ToArray();
        }

        /// <summary>
        /// 根据PM计划ID获取计划信息
        /// </summary>
        /// <returns></returns>
        public static PmScheduleInfo GetPMScheduleByID(string sessionid, string scheduleid)
        {
            var item = FleetServiceClientHelper.CreateClient<PMClient>(sessionid).GetPMScheduleItem(SystemParams.CompanyID, scheduleid, true);
            PmScheduleInfo pm = new PmScheduleInfo();
            pm.PmScheduleID = item.Id;
            pm.PmScheduleName = item.Name;
            pm.PmScheduleUom = item.UOM;
            pm.PmScheduleType = item.ScheduleType;
            pm.Notes = item.Notes;
            if (item.Intervals != null || item.Intervals.Count > 0)
            {
                List<PmIntervalItem> lsinterval = new List<PmIntervalItem>();
                foreach (var pi in item.Intervals)
                {
                    PmIntervalItem piclient = new PmIntervalItem();
                    Helper.CloneProperty(piclient, pi);
                    piclient.PmIntervalID = pi.Id;
                    lsinterval.Add(piclient);
                }
                pm.Intervals = lsinterval.ToArray();

                if (pm.PmScheduleType == "HM" || pm.PmScheduleType == "RDM" || pm.PmScheduleType == "TBM")
                    pm.AllIntervals = GetAllIntervals(item);
            }
            else
                pm.Intervals = new PmIntervalItem[0];


            return pm;
        }

        private static int[] GetAllIntervals(PMScheduleItem sc)
        {
            Dictionary<int, PMIntervalItem> result = new Dictionary<int, PMIntervalItem>();

            var intervals = sc.Intervals.Where(i => i.Recurring).OrderBy(i => i.Interval).ThenByDescending(i => i.Priority).ToList();
            if (intervals.Count == 0)
                return null;

            int maxInterval = 0;
            for (int i = 0; i < intervals.Count; i++)
            {
                PMIntervalItem ia = intervals[i];
                if (maxInterval <= 0)
                    maxInterval = ia.Interval;
                else
                    maxInterval = GetMinCommonMultiple(maxInterval, ia.Interval);
            }
            if (maxInterval < 0 || maxInterval > 10240000)//溢出或数据过大
                maxInterval = intervals.LastOrDefault().Interval;
            for (int i = 0; i < intervals.Count; i++)
            {
                PMIntervalItem ia = intervals[i];
                int tempInterval = ia.Interval;
                while (tempInterval <= maxInterval)
                {
                    if (result.ContainsKey(tempInterval))
                    {
                        if (ia.Priority < result[tempInterval].Priority
                            || (ia.Priority == result[tempInterval].Priority
                               && ia.Interval == result[tempInterval].Interval))
                            result[tempInterval] = ia;
                    }
                    else
                        result[tempInterval] = ia;

                    tempInterval += ia.Interval;
                }
            }

            return result.Select(r => r.Key).OrderBy(r => r).Take(1000).ToArray();
            //最大只取1000个，正常设置不会超过1000，异常设置数量太多会使前端页面卡死
        }

        private static int GetMaxCommonDivisor(int a, int b)
        {
            if (a < b) { a = a + b; b = a - b; a = a - b; }
            return (a % b == 0) ? b : GetMaxCommonDivisor(a % b, b);
        }

        private static int GetMinCommonMultiple(int a, int b)
        {
            return a * b / GetMaxCommonDivisor(a, b);
        }

        public static PmIntervalItem[] GetPmInterval(string sessionid, string scheduleid)
        {
            var items = FleetServiceClientHelper.CreateClient<PMClient>(sessionid).GetPMIntervals(SystemParams.CompanyID, scheduleid);
            if (items == null || items.Length == 0)
                return new PmIntervalItem[0];

            List<PmIntervalItem> list = new List<PmIntervalItem>();
            foreach (var pi in items)
            {
                PmIntervalItem piclient = new PmIntervalItem();
                Helper.CloneProperty(piclient, pi);
                piclient.PmIntervalID = pi.Id;
                list.Add(piclient);
            }

            return list.ToArray();
        }

        /// <summary>
        /// 根据机器id获取PM计划列表
        /// </summary>
        /// <returns></returns>
        public static PMAssetAlertInfo[] GetPmScheduleByAsset(string sessionid, long assetid, bool includeinterval)
        {
            List<PMAssetAlertInfo> result = new List<PMAssetAlertInfo>();
            var client = FleetServiceClientHelper.CreateClient<PMClient>(sessionid);
            var sches = client.GetPMScheduleItems(SystemParams.CompanyID, "", string.Empty, true);
            PMAssetAlertItem[] aas = null;
            if (includeinterval)
                aas = client.GetPMAssetAlertItems(SystemParams.CompanyID, assetid);
            foreach (var item in sches)
            {
                PMAssetAlertInfo pm = new PMAssetAlertInfo();
                pm.PmScheduleID = item.Id;
                pm.PmScheduleName = item.Name;
                pm.PmScheduleUom = item.UOM;
                pm.PmScheduleType = item.ScheduleType;
                pm.Notes = item.Notes;
                if (includeinterval && item.Intervals != null || item.Intervals.Count > 0)
                {
                    List<PmIntervalItem> lsinterval = new List<PmIntervalItem>();
                    foreach (var pi in item.Intervals)
                    {
                        PmIntervalItem piclient = new PmIntervalItem();
                        Helper.CloneProperty(piclient, pi);
                        piclient.PmIntervalID = pi.Id;
                        lsinterval.Add(piclient);
                    }
                    pm.Intervals = lsinterval.ToArray();

                    if (pm.PmScheduleType == "HM" || pm.PmScheduleType == "RDM" || pm.PmScheduleType == "TBM")
                        pm.AllIntervals = GetAllIntervals(item);
                }
                else
                    pm.Intervals = new PmIntervalItem[0];

                if (includeinterval && aas != null)
                {
                    var aa = aas.FirstOrDefault(a => a.PMScheduleId.Equals(pm.PmScheduleID, StringComparison.OrdinalIgnoreCase));
                    if (aa != null)
                    {
                        pm.Selected = true;
                        pm.AssetId = aa.AssetId;
                        pm.PmScheduleID = aa.PMScheduleId;
                        pm.PmIntervalId = aa.PMIntervalId;
                        pm.ServiceName = aa.ServiceName;
                        pm.LastAlertTime = aa.LastAlertTime;
                        pm.StartDate = aa.StartDate;
                        pm.StartHours = aa.StartHours;
                        pm.StartOdometer = aa.StartOdometer;
                        pm.StartIntervalValue = aa.StartIntervalValue;
                        pm.UnMaintainedAlert = aa.UnMaintainedAlert;
                    }
                }

                result.Add(pm);
            }
            return result.ToArray();
        }

        public static void UpdatePmSchedule(string sessionid, PmScheduleInfo si, string useriid)
        {
            PMScheduleItem pm = new PMScheduleItem();
            pm.Id = si.PmScheduleID;
            pm.Name = si.PmScheduleName;
            pm.UOM = si.PmScheduleUom;
            pm.ScheduleType = si.PmScheduleType;
            pm.Notes = si.Notes;
            if (si.Intervals != null && si.Intervals.Length > 0)
            {
                List<PMIntervalItem> list = new List<PMIntervalItem>();
                foreach (PmIntervalItem piclient in si.Intervals)
                {
                    PMIntervalItem pi = new PMIntervalItem();
                    Helper.CloneProperty(pi, piclient);
                    pi.Id = piclient.PmIntervalID;
                    pi.ScheduleId = pm.Id;
                    list.Add(pi);
                }
                pm.Intervals.AddRange(list);
            }
            FleetServiceClientHelper.CreateClient<PMClient>(sessionid).UpdatePMSchedule(SystemParams.CompanyID, pm, useriid);
        }

        public static void UpdatePmInterval(string sessionid, PmIntervalItem piclient, string useriid)
        {
            PMIntervalItem interval = new PMIntervalItem();
            Helper.CloneProperty(interval, piclient);
            interval.Id = piclient.PmIntervalID;
            FleetServiceClientHelper.CreateClient<PMClient>(sessionid).UpdatePMInterval(SystemParams.CompanyID, interval, useriid);
        }

        #endregion

        #region Maintenance Log

        public static MaintenanceLogInfo[] GetMaintenanceLog(string sessionid, long assetid, string maintenancetype, int machinetype, string searchtxt, DateTime starttime, DateTime endtime, string useriid)
        {
            const string SQL = @"select a.MAINTENANCEID,a.MACHINEID,a.MAINTENANCEDATE,a.MAINTENANCEHOURS,a.NOTES,a.ALERTID,b.MACHINENAME,b.MACHINENAME2, b.VIN,b.MAKEID, b.MODELID,b.TYPEID,ISNULL(b.ENGINEHOURS,0) as ENGINEHOURS,
            t.ALERTTYPE,t.ALERTTITLE,t.ALERTTIME_UTC,ISNULL(a.ODOMETER,0) AS ODOMETER,ISNULL(a.ODOMETERUOM,'Hour') AS ODOMETERUOM, isnull(LOGTYPE,'Hours') AS LOGTYPE ,a.COST,a.INVOICENUMBER,a.COMPLETEDBY,a.COMPLETEDBYUSERNAME,
            (select top 1 ATTACHID from ATTACHES with(nolock) where SOURCE='MaintenanceLog' and REFID=a.MAINTENANCEID and isnull(DELETED,0)=0) ATTACHID
            from MAINTENANCELOG a with(nolock) left join ALERTS t with(nolock) on a.ALERTID=t.ALERTID,MACHINES b 
            where a.MACHINEID = b.MACHINEID and ISNULL(b.HIDE,0)<>1 and a.MAINTENANCEDATE>={0} and a.MAINTENANCEDATE<={1} ";
            const string ORDER_BY = "  ORDER BY a.ADDEDON DESC";

            DateTime sttime = new DateTime(starttime.Year, starttime.Month, starttime.Day, 0, 0, 0);
            DateTime ettime = new DateTime(endtime.Year, endtime.Month, endtime.Day, 23, 59, 59);

            string sql = SQL;
            if (assetid > 0)
            {
                sql = sql + " and  a.MACHINEID=" + assetid;
            }
            if (machinetype >= 0)
            {
                sql = sql + " and  b.TYPEID=" + machinetype.ToString() + ORDER_BY;
            }
            else
            {
                sql = sql + ORDER_BY;
            }

            FISqlConnection db = SystemParams.GetDbInstance();
            DataTable dt = db.GetDataTableBySQL(sql, sttime, ettime);
            if (dt.Rows.Count == 0)
            {
                return new MaintenanceLogInfo[0];
            }

            long[] availableAssetsids = null;
            var user = Users.UserManagement.GetUserByIID(useriid);
            if (user.UserType < Users.UserTypes.Admin)
                availableAssetsids = FleetServiceClientHelper.CreateClient<AssetQueryClient>(sessionid).GetAvailableAssetsForUsers(SystemParams.CompanyID, useriid);

            MachineManagement.RefreshBaseData();
            AssetMake[] makes = MachineManagement.GetMachineMakes();
            AssetModel[] models = MachineManagement.GetMachineModels();
            AssetType[] types = MachineManagement.GetMachineTypes();

            List<MaintenanceLogInfo> list = new List<MaintenanceLogInfo>();
            foreach (DataRow dr in dt.Rows)
            {
                long mid = FIDbAccess.GetFieldInt64(dr["MACHINEID"], 0);
                if (user.UserType < Users.UserTypes.Admin && !availableAssetsids.Contains(mid))
                    continue;

                MaintenanceLogInfo ml = ConvertToMaintenanceLogInfo(dr, makes, models, types);
                ml.AlertTitle = FIDbAccess.GetFieldString(dr["ALERTTITLE"], string.Empty);
                ml.AlertType = FIDbAccess.GetFieldString(dr["ALERTTYPE"], string.Empty);
                ml.AlertTime = FIDbAccess.GetFieldDateTime(dr["ALERTTIME_UTC"], DateTime.MinValue);
                ml.HasAttachment = !string.IsNullOrWhiteSpace(FIDbAccess.GetFieldString(dr["ATTACHID"], string.Empty));

                if (!string.IsNullOrWhiteSpace(searchtxt))
                {
                    if (Helper.Contains(ml.MachineID.ToString(), searchtxt)
                        || Helper.Contains(ml.MachinePin, searchtxt)
                        || Helper.Contains(ml.MachineName, searchtxt)
                        || Helper.Contains(ml.MachineName2, searchtxt)
                        || Helper.Contains(ml.MachineMake, searchtxt)
                        || Helper.Contains(ml.MachineModel, searchtxt)
                        || Helper.Contains(ml.MachineType, searchtxt)
                        || Helper.Contains(ml.StrForMaintenanceDate, searchtxt)
                        || Helper.Contains(ml.Notes, searchtxt))
                    {
                        list.Add(ml);
                    }
                }
                else
                {
                    list.Add(ml);
                }
            }
            return list.ToArray();
        }

        public static MaintenanceLogInfo GetMaintenanceInfo(string maintenanceid)
        {
            const string SQL = @"select a.MAINTENANCEID,a.MACHINEID,a.MAINTENANCEDATE,a.MAINTENANCEHOURS,a.NOTES,a.ALERTID,b.MACHINENAME,b.MACHINENAME2,b.VIN,b.MAKEID,b.MODELID,b.TYPEID,ISNULL(b.ENGINEHOURS,0) as ENGINEHOURS,
            t.ALERTTYPE,t.ALERTTITLE,t.ALERTTIME_UTC,ISNULL(a.ODOMETER,0) AS ODOMETER,ISNULL(a.ODOMETERUOM,'Hour') AS ODOMETERUOM, isnull(LOGTYPE,'Hours') AS LOGTYPE 
            ,a.COST,a.INVOICENUMBER,a.COMPLETEDBY,a.COMPLETEDBYUSERNAME from MAINTENANCELOG a left join ALERTS t on a.ALERTID=t.ALERTID,MACHINES b 
            where a.MACHINEID = b.MACHINEID and ISNULL(b.HIDE,0)<>1 and a.MAINTENANCEID={0} ORDER BY a.ADDEDON DESC";

            FISqlConnection db = SystemParams.GetDbInstance();
            DataTable dt = db.GetDataTableBySQL(SQL, maintenanceid);
            if (dt.Rows.Count == 0)
            {
                return new MaintenanceLogInfo();
            }

            MachineManagement.RefreshBaseData();
            AssetMake[] makes = MachineManagement.GetMachineMakes();
            AssetModel[] models = MachineManagement.GetMachineModels();
            AssetType[] types = MachineManagement.GetMachineTypes();

            MaintenanceLogInfo ml = ConvertToMaintenanceLogInfo(dt.Rows[0], makes, models, types);
            return ml;
        }

        public static MaintenanceLogInfo[] GetMaintenanceLogByMachineID(long MachineID, string maintenanceType)
        {
            string SQL = @"select a.MAINTENANCEID,a.MACHINEID,a.MAINTENANCEDATE,a.MAINTENANCEHOURS,a.NOTES,a.ALERTID,b.MACHINENAME,b.MACHINENAME2,b.VIN,b.MAKEID,b.MODELID,b.TYPEID,ISNULL(b.ENGINEHOURS,0) as ENGINEHOURS, ISNULL(a.ODOMETER,0) AS ODOMETER,ISNULL(a.ODOMETERUOM,'Mile') AS ODOMETERUOM, isnull(LOGTYPE,'Hours') AS LOGTYPE 
                               ,a.COST,a.INVOICENUMBER,a.COMPLETEDBY,a.COMPLETEDBYUSERNAME from MAINTENANCELOG a, MACHINES b where a.MACHINEID = b.MACHINEID and  a.MACHINEID={0}";
            if (maintenanceType != null)
                SQL += " and LOGTYPE={1} ";
            SQL += " ORDER BY a.ADDEDON DESC";
            FISqlConnection db = SystemParams.GetDbInstance();
            DataTable dt = db.GetDataTableBySQL(SQL, MachineID, maintenanceType);
            if (dt.Rows.Count == 0)
            {
                return new MaintenanceLogInfo[0];
            }

            MachineManagement.RefreshBaseData();
            AssetMake[] makes = MachineManagement.GetMachineMakes();
            AssetModel[] models = MachineManagement.GetMachineModels();
            AssetType[] types = MachineManagement.GetMachineTypes();

            List<MaintenanceLogInfo> list = new List<MaintenanceLogInfo>();
            foreach (DataRow dr in dt.Rows)
            {
                MaintenanceLogInfo ml = ConvertToMaintenanceLogInfo(dr, makes, models, types);
                list.Add(ml);
            }
            return list.ToArray();
        }

        public static MaintenanceLogInfo GetMaintenanceLogByMaintenanceID(string MaintenanceID)
        {
            const string SQL = @"select a.MAINTENANCEID,a.MACHINEID,a.MAINTENANCEDATE,a.MAINTENANCEHOURS,a.NOTES,a.ALERTID,b.MACHINENAME,b.MACHINENAME2,b.VIN,b.MAKEID,b.MODELID,b.TYPEID
               ,ISNULL(b.ENGINEHOURS,0) as ENGINEHOURS,ISNULL(a.ODOMETER,0) AS ODOMETER,ISNULL(a.ODOMETERUOM,'Mile') AS ODOMETERUOM, isnull(LOGTYPE,'Hours') AS LOGTYPE 
              ,a.COST,a.INVOICENUMBER,a.COMPLETEDBY,a.COMPLETEDBYUSERNAME from MAINTENANCELOG a , MACHINES b where a.MACHINEID = b.MACHINEID and a.MAINTENANCEID={0}";

            FISqlConnection db = SystemParams.GetDbInstance();
            DataTable dt = db.GetDataTableBySQL(SQL, MaintenanceID);
            if (dt.Rows.Count == 0)
            {
                return new MaintenanceLogInfo();
            }
            MachineManagement.RefreshBaseData();
            AssetMake[] makes = MachineManagement.GetMachineMakes();
            AssetModel[] models = MachineManagement.GetMachineModels();
            AssetType[] types = MachineManagement.GetMachineTypes();

            MaintenanceLogInfo ml = ConvertToMaintenanceLogInfo(dt.Rows[0], makes, models, types);
            return ml;
        }

        public static void UpdateMaintenanceLog(MaintenanceLogInfo ml, string addedby)
        {
            const string SQL = @"if exists(select 1 from MAINTENANCELOG where MAINTENANCEID={0}) update MAINTENANCELOG set MACHINEID ={1},MAINTENANCEDATE ={2},
                MAINTENANCEHOURS={3},NOTES={4},LASTUPDATEDBY={5},LASTUPDATEDON=GETUTCDATE(),ALERTID={6},ODOMETER={7},ODOMETERUOM={8},LOGTYPE={9},COST={10},INVOICENUMBER={11},COMPLETEDBYUSERNAME={12},COMPLETED={13},COMPLETEDDATE_UTC= (case {13} when 1 then GETDATE() else null end) where MAINTENANCEID={0} else insert into MAINTENANCELOG(MAINTENANCEID,
                MACHINEID,MAINTENANCEDATE,MAINTENANCEHOURS,NOTES,ADDEDBY,ADDEDON,LASTUPDATEDBY,LASTUPDATEDON,ALERTID,ODOMETER,ODOMETERUOM,LOGTYPE,COST,INVOICENUMBER,COMPLETEDBYUSERNAME,COMPLETED,COMPLETEDDATE_UTC) values({0},{1},{2},{3},{4},{5},GETUTCDATE(),{5},GETUTCDATE(),{6},{7},{8},{9},{10},{11},{12},{13},(case {13} when 1 then GETDATE() else null end))";
            FISqlConnection db = SystemParams.GetDbInstance();
            db.ExecSQL(SQL, ml.MaintenanceID, ml.MachineID, ml.MaintenanceDate, ml.MaintenanceHours, ml.Notes, addedby, ml.AlertID, ml.ODOMeter, ml.ODOMemterUOM, ml.LogType, ml.Cost, ml.InvoiceNumber, ml.CompletedByName, ml.Completed ? 1 : 0);//COMPLETEDDATE_UTC保存的GETDATE(),与WorkOrder里面的录入的实际保存一致
        }

        public static void DeleteMaintenanceLog(string maintencelogid)
        {
            const string SQL = "delete from MAINTENANCELOG where MAINTENANCEID={0}";
            FISqlConnection db = SystemParams.GetDbInstance();
            db.ExecSQL(SQL, maintencelogid);
        }

        public static PMAlert[] GetUnCompletedPMAlerts(long machineid, string maintencelogid)
        {
            List<PMAlert> alerts = new List<PMAlert>();
            const string SQL = "select LOGID,pm.ALERTID,pm.ALERTTIME_UTC,ALERTTITLE from PM_ALERTS pm left join ALERTS a on pm.ALERTID=a.ALERTID where pm.MACHINEID={0} and ((ISNULL(a.COMPLETED,0)<>1 and ISNULL(a.ACKNOWLEDGED,0)<>1) or exists(select 1 from MAINTENANCELOG ml where ml.ALERTID=a.ALERTID and MAINTENANCEID={1} ))";
            var db = SystemParams.GetDbInstance();
            DataTable dt = db.GetDataTableBySQL(SQL, machineid, maintencelogid);
            foreach (DataRow dr in dt.Rows)
            {
                PMAlert alert = new PMAlert();
                alert.LogID = FIDbAccess.GetFieldString(dr["LOGID"], string.Empty);
                alert.AlertID = FIDbAccess.GetFieldString(dr["ALERTID"], string.Empty);
                alert.AlertTitle = FIDbAccess.GetFieldString(dr["ALERTTITLE"], string.Empty);
                DateTime at = FIDbAccess.GetFieldDateTime(dr["ALERTTIME_UTC"], DateTime.MinValue);
                if (at != DateTime.MinValue)
                    alert.AlertTime = at.ToString("M/d/yyyy h:mm:ss tt");
                alerts.Add(alert);
            }
            return alerts.ToArray();
        }

        public static void SetPMAlertCompleted(long alertID, bool completed, string completedby)
        {
            const string SQL = "update ALERTS set COMPLETED={0},COMPLETEDBY={2},COMPLETEDDATE_UTC=(case {0} when 1 then GETUTCDATE() else null end) where ALERTID={1}";
            var db = SystemParams.GetDbInstance();
            db.ExecSQL(SQL, completed ? 1 : 0, alertID, completedby);
        }

        private static MaintenanceLogInfo ConvertToMaintenanceLogInfo(DataRow dr, AssetMake[] makes, AssetModel[] models, AssetType[] types)
        {
            MaintenanceLogInfo ml = new MaintenanceLogInfo();
            ml.MaintenanceID = FIDbAccess.GetFieldString(dr["MAINTENANCEID"], string.Empty);
            ml.MachineID = FIDbAccess.GetFieldInt(dr["MACHINEID"], 0);
            ml.MaintenanceDate = FIDbAccess.GetFieldDateTime(dr["MAINTENANCEDATE"], DateTime.MinValue);
            ml.MaintenanceHours = FIDbAccess.GetFieldDouble(dr["MAINTENANCEHOURS"], 0);
            ml.Notes = FIDbAccess.GetFieldString(dr["NOTES"], string.Empty);
            ml.AlertID = FIDbAccess.GetFieldInt(dr["ALERTID"], -1);
            ml.MachinePin = FIDbAccess.GetFieldString(dr["VIN"], string.Empty);
            ml.MachineName = FIDbAccess.GetFieldString(dr["MACHINENAME"], string.Empty);
            ml.MachineName2 = FIDbAccess.GetFieldString(dr["MACHINENAME2"], string.Empty);
            ml.EngineHours = FIDbAccess.GetFieldDouble(dr["ENGINEHOURS"], 0);
            ml.ODOMeter = FIDbAccess.GetFieldDouble(dr["ODOMETER"], 0);
            ml.ODOMemterUOM = FIDbAccess.GetFieldString(dr["ODOMETERUOM"], "Mile");
            ml.LogType = FIDbAccess.GetFieldString(dr["LOGTYPE"], "Hours");
            ml.Cost = FIDbAccess.GetFieldDouble(dr["COST"], 0);
            ml.InvoiceNumber = FIDbAccess.GetFieldString(dr["INVOICENUMBER"], "");
            ml.CompletedByName = FIDbAccess.GetFieldString(dr["COMPLETEDBYUSERNAME"], "");

            int makeid = FIDbAccess.GetFieldInt(dr["MAKEID"], 0);
            AssetMake make = MachineManagement.GetMachineMake(makes, makeid);
            ml.MachineMake = make == null ? string.Empty : make.Name;

            int modelid = FIDbAccess.GetFieldInt(dr["MODELID"], 0);
            AssetModel model = MachineManagement.GetMachineModel(models, modelid);
            ml.MachineModel = model == null ? string.Empty : model.Name;

            int typeid = FIDbAccess.GetFieldInt(dr["TYPEID"], 0);
            AssetType mtype = MachineManagement.GetMachineType(types, typeid);
            ml.MachineType = mtype == null ? string.Empty : mtype.Name;

            return ml;
        }

        public static WorkOrderListItemClient[] GetMaintenanceWorkOrders(string sessionid, string custid, string[] assignedusers, string[] asseitgroups, string filter, string useriid)
        {
            const string SQL = @"select m.MAINTENANCEID,m.COMPLETEDBY,(select USERNAME from USERS with(nolock) where USERS.USERIID=m.COMPLETEDBY) as ASSIGNEDTONAME,m.NOTES,m.MAINTENANCEDATE
            ,b.MACHINEID,b.VIN,b.MACHINENAME,b.MACHINENAME2 from MAINTENANCELOG m with(nolock) left join MACHINES b with(nolock) on b.MACHINEID=m.MACHINEID
			where m.ALERTID not in (select ALERTID from WORKORDER_ALERTS with(nolock)) and m.MACHINEID = b.MACHINEID and ISNULL(b.HIDE,0)<>1  ";
            const string SQL_FILTER = " and (m.NOTES like {0} or b.MACHINEID like {0} or b.VIN like {0}  or b.MACHINENAME like {0} or b.MACHINENAME2 like {0}) ";
            const string SQL_ORDERBY = " order by m.MAINTENANCEID";

            var user = FleetServiceClientHelper.CreateClient<UserQueryClient>(custid, sessionid).GetUserByIID(useriid);
            if (user == null || (!user.Active))
            {
                return new WorkOrderListItemClient[0];
            }
            if (user == null || (!user.Active))
            {
                return new WorkOrderListItemClient[0];
            }
            if (string.Compare(user.CompanyID, SystemParams.CompanyID, true) != 0 && (!user.IsForesightUser))
            {
                return new WorkOrderListItemClient[0];
            }

            string sql = SQL;
            if ((!user.IsForesightUser) && (user.ContactType == Foresight.Fleet.Services.User.ContactTypes.Technician))
            {
                sql += " and m.COMPLETEDBY in ('" + useriid + "') ";
            }
            else if (assignedusers != null && assignedusers.Length > 0)
            {
                string uids = JoinSQLString(assignedusers);
                sql += " and m.COMPLETEDBY in (" + uids + ") ";
            }

            FISqlConnection db = SystemParams.GetDbInstance();
            long[] assets = null;
            if (asseitgroups != null && asseitgroups.Length > 0)
            {
                assets = MachineManagement.GetGroupMachines(asseitgroups, db);
            }
            DataTable dt = null;
            if (string.IsNullOrWhiteSpace(filter))
                dt = db.GetDataTableBySQL(sql + SQL_ORDERBY);
            else
                dt = db.GetDataTableBySQL(sql + SQL_FILTER + SQL_ORDERBY, "%" + filter + "%");

            if (dt.Rows.Count == 0)
                return new WorkOrderListItemClient[0];

            List<WorkOrderListItemClient> list = new List<WorkOrderListItemClient>();
            foreach (DataRow dr in dt.Rows)
            {
                WorkOrderListItemClient wo = new WorkOrderListItemClient();

                long assetid = FIDbAccess.GetFieldInt64(dr["MACHINEID"], 0);
                if (assets != null && assets.Length > 0)
                {
                    if (!assets.Contains(assetid))
                    {
                        continue;
                    }
                }
                wo.AssetId = assetid;
                wo.MaintenanceID = FIDbAccess.GetFieldString(dr["MAINTENANCEID"], string.Empty);
                wo.Description = FIDbAccess.GetFieldString(dr["NOTES"], string.Empty);
                wo.CompleteDate = FIDbAccess.GetFieldDateTime(dr["MAINTENANCEDATE"], DateTime.MinValue);
                wo.AssetName = FIDbAccess.GetFieldString(dr["MACHINENAME"], string.Empty);
                //var assignedTo = FIDbAccess.GetFieldString(dr["COMPLETEDBY"], string.Empty);
                //wo.AssignedToName = FIDbAccess.GetFieldString(dr["ASSIGNEDTONAME"], assignedTo);

                wo.WorkOrderNumber = "";

                list.Add(wo);
            }
            return list.ToArray();
        }

        public static string JoinSQLString(IEnumerable<string> items)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string s in items)
            {
                if (sb.Length == 0)
                {
                    sb.Append("'" + s + "'");
                }
                else
                {
                    sb.Append(",'" + s + "'");
                }
            }
            return sb.ToString();
        }

        #endregion

        #region Machines


        public static MaintenanceMachineInfo[] GetMaintenanceMachines(string sessionid, int machinetype, string searchtxt, string useriid, string companyid = null)
        {
            if (string.IsNullOrEmpty(companyid))
                companyid = SystemParams.CompanyID;
            //普通用户机器权限过滤
            long[] availableAssetsids = null;
            var user = Users.UserManagement.GetUserByIID(useriid);
            var client = FleetServiceClientHelper.CreateClient<AssetQueryClient>(companyid, sessionid);
            if (user.UserType < Users.UserTypes.Admin)
                availableAssetsids = client.GetAvailableAssetsForUsers(companyid, useriid);
            AssetBasicInfo[] assets = client.GetAssetBasicInfo(companyid, searchtxt, availableAssetsids, 0);
            if (assets != null && machinetype != -1)
                assets = assets.Where(m => m.TypeID == machinetype).ToArray();
            long[] mids = null;
            if (assets != null)
                mids = assets.AsEnumerable().Select(m => m.ID).ToArray();
            //var ehs = SystemParams.AssetClient.GetAssetsCurrentPrimaryEngineHours(companyid, mids);
            var odos = client.GetAssetsCurrentPrimaryOdometer(companyid, mids);
            List<MaintenanceMachineInfo> list = new List<MaintenanceMachineInfo>();
            foreach (var a in assets)
            {
                if (a.Hide) continue;
                MaintenanceMachineInfo mi = new MaintenanceMachineInfo();
                mi.MachineID = a.ID;
                mi.VIN = a.VIN;
                mi.MachineName = a.Name;
                mi.MachineName2 = a.Name2;
                mi.Make = a.MakeName;
                mi.Model = a.ModelName;
                mi.TypeID = a.TypeID;
                mi.MachineType = a.TypeName;
                mi.Hide = a.Hide;
                mi.EngineHours = a.EngineHours == null ? 0 : a.EngineHours.Value;
                if (odos != null && odos.Length > 0)
                {
                    var odo = odos.FirstOrDefault((o) => o.AssetID == mi.MachineID);
                    if (odo != null)
                        mi.Odometer = odo.Corrected;
                }

                list.Add(mi);
            }

            return list.ToArray();
        }

        public static MaintenanceMachineInfo ConvertToMaintenanceMachineInfo(DataRow dr, AssetMake[] makes, AssetModel[] models, AssetType[] types)
        {
            MaintenanceMachineInfo mi = new MaintenanceMachineInfo();
            mi.MachineID = Convert.ToInt64(dr["MACHINEID"]);
            mi.MachineName = FIDbAccess.GetFieldString(dr["MACHINENAME"], string.Empty);
            mi.MachineName2 = FIDbAccess.GetFieldString(dr["MACHINENAME2"], string.Empty);
            mi.VIN = FIDbAccess.GetFieldString(dr["VIN"], string.Empty);
            mi.EngineHours = FIDbAccess.GetFieldDouble(dr["ENGINEHOURS"], 0);
            mi.Odometer = FIDbAccess.GetFieldDouble(dr["ODOMETER"], 0);

            int makeid = FIDbAccess.GetFieldInt(dr["MAKEID"], 0);
            AssetMake make = MachineManagement.GetMachineMake(makes, makeid);
            mi.Make = make == null ? string.Empty : make.Name;

            int modelid = FIDbAccess.GetFieldInt(dr["MODELID"], 0);
            AssetModel model = MachineManagement.GetMachineModel(models, modelid);
            mi.Model = model == null ? string.Empty : model.Name;

            int typeid = FIDbAccess.GetFieldInt(dr["TYPEID"], 0);
            AssetType mtype = MachineManagement.GetMachineType(types, typeid);
            mi.TypeID = mtype == null ? 0 : mtype.ID;
            mi.MachineType = mtype == null ? string.Empty : mtype.Name;


            if (dr.Table.Columns.Contains("STARTDATE"))
            {
                mi.StartDate = FIDbAccess.GetFieldDateTime(dr["STARTDATE"], DateTime.MinValue);
            }
            if (dr.Table.Columns.Contains("STARTHOURS"))
            {
                mi.StartHours = FIDbAccess.GetFieldDouble(dr["STARTHOURS"], 0);
            }
            if (dr.Table.Columns.Contains("STARTOTOMETER"))
            {
                mi.StartOdometer = FIDbAccess.GetFieldDouble(dr["STARTOTOMETER"], 0);
            }

            return mi;
        }

        #endregion

    }
}
