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

    // ========================== ATTRIBUTES ==============================
    // set response, so it's available across function calls
    priv.response;

    priv.generateGallery = function (response) {
      // expose response (will be overwritten, when next item loads
      priv.response = response;

      // TODO: we will generate two listviews now, until the gallery widget
      // also has a thumbnail option
      // TODO: allow the gallery to exist without links...
      // TODO: zoom is missing, this should also be a feature of gallery
      // TODO: 404 fallback images!
      // ala photoswipe
      var i, j, item, img, gallery, thumbnails = "", str, obj, variations;

      gallery = "<div class='gallery_wrap'><ul data-role='carousel' " +
        "data-inset='true' class='ui-responsive tester'" +
        " data-captions='true' data-transition='" +
        "slide'>";

      if (response.items) {
        gallery += priv.generateTeaserItems(response);
      } else {
        // TODO: fetch hash and pass as parameter
        gallery += priv.generateGalleryItems();

        variations = priv.response.dimensions[0].vars;

        if (variations.length > 1) {
          thumbnails += "<div class='gallery_thumbnails '><ul data-role='" +
          "listview' data-inset='true' class='gallery_thumbnail_wrapper'>";
          for (i = 0; i < variations.length; i += 1) {
            item = variations[i];

            // thumbnails - click on link should trigger the display method
            thumbnails += "<li data-icon='false'><a href='#" + item.name + "' class='" +
              "display_item'><img src='" + response.media + item.media.img[0]["t"] + "' alt='"
              + item.name + "' /><h3 class='translate gallery_header' data-i18n='" +
              item.i18n + "'>" + item.name + "</h3></li>";
          }
          thumbnails += "</ul></div>";
        }
      }

      gallery += "</ul></div>";

      return str = gallery + thumbnails;
    };

    // TODO: show some thing
    priv.generateError = function () {
      return "<p>JIO ERROR</p>";
    };

    // generate teaser items
    priv.generateTeaserItems = function (response) {
      var i, obj, str = "";

      for (i = 0; i < response.items.length; i += 1) {
        obj = response.items[i];

        str += "<li class='teaser_img'><a href='" + obj.href + "'><img src='"
          + obj.src + "' alt='" + obj.caption + "' />" +
          "<h3 class='translate gallery_header' data-i18n='" +
          obj.i18n + "'>" + obj.caption + "</h3></a></li>";
      }
      return str;
    };

    // generate gallery list items
    priv.generateGalleryItems = function (name) {
      var i, j, item, img, str = "";

      item = priv.response.dimensions[0].vars[0];

      // find item name or default to first variant in dimension
      if (name !== undefined) {
        for (i = 0; i < priv.response.dimensions[0].vars.length; i += 1) {
          item = priv.response.dimensions[0].vars[i];
          if (item.name === name || location.hash === name) {
            break;
          }
        }
      }

      // for every variant (colors, size?, foo?)
      // TODO: declare a variant that carries images in products JSON!
      // build string
      for (j = 0; j < item.media.img.length; j += 1) {
        img = item.media.img[j];
        // TODO: add zoom/photoswipe later!
        str += "<li class='product_img'><a href='#'><img src='" + priv.response.media +
          img[shortcut] + size + "' alt='" + item.name + "' />" +
          "<h3 class='translate gallery_header' data-i18n='" +
          item.i18n + "'></h3></a></li>";
      }

      return str;
    };

    priv.swapGalleryItems = function (name, element) {
      var newString = priv.generateGalleryItems(name),
        // TODO: if thumbnails are a gallery option, it should be possible
        // to reference the gallery from the thumbnail without doing this:
        wrap = App.util.closest(element, ".gallery_thumbnails").previousSibling,
        gallery = wrap.getElementsByTagName("ul");

      $(gallery[0]).empty().append(newString).carousel("refresh");
    };

    // generate items to display
    priv.generateItems = function (params) {
      var markup, spec, response;
        id = params.gadget.dom.attr('id').split("__").splice(-1)[0],
        config = params.gadget.state[0][id]._config,
        module = config.datasource.module,
        urlPointer = params.pointer.length > 1,
        jsonPointer = config.datasource.pointer,

        // TODO: settable options
        screen = App.settings.screen_format,
        size = screen === "small" ? "small" : "medium",
        shortcut = size.substring(0, 1);

      // if we have a pointer-array passed, query that
      // TODO: this is not flexible yet, because "items" and "get" are hardcoded
      // TODO: also, jIO GET only allows to query by id, so that should be
      // what is stored on the image links...
      if (urlPointer) {
        spec = {};
        spec.storage = "items"
        spec.method = "get"
        spec.doc = {"_id": params.pointer[1]}
      }

      if (jsonPointer) {
        spec = {};
        // TODO: no time to get items form somewhere now. This should be passed
        // in the configuration file, as it's something the user can use or not
        // also - should be possible to make this fullscreen by supplying the
        // carousel options!
        spec.items = [
          {"src":"img/stella.jpg", "caption":"Stella", "i18n": "custom.teaser.stella", "href": "products.html?search=stella"},
          {"src":"img/nannin.jpg", "caption":"Nan", "i18n": "custom.teaser.nan", "href": "products.html?search=nan"},
          {"src":"img/vila.jpg", "caption":"Vila", "i18n": "custom.teaser.vila", "href": "products.html?search=vila"}
        ]
      }

      // callback to generate gallery
      spec.callback = function(err, response) {
        if (err) {
          str = priv.generateError();
        } else {
          if (spec.items) {
            str = priv.generateGallery(response);
          } else {
            str = priv.generateGallery(response);
          }
        }

        // TODO: this should not replace the whole gadget content
        markup = params.source.replace(/<!-- gallery -->/g, str);
 
        // this is not response.callback(!!)
        params.callback_mockup(markup);
      };

      if (urlPointer) {
        // query for items
        App[module].switchboard(spec);
      }
      if (jsonPointer) {
        // TODO: image pictures should also be fetched and stored in JIO
        // just run callback now and generate gallery
        spec.callback(undefined, spec);
      }
    }

    // response object
    that.data = source;
    that.mockup = function (source, callback_mockup) {
      var spec = {};

      spec.gadget = RenderJs.getSelfGadget();
      spec.page = App.util.closest(spec.gadget.dom.get(0), "div[data-role='page']");
      spec.pageId = "#" + spec.page.id;
      // TODO: retrieving pointers should be a generic method that retrieves
      // pointers either from the URL or from a JSON config object passed!
      spec.pointer = location.search.split("=");
      spec.callback_mockup = callback_mockup;
      spec.source = source;

      // TODO: remove to separate function
      if (!spec.page.getAttribute("events_gallery")) {
        spec.page.setAttribute("events_gallery", true);

        $(document).on("pagebeforeshow.gallery", spec.pageId, function (e) {
          // the pointer in the URL may be updated
          if (location.search) {
            spec.pointer = location.search.split("=");
          }
          priv.generateItems(spec, true);
        })
        .on("click.gallery", spec.pageId + " .display_item", function (e) {
          var target = e.target,
            color;

          if (e.target.tagName === "A") {
            color = target.href.split("#")[1];
          } else {
            color = App.util.closest(target, "a").href.split("#")[1];
          }
          priv.swapGalleryItems(color, e.target);
        });
        // and run intial
        priv.generateItems(spec);
      }
    };

    that.callback = 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;
  }
);
