private void HandleDetailReset( object masterItem, DetailGeneratorNode detailNode )
    {
      GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 );
      int masterIndex = nodeHelper.FindItem( masterItem );

      // -1 means either taht the master item is below a collapsed group node, or that the item does not exists, validate.
      if( masterIndex == -1 )
      {
        nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 );
        if( !nodeHelper.Contains( masterItem ) )
          throw new DataGridInternalException();
      }

      ItemsGeneratorNode masterNode = nodeHelper.CurrentNode as ItemsGeneratorNode;

      Debug.Assert( masterNode != null, "masterNode != null" );
#if LOG
      Log.Assert( this, masterNode != null, "masterNode != null" );
#endif

      //start index will be ignored later on if the masterIndex is -1!!
      int startIndex = nodeHelper.Index + masterNode.IndexOf( masterItem ) + 1; //details start a master index + 1

      List<DetailGeneratorNode> detailsForMaster = null;

      //edge case, it is possible to receive a Reset from Floating details!
      if( masterNode.Details == null )
      {
        //check for floating details, if not present, throw, this is an abnormal case.
        if( !m_floatingDetails.Contains( masterItem ) )
        {
          throw new DataGridInternalException();
        }
      }
      else
      {
        masterNode.Details.TryGetValue( masterNode.Items.IndexOf( masterItem ), out detailsForMaster );

        Debug.Assert( detailsForMaster != null, "detailsForMaster != null" );
#if LOG
        Log.Assert( this, detailsForMaster != null, "detailsForMaster != null" );
#endif
      }

      if( detailsForMaster != null )
      {
        //this is required to ensure that if the details that resets is not the first one, the index is calculated appropriatly.
        foreach( DetailGeneratorNode node in detailsForMaster )
        {
          if( node == detailNode )
          {
            break;
          }
          else
          {
            startIndex += node.ItemCount;
          }
        }

        //if there were 'items' in the detail node, process the remove of them
        int oldDetailCount = detailNode.ItemCount;
        if( oldDetailCount > 0 )
        {
          int endIndex = startIndex + oldDetailCount - 1; //last detail index

          GeneratorPosition removeGenPos = ( masterIndex != -1 )
            ? this.GeneratorPositionFromIndex( startIndex )
            : new GeneratorPosition( -1, 1 );

          int genRemCount = 0;

          List<DependencyObject> removedContainers = new List<DependencyObject>();

          //this has no uses if the masterIndex is -1 ( collapsed master item )
          if( masterIndex != -1 )
          {
            genRemCount = this.RemoveGeneratedItems( startIndex, endIndex, removedContainers );
          }

          masterNode.AdjustItemCount( -oldDetailCount );

          this.IncrementCurrentGenerationCount();

          //this has no uses if the masterIndex is -1 ( collapsed master item )
          if( masterIndex != -1 )
          {
            this.SendRemoveEvent( removeGenPos, masterIndex + 1, oldDetailCount, genRemCount, removedContainers );
          }
        }

        detailNode.UpdateItemCount();

        int newDetailCount = detailNode.ItemCount;
        if( newDetailCount > 0 )
        {
          GeneratorPosition addGenPos = new GeneratorPosition( -1, 1 );

          //this has no uses if the masterIndex is -1 ( collapsed master item )
          if( masterIndex != -1 )
          {
            addGenPos = this.GeneratorPositionFromIndex( startIndex );
          }

          masterNode.AdjustItemCount( newDetailCount );

          this.IncrementCurrentGenerationCount();

          //this has no uses if the masterIndex is -1 ( collapsed master item )
          if( masterIndex != -1 )
          {
            this.SendAddEvent( addGenPos, masterIndex + 1, newDetailCount );
          }
        }
      }
    }
    private void HandleDetailMoveRemove( object masterItem, DetailGeneratorNode detailNode, CustomGeneratorChangedEventArgs e )
    {
      GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 );
      int masterIndex = nodeHelper.FindItem( masterItem );

      //If the masterItem is part of an ItemsGeneratorNode which is below a collapsed group, masterIndex will be -1
      if( masterIndex == -1 )
      {
        //in that case, I need to determine the appropriate masterNode another way
        nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 );
        if( !nodeHelper.Contains( masterItem ) )
          throw new DataGridInternalException();
      }

      ItemsGeneratorNode masterNode = nodeHelper.CurrentNode as ItemsGeneratorNode;

      Debug.Assert( masterNode != null, "masterNode != null" );
#if LOG
      Log.Assert( this, masterNode != null, "masterNode != null" );
#endif

      int globalIndex = -1;
      GeneratorPosition convertedGeneratorPosition = ( masterIndex != -1 ) ? this.ConvertDetailGeneratorPosition( e.OldPosition, masterItem, detailNode, out globalIndex ) : new GeneratorPosition( -1, 1 );

      if( masterIndex != -1 )
      {
        this.RemoveDetailContainers( convertedGeneratorPosition, e.ItemUICount );
      }

      if( e.Action == NotifyCollectionChangedAction.Remove )
      {
        masterNode.AdjustItemCount( -e.ItemCount );

        detailNode.UpdateItemCount();
      }

      this.IncrementCurrentGenerationCount();

      if( masterIndex != -1 )
      {
        this.SendRemoveEvent( convertedGeneratorPosition, globalIndex, e.ItemCount, e.ItemUICount, e.RemovedContainers );
      }
    }
    private int FindGlobalIndexForDetailNode( DetailGeneratorNode detailNode )
    {
      int retval = -1;

      //first thing, loop through the details for the 
      foreach( KeyValuePair<object, List<DetailGeneratorNode>> masterItemToDetails in m_masterToDetails )
      {
        //in each master to details entry, try to find the detail node passed
        int detailIndex = masterItemToDetails.Value.IndexOf( detailNode );
        if( detailIndex != -1 )
        {
          //if the desired detailNode is present for this master item... then evaluate it...
          int detailNodeOffset = 0;
          for( int i = 0; i < detailIndex; i++ )
          {
            detailNodeOffset += masterItemToDetails.Value[ i ].ItemCount - 1;
          }

          int index = m_genPosToItem.IndexOf( masterItemToDetails.Key );
          int masterItemIndex;

          if( index > -1 )
          {
            masterItemIndex = m_genPosToIndex[ index ];
          }
          else
          {
            GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 );
            masterItemIndex = nodeHelper.FindItem( masterItemToDetails.Key );
          }

          if( masterItemIndex == -1 )
            throw new DataGridInternalException();

          retval = detailNodeOffset + masterItemIndex + detailIndex + 1;

          //leave the top level loop
          break;
        }
      }

      return retval;
    }
    private void UpdateGenPosToIndexList()
    {
#if LOG
      int count = m_genPosToIndex.Count;
      int previousIndex = -1;

      for( int i = 0; i < count; i++ )
      {
        int tempIndex = m_genPosToIndex[ i ];

        if( tempIndex >= previousIndex )
        {
          previousIndex = tempIndex;
        }
        else
        {
          Debug.Assert( false, "### none sequential index detected (before)" );
          Log.Assert( this, false, "### none sequential index detected (before)" );
          this.WriteStateInLog();
          break;
        }
      }
#endif
      //after the modification to have the item count stored "locally" in the DetailGeneratorNodes,
      //it becomes important to have the nodes updated when the layout of the items changes.
      if( m_masterToDetails.Count > 0 )
      {
        foreach( KeyValuePair<object, List<DetailGeneratorNode>> masterToDetails in m_masterToDetails )
        {
          foreach( DetailGeneratorNode detailNode in masterToDetails.Value )
          {
            detailNode.UpdateItemCount();
          }
        }
      }

      if( m_startNode != null )
      {
        GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 ); //index is 0, since i'm beginning at the start 
        //(and I want to reindex the whole list)

        DetailGeneratorNode cachedDetailNode = null;
        int cachedDetailNodeIndex = -1;
        int previousDetailIndex = -1;

        //loop through the realized items. By design they are present sequentially in the linked list, so I do not need to reset the GeneratorNodeHelper
        for( int i = 0; i < m_genPosToItem.Count; i++ )
        {
          object item = m_genPosToItem[ i ];

          DetailGeneratorNode detailNode = m_genPosToNode[ i ] as DetailGeneratorNode;
          if( detailNode == null )
          {
            //find the Item 
            int tmpIndex = nodeHelper.FindItem( item );
            if( tmpIndex != -1 )
            {
              //set the Index (new) for the item
              ItemsGeneratorNode itemsNode = nodeHelper.CurrentNode as ItemsGeneratorNode;
              if( itemsNode != null )
              {
                tmpIndex = nodeHelper.Index + itemsNode.IndexOf( item );
              }

              m_genPosToIndex[ i ] = tmpIndex;
            }
            else
            {
#if LOG
              if( item == null )
              {
                Log.WriteLine( this, "# UpdateGenPosToIndexList - item not found Dnull" );
              }
              else
              {
                Log.WriteLine( this, "# UpdateGenPosToIndexList - Item not found D" + item.GetHashCode() );
              }
#endif
              //a possible fix for this is to set the index of the "not found" element to the same index as previous item in the generated list...
              m_genPosToIndex[ i ] = ( i > 0 ) ? m_genPosToIndex[ i - 1 ] : 0;

              //item is not in the linked list... there is a problem, throw.
              //throw new DataGridInternalException();

            }
          }
          else //else is detailNode != null
          {
            if( cachedDetailNode != detailNode )
            {
              cachedDetailNodeIndex = this.FindGlobalIndexForDetailNode( detailNode );
              cachedDetailNode = detailNode;
              previousDetailIndex = -1;
            }
            int detailIndex = detailNode.DetailGenerator.IndexFromRealizedItem( item, previousDetailIndex + 1, out previousDetailIndex );
            m_genPosToIndex[ i ] = cachedDetailNodeIndex + detailIndex;
          }
        } //end for()
      }

#if LOG
      count = m_genPosToIndex.Count;
      previousIndex = -1;

      for( int i = 0; i < count; i++ )
      {
        int tempIndex = m_genPosToIndex[ i ];

        if( tempIndex >= previousIndex )
        {
          previousIndex = tempIndex;
        }
        else
        {
          Debug.Assert( false, "### none sequential index detected (after)" );
          Log.Assert( this, false, "### none sequential index detected (after)" );
          this.WriteStateInLog();
          break;
        }
      }
#endif
    }
    public int IndexFromItem( object item )
    {
      int retval = -1;

      if( item != null )
      {
        this.EnsureNodeTreeCreated();

        if( m_startNode != null )
        {
          //if item is generated
          int generatedIndex = this.FindFirstGeneratedIndexForLocalItem( item );
          if( generatedIndex != -1 )
          {
            retval = m_genPosToIndex[ generatedIndex ];
          }
          //if the item is not generated
          else
          {
            GeneratorNodeHelper nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 );
            //Note: Under that specific case, I do not want to search through collapsed group nodes... Effectivelly, an item "below" a collapsed group node 
            // Have no index as per the "item to index" interface of the generator. 
            retval = nodeHelper.FindItem( item );
          }
        }
      }

      return retval;
    }
    public List<StickyContainerGenerated> GenerateStickyFooters(
      DependencyObject container,
      bool areFootersSticky,
      bool areGroupFootersSticky )
    {
      List<StickyContainerGenerated> generatedStickyContainers = new List<StickyContainerGenerated>();

      GeneratorNode containerNode;
      int containerRealizedIndex;
      object containerDataItem;


      if( this.FindGeneratorListMappingInformationForContainer( container,
                                                                out containerNode,
                                                                out containerRealizedIndex,
                                                                out containerDataItem ) )
      {
        GeneratorNodeHelper nodeHelper = null;
        DetailGeneratorNode detailNode = containerNode as DetailGeneratorNode;

        if( detailNode != null )
        {
          // Get the parent item of the detail node to be able
          // to readjust the containerRealizedIndex to the one
          // of the master item container since the detail node
          // will be processed by the DetailGenerator.
          containerDataItem = detailNode.DetailContext.ParentItem;

          // OPTIMIZATION: We will look in the m_genPos* first to avoid using
          //               FindItem for performance reason.
          int index = m_genPosToItem.IndexOf( containerDataItem );
          if( index > -1 )
          {
            int sourceDataIndex = ( int )m_genPosToContainer[ index ].GetValue( DataGridVirtualizingPanel.ItemIndexProperty );
            containerNode = m_genPosToNode[ index ];
            containerRealizedIndex = m_genPosToIndex[ index ];

            CollectionGeneratorNode collectionNode = containerNode as CollectionGeneratorNode;
            if( collectionNode != null )
            {
              nodeHelper = new GeneratorNodeHelper( containerNode, containerRealizedIndex - collectionNode.IndexOf( containerDataItem ), sourceDataIndex );
            }
          }

          if( nodeHelper == null )
          {
            // We want to find the ItemsGeneratorNode for the DetailNode.
            nodeHelper = new GeneratorNodeHelper( m_startNode, 0, 0 );
            containerRealizedIndex = nodeHelper.FindItem( containerDataItem );
            containerNode = nodeHelper.CurrentNode;
          }

          if( containerRealizedIndex == -1 )
            throw new DataGridInternalException();

          generatedStickyContainers.AddRange(
            this.GenerateStickyFootersForDetail( container, detailNode, areFootersSticky, areGroupFootersSticky ) );
        }
        else
        {
          CollectionGeneratorNode collectionNode = containerNode as CollectionGeneratorNode;
          if( collectionNode != null )
          {
            // We don't need to have an up to date sourceDataIndex so we pass 0
            nodeHelper = new GeneratorNodeHelper( containerNode, containerRealizedIndex - collectionNode.IndexOf( containerDataItem ), 0 );
          }

          if( nodeHelper == null )
          {
            nodeHelper = new GeneratorNodeHelper( containerNode, 0, 0 );
            nodeHelper.ReverseCalculateIndex();
          }
        }

        bool isHeaderNode =
          ( ( nodeHelper.CurrentNode is HeadersFootersGeneratorNode ) &&
            ( nodeHelper.CurrentNode.Previous == null ) );

        // We want to find the HeaderFooterGeneratorNode for the container 
        // node. This is to find the footers for the container.
        nodeHelper.MoveToEnd();
        HeadersFootersGeneratorNode footersNode = nodeHelper.CurrentNode as HeadersFootersGeneratorNode;

        if( !isHeaderNode )
        {
          // There is no footers to generate if the item count of the node is 0.
          if( footersNode.ItemCount > 0 )
          {
            if( ( ( areFootersSticky ) && ( footersNode.Parent == null ) )
              || ( ( areGroupFootersSticky ) && ( footersNode.Parent is GroupGeneratorNode ) ) )
            {
              generatedStickyContainers.AddRange(
                this.GenerateStickyFootersForNode( footersNode,
                                                   nodeHelper.Index,
                                                   containerRealizedIndex,
                                                   ( footersNode == containerNode ) ) );
            }
          }
        }

        // We must also find the bottom most footers for our level of detail and, if they need to be sticky,
        // we will generate the containers and add them the to list.
        HeadersFootersGeneratorNode bottomFootersNode = this.GetDetailFootersNode( nodeHelper );

        if( ( areFootersSticky )
          && ( bottomFootersNode != null )
          && ( bottomFootersNode != footersNode )
          && ( bottomFootersNode.ItemCount > 0 ) )
        {
          generatedStickyContainers.AddRange(
            this.GenerateStickyFootersForNode( bottomFootersNode, nodeHelper.Index ) );
        }
      }

      return generatedStickyContainers;
    }