Concrete Pagers strategy :wrench:
diff --git a/collections.go b/collections.go
index 38078f0..1383f24 100644
--- a/collections.go
+++ b/collections.go
@@ -1,62 +1,47 @@
 package gophercloud
 
-import "errors"
+import (
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+	"net/http"
+
+	"github.com/mitchellh/mapstructure"
+)
 
 var (
 	// ErrPageNotAvailable is returned from a Pager when a next or previous page is requested, but does not exist.
 	ErrPageNotAvailable = errors.New("The requested Collection page does not exist.")
 )
 
-// Collection must be satisfied by the result type of any resource collection.
+// Page must be satisfied by the result type of any resource collection.
 // It allows clients to interact with the resource uniformly, regardless of whether or not or how it's paginated.
-type Collection interface {
+type Page interface {
 
 	// NextPageURL generates the URL for the page of data that follows this collection.
 	// Return "" if no such page exists.
 	NextPageURL() string
-
-	// Concat creates a new Collection that contains all of the elements from this page and another page.
-	// It's used to aggregate results for the AllPages method.
-	Concat(Collection) Collection
 }
 
 // Pager knows how to advance through a specific resource collection, one page at a time.
 type Pager struct {
 	initialURL string
 
-	advance func(string) (Collection, error)
+	advance func(string) (Page, error)
 }
 
 // NewPager constructs a manually-configured pager.
 // Supply the URL for the first page and a function that requests a specific page given a URL.
-func NewPager(initialURL string, advance func(string) (Collection, error)) Pager {
+func NewPager(initialURL string, advance func(string) (Page, error)) Pager {
 	return Pager{
 		initialURL: initialURL,
 		advance:    advance,
 	}
 }
 
-// NewSinglePager constructs a Pager that "iterates" over a single-paged Collection.
-// Supply a function that returns the only page.
-func NewSinglePager(only func() (Collection, error)) Pager {
-	consumed := false
-	single := func(_ string) (Collection, error) {
-		if !consumed {
-			consumed = true
-			return only()
-		}
-		return nil, ErrPageNotAvailable
-	}
-
-	return Pager{
-		initialURL: "",
-		advance:    single,
-	}
-}
-
 // EachPage iterates over each page returned by a Pager, yielding one at a time to a handler function.
 // Return "false" from the handler to prematurely stop iterating.
-func (p Pager) EachPage(handler func(Collection) bool) error {
+func (p Pager) EachPage(handler func(Page) bool) error {
 	currentURL := p.initialURL
 	for {
 		currentPage, err := p.advance(currentURL)
@@ -75,28 +60,112 @@
 	}
 }
 
-// AllPages accumulates every page reachable from a Pager into a single Collection, for convenience.
-func (p Pager) AllPages() (Collection, error) {
-	var megaPage Collection
-
-	err := p.EachPage(func(page Collection) bool {
-		if megaPage == nil {
-			megaPage = page
-		} else {
-			megaPage = megaPage.Concat(page)
-		}
-		return true
-	})
-
-	return megaPage, err
+// AllPages accumulates every page reachable from a Pager into a single Page, for convenience.
+func (p Pager) AllPages() (Page, error) {
+	return nil, errors.New("Wat")
 }
 
-// PaginationLinks stores the `next` and `previous` links that are provided by some (but not all) paginated resources.
-type PaginationLinks struct {
+// ConcretePage stores generic information derived from an HTTP response.
+type ConcretePage struct {
+	http.Header
+	Body map[string]interface{}
+}
 
-	// Next is the full URL to the next page of results, or nil if this is the last page.
-	Next *string `json:"next,omitempty"`
+// NewConcretePage parses an HTTP response as JSON and returns a ConcretePage containing the results.
+func NewConcretePage(resp http.Response) (ConcretePage, error) {
+	var parsedBody map[string]interface{}
 
-	// Previous is the full URL to the previous page of results, or nil if this is the first page.
-	Previous *string `json:"previous,omitempty"`
+	defer resp.Body.Close()
+	rawBody, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return ConcretePage{}, err
+	}
+	err = json.Unmarshal(rawBody, &parsedBody)
+	if err != nil {
+		return ConcretePage{}, err
+	}
+
+	return ConcretePage{Header: resp.Header, Body: parsedBody}, err
+}
+
+// SinglePage is a page that contains all of the results from an operation.
+type SinglePage ConcretePage
+
+// NextPageURL always returns "" to indicate that there are no more pages to return.
+func (current SinglePage) NextPageURL() string {
+	return ""
+}
+
+// NewSinglePager constructs a Pager that "iterates" over a single Page.
+// Supply a function that returns the only page.
+func NewSinglePager(only func() (http.Response, error)) Pager {
+	consumed := false
+	single := func(_ string) (Page, error) {
+		if !consumed {
+			consumed = true
+			resp, err := only()
+			if err != nil {
+				return SinglePage{}, err
+			}
+
+			cp, err := NewConcretePage(resp)
+			if err != nil {
+				return SinglePage{}, err
+			}
+			return SinglePage(cp), nil
+		}
+		return SinglePage{}, ErrPageNotAvailable
+	}
+
+	return Pager{
+		initialURL: "",
+		advance:    single,
+	}
+}
+
+// PaginatedLinksPage is a page in a collection that provides navigational "Next" and "Previous" links within its result.
+type PaginatedLinksPage ConcretePage
+
+// NextPageURL extracts the pagination structure from a JSON response and returns the "next" link, if one is present.
+func (current PaginatedLinksPage) NextPageURL() string {
+	type response struct {
+		Links struct {
+			Next *string `mapstructure:"next,omitempty"`
+		} `mapstructure:"links"`
+	}
+
+	var r response
+	err := mapstructure.Decode(current.Body, &r)
+	if err != nil {
+		// FIXME NextPageURL should be able to fail
+		panic(err)
+	}
+
+	if r.Links.Next == nil {
+		return ""
+	}
+
+	return *r.Links.Next
+}
+
+// NewLinkedPager creates a Pager that uses a "links" element in the JSON response to locate the next page.
+func NewLinkedPager(initialURL string, request func(string) (http.Response, error)) Pager {
+	advance := func(url string) (Page, error) {
+		resp, err := request(url)
+		if err != nil {
+			return nil, err
+		}
+
+		cp, err := NewConcretePage(resp)
+		if err != nil {
+			return nil, err
+		}
+
+		return PaginatedLinksPage(cp), nil
+	}
+
+	return Pager{
+		initialURL: initialURL,
+		advance:    advance,
+	}
 }