/// <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); }
/// <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); } }