/* Function: SegmentMenu * Segments the menu into smaller pieces and generates data file names. */ protected void SegmentMenu(MenuEntries.Base.Container container, string dataFileType, ref StringTable <IDObjects.NumberSet> usedDataFiles) { // Generate the data file name for this container. IDObjects.NumberSet usedDataFileNumbers = usedDataFiles[dataFileType]; if (usedDataFileNumbers == null) { usedDataFileNumbers = new IDObjects.NumberSet(); usedDataFiles.Add(dataFileType, usedDataFileNumbers); } int dataFileNumber = usedDataFileNumbers.LowestAvailable; usedDataFileNumbers.Add(dataFileNumber); ContainerExtraData extraData = (ContainerExtraData)container.ExtraData; extraData.DataFileName = HTMLBuilder.Menu_DataFileNameOnly(dataFileType, dataFileNumber); // The data file has to include all the members in this container no matter what. int containerJSONSize = extraData.JSONBeforeMembers.Length + extraData.JSONAfterMembers.Length + extraData.JSONLengthOfMembers; List <MenuEntries.Base.Container> subContainers = null; foreach (var member in container.Members) { if (member is MenuEntries.Base.Container) { if (subContainers == null) { subContainers = new List <MenuEntries.Base.Container>(); } subContainers.Add((MenuEntries.Base.Container)member); } } // Now start including the contents of subcontainers until we reach the size limit. We're going breadth-first instead of // depth first. List <MenuEntries.Base.Container> nextSubContainers = null; for (;;) { if (subContainers == null || subContainers.Count == 0) { if (nextSubContainers == null || nextSubContainers.Count == 0) { break; } else { subContainers = nextSubContainers; nextSubContainers = null; } } // Add subcontainers to the file in the order from smallest to largest. This prevents one very large container early // in the list from causing all the other ones to be broken out into separate files. // DEPENDENCY: ContainerExtraData.JSONLengthOfMembers must cache its value for this algorithm to be efficient. int smallestSubContainerIndex = 0; int smallestSubContainerSize = (subContainers[0].ExtraData as ContainerExtraData).JSONLengthOfMembers; for (int i = 1; i < subContainers.Count; i++) { if ((subContainers[i].ExtraData as ContainerExtraData).JSONLengthOfMembers < smallestSubContainerSize) { smallestSubContainerIndex = i; smallestSubContainerSize = (subContainers[i].ExtraData as ContainerExtraData).JSONLengthOfMembers; } } containerJSONSize += smallestSubContainerSize; if (containerJSONSize > SegmentLength) { break; } foreach (var member in subContainers[smallestSubContainerIndex].Members) { if (member is MenuEntries.Base.Container) { if (nextSubContainers == null) { nextSubContainers = new List <MenuEntries.Base.Container>(); } nextSubContainers.Add((MenuEntries.Base.Container)member); } } subContainers.RemoveAt(smallestSubContainerIndex); } // Now recurse through any remaining subcontainers so they get their own files. if (subContainers != null) { foreach (var subContainer in subContainers) { SegmentMenu(subContainer, dataFileType, ref usedDataFiles); } } if (nextSubContainers != null) { foreach (var subContainer in nextSubContainers) { SegmentMenu(subContainer, dataFileType, ref usedDataFiles); } } }