!=========================================================================
!
! Methods that depend upon IndexManager for 
!         UnorderedCollection, IdentityIndex, SortNodeArray, and 
!         RangeEqualityIndex
!
!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: unorderedcoll3.gs,v 1.15 2008-01-09 22:50:20 stever Exp $
!
!========================================================================
category: 'Updating Indexes'
method: UnorderedCollection
createIdentityIndexOn: aPathString

"Creates an identity index on aPathString.  Generates an error if aPathString
 is not a path for the element kind of the receiver or if any term of the path
 except the last term is not constrained."

"If an error occurs during index creation, it may not be possible to commit the
 current transaction later."

self _checkIndexPathExpression: aPathString.

IndexManager current executeStartingIndexMaintenance: [
  IndexManager current
     createIdentityIndexFor: self
     on: aPathString.
].
%

category: 'Updating Indexes'
method: UnorderedCollection
createEqualityIndexOn: aPathString
withLastElementClass: aClass

"Creates an equality index on the path specified by aPathString.  The equality
 index is ordered according to the sort-provided comparison operators provided
 by aClass."

"Note: An error occurring during index creation may cause the
 current transaction to be unable to commit."

| result |

"validate user parameters."
aClass _validateClass: Behavior.

self _checkIndexPathExpression: aPathString.

IndexManager current executeStartingIndexMaintenance: [
  result := IndexManager current
     createEqualityIndexFor: self
     on: aPathString
     withLastElementClass: aClass.
].

result ~~ nil
  ifTrue: [ ^ self _error: (result at: 1) args: (result at: 2) ]
%

category: 'Updating Indexes'
method: UnorderedCollection
createRcEqualityIndexOn: aPathString
withLastElementClass: aClass

"Creates an equality index on the path specified by aPathString.  The equality
 index is ordered according to the sort-provided comparison operators provided
 by aClass."

"Note: An error occurring during index creation may cause the
 current transaction to be unable to commit."

| result |

"validate user parameters."
aClass _validateClass: Behavior.

self _checkIndexPathExpression: aPathString.

IndexManager current executeStartingIndexMaintenance: [
  result := IndexManager current
     createRcEqualityIndexFor: self
     on: aPathString
     withLastElementClass: aClass.
].

result ~~ nil
  ifTrue: [ ^ self _error: (result at: 1) args: (result at: 2) ]
%

category: 'Updating Indexes'
method: UnorderedCollection
removeAllIndexes

"Remove all indexes for the receiver. If all of the receiver's indexes can be 
 removed, this method returns the receiver."

"If an error occurs during index removal, it may not be possible to commit the
 current transaction later."

^ IndexManager current removeAllIndexesOn: self.
%

category: 'Updating Indexes'
method: UnorderedCollection
removeEqualityIndexOn: aPathString

"If an equality index exists on aPathString, remove that index.  If the
 path string is invalid or no index exists on the given path, an error
 is raised.  If aPathString is an implicit index (due to the receiver's
 participation as a set-valued instance variable in some other NSC's
 index), then this method returns the path string."

"If an error occurs during index removal, it may not be possible to commit the
 current transaction later."

self _checkIndexPathExpression: aPathString.

IndexManager current removeEqualityIndexFor: self on: aPathString
%

category: 'Updating Indexes'
method: UnorderedCollection
removeIdentityIndexOn: aPathString

"If an identity index exists on aPathString, and aPathString is not a
 proper prefix of some indexed path, the the index is removed.  If the
 path string is invalid or no index exists on the given path, an error
 is raised.  If aPathString is an implicit index (due to the receiver's
 participation as a set-valued instance variable in some other NSC's
 index), then this method returns the path string."

"If an error occurs during index removal, it may not be possible to commit the
 current transaction later."

self _checkIndexPathExpression: aPathString.

IndexManager current removeIdentityIndexFor: self on: aPathString
%

category: 'Accessing'
method: IdentityIndex
indexManager

^IndexManager current
%

category: 'Accessing'
method: RangeEqualityIndex
indexManager

^IndexManager current
%

category: 'Accessing'
method: Behavior
indexManager

^IndexManager current
%

category: 'Accessing'
method: SortNodeArray
indexManager

^IndexManager current
%

category: 'Accessing'
method: RcIndexDictionary
indexManager

^IndexManager current
%


category: 'Updating Indexes - Private'
method: UnorderedCollection
_removeIndex: indexObj

"Removes the index from the receiver.  Returns the receiver."

| pathTerm endObj parentTerm obj iList bag incomplete allTerms indexManager |

" since indexes may share path terms, find the first one that is not shared "
indexManager := IndexManager current.
pathTerm := indexObj _findFirstUnsharedPathTerm.
pathTerm == nil
  ifFalse: [
    parentTerm := pathTerm getParentTerm.
    bag := self _asIdentityBag.
    incomplete := #_incompletePathTraversal.

    " see if the index is on elements of the NSC "
    pathTerm indicatesIndexOnRootNsc
      ifTrue: [
        1 to: bag size do: [ :j |
          obj := bag _at: j.
          pathTerm removeDirectMappingFor: obj logging: false.
          DependencyList removePathTerm: pathTerm for: obj.
          indexManager commitIndexMaintenance: indexObj at: j.
        ]
      ]
      ifFalse: [
        Exception
          category: GemStoneError
          number: (ErrorSymbols at: #rtErrObjectPathTermNotInDependencyList) 
          do: [ :ex :cat :num :args |
          "catch #rtErrObjectPathTermNotInDependencyList and continue, don't want
           this error to stop us ..."
        ].
        1 to: bag size do: [ :j |
          endObj := indexObj traverse: (bag _at: j) upTo: pathTerm.
          ( nil ~~ endObj _and: [ incomplete ~~ endObj ] )
            ifTrue: [
              pathTerm removeMappingsFor: endObj
                lastOne: true
                logging: false.
              DependencyList removePathTerm: pathTerm for: endObj.
              indexManager commitIndexMaintenance: indexObj at: j.
            ]
        ]
      ].
    allTerms := pathTerm _thisAndAllChildTerms.
  ].

" remove index from each path term "
1 to: indexObj size do: [ :i |
  (indexObj at: i) removeIndex: indexObj
].

" remove dependency lists from global table that are no longer needed "
allTerms ~~ nil
  ifTrue: [
    SharedDependencyLists removeEntriesContaining: allTerms.
  ].

iList := self _indexedPaths.
" remove the entry in the receiver's index list "
iList removeIndex: indexObj withOffset: 1 for: self.

parentTerm ~~ nil
  ifTrue: [ parentTerm _determineChildren ]
%

category: 'Updating Indexes - Private'
method: UnorderedCollection
_undoIndexCreation: indexObj pathTerm: pathTerm

"Removes any vestiges of the incomplete index, and attempts to commit this
 transaction until successful."

| parentTerm iList bag incomplete indexManager obj endObj |
  indexManager := IndexManager current.
  parentTerm := pathTerm getParentTerm.
  bag := self _asIdentityBag.
  incomplete := #_incompletePathTraversal.
  pathTerm indicatesIndexOnRootNsc
      ifTrue: [
        1 to: bag size do: [ :j |
          obj := bag _at: j.
          pathTerm undoDirectMappingFor: obj logging: false.
          DependencyList removePathTerm: pathTerm for: obj.
        ]
      ]
      ifFalse: [
        1 to: bag size do: [ :j |
          endObj := indexObj traverse: (bag _at: j) upTo: pathTerm.
          ( nil ~~ endObj _and: [ incomplete ~~ endObj ] )
            ifTrue: [
              pathTerm undoMappingsFor: endObj
                lastOne: true
                logging: false.
              DependencyList removePathTerm: pathTerm for: endObj
            ]
        ]
    ].

  " remove index from each path term "
  1 to: indexObj size do: [ :i | (indexObj at: i) removeIndex: indexObj ].

  " make path term (and its children) unusable "
  pathTerm _makeObsolete.

  " remove the entry in the receiver's index list "
  (iList := self _indexedPaths) ~~ nil
    ifTrue: [ iList removeIndex: indexObj withOffset: 1 for: self ].

  parentTerm ~~ nil
    ifTrue: [ parentTerm _determineChildren ].
%

category: 'Updating Indexes - Private'
method: UnorderedCollection
_removeAllIncompleteIndexes

" Remove index list entries for any incomplete indexes found in the receiver.
Returns the number of incomplete indexes found."

^IndexManager current removeAllIncompleteIndexesOn: self
%
