Add support for index pagination

We add limit and skip parameters to GET so that the dashboard
can utilize these parameters for pagination.

Fixes:COUCHDB-2652
diff --git a/src/mango_error.erl b/src/mango_error.erl
index 6dcf7c8..dfd4bd7 100644
--- a/src/mango_error.erl
+++ b/src/mango_error.erl
@@ -77,6 +77,12 @@
         <<"error_saving_ddoc">>,
         fmt("Unknown error while saving the design document: ~s", [Reason])
     };
+info(mango_httpd, invalid_list_index_params) ->
+    {
+        500,
+        <<"invalid_list_index_params">>,
+        <<"Index parameter ranges: limit > 1, skip > 0" >>
+    };
 
 info(mango_idx, {invalid_index_type, BadType}) ->
     {
diff --git a/src/mango_httpd.erl b/src/mango_httpd.erl
index 671ffd2..d3fde9c 100644
--- a/src/mango_httpd.erl
+++ b/src/mango_httpd.erl
@@ -50,9 +50,27 @@
 
 
 handle_index_req(#httpd{method='GET', path_parts=[_, _]}=Req, Db) ->
+    Params = lists:flatmap(fun({K, V}) -> parse_index_param(K, V) end,
+        chttpd:qs(Req)),
     Idxs = lists:sort(mango_idx:list(Db)),
-    JsonIdxs = lists:map(fun mango_idx:to_json/1, Idxs),
-	chttpd:send_json(Req, {[{indexes, JsonIdxs}]});
+    JsonIdxs0 = lists:map(fun mango_idx:to_json/1, Idxs),
+    TotalRows = length(JsonIdxs0),
+    Limit = case couch_util:get_value(limit, Params, TotalRows) of
+        Limit0 when Limit0 < 1 ->
+            ?MANGO_ERROR(invalid_list_index_params);
+        Limit0 ->
+            Limit0
+    end,
+    Skip = case couch_util:get_value(skip, Params, 0) of
+        Skip0 when Skip0 < 0 ->
+            ?MANGO_ERROR(invalid_list_index_params);
+        Skip0 when Skip0 > TotalRows ->
+            TotalRows;
+        Skip0 ->
+            Skip0
+    end,
+    JsonIdxs = lists:sublist(JsonIdxs0, Skip+1, Limit),
+	chttpd:send_json(Req, {[{total_rows, TotalRows}, {indexes, JsonIdxs}]});
 
 handle_index_req(#httpd{method='POST', path_parts=[_, _]}=Req, Db) ->
     {ok, Opts} = mango_opts:validate_idx_create(chttpd:json_body_obj(Req)),
@@ -217,3 +235,19 @@
     Chunk = [Prepend, ?JSON_ENCODE(Doc)],
     {ok, Resp1} = chttpd:send_delayed_chunk(Resp0, Chunk),
     {ok, {Resp1, ",\r\n", KVs}}.
+
+
+parse_index_param("limit", Value) ->
+    [{limit, parse_val(Value)}];
+parse_index_param("skip", Value) ->
+    [{skip, parse_val(Value)}];
+parse_index_param(_Key, _Value) ->
+     [].
+
+parse_val(Value) ->
+    case (catch list_to_integer(Value)) of
+    IntVal when is_integer(IntVal) ->
+        IntVal;
+    _ ->
+        ?MANGO_ERROR(invalid_list_index_params)
+    end.
diff --git a/test/01-index-crud-test.py b/test/01-index-crud-test.py
index a44376c..d83e97f 100644
--- a/test/01-index-crud-test.py
+++ b/test/01-index-crud-test.py
@@ -222,3 +222,33 @@
             assert e.response.status_code == 404
         else:
             raise AssertionError("bad index delete")
+
+    def test_limit_skip_index(self):
+        fields = ["field1"]
+        ret = self.db.create_index(fields, name="idx_01")
+        assert ret is True
+
+        fields = ["field2"]
+        ret = self.db.create_index(fields, name="idx_02")
+        assert ret is True
+
+        fields = ["field3"]
+        ret = self.db.create_index(fields, name="idx_03")
+        assert ret is True
+
+        assert len(self.db.list_indexes(limit=2)) == 2
+        assert len(self.db.list_indexes(limit=5,skip=4)) == 2
+        assert len(self.db.list_indexes(skip=5)) == 1
+        assert len(self.db.list_indexes(skip=6)) == 0
+        assert len(self.db.list_indexes(skip=100)) == 0
+        assert len(self.db.list_indexes(limit=10000000)) == 6
+
+        try:
+            self.db.list_indexes(skip=-1)
+        except Exception, e:
+            assert e.response.status_code == 500
+
+        try:
+            self.db.list_indexes(limit=0)
+        except Exception, e:
+            assert e.response.status_code == 500
diff --git a/test/mango.py b/test/mango.py
index b39c916..bde9323 100644
--- a/test/mango.py
+++ b/test/mango.py
@@ -125,8 +125,12 @@
         r.raise_for_status()
         return r.json()["result"] == "created"
 
-    def list_indexes(self):
-        r = self.sess.get(self.path("_index"))
+    def list_indexes(self, limit="", skip=""):
+        if limit != "":
+            limit = "limit=" + str(limit)
+        if skip != "":
+            skip = "skip=" + str(skip)
+        r = self.sess.get(self.path("_index?"+limit+";"+skip))
         r.raise_for_status()
         return r.json()["indexes"]