/**
 * Copyright (C) 2006 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.inject.internal;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.inject.Key;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.DependencyAndSource;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Internal context. Used to coordinate injections and support circular
 * dependencies.
 *
 * @author crazybob@google.com (Bob Lee)
 */
final class InternalContext {

  private Map<Object, ConstructionContext<?>> constructionContexts = Maps.newHashMap();
  /** Keeps track of the type that is currently being requested for injection. */
  private Dependency dependency;
  /** Keeps track of the hierarchy of types needed during injection. */
  private LinkedList<DependencyAndSource> state = new LinkedList<DependencyAndSource>();

  @SuppressWarnings("unchecked")
  public <T> ConstructionContext<T> getConstructionContext(Object key) {
    ConstructionContext<T> constructionContext
        = (ConstructionContext<T>) constructionContexts.get(key);
    if (constructionContext == null) {
      constructionContext = new ConstructionContext<T>();
      constructionContexts.put(key, constructionContext);
    }
    return constructionContext;
  }

  public Dependency getDependency() {
    return dependency;
  }

  /** Sets the new current dependency & adds it to the state. */
  public Dependency pushDependency(Dependency dependency, Object source) {
    Dependency previous = this.dependency;
    this.dependency = dependency;
    state.addLast(new DependencyAndSource(dependency, source));
    return previous;
  }
  
  /** Pops the current state & sets the new dependency. */
  public void popStateAndSetDependency(Dependency newDependency) {
    popState();
    this.dependency = newDependency;
  }
  
  /** Adds to the state without setting the dependency. */
  public void pushState(Key<?> key, Object source) {
    state.addLast(new DependencyAndSource(key == null ? null : Dependency.get(key), source));
  }
  
  /** Pops from the state without setting a dependency. */
  public void popState() {
    state.removeLast();
  }
  
  /** Returns the current dependency chain (all the state). */
  public List<DependencyAndSource> getDependencyChain() {
    return ImmutableList.copyOf(state);
  }
}

@@ -671,24 +671,64 @@
 utableList;%0A
+import com.google.common.collect.Lists;%0A
 import com.g
@@ -893,22 +893,21 @@
 va.util.
-Linked
+Array
 List;%0Aim
@@ -1210,16 +1210,17 @@
 hMap();%0A
+%0A
   /** Ke
@@ -1305,32 +1305,35 @@
 ivate Dependency
+%3C?%3E
  dependency;%0A  /
@@ -1329,21 +1329,27 @@
 ndency;%0A
+%0A
   /**
+%0A   *
  Keeps t
@@ -1407,97 +1407,361 @@
 ion.
+%0A  
  *
-/
 %0A  
-private LinkedList%3CDependencyAndSource%3E state = new LinkedList%3CDependencyAndSource%3E
+ * %3Cp%3EThis is a pairwise combination of dependencies and sources, with dependencies on even%0A   * indices, and sources on odd indices. This structure is to avoid the memory overhead of%0A   * DependencyAndSource objects, which can add to several tens of megabytes in large applications.%0A   */%0A  private final List%3CObject%3E state = Lists.newArrayList
 ();%0A
@@ -2197,16 +2197,19 @@
 pendency
+%3C?%3E
  getDepe
@@ -2331,16 +2331,19 @@
 pendency
+%3C?%3E
  pushDep
@@ -2360,16 +2360,19 @@
 pendency
+%3C?%3E
  depende
@@ -2407,16 +2407,19 @@
 pendency
+%3C?%3E
  previou
@@ -2490,57 +2490,43 @@
 .add
-Last(new DependencyAndSource(dependency, 
+(dependency);%0A    state.add(
 source)
-)
 ;%0A  
@@ -2659,16 +2659,19 @@
 pendency
+%3C?%3E
  newDepe
@@ -2869,36 +2869,8 @@
 .add
-Last(new DependencyAndSource
 (key
@@ -2910,18 +2910,32 @@
 key)
-, 
+);%0A    state.add(
 source)
-)
 ;%0A  
@@ -3045,13 +3045,61 @@
 move
-Last(
+(state.size() - 1);%0A    state.remove(state.size() - 1
 );%0A 
@@ -3233,41 +3233,268 @@
     
-return ImmutableList.copyOf(state
+ImmutableList.Builder%3CDependencyAndSource%3E builder = ImmutableList.builder();%0A    for (int i = 0; i %3C state.size(); i += 2) %7B%0A      builder.add(new DependencyAndSource(%0A          (Dependency%3C?%3E) state.get(i), state.get(i + 1)));%0A    %7D%0A    return builder.build(
 );%0A 

Switch InternalContext to store dependency/source pairs more compactly.