using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Web;
using Foresight.Data;
using Foresight.ServiceModel;
using IronIntel.Services.Business.Admin;
using IronIntel.Contractor.Machines;
using IronIntel.Services.MapView;
using Foresight.Fleet.Services.Asset;

namespace IronIntel.Contractor.MapView
{
    public class MachinesMapViewerManagement : MachineManagement
    {

        private const string MachineFields = "{0}MACHINEID,{0}MACHINENAME,{0}MAKEID,{0}MODELID,{0}TYPEID,{0}MACHINEICONID,{0}DEVICEID,{0}VIN,{0}MAKEYEAR,{0}NOTES,{0}STATUS,{0}CONTRACTORID,{0}DEALERID,{0}UID,{0}ADDEDON,{0}CUR_LONGITUDE,{0}CUR_LATITUDE,{0}LOCDATE_UTC,{0}ENGINEHOURS,{0}HOURSDATE_UTC,{0}DATASOURCE,{0}HIDE,{0}FUEL_CONSUMED,{0}FUEL_UNITS,{0}FUEL_DATE,{0}ODOMETER,{0}ODODATE_UTC,{0}ODOMETERUOM,{0}FUELCOST,{0}FUELCOSTUOM,{0}MACHINERATE,{0}WORKTYPE,{0}RETIREMENTHOURS,{0}RETIREMENTODO,{0}ALTITUDE,{0}ALTITUDEUNITS,{0}IDLEHOURSUTC,{0}IDLEHOURS,{0}LOADCOUNTUTC,{0}LOADCOUNT,{0}PAYLOADTOTALUTC,{0}PAYLOADTOTAL,{0}PAYLOADTOTALUNITS,{0}DEFREMAININGUTC,{0}DEFREMAINING,{0}FUELREMAININGUTC,{0}FUELREMAININGPERCENT,{0}MACHINENAME2,{0}ONROAD,{0}LEASESTART,{0}LEASEEND,{0}LEASEHOURS,{0}UNDERCARRIAGEHOURS,{0}ODOSTART2,{0}ISDELETED,{0}DELETEDDATE,{0}ODOSTART2DATASOURCE,{0}LOCDATASOURCE,{0}HOURSDATASOURCE,{0}FUELDATASOURCE,{0}AQUISITIONTYPE,{0}ICONFILENAME,{0}STARTINGENGINEHOURS,{0}DISTANCECALCBY,{0}TELEMATICSENABLED,{0}COSTCENTER,{0}EQCLASS,{0}DESCRIPTION,{0}MoveStatus,{0}DIRECTIONALHEADING";

        private static readonly List<string> Status_InMotion = new List<string> { "InMotion", "START", "PRIOD", "TOWING_START" };
        /// <summary>
        /// 根据Contractorid获取机器列表
        /// </summary>
        /// <returns></returns>
        public static MachineViewItem[] GetMachines(string sessionid, string companyid, string useriid, string filtertext, int onroad, MachineAlertViewQueryParameter param)
        {
            string companyid1 = string.IsNullOrWhiteSpace(companyid) ? SystemParams.CompanyID : companyid;
            MachineViewItem[] rst = GetMachineMapViewItem(sessionid, companyid1, useriid, filtertext, onroad);
            if (param == null || string.IsNullOrWhiteSpace(param.ViewID))
                return ProcessMachineIconUrl(rst);
            else
                return ProcessMachineIconUrl(rst, companyid1, param);
        }

        private static long[] ToMachineLongID(IEnumerable<string> machines)
        {
            List<long> ls = new List<long>();
            foreach (string s in machines)
            {
                ls.Add(Convert.ToInt64(s));
            }
            return ls.ToArray();
        }

        public static MachineViewItem[] GetMachines(string sessionid, string companyid, string useriid, MachineAlertViewQueryParameter param, string[] machines)
        {
            string companyid1 = string.IsNullOrWhiteSpace(companyid) ? SystemParams.CompanyID : companyid;
            MachineViewItem[] rst = GetMachineMapViewItems(sessionid, companyid1, useriid, ToMachineLongID(machines));
            if (param == null || string.IsNullOrWhiteSpace(param.ViewID))
                return ProcessMachineIconUrl(rst);
            else
                return ProcessMachineIconUrl(rst, companyid1, param);
        }

        public static MachineViewItem GetMachine(string sessionid, string companyid, string useriid, MachineAlertViewQueryParameter param, string machineid)
        {
            string companyid1 = string.IsNullOrWhiteSpace(companyid) ? SystemParams.CompanyID : companyid;
            MachineViewItem item = GetMachineMapViewItem(sessionid, companyid1, useriid, machineid);
            MachineViewItem[] result;
            if (param == null || string.IsNullOrWhiteSpace(param.ViewID))
                result = ProcessMachineIconUrl(new MachineViewItem[] { item });
            else
                result = ProcessMachineIconUrl(new MachineViewItem[] { item }, companyid1, param);
            if (result != null && result.Length > 0)
                return result[0];
            return null;
        }

        public static MachineViewItem GetMachineWithDatasource(string sessionid, string companyid, string useriid, string machineid, string datasource)
        {
            companyid = string.IsNullOrWhiteSpace(companyid) ? SystemParams.CompanyID : companyid;
            MachineViewItem item = GetMachineMapViewItem(companyid, useriid, machineid, datasource);
            MachineViewItem[] result = ProcessMachineIconUrl(new MachineViewItem[] { item });
            if (result != null && result.Length > 0)
            {
                item = result[0];
                var locs = FleetServiceClientHelper.CreateClient<AssetQueryClient>(companyid, sessionid).GetAssetCurrentLocation(companyid, item.ID);
                var loc = locs.FirstOrDefault(l => l.IsPrimary);
                if (loc != null)
                {
                    item.Location.Latitude = loc.Latitude;
                    item.Location.Longitude = loc.Longitude;
                    item.Location.LocationTime = loc.AsofTimeLocal;
                }
                return item;
            }
            return null;
        }

        private static Dictionary<string, List<MachineViewItem>> GetGroupAssets(string useriid, FISqlConnection db = null)
        {
            const string SQL = @"if(select count(1) from USERMACHINEGROUPMAP where USERIID={0})=0
            select a.MACHINEID,a.GROUPID,b.VIN,b.MACHINENAME,b.MACHINENAME2 from MACHINEGROUPMAP a,MACHINES b where a.MACHINEID=b.MACHINEID and ISNULL(b.HIDE,0)=0 
            else
            select a.MACHINEID,a.GROUPID,b.VIN,b.MACHINENAME,b.MACHINENAME2 from MACHINEGROUPMAP a,MACHINES b where a.MACHINEID=b.MACHINEID and ISNULL(b.HIDE,0)=0
            and b.MACHINEID in (select distinct MACHINEID from MACHINEGROUPMAP
            where GROUPID in (select GROUPID from USERMACHINEGROUPMAP where USERIID={0}))";

            if (db == null)
                db = SystemParams.GetDbInstance();
            DataTable dt = null;
            dt = db.GetDataTableBySQL(SQL, useriid);

            Dictionary<string, List<MachineViewItem>> result = new Dictionary<string, List<MachineViewItem>>(StringComparer.OrdinalIgnoreCase);
            if (dt.Rows.Count == 0)
            {
                return result;
            }
            foreach (DataRow dr in dt.Rows)
            {
                MachineViewItem mi = new MachineViewItem();
                mi.ID = FIDbAccess.GetFieldInt64(dr["MACHINEID"], 0);
                mi.Name = FIDbAccess.GetFieldString(dr["MACHINENAME"], string.Empty);
                mi.Name2 = FIDbAccess.GetFieldString(dr["MACHINENAME2"], string.Empty);
                mi.VIN = FIDbAccess.GetFieldString(dr["VIN"], string.Empty);
                string groupID = FIDbAccess.GetFieldString(dr["GROUPID"], string.Empty);
                if (!result.ContainsKey(groupID))
                    result[groupID] = new List<MachineViewItem>();
                result[groupID].Add(mi);
            }
            return result;
        }

        private static List<MachineViewItem> GetNoGroupAssets(FISqlConnection db = null)
        {
            const string SQL = @"select b.MACHINEID,b.VIN,b.MACHINENAME,b.MACHINENAME2 from MACHINES b where not exists(select 1 from MACHINEGROUPMAP a where a.MACHINEID=b.MACHINEID)";

            if (db == null)
                db = SystemParams.GetDbInstance();
            DataTable dt = db.GetDataTableBySQL(SQL);

            List<MachineViewItem> result = new List<MachineViewItem>();
            if (dt.Rows.Count == 0)
            {
                return result;
            }
            foreach (DataRow dr in dt.Rows)
            {
                MachineViewItem mi = new MachineViewItem();
                mi.ID = FIDbAccess.GetFieldInt64(dr["MACHINEID"], 0);
                mi.Name = FIDbAccess.GetFieldString(dr["MACHINENAME"], string.Empty);
                mi.Name2 = FIDbAccess.GetFieldString(dr["MACHINENAME2"], string.Empty);
                mi.VIN = FIDbAccess.GetFieldString(dr["VIN"], string.Empty);
                result.Add(mi);
            }
            return result;
        }

        private static ViewTemp GetMapAlertViewData(string companyid, string alertviewid)
        {
            if (string.IsNullOrWhiteSpace(alertviewid))
            {
                return null;
            }
            MapAlertLayerClient mc = SystemParams.GetMapAlertLayerClient();
            MapAlertViewItem view = mc.GetMapAlertView(alertviewid, true);
            if (view == null)
            {
                return null;
            }
            List<LayerDataTemp> ls = new List<LayerDataTemp>();
            foreach (MapAlertLayerItem layer in view.Layers)
            {
                LayerDataTemp ld = new LayerDataTemp();
                ld.Layer = layer;
                ld.Machines = GetAlertViewMachines(companyid, layer.ID);
                if (!string.IsNullOrWhiteSpace(layer.AlertSQL))
                {
                    ld.AlertDescriptions = GetAlertSQLResult(companyid, layer.ID);
                }
                ls.Add(ld);
            }
            ViewTemp tmp = new ViewTemp();
            tmp.Layers = ls.ToArray();
            return tmp;
        }

        private static MachineViewItem[] ProcessMachineIconUrl(MachineViewItem[] items)
        {
            const string DEFAULT_BACKCOLOR = "#FF000000";
            const string DEFAULT_DOTCOLOR = "#FF000000";
            const string DEFAULT_COLOR_InMotion = "#FF008000";//Color.Green
            const string PARAM = "?typeid={0}&bkcolor={1}&dotcolor={2}&move={3}&angle={4}&sn={5}";
            const string PARAMMACHINE = "?mid={0}&typeid={1}&bkcolor={2}&dotcolor={3}&move={4}&angle={5}&sn={6}";

            if (items.Count() == 0)
            {
                return new MachineViewItem[0];
            }

            string path = SystemParams.MachineTypeMapViewIconUrl;
            foreach (MachineViewItem item in items)
            {
                string pcolor = HttpUtility.UrlEncode(DEFAULT_BACKCOLOR);
                string scolor = HttpUtility.UrlEncode(DEFAULT_DOTCOLOR);
                if (Status_InMotion.Contains(item.MoveStatus, StringComparer.OrdinalIgnoreCase) && item.Directionalheading >= 0)
                    scolor = HttpUtility.UrlEncode(DEFAULT_COLOR_InMotion);

                if (!string.IsNullOrWhiteSpace(item.IconFileName))
                    item.IconUrl = path + string.Format(PARAMMACHINE, item.ID, item.TypeID, pcolor, scolor, item.MoveStatus, item.Directionalheading, DateTime.Now.Ticks);
                else
                    item.IconUrl = path + string.Format(PARAM, item.TypeID, pcolor, scolor, item.MoveStatus, item.Directionalheading, DateTime.Now.Ticks);
                item.EmptyIconUrl = path + string.Format(PARAM, "-1", pcolor, scolor, item.MoveStatus, item.Directionalheading, DateTime.Now.Ticks);

            }
            return items;
        }

        private static MachineViewItem[] ProcessMachineIconUrl(MachineViewItem[] items, string companyid, MachineAlertViewQueryParameter param)
        {
            const string DEFAULT_BACKCOLOR = "#FF000000";
            const string DEFAULT_DOTCOLOR = "#FF000000";
            const string DEFAULT_COLOR_InMotion = "#FF008000";//Color.Green
            const string PARAM = "?typeid={0}&bkcolor={1}&dotcolor={2}&move={3}&angle={4}&sn={5}";
            const string PARAMMACHINE = "?mid={0}&typeid={1}&bkcolor={2}&dotcolor={3}&move={4}&angle={5}&sn={6}";

            if (items.Count() == 0)
            {
                return new MachineViewItem[0];
            }

            string path = SystemParams.MachineTypeMapViewIconUrl;

            MachineAlertViewQueryResult result = null;
            if (param != null)
            {
                MachineAlertViewClient mc = GetMachineAlertViewClient();
                result = mc.QueryMachineAlertView(companyid, param.ViewID, param);
            }

            List<MachineViewItem> list = new List<MachineViewItem>();
            foreach (MachineViewItem item in items)
            {
                long machineid = Convert.ToInt64(item.ID);
                MachineAlertViewLayerQueryResult primarylayer = null;
                MachineAlertViewLayerQueryResult secondlayer = null;
                if (result != null)
                {
                    primarylayer = result.GetLayer(machineid, true);
                    secondlayer = result.GetLayer(machineid, false);
                }
                if ((primarylayer == null) && (secondlayer == null))
                {
                    continue;//如果机器没有出现在alert view当中，则不在地图上显示
                }

                list.Add(item);
                string pcolor = HttpUtility.UrlEncode(primarylayer == null ? DEFAULT_BACKCOLOR : primarylayer.Layer.IconColor);
                string scolor = "";
                if (Status_InMotion.Contains(item.MoveStatus, StringComparer.OrdinalIgnoreCase) && item.Directionalheading >= 0)//InMotion
                {
                    scolor = HttpUtility.UrlEncode(secondlayer == null ? DEFAULT_COLOR_InMotion : secondlayer.Layer.IconColor);
                }
                else
                {
                    scolor = HttpUtility.UrlEncode(secondlayer == null ? DEFAULT_DOTCOLOR : secondlayer.Layer.IconColor);
                }

                if (!string.IsNullOrWhiteSpace(item.IconFileName))
                    item.IconUrl = path + string.Format(PARAMMACHINE, item.ID, item.TypeID, pcolor, scolor, item.MoveStatus, item.Directionalheading, DateTime.Now.Ticks);
                else
                    item.IconUrl = path + string.Format(PARAM, item.TypeID, pcolor, scolor, item.MoveStatus, item.Directionalheading, DateTime.Now.Ticks);
                item.EmptyIconUrl = path + string.Format(PARAM, -1, pcolor, scolor, item.MoveStatus, item.Directionalheading, DateTime.Now.Ticks);
                if (primarylayer != null)
                    item.MapAlertLayerPriority = primarylayer.Layer.Priority;
                if (primarylayer != null)
                {
                    item.AlertTip = primarylayer.GetAlertTip(machineid);
                }
                if (secondlayer != null)
                {
                    if (string.IsNullOrWhiteSpace(item.AlertTip))
                    {
                        item.AlertTip = secondlayer.GetAlertTip(machineid);
                    }
                    else
                    {
                        item.AlertTip = item.AlertTip + "\r\n" + secondlayer.GetAlertTip(machineid);
                    }
                }
            }

            return list.ToArray();
        }

        private static long[] GetAlertViewMachines(string companyid, string alertlayerid)
        {
            if (string.IsNullOrWhiteSpace(companyid) || string.IsNullOrWhiteSpace(alertlayerid))
            {
                return new long[0];
            }
            try
            {
                MapAlertLayerClient mc = SystemParams.GetMapAlertLayerClient();
                return mc.GetCriteriaMachines(companyid, alertlayerid);
            }
            catch (Exception ex)
            {
                SystemParams.WriteLog("Error", typeof(MachinesMapViewerManagement).FullName + ".GetAlertViewMachines(string companyid, string alertlayerid)", ex.Message, ex.ToString());
                return new long[0];
            }
        }

        private static StringKeyValue[] GetAlertSQLResult(string companyid, string alertlayerid)
        {
            if (string.IsNullOrWhiteSpace(companyid) || string.IsNullOrWhiteSpace(alertlayerid))
            {
                return new StringKeyValue[0];
            }
            try
            {
                MapAlertLayerClient mc = SystemParams.GetMapAlertLayerClient();
                return mc.GetAlertDescriptionResult(companyid, alertlayerid);
            }
            catch (Exception ex)
            {
                SystemParams.WriteLog("Error", typeof(MachinesMapViewerManagement).FullName + ".GetAlertSQLResult(string companyid, string alertlayerid)", ex.Message, ex.ToString());
                return new StringKeyValue[0];
            }
        }


        private static MachineViewItem[] GetMachineMapViewItem(string sessionid, string companyid, string useriid, string filtertext, int onroad)
        {
            string SQL_M = "select " + string.Format(MachineFields, "") + " from MACHINES where ISNULL(HIDE,0)=0";

            const string SQL_L = @"select AssetId as MACHINEID,LATITUDE,LONGITUDE,AsofTime as ASOFTIME_UTC,MOVESTATUS,HEADING, Speed,SpeedUnits,PostedSpeedLimit,SpeedLimitUnits,Street from AssetLocation where IsPrimary=1";
            const string SQL_EH = @"select * from
(select AssetId as MACHINEID,AsofTime as ASOFTIME_UTC,Amount,UOM,ROW_NUMBER() over(partition by AssetId order by AsofTime desc) as RowIndex from AssetEngineHours where Datasource<>'Calamp') t
where RowIndex=1";

            FISqlConnection db = SystemParams.GetCompanyDbConnection(companyid);
            if (db == null)
            {
                return new MachineViewItem[0];
            }
            DataTable tb = db.GetDataTableBySQL(SQL_M, useriid);
            if (tb.Rows.Count == 0)
            {
                return new MachineViewItem[0];
            }

            double timeadjust = SystemParams.GetHoursOffset();
            DataTable tbl = null;
            DataTable tbeh = null;
            string dbString2 = SystemParams.GetIronIntelReportDataDbString(companyid);
            if (!string.IsNullOrWhiteSpace(dbString2))
            {
                var db2 = new FISqlConnection(dbString2);
                tbl = db2.GetDataTableBySQL(SQL_L);
                //tbeh = db2.GetDataTableBySQL(SQL_EH);
            }

            Dictionary<long, AssetLocation> machineLocations = new Dictionary<long, AssetLocation>();
            if (tbl != null && tbl.Rows.Count > 0)
            {
                foreach (DataRow dr in tbl.Rows)
                {
                    long mID = FIDbAccess.GetFieldInt64(dr["MACHINEID"], 0);
                    var ml = new AssetLocation();
                    ml.Location = new LocationViewItem();
                    ml.Location.Latitude = FIDbAccess.GetFieldDouble(dr["LATITUDE"], 0);
                    ml.Location.Longitude = FIDbAccess.GetFieldDouble(dr["LONGITUDE"], 0);
                    ml.Location.LocationTime = FIDbAccess.GetFieldDateTime(dr["ASOFTIME_UTC"], DateTime.MinValue);
                    if (ml.Location.LocationTime != DateTime.MinValue)
                        ml.Location.LocationTime = ml.Location.LocationTime.AddHours(timeadjust);

                    ml.MoveStatus = FIDbAccess.GetFieldString(dr["MOVESTATUS"], string.Empty);
                    ml.Directionalheading = FIDbAccess.GetFieldInt(dr["HEADING"], -1);
                    ml.Location.Speed = FIDbAccess.GetFieldDouble(dr["Speed"], -1);
                    ml.Location.SpeedUnit = FIDbAccess.GetFieldString(dr["SpeedUnits"], string.Empty);
                    ml.Location.PostedSpeed = FIDbAccess.GetFieldDouble(dr["PostedSpeedLimit"], -1);
                    ml.Location.PostedSpeedUnit = FIDbAccess.GetFieldString(dr["SpeedLimitUnits"], string.Empty);
                    ml.Location.Street = FIDbAccess.GetFieldString(dr["Street"], string.Empty);

                    machineLocations[mID] = ml;
                }
            }

            //Dictionary<string, AssetEngineHour> machineEngineHours = new Dictionary<string, AssetEngineHour>();
            //if (tbeh != null && tbeh.Rows.Count > 0)
            //{
            //    foreach (DataRow dr in tbeh.Rows)
            //    {
            //        string mID = FIDbAccess.GetFieldString(dr["MACHINEID"], string.Empty);
            //        var meh = new AssetEngineHour();
            //        meh.EngineHours = FIDbAccess.GetFieldDouble(dr["Amount"], -1);
            //        string uom = FIDbAccess.GetFieldString(dr["UOM"], string.Empty);
            //        if (uom.ToLower() == "s")
            //            meh.EngineHours = meh.EngineHours / 3600;
            //        meh.EngineHoursDate = FIDbAccess.GetFieldDateTime(dr["ASOFTIME_UTC"], DateTime.MinValue);
            //        if (meh.EngineHoursDate != DateTime.MinValue)
            //            meh.EngineHoursDate = meh.EngineHoursDate.AddHours(timeadjust);

            //        machineEngineHours[mID] = meh;
            //    }
            //}

            var mids = tb.AsEnumerable().Select(c => c.Field<long>("MACHINEID")).ToArray();
            var client = FleetServiceClientHelper.CreateClient<AssetQueryClient>(companyid, sessionid);
            var ehs = client.GetAssetsCurrentPrimaryEngineHours(companyid, mids);
            var odos = client.GetAssetsCurrentPrimaryOdometer(companyid, mids);

            long[] availableAssetsids = null;
            var user = Users.UserManagement.GetUserByIID(useriid);
            if (user.UserType < Users.UserTypes.Admin)
                availableAssetsids = client.GetAvailableAssetsForUsers(companyid, useriid);

            RefreshBaseData();
            MachineMake[] makes = GetMachineMakes();
            MachineModel[] models = GetMachineModels();
            MachineType[] types = GetMachineTypes();
            List<MachineViewItem> ls = new List<MachineViewItem>();
            if (tb.Rows.Count > 0)
            {
                var groupassets = GetGroupsAssets(db);
                foreach (DataRow dr in tb.Rows)
                {
                    long mid = FIDbAccess.GetFieldInt64(dr["MACHINEID"], 0);
                    if (user.UserType < Users.UserTypes.Admin && !availableAssetsids.Contains(mid))
                        continue;
                    MachineViewItem mi = ConvertToMachineViewItem(dr, makes, models, types, timeadjust);
                    if (onroad >= 0 && onroad != mi.Onroad)
                        continue;

                    if (!string.IsNullOrWhiteSpace(filtertext)
                        && !Contains(mi.Name, filtertext)
                        && !Contains(mi.Name2.ToString(), filtertext)
                        && !Contains(mi.VIN.ToString(), filtertext)
                        && !Contains(mi.ID.ToString(), filtertext)
                        && !Contains(mi.Make, filtertext)
                        && !Contains(mi.MachineType, filtertext)
                        && !Contains(mi.Model, filtertext))
                    {
                        continue;
                    }

                    if (groupassets.ContainsKey(Convert.ToInt32(mi.ID)))
                    {
                        var groups = groupassets[Convert.ToInt32(mi.ID)].ToArray();
                        mi.AssetGroupNames = string.Join(", ", groups.Select(m => m.Value));
                    }
                    else
                        mi.AssetGroupNames = string.Empty;

                    if (machineLocations.ContainsKey(mi.ID))
                    {
                        var ml = machineLocations[mi.ID];
                        mi.Location = ml.Location;
                        mi.MoveStatus = ml.MoveStatus;
                        mi.Directionalheading = ml.Directionalheading;
                    }

                    ConvertSpeedUnitToMile(mi.Location);
                    //if (machineEngineHours.ContainsKey(mi.ID))
                    //{
                    //    var meh = machineEngineHours[mi.ID];
                    //    mi.EngineHours = meh.EngineHours;
                    //    mi.EngineHoursDate = meh.EngineHoursDate;
                    //}
                    if (ehs != null && ehs.Length > 0)
                    {
                        var eh = ehs.FirstOrDefault((o) => o.AssetID == mi.ID);
                        if (eh != null)
                        {
                            mi.EngineHours = eh.Corrected;
                            mi.EngineHoursDate = eh.AsofTimeLocal;
                        }
                    }

                    if (odos != null && odos.Length > 0)
                    {
                        var odo = odos.FirstOrDefault((o) => o.AssetID == mi.ID);
                        if (odo != null)
                        {
                            mi.Odometer = odo.Corrected;
                            mi.OdometerUOM = odo.UOM;
                        }
                    }
                    ls.Add(mi);
                }
            }
            return ls.ToArray();
        }

        private static MachineViewItem[] GetMachineMapViewItems(string sessionid, string companyid, string useriid, long[] machinids)
        {
            string SQL = "select " + string.Format(MachineFields, "") + " from MACHINES where MACHINEID in({MIDS}) and ISNULL(HIDE,0)=0";

            const string SQL_L = @"select AssetId as MACHINEID,LATITUDE,LONGITUDE,AsofTime as ASOFTIME_UTC,MOVESTATUS,HEADING, Speed,SpeedUnits,PostedSpeedLimit,SpeedLimitUnits,Street from AssetLocation where IsPrimary=1 and AssetId in({MIDS})";
            const string SQL_EH = @"select * from
(select AssetId as MACHINEID,AsofTime as ASOFTIME_UTC,Amount,UOM,ROW_NUMBER() over(partition by AssetId order by AsofTime desc) as RowIndex from AssetEngineHours where AssetId in({MIDS}) and Datasource<>'Calamp') t
where RowIndex=1";

            FISqlConnection db = SystemParams.GetCompanyDbConnection(companyid);
            if (db == null)
            {
                return new MachineViewItem[0];
            }
            string wh = string.Empty;
            foreach (long id in machinids)
            {
                if (string.IsNullOrWhiteSpace(wh))
                {
                    wh = id.ToString();
                }
                else
                {
                    wh = wh + "," + id.ToString();
                }
            }
            DataTable tb = db.GetDataTableBySQL(SQL.Replace("{MIDS}", wh), useriid);
            if (tb.Rows.Count == 0)
            {
                return new MachineViewItem[0];
            }

            double timeadjust = SystemParams.GetHoursOffset();
            DataTable tbl = null;
            DataTable tbeh = null;
            string dbString2 = SystemParams.GetIronIntelReportDataDbString(companyid);
            if (!string.IsNullOrWhiteSpace(dbString2))
            {
                var db2 = new FISqlConnection(dbString2);
                tbl = db2.GetDataTableBySQL(SQL_L.Replace("{MIDS}", wh));
                //tbeh = db2.GetDataTableBySQL(SQL_EH.Replace("{MIDS}", wh));
            }

            Dictionary<long, AssetLocation> machineLocations = new Dictionary<long, AssetLocation>();
            if (tbl != null && tbl.Rows.Count > 0)
            {
                foreach (DataRow dr in tbl.Rows)
                {
                    long mID = FIDbAccess.GetFieldInt64(dr["MACHINEID"], 0);
                    var ml = new AssetLocation();
                    ml.Location = new LocationViewItem();
                    ml.Location.Latitude = FIDbAccess.GetFieldDouble(dr["LATITUDE"], 0);
                    ml.Location.Longitude = FIDbAccess.GetFieldDouble(dr["LONGITUDE"], 0);
                    ml.Location.LocationTime = FIDbAccess.GetFieldDateTime(dr["ASOFTIME_UTC"], DateTime.MinValue);
                    if (ml.Location.LocationTime != DateTime.MinValue)
                        ml.Location.LocationTime = ml.Location.LocationTime.AddHours(timeadjust);

                    ml.MoveStatus = FIDbAccess.GetFieldString(dr["MOVESTATUS"], string.Empty);
                    ml.Directionalheading = FIDbAccess.GetFieldInt(dr["HEADING"], -1);
                    ml.Location.Speed = FIDbAccess.GetFieldDouble(dr["Speed"], -1);
                    ml.Location.SpeedUnit = FIDbAccess.GetFieldString(dr["SpeedUnits"], string.Empty);
                    ml.Location.PostedSpeed = FIDbAccess.GetFieldDouble(dr["PostedSpeedLimit"], -1);
                    ml.Location.PostedSpeedUnit = FIDbAccess.GetFieldString(dr["SpeedLimitUnits"], string.Empty);
                    ml.Location.Street = FIDbAccess.GetFieldString(dr["Street"], string.Empty);

                    machineLocations[mID] = ml;
                }
            }

            //Dictionary<string, AssetEngineHour> machineEngineHours = new Dictionary<string, AssetEngineHour>();
            //if (tbeh != null && tbeh.Rows.Count > 0)
            //{
            //    foreach (DataRow dr in tbeh.Rows)
            //    {
            //        string mID = FIDbAccess.GetFieldString(dr["MACHINEID"], string.Empty);
            //        var meh = new AssetEngineHour();
            //        meh.EngineHours = FIDbAccess.GetFieldDouble(dr["Amount"], -1);
            //        string uom = FIDbAccess.GetFieldString(dr["UOM"], string.Empty);
            //        if (uom.ToLower() == "s")
            //            meh.EngineHours = meh.EngineHours / 3600;
            //        meh.EngineHoursDate = FIDbAccess.GetFieldDateTime(dr["ASOFTIME_UTC"], DateTime.MinValue);
            //        if (meh.EngineHoursDate != DateTime.MinValue)
            //            meh.EngineHoursDate = meh.EngineHoursDate.AddHours(timeadjust);

            //        machineEngineHours[mID] = meh;
            //    }
            //}
            var client = FleetServiceClientHelper.CreateClient<AssetQueryClient>(companyid, sessionid);
            var ehs = client.GetAssetsCurrentPrimaryEngineHours(companyid, machinids);
            var odos = client.GetAssetsCurrentPrimaryOdometer(companyid, machinids);

            long[] availableAssetsids = null;
            var user = Users.UserManagement.GetUserByIID(useriid);
            if (user.UserType < Users.UserTypes.Admin)
                availableAssetsids = client.GetAvailableAssetsForUsers(companyid, useriid);

            MachineMake[] makes = GetMachineMakes();
            MachineModel[] models = GetMachineModels();
            MachineType[] types = GetMachineTypes();
            List<MachineViewItem> ls = new List<MachineViewItem>();
            if (tb.Rows.Count > 0)
            {
                var groupassets = GetGroupsAssets(db);
                foreach (DataRow dr in tb.Rows)
                {
                    long mid = FIDbAccess.GetFieldInt64(dr["MACHINEID"], 0);
                    if (user.UserType < Users.UserTypes.Admin && !availableAssetsids.Contains(mid))
                        continue;

                    MachineViewItem mi = ConvertToMachineViewItem(dr, makes, models, types, timeadjust);

                    if (groupassets.ContainsKey(Convert.ToInt32(mi.ID)))
                    {
                        var groups = groupassets[Convert.ToInt32(mi.ID)].ToArray();
                        mi.AssetGroupNames = string.Join(", ", groups.Select(m => m.Value));
                    }
                    else
                        mi.AssetGroupNames = string.Empty;

                    if (machineLocations.ContainsKey(mi.ID))
                    {
                        var ml = machineLocations[mi.ID];
                        mi.Location = ml.Location;
                        mi.MoveStatus = ml.MoveStatus;
                        mi.Directionalheading = ml.Directionalheading;
                    }

                    ConvertSpeedUnitToMile(mi.Location);
                    //if (machineEngineHours.ContainsKey(mi.ID))
                    //{
                    //    var meh = machineEngineHours[mi.ID];
                    //    mi.EngineHours = meh.EngineHours;
                    //    mi.EngineHoursDate = meh.EngineHoursDate;
                    //}

                    if (ehs != null && ehs.Length > 0)
                    {
                        var eh = ehs.FirstOrDefault((o) => o.AssetID == mi.ID);
                        if (eh != null)
                        {
                            mi.EngineHours = eh.Corrected;
                        }
                    }

                    if (odos != null && odos.Length > 0)
                    {
                        var odo = odos.FirstOrDefault((o) => o.AssetID == mi.ID);
                        if (odo != null)
                        {
                            mi.Odometer = odo.Corrected;
                            mi.OdometerUOM = odo.UOM;
                        }
                    }
                    ls.Add(mi);
                }
            }
            return ls.ToArray();
        }

        private static MachineViewItem GetMachineMapViewItem(string sessionid, string companyid, string useriid, string machineid, string datasource = "")
        {
            string SQL = "select " + string.Format(MachineFields, "") + " from MACHINES where MACHINEID={1}";

            const string SQL_L = @"select AssetId as MACHINEID,LATITUDE,LONGITUDE,AsofTime as ASOFTIME_UTC,MOVESTATUS,HEADING, Speed,SpeedUnits,PostedSpeedLimit,SpeedLimitUnits,Street from AssetLocation where IsPrimary=1 and AssetId={0}";
            const string SQL_L_Datasource = @"select top 1 a.AssetId as MACHINEID,LATITUDE,LONGITUDE,AsofTime as ASOFTIME_UTC,MOVESTATUS,HEADING,Speed,SpeedUnits,PostedSpeedLimit,SpeedLimitUnits,Street from AssetLocation a where a.AssetId={0} and a.Datasource={1} order by AsofTime desc";

            const string SQL_EH = @"select * from
(select AssetId as MACHINEID,AsofTime as ASOFTIME_UTC,Amount,UOM,ROW_NUMBER() over(partition by AssetId order by AsofTime desc) as RowIndex from AssetEngineHours where AssetId={0} and Datasource<>'Calamp') t
where RowIndex=1";
            FISqlConnection db = SystemParams.GetCompanyDbConnection(companyid);
            if (db == null)
            {
                return null;
            }
            DataTable tb = db.GetDataTableBySQL(SQL, useriid, machineid);
            if (tb.Rows.Count == 0)
            {
                return null;
            }
            DataTable tbl = null;
            DataTable tbeh = null;
            string dbString2 = SystemParams.GetIronIntelReportDataDbString(companyid);
            if (!string.IsNullOrWhiteSpace(dbString2))
            {
                var db2 = new FISqlConnection(dbString2);
                if (string.IsNullOrEmpty(datasource))
                    tbl = db2.GetDataTableBySQL(SQL_L, machineid);
                else
                    tbl = db2.GetDataTableBySQL(SQL_L_Datasource, machineid, datasource);
                //tbeh = db2.GetDataTableBySQL(SQL_EH, machineid);
            }

            double timeadjust = SystemParams.GetHoursOffset();
            AssetLocation machineLocation = null;
            if (tbl != null && tbl.Rows.Count > 0)
            {
                DataRow dr = tbl.Rows[0];
                string mID = FIDbAccess.GetFieldString(dr["MACHINEID"], string.Empty);
                var ml = new AssetLocation();
                ml.Location = new LocationViewItem();
                ml.Location.Latitude = FIDbAccess.GetFieldDouble(dr["LATITUDE"], 0);
                ml.Location.Longitude = FIDbAccess.GetFieldDouble(dr["LONGITUDE"], 0);
                ml.Location.LocationTime = FIDbAccess.GetFieldDateTime(dr["ASOFTIME_UTC"], DateTime.MinValue);
                if (ml.Location.LocationTime != DateTime.MinValue)
                    ml.Location.LocationTime = ml.Location.LocationTime.AddHours(timeadjust);

                ml.MoveStatus = FIDbAccess.GetFieldString(dr["MOVESTATUS"], string.Empty);
                ml.Directionalheading = FIDbAccess.GetFieldInt(dr["HEADING"], -1);
                ml.Location.Speed = FIDbAccess.GetFieldDouble(dr["Speed"], -1);
                ml.Location.SpeedUnit = FIDbAccess.GetFieldString(dr["SpeedUnits"], string.Empty);
                ml.Location.PostedSpeed = FIDbAccess.GetFieldDouble(dr["PostedSpeedLimit"], -1);
                ml.Location.PostedSpeedUnit = FIDbAccess.GetFieldString(dr["SpeedLimitUnits"], string.Empty);
                ml.Location.Street = FIDbAccess.GetFieldString(dr["Street"], string.Empty);

                machineLocation = ml;
            }

            //AssetEngineHour machineEngineHour = null;
            //if (tbeh != null && tbeh.Rows.Count > 0)
            //{
            //    DataRow dr = tbeh.Rows[0];
            //    string mID = FIDbAccess.GetFieldString(dr["MACHINEID"], string.Empty);
            //    var meh = new AssetEngineHour();
            //    meh.EngineHours = FIDbAccess.GetFieldDouble(dr["Amount"], -1);
            //    string uom = FIDbAccess.GetFieldString(dr["UOM"], string.Empty);
            //    if (uom.ToLower() == "s")
            //        meh.EngineHours = meh.EngineHours / 3600;
            //    meh.EngineHoursDate = FIDbAccess.GetFieldDateTime(dr["ASOFTIME_UTC"], DateTime.MinValue);
            //    if (meh.EngineHoursDate != DateTime.MinValue)
            //        meh.EngineHoursDate = meh.EngineHoursDate.AddHours(timeadjust);

            //    machineEngineHour = meh;
            //}

            var client = FleetServiceClientHelper.CreateClient<AssetQueryClient>(companyid, sessionid);
            var ehs = client.GetAssetsCurrentPrimaryEngineHours(companyid, new long[] { long.Parse(machineid) });
            var odos = client.GetAssetsCurrentPrimaryOdometer(companyid, new long[] { long.Parse(machineid) });

            MachineMake[] makes = GetMachineMakes();
            MachineModel[] models = GetMachineModels();
            MachineType[] types = GetMachineTypes();
            if (tb.Rows.Count > 0)
            {
                var groupassets = GetGroupsAssets(db);

                DataRow dr = tb.Rows[0];
                MachineViewItem mi = ConvertToMachineViewItem(dr, makes, models, types, timeadjust);

                if (groupassets.ContainsKey(Convert.ToInt32(mi.ID)))
                {
                    var groups = groupassets[Convert.ToInt32(mi.ID)].ToArray();
                    mi.AssetGroupNames = string.Join(", ", groups.Select(m => m.Value));
                }
                else
                    mi.AssetGroupNames = string.Empty;

                if (machineLocation != null)
                {
                    var ml = machineLocation;
                    mi.Location = ml.Location;
                    mi.MoveStatus = ml.MoveStatus;
                    mi.Directionalheading = ml.Directionalheading;
                }

                ConvertSpeedUnitToMile(mi.Location);
                //if (machineEngineHour != null)
                //{
                //    var meh = machineEngineHour;
                //    mi.EngineHours = meh.EngineHours;
                //    mi.EngineHoursDate = meh.EngineHoursDate;
                //}

                if (ehs != null && ehs.Length > 0)
                {
                    var eh = ehs.FirstOrDefault((o) => o.AssetID == mi.ID);
                    if (eh != null)
                    {
                        mi.EngineHours = eh.Corrected;
                    }
                }

                if (odos != null && odos.Length > 0)
                {
                    var odo = odos.FirstOrDefault((o) => o.AssetID == mi.ID);
                    if (odo != null)
                    {
                        mi.Odometer = odo.Corrected;
                        mi.OdometerUOM = odo.UOM;
                    }
                }

                return mi;
            }

            return null;
        }

        private static MachineViewItem ConvertToMachineViewItem(DataRow dr, MachineMake[] makes, MachineModel[] models, MachineType[] types, double timeadjust)
        {
            MachineViewItem mi = new MachineViewItem();
            mi.ID = FIDbAccess.GetFieldInt64(dr["MACHINEID"], 0);
            mi.Name = FIDbAccess.GetFieldString(dr["MACHINENAME"], string.Empty);
            mi.Name2 = FIDbAccess.GetFieldString(dr["MACHINENAME2"], string.Empty);
            mi.VIN = FIDbAccess.GetFieldString(dr["VIN"], string.Empty);
            mi.MakeYear = FIDbAccess.GetFieldInt(dr["MAKEYEAR"], 0);
            mi.EngineHours = FIDbAccess.GetFieldDouble(dr["ENGINEHOURS"], 0);
            mi.EngineHoursDate = FIDbAccess.GetFieldDateTime(dr["HOURSDATE_UTC"], DateTime.MinValue);
            if (mi.EngineHoursDate != DateTime.MinValue)
                mi.EngineHoursDate = mi.EngineHoursDate.AddHours(timeadjust);

            mi.Location = new LocationViewItem();
            mi.Location.Latitude = FIDbAccess.GetFieldDouble(dr["CUR_LATITUDE"], 0);
            mi.Location.Longitude = FIDbAccess.GetFieldDouble(dr["CUR_LONGITUDE"], 0);
            mi.Location.LocationTime = FIDbAccess.GetFieldDateTime(dr["LOCDATE_UTC"], DateTime.MinValue);
            if (mi.Location.LocationTime != DateTime.MinValue)
                mi.Location.LocationTime = mi.Location.LocationTime.AddHours(timeadjust);

            mi.Odometer = FIDbAccess.GetFieldDouble(dr["ODOMETER"], 0);
            mi.OdometerUOM = FIDbAccess.GetFieldString(dr["ODOMETERUOM"], string.Empty);
            mi.IconFileName = FIDbAccess.GetFieldString(dr["ICONFILENAME"], string.Empty);
            mi.Onroad = FIDbAccess.GetFieldInt(dr["ONROAD"], 0);

            mi.MoveStatus = FIDbAccess.GetFieldString(dr["MOVESTATUS"], string.Empty);
            mi.Directionalheading = FIDbAccess.GetFieldInt(dr["DIRECTIONALHEADING"], -1);

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

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

            int typeid = FIDbAccess.GetFieldInt(dr["TYPEID"], 0);
            mi.TypeID = typeid;
            MachineType mtype = GetMachineType(types, typeid);
            if (mtype != null)
            {
                mi.MachineType = mtype.Name;
                mi.IconUrl = mtype.IconUrl;
            }
            else
            {
                mi.MachineType = string.Empty;
                mi.IconUrl = DefaultMachineTypeIconUrl;
            }
            return mi;
        }

        public static MachineViewItem GetMachineViewItem(string companyid, long machineid)
        {
            string SQL = "select " + string.Format(MachineFields, "") + " from MACHINES where MACHINEID={0}";

            FISqlConnection db = SystemParams.GetCompanyDbConnection(companyid);
            if (db == null)
            {
                return null;
            }
            DataTable tb = db.GetDataTableBySQL(SQL, machineid);
            if (tb.Rows.Count == 0)
            {
                return null;
            }
            RefreshBaseData();
            MachineMake[] makes = GetMachineMakes();
            MachineModel[] models = GetMachineModels();
            MachineType[] types = GetMachineTypes();

            double timeadjust = SystemParams.GetHoursOffset();
            MachineViewItem mi = ConvertToMachineViewItem(tb.Rows[0], makes, models, types, timeadjust);

            SQL = "select string_agg(g.GROUPNAME,',') from MACHINEGROUPMAP mg left join MACHINEGROUPS g on mg.GROUPID=g.GROUPID where mg.MACHINEID={0} group by mg.MACHINEID";
            mi.AssetGroupNames = FIDbAccess.GetFieldString(db.GetRC1BySQL(SQL, machineid), "");

            return mi;
        }

        public static MachineLocationHistoryViewItem GetMachineLocation(string machineid, DateTime startTime, DateTime endTime, string companyid, bool notShow00loc, string datasource)
        {
            const string SQL = "select LATITUDE,LONGITUDE,EVENTTIME_UTC from MACHINE_EVENTS where MACHINEID={0} and EVENTTIME_UTC>={1} and EVENTTIME_UTC<={2} order by EVENTTIME_UTC";
            const string SQL_L = "select LATITUDE,LONGITUDE, AsofTime as EVENTTIME_UTC,Speed,SpeedUnits,PostedSpeedLimit,SpeedLimitUnits,Street from AssetLocationHis where AssetId={0} and AsofTime>={1} and AsofTime<={2} and Datasource=(select top 1 from AssetLocation where AssetId={0} and IsPrimary=1) order by AsofTime";
            const string SQL_L_Datasource = "select LATITUDE,LONGITUDE, AsofTime as EVENTTIME_UTC,Speed,SpeedUnits,PostedSpeedLimit,SpeedLimitUnits,Street from AssetLocationHis where AssetId={0} and AsofTime>={1} and AsofTime<={2} and Datasource={3} order by AsofTime";
            const string SQL_EXISTS = "select COUNT(1) from AssetLocationHis where AssetId={0}";

            if (string.IsNullOrEmpty(companyid))
                companyid = SystemParams.CompanyID;

            MachineViewItem machine = GetMachineViewItem(companyid, Convert.ToInt64(machineid));//暂时确定为取本单位的机器，因为Dealer目前不显示机器的历史位置       
            if (machine == null)
            {
                return null;
            }

            FISqlConnection db = SystemParams.GetCompanyDbConnection(companyid);//暂时确定为取本单位的机器，因为Dealer目前不显示机器的历史位置    
            DataTable tb = null;
            string dbString2 = SystemParams.GetIronIntelReportDataDbString(companyid);
            if (!string.IsNullOrWhiteSpace(dbString2))
            {
                var db2 = new FISqlConnection(dbString2);
                object obj = db2.GetRC1BySQL(SQL_EXISTS, machineid);
                if (Convert.ToInt32(obj) > 0)
                    if (string.IsNullOrEmpty(datasource))
                        tb = db2.GetDataTableBySQL(SQL_L, machineid, startTime.ToUniversalTime(), endTime.ToUniversalTime());
                    else
                        tb = db2.GetDataTableBySQL(SQL_L_Datasource, machineid, startTime.ToUniversalTime(), endTime.ToUniversalTime(), datasource);
                else
                    tb = db.GetDataTableBySQL(SQL, machineid, startTime.ToUniversalTime(), endTime.ToUniversalTime());
            }
            else
                tb = db.GetDataTableBySQL(SQL, machineid, startTime.ToUniversalTime(), endTime.ToUniversalTime());

            List<LocationViewItem> ls = new List<LocationViewItem>();
            double timeOffset = SystemParams.GetHoursOffset();
            foreach (DataRow dr in tb.Rows)
            {
                double lat = FIDbAccess.GetFieldDouble(dr["LATITUDE"], 0);
                double lon = FIDbAccess.GetFieldDouble(dr["LONGITUDE"], 0);
                if (notShow00loc && lat == 0 && lon == 0)
                    continue;
                LocationViewItem li = new LocationViewItem();
                li.Latitude = lat;
                li.Longitude = lon;
                li.LocationTime = FIDbAccess.GetFieldDateTime(dr["EVENTTIME_UTC"], DateTime.Now);
                li.LocationTime = li.LocationTime.AddHours(timeOffset);

                if (tb.Columns.Count > 3)
                {
                    li.Speed = FIDbAccess.GetFieldDouble(dr["Speed"], -1);
                    li.SpeedUnit = FIDbAccess.GetFieldString(dr["SpeedUnits"], string.Empty);
                    li.PostedSpeed = FIDbAccess.GetFieldDouble(dr["PostedSpeedLimit"], -1);
                    li.PostedSpeedUnit = FIDbAccess.GetFieldString(dr["SpeedLimitUnits"], string.Empty);
                    li.Street = FIDbAccess.GetFieldString(dr["Street"], string.Empty);
                }
                ConvertSpeedUnitToMile(li);
                ls.Add(li);
            }
            MachineLocationHistoryViewItem ml = new MachineLocationHistoryViewItem();
            ml.Machine = machine;
            ml.Locations = ls.ToArray();
            return ml;
        }

        private static void ConvertSpeedUnitToMile(LocationViewItem loc)
        {
            if (loc == null) return;
            if (loc.Speed >= 0 && loc.SpeedUnit.StartsWith("K", StringComparison.OrdinalIgnoreCase))
            {
                loc.Speed = loc.Speed * 0.6213712;
                loc.SpeedUnit = "mi/h";
            }
            if (loc.PostedSpeed > 0 && loc.PostedSpeedUnit.StartsWith("K", StringComparison.OrdinalIgnoreCase))
            {
                loc.PostedSpeed = loc.PostedSpeed * 0.6213712;
                loc.PostedSpeedUnit = "mi/h";
            }
        }

        public static MachineLocationHistoryViewItem GetMachineLocationHistory(string sessionid, string machineid, DateTime startTime, DateTime endTime, string companyid, bool notShow00loc, string datasource)
        {
            if (string.IsNullOrEmpty(companyid))
                companyid = SystemParams.CompanyID;

            MachineViewItem machine = GetMachineViewItem(companyid, Convert.ToInt64(machineid));//暂时确定为取本单位的机器，因为Dealer目前不显示机器的历史位置       
            if (machine == null)
            {
                return null;
            }
            double timeOffset = SystemParams.GetHoursOffset();
            startTime = startTime.AddHours(-timeOffset);
            endTime = endTime.AddHours(-timeOffset);

            AssetLocationInfo[] assetLocs = FleetServiceClientHelper.CreateClient<AssetQueryClient>(companyid, sessionid).GetAssetBasicLocationHistory(companyid, long.Parse(machineid), startTime, endTime, datasource, "", !notShow00loc);

            List<LocationViewItem> ls = new List<LocationViewItem>();
            foreach (AssetLocationInfo assetLoc in assetLocs)
            {
                LocationViewItem li = new LocationViewItem();
                li.Latitude = assetLoc.Latitude;
                li.Longitude = assetLoc.Longitude;
                li.LocationTime = assetLoc.AsofTime.AddHours(timeOffset);

                li.Speed = assetLoc.Speed;
                li.SpeedUnit = assetLoc.SpeedUnits;
                li.PostedSpeed = assetLoc.PostedSpeedLimit;
                li.PostedSpeedUnit = assetLoc.SpeedLimitUnits;
                li.Street = assetLoc.Street;
                li.HarshDringEvent = assetLoc.HarshDringEvent;
                li.SpeedingBehavior = assetLoc.SpeedingBehavior;
                li.IconURL = GenerateLocationIconUrl(assetLoc);
                li.SmartWitnessVideoUrl = assetLoc.SmartWitnessVideoUrl;

                ConvertSpeedUnitToMile(li);
                ls.Add(li);
            }
            MachineLocationHistoryViewItem ml = new MachineLocationHistoryViewItem();
            ml.Machine = machine;
            ml.Locations = ls.ToArray();
            return ml;
        }

        private static string GenerateLocationIconUrl(AssetLocationInfo loc)
        {
            //http://iron.soft.rz/admin/machinetypeicon.ashx
            //http://iron.soft.rz/admin/machinemovingicon.ashx
            string path = SystemParams.MachineTypeMapViewIconUrl.ToLower().Replace("machinetypeicon.ashx", "machinemovingicon.ashx");
            const string PARAM = "?tp={0}&bkcolor={1}&heading={2}";
            int tp = (int)HarshDrivingEvents.HardAccelerationEvent;
            string color = "";
            switch (loc.HarshDringEvent)
            {
                case HarshDrivingEvents.None:
                    break;
                case HarshDrivingEvents.HardAccelerationEvent:
                    color = "#ff3f48cc";
                    break;
                case HarshDrivingEvents.HardBrakeEvent:
                    color = "#ff00a8f3";
                    break;
                case HarshDrivingEvents.HardTurnEvent:
                    color = "#fffff200";
                    break;
            }
            if (string.IsNullOrEmpty(color))
            {
                if (loc.SpeedingBehavior == SpeedingBehaviors.MinorSpeeding)
                    color = "#ffff7f27";
                else if (loc.SpeedingBehavior == SpeedingBehaviors.SevereSpeeding)
                    color = "#ffec1c24";
            }
            if (string.IsNullOrEmpty(color))
            {
                if (loc.MoveStatus == AssetMoveStatus.InMotion)
                    color = "#ff228B22";
            }

            if (string.IsNullOrEmpty(color))
            {
                if (loc.MoveStatus == AssetMoveStatus.StoppedOn)
                    return path + "?legend=StoppedOn";
                else if (loc.MoveStatus == AssetMoveStatus.StoppedOff)
                    return path + "?legend=StoppedOff";
            }
            color = HttpUtility.UrlEncode(color);
            path = path + string.Format(PARAM, tp, color, loc.Heading);

            return path;
        }

        public static MapAlertViewDefinitionItem[] GetMapAlertViews(string companyid, string selectedViewID)
        {
            MachineAlertViewItem[] views = null;
            MachineAlertViewClient mc = GetMachineAlertViewClient();
            if (string.IsNullOrWhiteSpace(companyid))
                companyid = SystemParams.CompanyID;
            views = mc.GetAvailableAlertViews(companyid, true);

            MachineAlertViewQueryResult viewInfo = null;
            try
            {
                if (!string.IsNullOrWhiteSpace(selectedViewID))//获取View下使用的数据源信息
                    viewInfo = mc.QueryMachineAlertView(companyid, selectedViewID, null);
            }
            catch { }

            string path = SystemParams.MachineTypeMapViewIconUrl;
            List<MapAlertViewDefinitionItem> ls = new List<MapAlertViewDefinitionItem>();
            foreach (MachineAlertViewItem ai in views)
            {
                MapAlertViewDefinitionItem mi = new MapAlertViewDefinitionItem();
                mi.ID = ai.ID;
                mi.Name = ai.Name;
                mi.Layers = new MapAlertLayerDefinitionItem[ai.Layers.Count];
                for (int i = 0; i < ai.Layers.Count; i++)
                {
                    mi.Layers[i] = new MapAlertLayerDefinitionItem();
                    mi.Layers[i].ID = ai.Layers[i].ID;
                    mi.Layers[i].Title = ai.Layers[i].Title;
                    mi.Layers[i].AlertLayerType = ai.Layers[i].AlertLayerType;
                    mi.Layers[i].IconColor = ai.Layers[i].IconColor;
                    mi.Layers[i].Description = ai.Layers[i].Description;
                    mi.Layers[i].LegendUrl = path + "?legend=" + ai.Layers[i].AlertLayerType + "&bkcolor=" + HttpUtility.UrlEncode(ai.Layers[i].IconColor);
                    if (ai.Layers[i].CriteriaSQLParameters != null && ai.Layers[i].CriteriaSQLParameters.Count > 0)
                        mi.Layers[i].CriteriaSQLParameters = ConvertToDbQueryParameterDefine(ai.Layers[i].CriteriaSQLParameters);

                    if (ai.Layers[i].AlertSQLParameters != null && ai.Layers[i].AlertSQLParameters.Count > 0)
                        mi.Layers[i].AlertSQLParameters = ConvertToDbQueryParameterDefine(ai.Layers[i].AlertSQLParameters);
                }
                mi.Layers = mi.Layers.OrderBy((l) => l.AlertLayerType).ToArray();

                if (viewInfo != null && viewInfo.ID.Equals(mi.ID, StringComparison.OrdinalIgnoreCase))
                    mi.LookupDataSources = ConvertLookupData(viewInfo.LookupDataSources);
                ls.Add(mi);
            }
            return ls.OrderBy((mal) => mal.Name).ToArray();

        }

        private static List<LookupDataSourceDataItem> ConvertLookupData(List<LookupDataSourceData> data)
        {
            List<LookupDataSourceDataItem> result = new List<LookupDataSourceDataItem>();
            if (data != null)
            {
                foreach (LookupDataSourceData d in data)
                {
                    LookupDataSourceDataItem item = new LookupDataSourceDataItem();
                    item.ID = d.ID;
                    item.Name = d.Name;
                    item.Items.AddRange(d.Items);
                    result.Add(item);
                }
            }
            return result;
        }



        private static DbQueryParameterItem[] ConvertToDbQueryParameterDefine(List<DbQueryParameterDefine> paramerters)
        {
            List<DbQueryParameterItem> list = new List<DbQueryParameterItem>();
            foreach (DbQueryParameterDefine pd in paramerters)
            {
                DbQueryParameterItem pi = new DbQueryParameterItem();
                Helper.CloneProperty(pi, pd);
                pi.DisplayCaptionField = pd.DisplayCaptionField;
                pi.IsField = pd.IsField;
                pi.IsAllAllowed = pd.IsAllAllowed;
                pi.MutipleSelect = pd.MutipleSelect;
                if (pi.DataType == Services.Common.DataTypes.Datetime)
                {
                    try
                    {
                        pi.DefaultValue = DateTime.Parse(pi.DefaultValue).ToString("M/d/yyyy");
                    }
                    catch
                    {
                    }
                }
                list.Add(pi);
            }

            return list.ToArray();
        }

        class ViewTemp
        {
            public LayerDataTemp[] Layers = null;

            public LayerDataTemp GetLayer(string machineid, bool isprimary)
            {
                if ((Layers == null) || (Layers.Length == 0))
                {
                    return null;
                }
                foreach (LayerDataTemp tmp in Layers)
                {
                    if (tmp.Layer.IsPrimary == isprimary)
                    {
                        if (tmp.Met(machineid))
                        {
                            return tmp;
                        }
                    }
                }
                return null;
            }
        }

        class LayerDataTemp
        {
            public MapAlertLayerItem Layer = null;
            public long[] Machines = null;
            public StringKeyValue[] AlertDescriptions = null;

            public string GetAlertTip(string machineid)
            {
                if ((AlertDescriptions == null) || (AlertDescriptions.Length == 0))
                {
                    return string.Empty;
                }
                string rst = string.Empty;
                foreach (StringKeyValue kv in AlertDescriptions)
                {
                    if (string.Compare(kv.Key, machineid, true) == 0)
                    {
                        if (!string.IsNullOrWhiteSpace(kv.Value))
                        {
                            if (string.IsNullOrEmpty(rst))
                            {
                                rst = kv.Value;
                            }
                            else
                            {
                                rst = rst + "\r\n" + kv.Value;
                            }
                        }
                    }
                }
                return rst;
            }

            public bool Met(string machineid)
            {
                if ((Machines == null) || (Machines.Length == 0))
                {
                    return false;
                }
                foreach (long m in Machines)
                {
                    if (string.Compare(m.ToString(), machineid, true) == 0)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        class AssetLocation
        {
            public string MachineID { get; set; }
            public LocationViewItem Location { get; set; }
            public string MoveStatus { get; set; }
            public int Directionalheading { get; set; }
        }

        public class AssetEngineHour
        {
            public string MachineID { get; set; }

            private double _EngineHours;
            public double EngineHours
            {
                get
                {
                    return _EngineHours;
                }
                set
                {
                    value = value > 0 ? value : 0;
                    _EngineHours = Math.Round(value, 2);
                }
            }
            public DateTime EngineHoursDate { get; set; }
        }
    }
}
