public void TestCaseDataInput()
        {
            var testDataTree   = MakeTreeFromListofLists(TagsTestClases.GetTagsCaseData());
            var resultMetaData = new OSMListWithPaths(testDataTree);

            CollectionAssert.AreEquivalent(resultMetaData.items, expectedCaseDataList);
        }
        public void TestSimpleInput()
        {
            var testDataTree = MakeTreeFromListofLists(new List <List <List <string> > >()
            {
                new List <List <string> >()
                {
                    TagsTestClases.itemATags, TagsTestClases.itemBTags
                }
            });
            var resultMetaData = new OSMListWithPaths(testDataTree);

            CollectionAssert.AreEquivalent(resultMetaData.items, expectedSimpleDataList);

            var catholicPaths = GetExpectedPathIndicesForTag(resultMetaData, expectedSimpleDataList[2]); // denom=catholic

            Assert.IsTrue(catholicPaths.Contains(itemAPath.ToString()));

            var futunaPaths = GetExpectedPathIndicesForTag(resultMetaData, expectedSimpleDataList[0]); // name=futuna

            Assert.IsTrue(futunaPaths.Contains(itemAPath.ToString()));

            var amenityPaths = GetExpectedPathIndicesForTag(resultMetaData, expectedSimpleDataList[3]); // amenity=*

            Assert.IsTrue(amenityPaths.Contains(itemAPath.ToString()));
            Assert.IsTrue(amenityPaths.Contains(itemBPath.ToString()));

            var buildingPaths = GetExpectedPathIndicesForTag(resultMetaData, expectedSimpleDataList[6]); // building=yes

            Assert.IsTrue(buildingPaths.Contains(itemAPath.ToString()));
            Assert.IsTrue(buildingPaths.Contains(itemBPath.ToString()));
        }
        /// <summary>Parse the Grasshopper data tree into the form's data tree</summary>
        protected TreeGridItemCollection GetSelectableTagsFromInputTree(OSMListWithPaths requests)
        {
            var indexOfParents = new Dictionary <string, int>();
            var sortedTags     = requests.items.OrderBy(t => t.ToString()).ToList();
            var selectableTags = new TreeGridItemCollection();

            foreach (var tag in sortedTags)
            {
                if (tag.Key != null)
                {
                    if (!indexOfParents.ContainsKey(tag.Key.Value))
                    {
                        var parentItem = new OSMTreeGridItem(tag.Key, 0, 0, true, false);
                        selectableTags.Add(parentItem);
                        indexOfParents[parentItem.OSMData.Value] = selectableTags.Count - 1;
                    }
                }

                var nodeCount = 0; var wayCount = 0;
                if (ProvidedNodes)
                {
                    nodeCount = requests.pathsPerItem[tag].Count();
                }
                else
                {
                    wayCount = requests.pathsPerItem[tag].Count();
                }

                var childItem = new OSMTreeGridItem(tag, nodeCount, wayCount, true, false);
                if (childItem.OSMData.Key != null)
                {
                    var parentKey = indexOfParents[childItem.OSMData.Key.Value];
                    var parent    = selectableTags[parentKey] as OSMTreeGridItem;
                    parent.Children.Add(childItem);
                }
            }

            foreach (OSMTreeGridItem tag in selectableTags) // Hack to sort numeric data properly
            {
                if (OSMSpecialTags.numericTags.ContainsKey(tag.OSMData.Value))
                {
                    var childrenCopy = tag.Children.Cast <OSMTreeGridItem>().OrderBy(
                        item => TreeGridUtilities.MayBeIntSort(item)).ToList();
                    tag.Children.Clear();
                    tag.Children.AddRange(childrenCopy);
                }
            }

            return(selectableTags);
        }
        protected override void CaribouSolveInstance(IGH_DataAccess da)
        {
            logger.Reset();

            #region Input Parsing

            da.GetDataTree(0, out GH_Structure <IGH_Goo> itemsTree);
            if (itemsTree.Branches[0][0] as IGH_GeometricGoo == null)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error,
                                       "It looks like you have provided a non-geometry input to the Items parameter. This input should connect to the Nodes, Ways, or Buildings outputs produced by the Extract components.");
                return;
            }

            ProvidedNodes = itemsTree.Branches[0][0] is GH_Point;

            da.GetDataTree(1, out GH_Structure <GH_String> tagsTree);
            if (tagsTree.Branches[0].Count >= 3)
            {
                if (tagsTree.Branches[0][2].ToString().Contains(" found"))
                {
                    this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error,
                                           "It looks like you have provided a Report parameter output as the Tag parameter input. Use a Tag parameter output instead.");
                    return;
                }
            }

            if (itemsTree.PathCount != tagsTree.PathCount)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning,
                                       "The path counts of the Items and Tags do not match - check these are coming from the same component.");
            }
            else if (itemsTree.Branches.Count != tagsTree.Branches.Count)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning,
                                       "The branch structure of the Items and Tags do not match - check these are coming from the same component.");
            }

            logger.NoteTiming("Input capture");
            #endregion

            #region Form Data Setup
            // Setup form-presentable items for tags provided and parsed into OSM objects
            var requests = new OSMListWithPaths(tagsTree); // Parse provided tree into OSM objects and a dictionary of paths per object
            logger.NoteTiming("Tag parsing");

            // If tags have changed we write out current state so we can try to preserve it in the new tags list
            if (this.PreviousTagsDescription != null)
            {
                if (tagsTree.DataDescription(false, false) != this.PreviousTagsDescription)
                {
                    this.storedSelectionState = GetStateKeys();
                }
            }

            // If loading from scratch, or if the tags have changed
            if (this.storedSelectionState != null)
            {
                var availableOSMs = GetSelectableTagsFromInputTree(requests);
                this.selectableOSMs = TreeGridUtilities.SetSelectionsFromStoredState(
                    availableOSMs, this.storedSelectionState);
                this.storedSelectionState = null; // Reset flag
            }
            else
            {
                this.selectableOSMs = GetSelectableTagsFromInputTree(requests);
            }

            this.PreviousTagsDescription  = tagsTree.DataDescription(false, false); // Track tag input identity
            this.selectionStateSerialized = GetSelectedKeyValuesFromForm();
            logger.NoteTiming("State loading/making");
            #endregion

            #region Outputting
            // Match geometry paths to selected filters
            var geometryOutput = new GH_Structure <IGH_Goo>();
            var tagOutput      = new GH_Structure <GH_String>();
            // Setup tracking dictionary for the report tree output
            var foundItemCountsForResult = new Dictionary <OSMTag, int>();

            for (int i = 0; i < this.selectionStateSerialized.Count; i++)
            {
                string itemKeyValue = this.selectionStateSerialized[i];
                OSMTag osmItem      = new OSMTag(itemKeyValue);

                if (!requests.pathsPerItem.ContainsKey(osmItem))
                {
                    continue;
                }

                foundItemCountsForResult[osmItem] = 0;
                // Match keyvalues to OSMListwithpaths
                for (int j = 0; j < requests.pathsPerItem[osmItem].Count; j++)
                {
                    GH_Path inputPath = requests.pathsPerItem[osmItem][j];

                    var geometryItemsForPath = itemsTree.get_Branch(inputPath);
                    var tagItemsForPath      = tagsTree.get_Branch(inputPath);
                    if (geometryItemsForPath == null)
                    {
                        continue; // No provided geometry path for that OSM item
                    }
                    foundItemCountsForResult[osmItem] += 1;
                    for (int k = 0; k < geometryItemsForPath.Count; k++)
                    {
                        GH_Path outputPathFor = new GH_Path(i, j);
                        geometryOutput.EnsurePath(outputPathFor); // Need to ensure even an empty path exists to enable data matching
                        tagOutput.EnsurePath(outputPathFor);      // Need to ensure even an empty path exists to enable data matching

                        geometryOutput.Append(geometryItemsForPath[k] as IGH_Goo, outputPathFor);
                        foreach (GH_String tag in tagItemsForPath)
                        {
                            tagOutput.Append(tag, outputPathFor);
                        }
                    }
                }
            }
            logger.NoteTiming("Geometry matching");

            var requestReport = TreeFormatters.MakeReportForRequests(foundItemCountsForResult);
            logger.NoteTiming("Tree formatting");

            this.OutputMessageBelowComponent();

            da.SetDataTree(0, geometryOutput);
            da.SetDataTree(1, tagOutput);
            da.SetDataTree(2, requestReport);
            logger.NoteTiming("Data tree setting");
            #endregion
        }
 private List <string> GetExpectedPathIndicesForTag(OSMListWithPaths resultMetaData, OSMTag tag)
 {
     return(resultMetaData.pathsPerItem[tag].Select(o => o.ToString()).ToList());
 }