define([
    'app'
  , 'text!pagination.html!strip'
  , 'css!pagination'
  ],
  function (App, source) {
    var priv = {};
    var that = {};

    // get previous and next id
    // TODO: this only works with id-numbers!!!
    // TODO: problem is also that no other field can be used to iterate
    // unless we want to get allDocs(includeDocs)
    // TODO: this should receive the total number of results of a query/search!
    priv.getPrevNextItem = function (arr, id, next, max) {
      var step = next ? 1 : -1, position, id;
      for (position = 1; position < max; position += 1) {
        if (position === parseFloat(id)) {

          // we have found the position in the array, get prev/next
          if (next) {
            if (arr[position] === undefined) {
              return false;
            }
            return arr[position].id;
          } else {
            // less 1 is self, less 2 is previous...
            if (arr[position-2] === undefined) {
              return false;
            }
            return arr[position-2].id;
          }
        }
      }
    };

    // reload a page with a new item
    priv.displayItem = function (target) {
      var url = target.split("?"),
        path = url[0],
        item = url[1];

      $.mobile.changePage(path, {
        "allowSamePageTransition": true,
        "data": item
      });
    };

    // get allDocs
    priv.iterate = function (params) {
      var spec,
        id = params.gadget.dom.attr('id').split("__").splice(-1)[0],
        config = params.gadget.state[0][id]._config,
        module = config.datasource.module;

      var spec = {};

      spec.pointer = config.datasource.pointer;
      spec.method = spec.pointer ? undefined : config.datasource.method || "allDocs";
      spec.storage = spec.pointer ? undefined : config.datasource.storage || "items";
      spec.options = spec.pointer ? undefined : config.datasource.options || {
        "sort_on": [["_id","ascending"]]
      }

      spec.callback = function (err, response) {
        var currentId = location.href.split("?")[1].split("=")[1],
          identifier = App.settings.identifier || "item_id",
          next, prev, markup;

        // TODO: error handling
        if (err) {

        } else {
          // set next
          // TODO: this is bad, because we can only point to doc_id, no matter what
          // identifier we are setting. item_id itself is... bad... fix!
          next = priv.getPrevNextItem(response.rows, currentId, true, response.total_rows);

          if (!next) {
            markup = params.source.replace("translate next", "translate next ui-state-disabled");
          } else {
            markup = params.source.replace(identifier + "=next", identifier + "=" + next);
          }
          // set previous
          prev = priv.getPrevNextItem(response.rows, currentId, false, response.total_rows);
          if (!prev) {
            markup = markup.replace("translate prev", "translate prev ui-state-disabled");
          } else {
            markup = markup.replace(identifier + "=prev", identifier + "=" + prev);
          }
        }
        params.callback_mockup(markup);
      };

      // query
      App[module].switchboard(spec);
    };

    priv.setBindings = function (param) {
      var doc = $(document);
//       doc
//         .on("pagebeforeshow.browser", param.pageId, function (e) {
//           console.log("pbs");
//         })
//         .on("pagebeforehide", param.pageId, function (e) {
//           console.log("pbh");
//           doc.off(".browser");
//         })
//         .on("click.browser", ".browser_bar .prev, .browser_bar .next",
//           function (e) {
//             var target;
// 
//             e.preventDefault();
//             target = e.target.href;
//             // changePage
//             priv.displayItem(target);
//         });
    };

    that.data = source;
    that.before = function (source, callback_mockup) {
      var spec = {};

      spec.gadget = RenderJs.getSelfGadget();
      // TODO: this is for page event bindings. Once JQM content replaces
      // page, remove this and make the gadget the content section to
      // be updated.
      spec.page = App.util.closest(spec.gadget.dom.get(0), "div[data-role='page']");
      spec.pageId = "#" + spec.page.id;
      spec.source = source;
      spec.callback_mockup = callback_mockup;

      if (!spec.page.getAttribute("events_pagination")) {
        spec.page.setAttribute("events_pagination", true);
        $(document).on("pagebeforeshow.pagination", spec.pageId, function (e, data) {
          // TODO: if we allow to reload, we also need to trigger refresh on
          // so we need to reload this every time a page is shown. question
          // is how to trigger a refresh on this element ONLY
          // > the gadgets should tell whether they need enhancement!
          // callback
          priv.iterate(spec);
        });

        // callback
        priv.iterate(spec);
      }
    };

    that.after = function (self) {
      if (App === undefined) {
        def = new $.Deferred;

        def.done(function(gadget) {
          // prefix instance-ids, pass JSON
          App.renderGadgets(gadget, true);
        });

        window.fallbackLoader.deferreds.push(def);
        window.fallbackLoader.args.push(self);
      } else {
        // prefix instance-ids, pass JSON
        App.renderGadgets(self, true);
      }
    };

  // return response object
  return that;
  }
);
