Incremental work for parser-filtering
diff --git a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
index f4d2533..3e22fbf 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
@@ -212,9 +212,10 @@
     {
         // Anything buffered?
         TokenFilterContext ctxt = _exposedContext;
+
         if (ctxt != null) {
             while (true) {
-                JsonToken t = _exposedContext.nextTokenToRead(_currToken);
+                JsonToken t = _exposedContext.nextTokenToRead();
                 if (t != null) {
                     _currToken = t;
                     return t;
@@ -358,45 +359,203 @@
     /**
      * Offlined handling for cases where there was no buffered token to
      * return, and the token read next could not be returned as-is,
-     * at least not yet.
+     * at least not yet, but where we have not yet established that
+     * buffering is needed.
      */
     protected final JsonToken _nextToken2() throws IOException
     {
+        main_loop:
         while (true) {
             JsonToken t = delegate.nextToken();
-            if (t == null) { // is this really legal? For the moment, assume it is
+
+            if (t == null) { // is this even legal?
                 return (_currToken = t);
             }
-            switch (_currToken.id()) {
+            TokenFilter f;
+
+            switch (t.id()) {
             case ID_START_ARRAY:
-                if (_itemFilter == TokenFilter.INCLUDE_ALL) {
-                    _headContext = _headContext.createChildArrayContext(_itemFilter, true);
+                f = _itemFilter;
+                if (f == TokenFilter.INCLUDE_ALL) {
+                    _headContext = _headContext.createChildArrayContext(f, true);
                     return (_currToken = t);
                 }
-                if (_itemFilter == null) { // does this occur?
+                if (f == null) { // does this occur?
                     delegate.skipChildren();
-                    break;
+                    continue main_loop;
                 }
-                _exposedContext = _headContext = _headContext.createChildArrayContext(_itemFilter, false);
-                break;
-    
+                // Otherwise still iffy, need to check
+                f = _headContext.checkValue(f);
+                if (f == null) {
+                    delegate.skipChildren();
+                    continue main_loop;
+                }
+                if (f != TokenFilter.INCLUDE_ALL) {
+                    f = f.filterStartArray();
+                }
+                _itemFilter = f;
+                _headContext = _headContext.createChildArrayContext(f, true);
+                if (f == TokenFilter.INCLUDE_ALL) {
+                    return (_currToken = t);
+                }
+                // but if we didn't figure it out yet, need to buffer possible events
+                return _nextTokenWithBuffering(_headContext);
+
             case ID_START_OBJECT:
-                if (_itemFilter == TokenFilter.INCLUDE_ALL) {
-                    _headContext = _headContext.createChildObjectContext(_itemFilter, true);
+                f = _itemFilter;
+                if (f == TokenFilter.INCLUDE_ALL) {
+                    _headContext = _headContext.createChildObjectContext(f, true);
                     return (_currToken = t);
                 }
-                if (_itemFilter == null) { // does this occur?
+                if (f == null) { // does this occur?
                     delegate.skipChildren();
-                    break;
+                    continue main_loop;
                 }
-                _exposedContext = _headContext = _headContext.createChildObjectContext(_itemFilter, false);
-                break;
-    
+                // Otherwise still iffy, need to check
+                f = _headContext.checkValue(f);
+                if (f == null) {
+                    delegate.skipChildren();
+                    continue main_loop;
+                }
+                if (f != TokenFilter.INCLUDE_ALL) {
+                    f = f.filterStartObject();
+                }
+                _itemFilter = f;
+                _headContext = _headContext.createChildObjectContext(f, true);
+                if (f == TokenFilter.INCLUDE_ALL) {
+                    return (_currToken = t);
+                }
+                // but if we didn't figure it out yet, need to buffer possible events
+                return _nextTokenWithBuffering(_headContext);
+
             case ID_END_ARRAY:
             case ID_END_OBJECT:
                 {
                     boolean returnEnd = _headContext.isStartHandled();
-                    TokenFilter f = _headContext.getFilter();
+                    f = _headContext.getFilter();
+                    if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
+                        f.filterFinishArray();
+                    }
+                    _headContext = _headContext.getParent();
+                    _itemFilter = _headContext.getFilter();
+                    if (returnEnd) {
+                        return (_currToken = t);
+                    }
+                }
+                continue main_loop;
+
+            case ID_FIELD_NAME:
+                {
+                    final String name = delegate.getCurrentName();
+                    f = _headContext.setFieldName(name);
+                    if (f == TokenFilter.INCLUDE_ALL) {
+                        _itemFilter = f;
+                        return (_currToken = t);
+                    }
+                    if (f == null) { // filter out the value
+                        delegate.nextToken();
+                        delegate.skipChildren();
+                        break;
+                    }
+                    f = f.includeProperty(name);
+                    if (f == null) { // filter out the value
+                        delegate.nextToken();
+                        delegate.skipChildren();
+                        break;
+                    }
+                    if (f == TokenFilter.INCLUDE_ALL) {
+                        _itemFilter = f;
+                        return (_currToken = t);
+                    }
+                    // !!! TODO: still not decided if to include, so...
+                    
+                    _itemFilter = f;
+                }
+                continue main_loop;
+
+            default: // scalar value
+                if (_itemFilter == TokenFilter.INCLUDE_ALL) {
+                    return (_currToken = t);
+                }
+                // Otherwise not included (leaves must be explicitly included)
+                continue main_loop;
+            }
+        }
+    }
+
+    /**
+     * Method called when a new potentially included context is found.
+     */
+    protected final JsonToken _nextTokenWithBuffering(TokenFilterContext buffRoot) throws IOException
+    {
+        _exposedContext = _headContext;
+
+        while (true) {
+            JsonToken t = delegate.nextToken();
+
+            if (t == null) { // is this even legal?
+                return (_currToken = t);
+            }
+            TokenFilter f;
+
+            switch (t.id()) {
+            case ID_START_ARRAY:
+                f = _itemFilter;
+                if (f == TokenFilter.INCLUDE_ALL) {
+                    _headContext = _headContext.createChildArrayContext(f, true);
+                    return (_currToken = t);
+                }
+                if (f == null) { // does this occur?
+                    delegate.skipChildren();
+                    break;
+                }
+                // Otherwise still iffy, need to check
+                f = _headContext.checkValue(f);
+                if (f == null) {
+                    delegate.skipChildren();
+                    break;
+                }
+                if (f != TokenFilter.INCLUDE_ALL) {
+                    f = f.filterStartArray();
+                }
+                _itemFilter = f;
+                _headContext = _headContext.createChildArrayContext(f, true);
+                if (f == TokenFilter.INCLUDE_ALL) {
+                    return (_currToken = t);
+                }
+                break;
+
+            case ID_START_OBJECT:
+                f = _itemFilter;
+                if (f == TokenFilter.INCLUDE_ALL) {
+                    _headContext = _headContext.createChildObjectContext(f, true);
+                    return (_currToken = t);
+                }
+                if (f == null) { // does this occur?
+                    delegate.skipChildren();
+                    break;
+                }
+                // Otherwise still iffy, need to check
+                f = _headContext.checkValue(f);
+                if (f == null) {
+                    delegate.skipChildren();
+                    break;
+                }
+                if (f != TokenFilter.INCLUDE_ALL) {
+                    f = f.filterStartObject();
+                }
+                _itemFilter = f;
+                _headContext = _headContext.createChildObjectContext(f, true);
+                if (f == TokenFilter.INCLUDE_ALL) {
+                    return (_currToken = t);
+                }
+                break;
+
+            case ID_END_ARRAY:
+            case ID_END_OBJECT:
+                {
+                    boolean returnEnd = _headContext.isStartHandled();
+                    f = _headContext.getFilter();
                     if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
                         f.filterFinishArray();
                     }
@@ -407,21 +566,32 @@
                     }
                 }
                 break;
-    
+
             case ID_FIELD_NAME:
                 {
                     final String name = delegate.getCurrentName();
-                    TokenFilter f = _headContext.setFieldName(name);
+                    f = _headContext.setFieldName(name);
+                    if (f == TokenFilter.INCLUDE_ALL) {
+                        _itemFilter = f;
+                        return (_currToken = t);
+                    }
                     if (f == null) { // filter out the value
                         delegate.nextToken();
                         delegate.skipChildren();
                         break;
                     }
-                    if (_itemFilter == TokenFilter.INCLUDE_ALL) {
+                    f = f.includeProperty(name);
+                    if (f == null) { // filter out the value
+                        delegate.nextToken();
+                        delegate.skipChildren();
+                        break;
+                    }
+                    if (f == TokenFilter.INCLUDE_ALL) {
                         _itemFilter = f;
                         return (_currToken = t);
                     }
-                    f = f.includeProperty(name);
+                    // !!! TODO: still not decided if to include, so...
+                    
                     _itemFilter = f;
                 }
                 break;
@@ -434,17 +604,7 @@
                 break;
             }
         }
-    }
-
-    /**
-     * Method called when a new potentially included context is found.
-     */
-    protected final JsonToken _nextTokenWithBuffering(TokenFilterContext buffRoot) throws IOException
-    {
-        _exposedContext = _headContext;
-        // !!! TODO
-        return null;
-    }
+   }
     
     @Override
     public JsonToken nextValue() throws IOException {