Beispiel #1
0
        private int GetLowestProductAllocationLevel(DeviceHierarchyElement isoDeviceElementHierarchy, Dictionary <string, List <ISOProductAllocation> > isoProductAllocations)
        {
            int level = -1;

            // If device element has direct product allocations, use its Depth.
            if (isoDeviceElementHierarchy != null &&
                isoProductAllocations.TryGetValue(isoDeviceElementHierarchy.DeviceElement.DeviceElementId, out List <ISOProductAllocation> productAllocations) &&
                productAllocations.Any(x => x.DeviceElementIdRef == isoDeviceElementHierarchy.DeviceElement.DeviceElementId))
            {
                level = isoDeviceElementHierarchy.Depth;
            }

            // Get max level from children elements
            int?maxChildLevel = isoDeviceElementHierarchy?.Children?.Max(x => GetLowestProductAllocationLevel(x, isoProductAllocations));

            return(Math.Max(level, maxChildLevel.GetValueOrDefault(-1)));
        }
        public IEnumerable <DeviceElement> ImportDeviceElements(ISODevice isoDevice)
        {
            EnumeratedValue deviceClassification = DecodeMachineInfo(isoDevice.ClientNAME);

            ISODeviceElement rootDeviceElement = isoDevice.DeviceElements.SingleOrDefault(det => det.DeviceElementType == ISODeviceElementType.Device);

            if (rootDeviceElement == null)
            {
                //Short circuit on invalid TaskData
                TaskDataMapper.AddError("Missing root DeviceElement.  Device will not be imported.", isoDevice.DeviceId.ToString(), "DeviceElementMapper");
                return(null);
            }

            DeviceHierarchyElement rootDeviceElementHierarchy = TaskDataMapper.DeviceElementHierarchies.Items[isoDevice.DeviceId];

            //Import device elements
            List <DeviceElement> adaptDeviceElements = new List <DeviceElement>();

            //Import down the hierarchy to ensure integrity of parent references
            for (int i = 0; i <= rootDeviceElementHierarchy.GetMaxDepth(); i++)
            {
                IEnumerable <ISODeviceElement> isoDeviceElements = rootDeviceElementHierarchy.GetElementsAtDepth(i).Select(h => h.DeviceElement);
                foreach (ISODeviceElement isoDeviceElement in isoDeviceElements)
                {
                    if (isoDeviceElement.DeviceElementType != ISODeviceElementType.Connector)
                    {
                        DeviceElement adaptDeviceElement = ImportDeviceElement(isoDeviceElement, deviceClassification);
                        if (isoDeviceElement.DeviceElementType == ISODeviceElementType.Device)
                        {
                            //Setting the Device serial number on the root Device Element only
                            adaptDeviceElement.SerialNumber = isoDevice.DeviceSerialNumber;
                        }
                        adaptDeviceElements.Add(adaptDeviceElement);
                        DataModel.Catalog.DeviceElements.Add(adaptDeviceElement);
                    }
                    else
                    {
                        //Connectors are not represented as DeviceElements in ADAPT
                        AddConnector(rootDeviceElementHierarchy, isoDeviceElement);
                    }
                }
            }

            return(adaptDeviceElements);
        }
        public List <WorkingData> Map(ISOTime time,
                                      IEnumerable <ISOSpatialRow> isoSpatialRows,
                                      DeviceElementUse deviceElementUse,
                                      DeviceHierarchyElement isoDeviceElementHierarchy,
                                      List <DeviceElementUse> pendingDeviceElementUses,
                                      Dictionary <string, List <ISOProductAllocation> > isoProductAllocations)
        {
            var workingDatas = new List <WorkingData>();

            //Create vrProductIndex on relevant device elements if more than one product on this OperationData
            if (TimeLogMapper.GetDistinctProductIDs(TaskDataMapper, isoProductAllocations).Count > 1 &&
                isoProductAllocations.Keys.Contains(isoDeviceElementHierarchy.DeviceElement.DeviceElementId))
            {
                WorkingData workingData = CreateProductIndexWorkingData(deviceElementUse.Id.ReferenceId);
                ISODeviceElementIDsByWorkingDataID.Add(workingData.Id.ReferenceId, isoDeviceElementHierarchy.DeviceElement.DeviceElementId);
                workingDatas.Add(workingData);
            }

            //Add the Working Datas for this DeviceElement
            IEnumerable <ISODataLogValue> deviceElementDLVs = time.DataLogValues.Where(dlv => dlv.DeviceElementIdRef == isoDeviceElementHierarchy.DeviceElement.DeviceElementId ||      //DLV DET reference matches the primary DET for the ADAPT element
                                                                                       isoDeviceElementHierarchy.MergedElements.Any(e => e.DeviceElementId == dlv.DeviceElementIdRef)); //DLV DET reference matches one of the merged DETs on the ADAPT element


            foreach (ISODataLogValue dlv in deviceElementDLVs)
            {
                IEnumerable <WorkingData> newWorkingDatas = Map(dlv,
                                                                isoSpatialRows,
                                                                deviceElementUse,
                                                                dlv.Index,
                                                                pendingDeviceElementUses,
                                                                isoDeviceElementHierarchy);
                if (newWorkingDatas.Count() > 0)
                {
                    int ddi = dlv.ProcessDataDDI.AsInt32DDI();
                    if (!EnumeratedMeterFactory.IsCondensedMeter(ddi))
                    {
                        //We skip adding Condensed WorkingDatas to this DeviceElementUse since they were added separately below to their specific DeviceElementUse
                        workingDatas.AddRange(newWorkingDatas);
                    }
                }
            }

            return(workingDatas);
        }
        private static MachineConfiguration AddMachineConfiguration(DeviceElement adaptDeviceElement, DeviceHierarchyElement deviceHierarchy, AgGateway.ADAPT.ApplicationDataModel.ADM.Catalog catalog)
        {
            MachineConfiguration machineConfig = new MachineConfiguration();

            //Description
            machineConfig.Description = $"{deviceHierarchy.DeviceElement.Device.DeviceDesignator} : {deviceHierarchy.DeviceElement.DeviceElementDesignator}";

            //Device Element ID
            machineConfig.DeviceElementId = adaptDeviceElement.Id.ReferenceId;

            //Offsets
            if (deviceHierarchy.XOffset.HasValue ||
                deviceHierarchy.YOffset.HasValue ||
                deviceHierarchy.ZOffset.HasValue)
            {
                machineConfig.Offsets = new List <NumericRepresentationValue>();
                if (deviceHierarchy.XOffset != null)
                {
                    machineConfig.Offsets.Add(deviceHierarchy.XOffsetRepresentation);
                }
                if (deviceHierarchy.YOffset != null)
                {
                    machineConfig.Offsets.Add(deviceHierarchy.YOffsetRepresentation);
                }
                if (deviceHierarchy.ZOffset != null)
                {
                    machineConfig.Offsets.Add(deviceHierarchy.ZOffsetRepresentation);
                }
            }

            //GPS Offsets
            if (deviceHierarchy.Children != null && deviceHierarchy.Children.Any(h => h.DeviceElement != null && h.DeviceElement.DeviceElementType == ISODeviceElementType.Navigation))
            {
                DeviceHierarchyElement navigation = (deviceHierarchy.Children.First(h => h.DeviceElement.DeviceElementType == ISODeviceElementType.Navigation));
                machineConfig.GpsReceiverXOffset = navigation.XOffsetRepresentation;
                machineConfig.GpsReceiverYOffset = navigation.YOffsetRepresentation;
                machineConfig.GpsReceiverZOffset = navigation.ZOffsetRepresentation;
            }


            catalog.DeviceElementConfigurations.Add(machineConfig);
            return(machineConfig);
        }
Beispiel #5
0
        private Dictionary <string, List <ISOProductAllocation> > GetProductAllocationsByDeviceElement(ISOTask loggedTask, ISODevice dvc)
        {
            Dictionary <string, Dictionary <string, ISOProductAllocation> > reportedPANs = new Dictionary <string, Dictionary <string, ISOProductAllocation> >();
            int panIndex = 0; // This supports multiple direct PANs for the same DET

            foreach (ISOProductAllocation pan in loggedTask.ProductAllocations.Where(p => !string.IsNullOrEmpty(p.DeviceElementIdRef)))
            {
                ISODeviceElement deviceElement = dvc.DeviceElements.FirstOrDefault(d => d.DeviceElementId == pan.DeviceElementIdRef);
                if (deviceElement != null) //Filter PANs by this DVC
                {
                    AddProductAllocationsForDeviceElement(reportedPANs, pan, deviceElement, $"{GetHierarchyPosition(deviceElement)}_{panIndex}");
                }
                panIndex++;
            }
            // Sort product allocations for each DeviceElement using it's position among ancestors.
            // This arranges PANs on each DET in reverse order: ones from lowest DET in hierarchy having precedence over ones from top.
            Dictionary <string, List <ISOProductAllocation> > output = reportedPANs.ToDictionary(x => x.Key, x =>
            {
                var allocations = x.Value.OrderByDescending(y => y.Key).Select(y => y.Value).ToList();
                // Check if there are any indirect allocations: ones that came from parent device element
                var indirectAllocations = allocations.Where(y => y.DeviceElementIdRef != x.Key).ToList();
                if (indirectAllocations.Count > 0 && indirectAllocations.Count != allocations.Count)
                {
                    // Only keep direct allocations
                    allocations = allocations.Except(indirectAllocations).ToList();
                }
                return(allocations);
            });

            // Determine the lowest depth at which product allocations are reported to eliminate any duplicate PANs
            // at multiple levels within the hierarchy
            DeviceHierarchyElement det = reportedPANs.Keys
                                         .Select(x => TaskDataMapper.DeviceElementHierarchies.GetMatchingElement(x))
                                         .Where(x => x != null)
                                         .FirstOrDefault();
            int lowestLevel = GetLowestProductAllocationLevel(det?.GetRootDeviceElementHierarchy(), output);

            // Remove allocations for all other levels
            return(output
                   .Where(x => TaskDataMapper.DeviceElementHierarchies.GetMatchingElement(x.Key)?.Depth == lowestLevel)
                   .ToDictionary(x => x.Key, x => x.Value));
        }
        /// <summary>
        /// Adds a connector with a hitch at the given reference point, referencing the parent DeviceElement as the DeviceElementConfiguration
        /// </summary>
        /// <param name="rootDeviceHierarchy"></param>
        /// <param name="connectorDeviceElement"></param>
        /// <param name="deviceElement"></param>
        private void AddConnector(DeviceHierarchyElement rootDeviceHierarchy, ISODeviceElement connectorDeviceElement)
        {
            //Per the TC-GEO specification, the connector is always a child of the root device element.
            DeviceHierarchyElement hierarchyElement = rootDeviceHierarchy.FromDeviceElementID(connectorDeviceElement.DeviceElementId);

            if (hierarchyElement.Parent == rootDeviceHierarchy)
            {
                int?rootDeviceElementID = TaskDataMapper.InstanceIDMap.GetADAPTID(rootDeviceHierarchy.DeviceElement.DeviceElementId);
                if (rootDeviceElementID.HasValue)
                {
                    HitchPoint hitch = new HitchPoint();
                    hitch.ReferencePoint = new ReferencePoint()
                    {
                        XOffset = hierarchyElement.XOffsetRepresentation, YOffset = hierarchyElement.YOffsetRepresentation, ZOffset = hierarchyElement.ZOffsetRepresentation
                    };
                    hitch.HitchTypeEnum = HitchTypeEnum.Unkown;
                    DataModel.Catalog.HitchPoints.Add(hitch);

                    //Get the DeviceElementConfiguration for the root element in order that we may link the Connector to it.
                    DeviceElement root = DataModel.Catalog.DeviceElements.FirstOrDefault(d => d.Id.ReferenceId == rootDeviceElementID);
                    if (root != null)
                    {
                        DeviceElementConfiguration rootDeviceConfiguration = DeviceElementMapper.GetDeviceElementConfiguration(root, rootDeviceHierarchy, DataModel.Catalog);
                        if (rootDeviceConfiguration != null)
                        {
                            Connector connector = new Connector();
                            ImportIDs(connector.Id, hierarchyElement.DeviceElement.DeviceElementId);
                            connector.DeviceElementConfigurationId = rootDeviceConfiguration.Id.ReferenceId;
                            connector.HitchPointId = hitch.Id.ReferenceId;
                            DataModel.Catalog.Connectors.Add(connector);

                            //The ID mapping will link the ADAPT Connector to the ISO Device Element
                            TaskDataMapper.InstanceIDMap.Add(connector.Id.ReferenceId, connectorDeviceElement.DeviceElementId);
                        }
                    }
                }
            }
        }
        private void UpdateCondensedWorkingDatas(List <ISOEnumeratedMeter> condensedWorkingDatas, ISODataLogValue dlv, DeviceElementUse deviceElementUse, List <DeviceElementUse> pendingDeviceElementUses, DeviceHierarchyElement isoDeviceElementHierarchy)
        {
            ISODeviceElement        isoDeviceElement   = TaskDataMapper.DeviceElementHierarchies.GetISODeviceElementFromID(dlv.DeviceElementIdRef);
            List <ISODeviceElement> isoSectionElements = isoDeviceElement.ChildDeviceElements.Where(d => d.DeviceElementType == ISOEnumerations.ISODeviceElementType.Section).ToList();

            foreach (var subElement in isoDeviceElement.ChildDeviceElements)
            {
                //This handles cases where the condensed workstate is reported on a top-level boom with sub-booms in the hierarchy above the sections (e.g., ISO 11783-10:2015(E) Figure F.35)
                isoSectionElements.AddRange(subElement.ChildDeviceElements.Where(d => d.DeviceElementType == ISOEnumerations.ISODeviceElementType.Section).ToList());
            }
            //We have some sections in the DDOP
            if (isoSectionElements.Count > 0)
            {
                //Update the DeviceElementReference on the Condensed WorkingDatas
                foreach (var workingData in condensedWorkingDatas)
                {
                    if (workingData.SectionIndex - 1 >= isoSectionElements.Count)
                    {
                        break;
                    }
                    ISODeviceElement targetSection = isoSectionElements[workingData.SectionIndex - 1];

                    DeviceElementUse condensedDeviceElementUse = FindExistingDeviceElementUseForCondensedData(targetSection, pendingDeviceElementUses);
                    if (condensedDeviceElementUse == null)
                    {
                        //Make a new DeviceElementUse
                        condensedDeviceElementUse = new DeviceElementUse();
                        condensedDeviceElementUse.OperationDataId = deviceElementUse.OperationDataId;

                        int?deviceElementID = TaskDataMapper.InstanceIDMap.GetADAPTID(targetSection.DeviceElementId);
                        if (deviceElementID.HasValue)
                        {
                            DeviceElement deviceElement = DataModel.Catalog.DeviceElements.SingleOrDefault(d => d.Id.ReferenceId == deviceElementID.Value);
                            if (deviceElement != null)
                            {
                                //Reference the device element in its hierarchy so that we can get the depth & order
                                DeviceHierarchyElement deviceElementInHierarchy = isoDeviceElementHierarchy.FromDeviceElementID(targetSection.DeviceElementId);

                                //Get the config id
                                DeviceElementConfiguration deviceElementConfig = DeviceElementMapper.GetDeviceElementConfiguration(deviceElement, deviceElementInHierarchy, DataModel.Catalog);
                                condensedDeviceElementUse.DeviceConfigurationId = deviceElementConfig.Id.ReferenceId;

                                //Set the depth & order
                                condensedDeviceElementUse.Depth = deviceElementInHierarchy.Depth;
                                condensedDeviceElementUse.Order = deviceElementInHierarchy.Order;
                            }
                        }

                        condensedDeviceElementUse.GetWorkingDatas = () => new List <WorkingData> {
                            workingData
                        };

                        workingData.DeviceElementUseId = condensedDeviceElementUse.Id.ReferenceId;

                        pendingDeviceElementUses.Add(condensedDeviceElementUse);
                    }
                    else
                    {
                        //Use the existing DeviceElementUse
                        List <WorkingData>        data = new List <WorkingData>();
                        IEnumerable <WorkingData> existingWorkingDatas = condensedDeviceElementUse.GetWorkingDatas();
                        if (existingWorkingDatas != null)
                        {
                            data.AddRange(existingWorkingDatas.ToList());  //Add the preexisting
                        }
                        data.Add(workingData);
                        condensedDeviceElementUse.GetWorkingDatas = () => data;
                    }
                }
            }
        }
        /// <summary>
        /// This method returns multiple WorkingData objects for a single DLV in the ISO model
        /// to handle the Condensed DDI case where a single DLV can contain multiple logical
        /// data points.  For non-condensed DDIs, the method will return a single item in output enumerable.
        /// </summary>
        /// <param name="dlv"></param>
        /// <param name="isoSpatialRows"></param>
        /// <param name="deviceElementUse"></param>
        /// <param name="order"></param>
        /// <param name="pendingDeviceElementUses"></param>
        /// <param name="isoDeviceElementHierarchy"></param>
        /// <returns></returns>
        private IEnumerable <WorkingData> Map(ISODataLogValue dlv,
                                              IEnumerable <ISOSpatialRow> isoSpatialRows,
                                              DeviceElementUse deviceElementUse,
                                              byte order,
                                              List <DeviceElementUse> pendingDeviceElementUses,
                                              DeviceHierarchyElement isoDeviceElementHierarchy)
        {
            var workingDatas = new List <WorkingData>();

            if (_ddis.ContainsKey(dlv.ProcessDataDDI.AsInt32DDI()))
            {
                //Numeric Representations
                NumericWorkingData numericMeter = MapNumericMeter(dlv, deviceElementUse.Id.ReferenceId);
                DataLogValuesByWorkingDataID.Add(numericMeter.Id.ReferenceId, dlv);
                ISODeviceElementIDsByWorkingDataID.Add(numericMeter.Id.ReferenceId, dlv.DeviceElementIdRef);
                workingDatas.Add(numericMeter);
                return(workingDatas);
            }
            var meterCreator = _enumeratedMeterCreatorFactory.GetMeterCreator(dlv.ProcessDataDDI.AsInt32DDI());

            if (meterCreator != null)
            {
                //Enumerated Representations
                var isoEnumeratedMeters = meterCreator.CreateMeters(isoSpatialRows, dlv);
                foreach (ISOEnumeratedMeter enumeratedMeter in isoEnumeratedMeters)
                {
                    DataLogValuesByWorkingDataID.Add(enumeratedMeter.Id.ReferenceId, dlv);
                    ISODeviceElementIDsByWorkingDataID.Add(enumeratedMeter.Id.ReferenceId, dlv.DeviceElementIdRef);
                    enumeratedMeter.DeviceElementUseId = deviceElementUse.Id.ReferenceId;
                }
                workingDatas.AddRange(isoEnumeratedMeters);

                if (meterCreator is CondensedStateMeterCreator)
                {
                    UpdateCondensedWorkingDatas(workingDatas.Cast <ISOEnumeratedMeter>().ToList(), dlv, deviceElementUse, pendingDeviceElementUses, isoDeviceElementHierarchy);
                }
            }
            else
            {
                //Proprietary DDIs - report out as numeric value
                NumericWorkingData proprietaryWorkingData = new NumericWorkingData();
                proprietaryWorkingData.Representation = new ApplicationDataModel.Representations.NumericRepresentation {
                    Code = dlv.ProcessDataDDI, CodeSource = RepresentationCodeSourceEnum.ISO11783_DDI
                };
                proprietaryWorkingData.DeviceElementUseId = deviceElementUse.Id.ReferenceId;

                //Always set unit as count.   In SpatialRecordMapper, we will place the DVP unit on the NumericRepresentationValue.UserProvidedUnitOfMeasure
                //so that consumers can apply any offset/scaling to get to the desired display unit.
                proprietaryWorkingData.UnitOfMeasure = UnitSystemManager.GetUnitOfMeasure("count");

                //Take any information from DPD
                ISODeviceElement det = isoDeviceElementHierarchy.DeviceElement ??
                                       isoDeviceElementHierarchy.MergedElements.FirstOrDefault(me => me.DeviceElementId == dlv.DeviceElementIdRef);
                if (det != null)
                {
                    ISODeviceProcessData dpd = det.DeviceProcessDatas.FirstOrDefault(d => d.DDI == dlv.ProcessDataDDI);
                    if (dpd != null)
                    {
                        proprietaryWorkingData.Representation.Description = dpd.Designator; //Update the representation with a name since we have one here.
                    }
                }

                DataLogValuesByWorkingDataID.Add(proprietaryWorkingData.Id.ReferenceId, dlv);
                ISODeviceElementIDsByWorkingDataID.Add(proprietaryWorkingData.Id.ReferenceId, dlv.DeviceElementIdRef);
                workingDatas.Add(proprietaryWorkingData);
            }
            return(workingDatas);
        }
Beispiel #9
0
        public List <DeviceElementUse> Map(ISOTime time,
                                           IEnumerable <ISOSpatialRow> isoRecords,
                                           int operationDataId,
                                           IEnumerable <string> isoDeviceElementIDs,
                                           Dictionary <string, List <ISOProductAllocation> > isoProductAllocations)
        {
            var sections = new List <DeviceElementUse>();

            foreach (string isoDeviceElementID in isoDeviceElementIDs)
            {
                DeviceHierarchyElement hierarchyElement = TaskDataMapper.DeviceElementHierarchies.GetMatchingElement(isoDeviceElementID);
                if (hierarchyElement != null)
                {
                    DeviceElementUse   deviceElementUse = null;
                    List <WorkingData> workingDatas     = new List <WorkingData>();

                    //Get the relevant DeviceElementConfiguration
                    int           adaptDeviceElementId = TaskDataMapper.InstanceIDMap.GetADAPTID(isoDeviceElementID).Value;
                    DeviceElement adaptDeviceElement   = DataModel.Catalog.DeviceElements.SingleOrDefault(d => d.Id.ReferenceId == adaptDeviceElementId);
                    if (adaptDeviceElement != null)
                    {
                        DeviceElementConfiguration config = DeviceElementMapper.GetDeviceElementConfiguration(adaptDeviceElement, hierarchyElement, DataModel.Catalog);

                        int depth = hierarchyElement.Depth;
                        int order = hierarchyElement.Order;
                        if (config.DeviceElementId == adaptDeviceElement.ParentDeviceId)
                        {
                            //The configuration references the parent ISO element
                            depth = hierarchyElement.Parent.Depth;
                            order = hierarchyElement.Parent.Order;
                        }

                        deviceElementUse = sections.FirstOrDefault(d => d.DeviceConfigurationId == config.Id.ReferenceId);
                        if (deviceElementUse == null)
                        {
                            //Create the DeviceElementUse
                            deviceElementUse                       = new DeviceElementUse();
                            deviceElementUse.Depth                 = depth;
                            deviceElementUse.Order                 = order;
                            deviceElementUse.OperationDataId       = operationDataId;
                            deviceElementUse.DeviceConfigurationId = config.Id.ReferenceId;

                            //Add Working Data for any data on this device element
                            List <WorkingData> data = _workingDataMapper.Map(time, isoRecords, deviceElementUse, hierarchyElement, sections, isoProductAllocations);
                            if (data.Any())
                            {
                                workingDatas.AddRange(data);
                            }
                        }
                        else
                        {
                            workingDatas = deviceElementUse.GetWorkingDatas().ToList();

                            //Add Additional Working Data
                            List <WorkingData> data = _workingDataMapper.Map(time, isoRecords, deviceElementUse, hierarchyElement, sections, isoProductAllocations);
                            if (data.Any())
                            {
                                workingDatas.AddRange(data);
                            }
                        }

                        deviceElementUse.GetWorkingDatas = () => workingDatas;

                        if (!sections.Contains(deviceElementUse))
                        {
                            sections.Add(deviceElementUse);
                        }
                    }
                }
            }

            return(sections);
        }
        private static SectionConfiguration AddSectionConfiguration(DeviceElement adaptDeviceElement, DeviceHierarchyElement deviceHierarchy, AgGateway.ADAPT.ApplicationDataModel.ADM.Catalog catalog)
        {
            SectionConfiguration sectionConfiguration = new SectionConfiguration();

            //Description
            sectionConfiguration.Description = $"{deviceHierarchy.DeviceElement.Device.DeviceDesignator} : {deviceHierarchy.DeviceElement.DeviceElementDesignator}";


            //Device Element ID
            sectionConfiguration.DeviceElementId = adaptDeviceElement.Id.ReferenceId;

            NumericRepresentationValue width   = deviceHierarchy.WidthRepresentation;
            NumericRepresentationValue xOffset = deviceHierarchy.XOffsetRepresentation;
            NumericRepresentationValue yOffset = deviceHierarchy.YOffsetRepresentation;

            if (adaptDeviceElement.DeviceElementType == DeviceElementTypeEnum.Bin)
            {
                //A bin carries no geometry information and should inherit width from its parent and carry 0 offsets from its parent.
                width   = deviceHierarchy.Parent.WidthRepresentation;
                xOffset = 0.AsNumericRepresentationValue("0086", deviceHierarchy.RepresentationMapper);
                yOffset = 0.AsNumericRepresentationValue("0087", deviceHierarchy.RepresentationMapper);
            }

            //Width & Offsets
            sectionConfiguration.SectionWidth = width;
            sectionConfiguration.Offsets      = new List <NumericRepresentationValue>();
            if (xOffset != null)
            {
                sectionConfiguration.InlineOffset = xOffset;
                sectionConfiguration.Offsets.Add(xOffset);
            }
            if (yOffset != null)
            {
                sectionConfiguration.LateralOffset = yOffset;
                sectionConfiguration.Offsets.Add(yOffset);
            }

            catalog.DeviceElementConfigurations.Add(sectionConfiguration);
            return(sectionConfiguration);
        }
        private static ImplementConfiguration AddImplementConfiguration(DeviceElement adaptDeviceElement, DeviceHierarchyElement deviceHierarchy, AgGateway.ADAPT.ApplicationDataModel.ADM.Catalog catalog)
        {
            ImplementConfiguration implementConfig = new ImplementConfiguration();

            //Description
            implementConfig.Description = $"{deviceHierarchy.DeviceElement.Device.DeviceDesignator} : {deviceHierarchy.DeviceElement.DeviceElementDesignator}";

            //Device Element ID
            implementConfig.DeviceElementId = adaptDeviceElement.Id.ReferenceId;

            //Offsets
            implementConfig.Offsets = new List <NumericRepresentationValue>();
            if (deviceHierarchy.XOffsetRepresentation != null)
            {
                implementConfig.Offsets.Add(deviceHierarchy.XOffsetRepresentation);
            }
            if (deviceHierarchy.YOffsetRepresentation != null)
            {
                implementConfig.Offsets.Add(deviceHierarchy.YOffsetRepresentation);
            }
            if (deviceHierarchy.ZOffsetRepresentation != null)
            {
                implementConfig.Offsets.Add(deviceHierarchy.ZOffsetRepresentation);
            }

            //Total Width
            if (deviceHierarchy.Width != null)
            {
                //In an earlier implementation, we used Width for an individual Row Width and Physical Width for the max width.
                //Going forward, we are adopting a more conventional definition that Width is any reported width of the implement, and
                //Physical width is a reported max width specifically.
                //Widths set from Timelog binaries will have already observed this convention as they did not contain the row width variation.
                implementConfig.Width = deviceHierarchy.WidthRepresentation;
                if (deviceHierarchy.WidthDDI == "0046")
                {
                    implementConfig.PhysicalWidth = deviceHierarchy.WidthRepresentation;
                }
            }

            catalog.DeviceElementConfigurations.Add(implementConfig);

            return(implementConfig);
        }
        private static DeviceElementConfiguration AddDeviceElementConfiguration(DeviceElement adaptDeviceElement, DeviceHierarchyElement isoHierarchy, AgGateway.ADAPT.ApplicationDataModel.ADM.Catalog catalog)
        {
            switch (adaptDeviceElement.DeviceElementType)
            {
            case DeviceElementTypeEnum.Machine:
                return(AddMachineConfiguration(adaptDeviceElement, isoHierarchy, catalog));

            case DeviceElementTypeEnum.Implement:
                return(AddImplementConfiguration(adaptDeviceElement, isoHierarchy, catalog));

            case DeviceElementTypeEnum.Function:
                if (isoHierarchy.Parent.DeviceElement.DeviceElementType == ISODeviceElementType.Function)
                {
                    //Function is part of the implement.  I.e., TC-GEO example 9 / ISO 11783-10:2015(E) Figure F.24
                    return(AddSectionConfiguration(adaptDeviceElement, isoHierarchy, catalog));
                }
                else
                {
                    //Function is the entire implement
                    return(AddImplementConfiguration(adaptDeviceElement, isoHierarchy, catalog));
                }

            case DeviceElementTypeEnum.Section:
            case DeviceElementTypeEnum.Bin:
            case DeviceElementTypeEnum.Unit:
                return(AddSectionConfiguration(adaptDeviceElement, isoHierarchy, catalog));

            default:
                return(null);
            }
        }
        public static DeviceElementConfiguration GetDeviceElementConfiguration(DeviceElement adaptDeviceElement, DeviceHierarchyElement isoHierarchy, AgGateway.ADAPT.ApplicationDataModel.ADM.Catalog catalog)
        {
            if (isoHierarchy.DeviceElement.DeviceElementType == ISOEnumerations.ISODeviceElementType.Connector ||
                isoHierarchy.DeviceElement.DeviceElementType == ISOEnumerations.ISODeviceElementType.Navigation)
            {
                //Data belongs to the parent device element from the ISO element referenced
                //Connector and Navigation data may be stored in Timelog data, but Connectors are not DeviceElements in ADAPT.
                //The data refers to the parent implement, which must always be a Device DET per the ISO spec.
                DeviceElement parent = catalog.DeviceElements.FirstOrDefault(d => d.Id.ReferenceId == adaptDeviceElement.ParentDeviceId);
                while (parent != null && (parent.DeviceElementType != DeviceElementTypeEnum.Machine && parent.DeviceElementType != DeviceElementTypeEnum.Implement))
                {
                    parent = catalog.DeviceElements.FirstOrDefault(d => d.Id.ReferenceId == parent.ParentDeviceId);
                }
                if (parent == null)
                {
                    throw new ApplicationException($"Cannot identify Device for Navigation/Connector DeviceElement: {adaptDeviceElement.Description}.");
                }

                DeviceElementConfiguration parentConfig = catalog.DeviceElementConfigurations.FirstOrDefault(c => c.DeviceElementId == parent.Id.ReferenceId);
                if (parentConfig == null)
                {
                    DeviceElement parentElement = catalog.DeviceElements.Single(d => d.Id.ReferenceId == adaptDeviceElement.ParentDeviceId);
                    parentConfig = AddDeviceElementConfiguration(parentElement, isoHierarchy.Parent, catalog);
                }
                return(parentConfig);
            }
            else
            {
                DeviceElementConfiguration deviceConfiguration = catalog.DeviceElementConfigurations.FirstOrDefault(c => c.DeviceElementId == adaptDeviceElement.Id.ReferenceId);
                if (deviceConfiguration == null)
                {
                    deviceConfiguration = AddDeviceElementConfiguration(adaptDeviceElement, isoHierarchy, catalog);
                }
                return(deviceConfiguration);
            }
        }
 private bool HasGeometryInformation(DeviceHierarchyElement deviceHierarchyElement)
 {
     return(deviceHierarchyElement.Width.HasValue || deviceHierarchyElement.XOffset.HasValue || deviceHierarchyElement.YOffset.HasValue || deviceHierarchyElement.ZOffset.HasValue);
 }
        public DeviceElement ImportDeviceElement(ISODeviceElement isoDeviceElement, EnumeratedValue deviceClassification)
        {
            DeviceElement          deviceElement          = new DeviceElement();
            DeviceHierarchyElement deviceElementHierarchy = TaskDataMapper.DeviceElementHierarchies.GetMatchingElement(isoDeviceElement.DeviceElementId);

            //ID
            ImportIDs(deviceElement.Id, isoDeviceElement.DeviceElementId);
            deviceElement.ContextItems = ImportContextItems(isoDeviceElement.DeviceElementId, "ADAPT_Context_Items:DeviceElement", isoDeviceElement);

            //Device ID
            int?deviceModelId = TaskDataMapper.InstanceIDMap.GetADAPTID(isoDeviceElement.Device.DeviceId);

            if (deviceModelId.HasValue)
            {
                deviceElement.DeviceModelId = deviceModelId.Value;
            }

            //Description
            deviceElement.Description = isoDeviceElement.DeviceElementDesignator;

            //Classification
            deviceElement.DeviceClassification = deviceClassification;

            //Parent ID
            if (isoDeviceElement.Parent != null)
            {
                int?parentDeviceId = null;
                if (isoDeviceElement.ParentObjectId == isoDeviceElement.DeviceElementObjectId)
                {
                    //Element has listed itself as its own parent.   Do not include a parent on the adapt element as it will invalidate logic in the hierarchy creation.
                }
                else if (isoDeviceElement.Parent is ISODeviceElement)
                {
                    //Read the parent off of the DeviceElementHierarchy in case we merged the parent into another DeviceElement
                    parentDeviceId = TaskDataMapper.InstanceIDMap.GetADAPTID(deviceElementHierarchy.Parent.DeviceElement.DeviceElementId);
                }
                else if (isoDeviceElement.Parent is ISODevice parentDevice)
                {
                    parentDeviceId = TaskDataMapper.InstanceIDMap.GetADAPTID(parentDevice.DeviceId);
                }
                if (parentDeviceId.HasValue)
                {
                    deviceElement.ParentDeviceId = parentDeviceId.Value;
                }
            }

            //Device Element Type
            switch (isoDeviceElement.DeviceElementType)
            {
            case ISODeviceElementType.Device:      //This is the root device element
                if (deviceClassification != null &&
                    deviceClassification.Value != null &&
                    TaskDataMapper.DeviceOperationTypes.First(d => d.MachineEnumerationMember.DomainTag == deviceClassification.Value.Code).HasMachineConfiguration)
                {
                    //Device is a machine
                    deviceElement.DeviceElementType = DeviceElementTypeEnum.Machine;
                }
                else if (deviceElementHierarchy.Children != null &&
                         deviceElementHierarchy.Children.Any(d => d?.DeviceElement.DeviceElementType == ISODeviceElementType.Navigation) &&    //The Nav element should be a direct descendant of the root
                         (!deviceElementHierarchy.Children.Any(d => d?.DeviceElement.DeviceElementType == ISODeviceElementType.Section) &&     //If there are section or function elements, classify as an implement vs. a machine
                          !deviceElementHierarchy.Children.Any(d => d?.DeviceElement.DeviceElementType == ISODeviceElementType.Function)))
                {
                    //Device is a machine
                    deviceElement.DeviceElementType = DeviceElementTypeEnum.Machine;
                }
                else
                {
                    //Default: classify as an implement
                    deviceElement.DeviceElementType = DeviceElementTypeEnum.Implement;
                }
                break;

            case ISODeviceElementType.Bin:
                deviceElement.DeviceElementType = DeviceElementTypeEnum.Bin;
                break;

            case ISODeviceElementType.Function:
                deviceElement.DeviceElementType = DeviceElementTypeEnum.Function;
                break;

            case ISODeviceElementType.Section:
                deviceElement.DeviceElementType = DeviceElementTypeEnum.Section;
                break;

            case ISODeviceElementType.Unit:
                deviceElement.DeviceElementType = DeviceElementTypeEnum.Unit;
                break;

            case ISODeviceElementType.Navigation:
                deviceElement.DeviceElementType = DeviceElementTypeEnum.Function;
                break;
            }


            if (HasGeometryInformation(deviceElementHierarchy))
            {
                //Geometry information is on DeviceProperty elements.
                GetDeviceElementConfiguration(deviceElement, deviceElementHierarchy, DataModel.Catalog); //Add via the Get method to invoke business rules for configs
            }

            return(deviceElement);
        }