/// <summary>
        /// Exports specified stops to serializable stop information.
        /// </summary>
        /// <param name="stops">The reference to the collection of stops to be exported.</param>
        /// <param name="capacitiesInfo">The reference to capacities info object to be used
        /// for retrieving custom order properties for stops.</param>
        /// <param name="orderCustomPropertiesInfo">The reference custom order properties info
        /// object.</param>
        /// <param name="addressFields">The reference to address fields object to be used
        /// for retrieving custom order properties for stops.</param>
        /// <param name="solver">The reference to VRPSolver to be used for retrieving
        /// curb approach policies for stops.</param>
        /// <param name="orderPropertiesFilter">Function returning true for custom order
        /// property names which should not be exported.</param>
        /// <returns>A reference to the collection of serializable stop information objects.
        /// </returns>
        public static IEnumerable<StopInfo> ExportStops(
            IEnumerable<Stop> stops,
            CapacitiesInfo capacitiesInfo,
            OrderCustomPropertiesInfo orderCustomPropertiesInfo,
            AddressField[] addressFields,
            IVrpSolver solver,
            Func<string, bool> orderPropertiesFilter = null)
        {
            Debug.Assert(stops != null);
            Debug.Assert(stops.All(stop => stop != null));
            Debug.Assert(stops.All(stop => stop.Route != null));
            Debug.Assert(capacitiesInfo != null);
            Debug.Assert(orderCustomPropertiesInfo != null);
            Debug.Assert(addressFields != null);

            if (!stops.Any())
            {
                return Enumerable.Empty<StopInfo>();
            }

            var capacityProperties = Order.GetPropertiesInfo(capacitiesInfo);
            var addressProperties = Order.GetPropertiesInfo(addressFields);
            var customProperties = Order.GetPropertiesInfo(orderCustomPropertiesInfo);

            var exportOrderProperties = _CreateExportOrderProperties(
                capacitiesInfo,
                orderCustomPropertiesInfo,
                addressFields,
                orderPropertiesFilter);

            // Make a dictionary for mapping routes to collection of sorted route stops.
            var routesSortedStops = stops
                .Select(stop => stop.Route)
                .Distinct()
                .ToDictionary(route => route, route => CommonHelpers.GetSortedStops(route));

            // Prepare result by exporting each stop individually.
            var settings = CommonHelpers.GetSolverSettings(solver);
            var result = stops
                .Select(stop => _ExportStop(
                    stop,
                    routesSortedStops[stop.Route],
                    exportOrderProperties,
                    addressProperties,
                    capacityProperties,
                    customProperties,
                    settings))
                .ToList();

            return result;
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Initializes a new instance of ExportValidator.
        /// </summary>
        /// <param name="capacitiesInfo">Current capacities info.</param>
        /// <param name="addressFields">Current address fields.</param>
        public ExportValidator(CapacitiesInfo capacitiesInfo,
                               AddressField[] addressFields)
        {
            if (null == capacitiesInfo)
                throw new ArgumentNullException("capacitiesInfo"); // exception

            if (null == addressFields)
                throw new ArgumentNullException("addressFields"); // exception

            // load export structure
            ExportStructureReader reader = Exporter.GetReader(capacitiesInfo,
                                                              new OrderCustomPropertiesInfo(),
                                                              addressFields);

            _readedNames = new List<string>();
            _GetFieldNames(reader, ExportType.Access, _readedNames);
            _GetFieldNames(reader, ExportType.TextOrders, _readedNames);
            _GetFieldNames(reader, ExportType.TextStops, _readedNames);

            _description = reader.GetTableDescription(TableType.Stops);
        }
Beispiel #3
0
        /// <summary>
        /// Get order property titles.
        /// </summary>
        /// <param name="capacitiesInfo">Information about capacities.</param>
        /// <param name="orderCustomPropertiesInfo">Information about custom order properties.</param>
        /// <param name="addressFields">Set of geocoder address fields.</param>
        /// <returns>Returns full collection of order property title to show in UI.</returns>
        public static string[] GetPropertyTitles(CapacitiesInfo capacitiesInfo,
                    OrderCustomPropertiesInfo orderCustomPropertiesInfo, AddressField[] addressFields)
        {
            Type type = typeof(Order);

            List<string> propertyTitles = new List<string>();

            PropertyInfo[] properties = type.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                if (Attribute.IsDefined(property, typeof(DomainPropertyAttribute)))
                {
                    DomainPropertyAttribute attribute = (DomainPropertyAttribute)Attribute.GetCustomAttribute(property, typeof(DomainPropertyAttribute));
                    Debug.Assert(null != attribute);
                    Type typeProperty = _GetEffectiveType(property.PropertyType);

                    if (typeof(OrderCustomProperties) == typeProperty)
                    {   // specials type: order custom property
                        OrderCustomPropertiesInfo info = orderCustomPropertiesInfo;
                        for (int i = 0; i < info.Count; ++i)
                            propertyTitles.Add(info[i].Name);
                    }
                    else if (typeof(Capacities) == typeProperty)
                    {   // specials type: capacities
                        CapacitiesInfo info = capacitiesInfo;
                        for (int i = 0; i < info.Count; ++i)
                            propertyTitles.Add(info[i].Name);
                    }
                    else if (typeof(Address) == typeProperty)
                    {   // specials type: address
                        ESRI.ArcLogistics.Geocoding.AddressField[] fields = addressFields;
                        for (int i = 0; i < fields.Length; ++i)
                            propertyTitles.Add(fields[i].Title);
                    }
                    else if (typeof(Point) == typeProperty)
                    {
                        propertyTitles.Add(Properties.Resources.DomainPropertyNameX);
                        propertyTitles.Add(Properties.Resources.DomainPropertyNameY);
                    }
                    else
                        propertyTitles.Add(attribute.Title);
                }
            }

            return propertyTitles.ToArray();
        }
        /// <summary>
        /// Creates collection of custom order properties to be exported.
        /// </summary>
        /// <param name="capacitiesInfo">The reference to capacities info object to be used
        /// for retrieving custom order properties for stops.</param>
        /// <param name="orderCustomPropertiesInfo">The reference custom order properties info
        /// object.</param>
        /// <param name="addressFields">The reference to address fields object to be used
        /// for retrieving custom order properties for stops.</param>
        /// <param name="orderPropertiesFilter">Function returning true for custom order
        /// property names which should not be exported.</param>
        /// <returns>A reference to the collection of custom order properties to be exported.
        /// </returns>
        private static IEnumerable<OrderPropertyInfo> _CreateExportOrderProperties(
            CapacitiesInfo capacitiesInfo,
            OrderCustomPropertiesInfo orderCustomPropertiesInfo,
            AddressField[] addressFields,
            Func<string, bool> orderPropertiesFilter)
        {
            Debug.Assert(capacitiesInfo != null);
            Debug.Assert(orderCustomPropertiesInfo != null);
            Debug.Assert(addressFields != null);

            if (orderPropertiesFilter == null)
            {
                orderPropertiesFilter = _ => false;
            }

            var names = new List<string>(Order.GetPropertyNames(
                capacitiesInfo,
                orderCustomPropertiesInfo,
                addressFields));
            var titles = new List<string>(Order.GetPropertyTitles(
                capacitiesInfo,
                orderCustomPropertiesInfo,
                addressFields));
            var orderPropertiesToExport = names
                .Zip(titles, OrderPropertyInfo.Create)
                .Where(info => !orderPropertiesFilter(info.Name))
                .ToArray();

            return orderPropertiesToExport;
        }
        private static void _SaveStops(
            XmlWriter writer,
            Route route,
            ICollection<Stop> stops,
            ICollection<string> orderPropertiesToExport,
            Project project,
            AddressField[] addressFields)
        {
            Debug.Assert(route != null);

            var sortedStops = new List<Stop>(stops);
            CommonHelpers.SortBySequence(sortedStops);

            var orderPropertiesTitlesToExport = new List<string>();
            var names = new List<string>(Order.GetPropertyNames(project.CapacitiesInfo,
                                         project.OrderCustomPropertiesInfo, addressFields));
            var titles = new List<string>(Order.GetPropertyTitles(project.CapacitiesInfo,
                                          project.OrderCustomPropertiesInfo, addressFields));

            foreach (string name in orderPropertiesToExport)
            {
                int index = names.IndexOf(name);
                string title = titles[index];
                orderPropertiesTitlesToExport.Add(title);
            }

            var routeStops = CommonHelpers.GetSortedStops(route);

            writer.WriteStartElement(STOPS_NODE_NAME);
            foreach (Stop stop in sortedStops)
            {
                string name = _GetStopName(stop, routeStops);

                var mapLocation = stop.MapLocation;
                if (!mapLocation.HasValue)
                {
                    if (stop.StopType != StopType.Lunch)
                    {
                        throw new InvalidOperationException(
                            Properties.Messages.Error_GrfExporterNoLocationForStop); // exception
                    }

                    var currentIndex = stop.SequenceNumber - 1;
                    var stopWithLocation = SolveHelper.GetActualLunchStop(routeStops, currentIndex);
                    if (!stopWithLocation.MapLocation.HasValue)
                    {
                        throw new InvalidOperationException(
                            Properties.Messages.Error_GrfExporterNoLocationForStop); // exception
                    }

                    mapLocation = stopWithLocation.MapLocation.Value;
                }

                writer.WriteStartElement(STOP_NODE_NAME);
                writer.WriteAttributeString(ENABLED_ATTR_NAME, TRUE_VALUE);

                string comments = _GetComments(stop, orderPropertiesToExport, orderPropertiesTitlesToExport);

                _SaveLocationNode(writer, mapLocation.Value, name, comments);
                writer.WriteStartElement(DURATION_NODE_NAME);
                double duration = stop.TimeAtStop * 60;
                writer.WriteValue(duration.ToString(DOUBLE_FORMAT, NumberFormatInfo.InvariantInfo));
                writer.WriteEndElement();

                writer.WriteEndElement();
            }
            writer.WriteEndElement();
        }
        /// <summary>
        /// Create address fields from locator fields.
        /// </summary>
        private void _CreateAddressFieldsFromLocatorFields()
        {
            int fieldsCount = _addrFields.FieldArray.Length;
            _addressFields = new AddressField[fieldsCount];
            _locatorFieldNames = new string[fieldsCount];

            // Create address field array.
            for (int index = 0; index < _geocodingServiceInfo.FieldMappings.FieldMapping.Length; index++)
            {
                // Get field mapping for currect address field.
                InputFieldMapping fieldMapping = _geocodingServiceInfo.FieldMappings.FieldMapping[index];

                // Get mapped address part (which part of address will be linked to locator alias name).
                string addressPartName = fieldMapping.AddressField;
                AddressPart addressPart = (AddressPart)Enum.Parse(typeof(AddressPart), addressPartName, true);

                // Get title for current mapping.
                string locatorName = fieldMapping.LocatorField;
                string title = null;
                foreach (Field field in _addrFields.FieldArray)
                {
                    if (field.Name.Equals(locatorName, StringComparison.OrdinalIgnoreCase))
                    {
                        title = field.Name;
                        break;
                    }
                }

                _locatorFieldNames[index] = locatorName;

                // Create address field.
                _addressFields[index] = new AddressField(title, addressPart, fieldMapping.Visible, fieldMapping.Description);
            }
        }
        /// <summary>
        /// Create address fields from service info. To support work without connection.
        /// </summary>
        private void _CreateAddressFieldsFromServiceInfo()
        {
            int fieldsCount = _geocodingServiceInfo.FieldMappings.FieldMapping.Length;
            _addressFields = new AddressField[fieldsCount];
            _locatorFieldNames = new string[fieldsCount];

            // Create address field array.
            for (int index = 0; index < _geocodingServiceInfo.FieldMappings.FieldMapping.Length; index++)
            {
                // Get field mapping for currect address field.
                InputFieldMapping fieldMapping = _geocodingServiceInfo.FieldMappings.FieldMapping[index];

                // Get mapped address part (which part of address will be linked to locator alias name).
                string addressPartName = fieldMapping.AddressField;
                AddressPart addressPart = (AddressPart)Enum.Parse(typeof(AddressPart), addressPartName, true);

                // Get title for current mapping.
                string locatorName = fieldMapping.LocatorField;

                _locatorFieldNames[index] = locatorName;

                // Create address field.
                _addressFields[index] = new AddressField(locatorName, addressPart, fieldMapping.Visible, fieldMapping.Description);
            }
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Creates a new instance of the <c>TableDescription</c> class.
        /// </summary>
        /// <param name="name">Table name.</param>
        /// <param name="type">Table type.</param>
        /// <param name="fields">Table fields.</param>
        /// <param name="capacityInfos">Capacity infos.</param>
        /// <param name="orderCustomPropertyInfos">Order custom properties infos.</param>
        /// <param name="addressFields">Address fields.</param>
        public TableDescription(string name,
                                TableType type,
                                List<FieldInfo> fields,
                                CapacitiesInfo capacityInfos,
                                OrderCustomPropertiesInfo orderCustomPropertyInfos,
                                AddressField[] addressFields)
        {
            Debug.Assert(!string.IsNullOrEmpty(name));
            Debug.Assert(0 < fields.Count);
            Debug.Assert(null != capacityInfos);
            Debug.Assert(null != orderCustomPropertyInfos);
            Debug.Assert(null != addressFields);

            _capacityInfos = capacityInfos;
            _orderCustomPropertyInfos = orderCustomPropertyInfos;
            _addressFields = addressFields;

            _name = name;
            _type = type;

            foreach (FieldInfo info in fields)
            {
                Debug.Assert(!_fieldsMap.ContainsKey(info.Name));

                if (string.IsNullOrEmpty(info.RelationType))
                    _fieldsMap.Add(info.Name, info);
                else
                {   // special routine to relative fields
                    switch (info.RelationType)
                    {
                        case "Capacities":
                            _AddCapacityRelativeFields(capacityInfos, info);
                            break;

                        case "CustomOrderProperties":
                            _AddCustomOrderPropertyRelativeFields(orderCustomPropertyInfos, info);
                            break;

                        case "Address":
                            _AddAddressRelativeFields(addressFields, info);
                            break;

                        default:
                            Debug.Assert(false); // NOTE: not supported
                            break;
                    }
                }
            }
        }
        /// <summary>
        /// Loads table descriptions.
        /// </summary>
        /// <param name="nodeTables">Tables node.</param>
        /// <param name="capacityInfos">Capacity informations.</param>
        /// <param name="orderCustomPropertyInfos">Order custom property informations.</param>
        /// <param name="addressFields">Address fields.</param>
        private void _LoadTableDescriptions(XmlNode nodeTables,
                                            CapacitiesInfo capacityInfos,
                                            OrderCustomPropertiesInfo orderCustomPropertyInfos,
                                            AddressField[] addressFields)
        {
            foreach (XmlNode node in nodeTables.ChildNodes)
            {
                if (node.NodeType != XmlNodeType.Element)
                    continue; // skip comments and other non element nodes

                if (node.Name.Equals(NODE_NAME_TABLEDEFINITION, StringComparison.OrdinalIgnoreCase))
                {
                    TableDescription table = _LoadTableDescription(node,
                                                                   capacityInfos,
                                                                   orderCustomPropertyInfos,
                                                                   addressFields);
                    if (null != table)
                    {
                        Debug.Assert(!_listTables.ContainsKey(table.Type));
                        _listTables.Add(table.Type, table);
                    }
                }
            }
        }
        /// <summary>
        /// Loads table description.
        /// </summary>
        /// <param name="nodeTable">Table's node.</param>
        /// <param name="capacityInfos">Capacity informations.</param>
        /// <param name="orderCustomPropertyInfos">Order custom property informations.</param>
        /// <param name="addressFields">Address fields.</param>
        /// <returns>Readed table description.</returns>
        private TableDescription _LoadTableDescription(XmlNode nodeTable,
                                                       CapacitiesInfo capacityInfos,
                                                       OrderCustomPropertiesInfo orderCustomPropertyInfos,
                                                       AddressField[] addressFields)
        {
            TableType type =
                (TableType)Enum.Parse(typeof(TableType),
                                      nodeTable.Attributes[ATTRIBUTE_NAME_TYPE].Value);

            string name = nodeTable.Attributes[ATTRIBUTE_NAME_NAME].Value;

            List<FieldInfo> fields = null;
            foreach (XmlNode node in nodeTable.ChildNodes)
            {
                if (node.NodeType != XmlNodeType.Element)
                    continue; // skip comments and other non element nodes

                if (node.Name.Equals(NODE_NAME_FIELDS, StringComparison.OrdinalIgnoreCase))
                    fields = _LoadFields(node);
            }

            return new TableDescription(name,
                                        type,
                                        fields,
                                        capacityInfos,
                                        orderCustomPropertyInfos,
                                        addressFields);
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Loads export settings.
        /// </summary>
        /// <param name="doc">Export keeper document.</param>
        /// <param name="capacityInfos">Capacity informations.</param>
        /// <param name="orderCustomPropertiesInfo">Order custom property informations.</param>
        /// <param name="addressFields">Address fields.</param>
        public void Load(XmlDocument doc, CapacitiesInfo capacityInfos,
                         OrderCustomPropertiesInfo orderCustomPropertiesInfo,
                         AddressField[] addressFields)
        {
            Debug.Assert(null != doc);

            foreach (XmlNode node in doc.DocumentElement.ChildNodes)
            {
                if (node.NodeType != XmlNodeType.Element)
                    continue; // skip comments and other non element nodes

                if (node.Name.Equals(NODE_NAME_EXPORTPATTERNS, StringComparison.OrdinalIgnoreCase))
                    _LoadPatterns(node);
                else if (node.Name.Equals(NODE_NAME_TABLEDEFINITIONS, StringComparison.OrdinalIgnoreCase))
                    _LoadTableDescriptions(node, capacityInfos, orderCustomPropertiesInfo, addressFields);
                else if (node.Name.Equals(NODE_NAME_RESERVEDWORDS, StringComparison.OrdinalIgnoreCase))
                    _LoadReservedWords(node);
                else if (node.Name.Equals(NODE_NAME_HARDFIELDS, StringComparison.OrdinalIgnoreCase))
                    _LoadHardFields(node);
                else
                    throw new NotSupportedException();
            }

            _capacityInfos = capacityInfos;
            _orderCustomPropertyInfos = orderCustomPropertiesInfo;
        }
        /// <summary>
        /// Add address relative fields.
        /// </summary>
        /// <param name="addressFields">Address fields.</param>
        /// <param name="info">Field information with data settings.</param>
        private void _AddAddressRelativeFields(AddressField[] addressFields, FieldInfo info)
        {
            for (int index = 0; index < addressFields.Length; ++index)
            {
                AddressField adress = addressFields[index];

                FieldInfo infoRealtion = (FieldInfo)info.Clone();
                infoRealtion.Name = infoRealtion.LongName = adress.Title;
                infoRealtion.ShortName = (SHORT_NAME_LENGTH < infoRealtion.LongName.Length) ?
                        infoRealtion.LongName.Substring(0, SHORT_NAME_LENGTH) :
                        infoRealtion.LongName;
                infoRealtion.NameFormat = adress.Type.ToString();
                Debug.Assert(string.IsNullOrEmpty(infoRealtion.Description));
                if (string.IsNullOrEmpty(infoRealtion.Description))
                    infoRealtion.Description = adress.Description;

                Debug.Assert(!string.IsNullOrEmpty(infoRealtion.Name));
                _fieldsMap.Add(infoRealtion.Name, infoRealtion);
            }
        }