(function (window, rJS, RSVP, jIO, File, Blob, document, JSZip) {
    "use strict";
    rJS(window)
    .declareAcquiredMethod("notifySubmitting", "notifySubmitting")
    .declareAcquiredMethod("notifySubmitted", "notifySubmitted")
    .declareAcquiredMethod("getSetting", "getSetting")
    .declareAcquiredMethod("jio_get", "jio_get")
    .declareAcquiredMethod("jio_allDocs", "jio_allDocs")

    .ready(function () {
      var gadget = this;
      return this.getDeclaredGadget("model")
      .push(function (model) {
        return gadget.changeState({
          model_gadget: model
        });
      });
    })

    .declareMethod("preRenderDocument", function (parent_options) {
        var gadget = this;
        if (!parent_options.jio_key)
          return;
        return gadget.jio_get(parent_options.jio_key)
          .push(function (parent_document) {
              return parent_document;
          });
    })

    .declareMethod("getIndexPage", function (ids, include_content) {
      var gadget = this,
          i,
          get_page,
          page_dict = {},
          get_queue = new RSVP.Queue();

      get_page = function (page_id) {
        get_queue
          .push(function () {
            return gadget.state.model_gadget.get_page(page_id);
          })
          .push(function (page) {
            page_dict[page_id] = page;
            page_dict[page_id].content = include_content ? page.content : undefined;
          });
      };

      // get all page of this index
      for (i = 0; i < ids.length; i += 1) {
        get_page(ids[i].slice(1));
      }
      return get_queue
        .push(function () {
          return page_dict;
        });
    })

    .declareMethod("putIndexPage", function (page_dict) {
      var gadget = this,
          key,
          put_page,
          put_queue = new RSVP.Queue();

      put_page = function (page_id, data) {
        put_queue
          .push(function () {
            return gadget.state.model_gadget.put(page_id, data);
          });
      };

      for (key in page_dict) {
        put_page(key, page_dict[key]);
      }
      return put_queue;
    })

    .declareMethod("exportIndex", function (index_doc, include_content, zip) {
      var gadget = this,
          ids,
          map,
          ctx,
          index_name = index_doc.title,
          index_id = "index-" + index_name;

      return gadget.state.model_gadget.getAttachment(
        index_id,
        "ids",
        {"format": "json"})
      .push(function (result) {
        ids = result;
        return gadget.state.model_gadget.getAttachment(
          index_id,
          "map",
          {"format": "text"});
      })
      .push(function (result) {
        map = result;
        return gadget.state.model_gadget.getAttachment(
          index_id,
          "ctx",
          {"format": "text"});
      })
      .push(function (result) {
        ctx = result;
        return gadget.getIndexPage(ids, include_content);
      })
      .push(function (result) {
        var i,
            file_dict,
            file_blob,
            link,
            url,
            zip_file;

        file_dict = {
          name: index_name,
          links: index_doc.links,
          ids: JSON.stringify(ids),
          map: map,
          ctx: ctx,
          page: result
        };

        if (!zip) {
          file_blob = new Blob([JSON.stringify(file_dict)], {type : "application/json"});
          return gadget.downloadBlob(index_id + ".json", file_blob);
        }

        zip_file = new JSZip();
        zip_file.file(index_id + ".json", JSON.stringify(file_dict));
        zip_file.generateAsync({
          type : "blob",
          compression: "DEFLATE",
          compressionOptions: {level: 9}
        })
          .then(function (ziped) {
            return gadget.downloadBlob(index_id + ".zip", ziped);
          });
      });
    })

    .declareMethod("downloadBlob", function (name, blob) {
      var link,
          url;

      link = document.createElement("a");
      link.style = "display: none";
      document.body.appendChild(link);
      url = window.URL.createObjectURL(blob);
      link.href = url;
      link.download = name;
      link.click();
      window.URL.revokeObjectURL(url);
    })

    .declareMethod("importIndex", function (dataurl) {
      var gadget = this,
          index_dict,
          doc = {},
          index_id;

      return new RSVP.Queue()
        .push(function () {
          return jIO.util.dataURItoBlob(dataurl);
        })
        .push(function (data) {
          var zip;
          if (data.type === "application/zip") {
            zip = new JSZip();
            return zip.loadAsync(data)
              .then(function(data){
                return zip.file(Object.keys(data.files)[0]).async("string");
              })
              .then(function(data){
                index_dict = JSON.parse(data);
                doc.title = index_dict.name;
                doc.links = index_dict.links;
                doc.status = "built";
                index_id = "index-" + doc.title;
                return gadget.state.model_gadget.pushIndexBlob(
                  index_id,
                  index_dict,
                  {});
              });
          } else if (data.type === "application/json") {
            return new RSVP.Queue()
              .push(function () {
                return jIO.util.readBlobAsText(data, "application/json");
              })
              .push(function (evt) {
                index_dict = JSON.parse(evt.target.result);
                doc.title = index_dict.name;
                doc.links = index_dict.links;
                doc.status = "built";
                index_id = "index-" + doc.title;
                return gadget.state.model_gadget.pushIndexBlob(
                  index_id,
                  index_dict,
                  {});
            });
          }
        })
        .push(function () {
          return gadget.putIndexPage(index_dict.page);
        })
        .push(function () {
          return gadget.state.model_gadget.createIndexDoc(doc);
        })
        .push(function () {
          return gadget.state.model_gadget.pushIndex(index_dict.name);
        });
    })

    .declareMethod("importIndexCollection", function (dataurl) {
      var gadget = this;

      return new RSVP.Queue()
        .push(function () {
          return jIO.util.dataURItoBlob(dataurl);
        })
        .push(function (file_blob) {
          return jIO.util.readBlobAsText(file_blob, "application/json");
        })
        .push(function (evt) {
          var index_list = JSON.parse(evt.target.result),
              promise_list = [],
              i;
          for (i = 0; i < index_list.length; i += 1) {
            promise_list.push(gadget.state.model_gadget.createIndexDoc(index_list[i]));
          }
          return RSVP.all(promise_list);
        });
    })

    .declareMethod("handleSubmit", function (content_dict, parent_options) {
        var return_submit_dict,
        gadget = this,
        jio_key = parent_options.action_options.jio_key;

        return new RSVP.Queue()
        .push(function(){
            return gadget.notifySubmitting();
        })
        .push(function(){
            return gadget.getSetting('index_list', []);
        })
        .push(function(index_list){
            var i,
                built = false,
                index = parent_options.doc,
                redirect = {
                  command: "display",
                  options: {page : "ojs_local_controller", jio_key: jio_key}
                },
                missing_parameter = {
                  message: "Parameter is missing!",
                  status: "error"
                };

            if (content_dict.export_collection === "on") {
              return gadget.jio_allDocs({query: 'portal_type:"Mynij Search Collection"',
                                        select_list: ["title", "links"]})
                .push(function (results) {
                  var i,
                      file_blob,
                      index_list = [];
                  for (i = 0; i < results.data.rows.length; i += 1) {
                    index_list.push({
                      title: results.data.rows[i].value.title,
                      links: results.data.rows[i].value.links
                    });
                  }
                  file_blob = new Blob([JSON.stringify(index_list)], {type : "application/json"});
                  return gadget.downloadBlob("mynij_index_collection.json", file_blob)
                    .push(function () {
                      return {
                        notify: {
                          message: "Indexes Collection Exported.",
                          status: "success"
                        },
                        redirect: redirect
                      };
                    });
                });
            }
            else if (content_dict.import_collection === "on") {
              if (!content_dict.index_file || !content_dict.index_file.url)
                return {
                  notify: missing_parameter,
                  redirect: redirect
                };
              return gadget.importIndexCollection(content_dict.index_file.url)
                .push(function () {
                return {
                  notify: {
                    message: "Index definition imported.",
                    status: "success"
                  },
                  redirect: redirect
                };
              })
              .push(undefined, function (e) {
                console.log(e);
                return {
                  notify: {
                    message: "Failed to import index collection!",
                    status: "error"
                  },
                  redirect: redirect
                };
              });
            }
            else if (content_dict.import_file === "on") {
              if (!content_dict.index_file || !content_dict.index_file.url)
                return {
                  notify: missing_parameter,
                  redirect: redirect
                };
              return gadget.importIndex(content_dict.index_file.url)
                .push(function () {
                return {
                  notify: {
                    message: "Index " + content_dict.index_file.file_name  + " Imported.",
                    status: "success"
                  },
                  redirect: redirect
                };
              })
              .push(undefined, function (e) {
                console.log(e);
                return {
                  notify: {
                    message: "Failed to import index '" + index.title + "'",
                    status: "error"
                  },
                  redirect: redirect
                };
              });
            }
            else {
              // try to export
              if (index_list.indexOf(index.title) === -1) {
                return {
                  notify: {
                    message: "Index " + index.title  + " is not built.",
                    status: "error"
                  },
                  redirect: redirect
                };
              }
              return gadget.exportIndex(index, content_dict.include_content === "on",
                                        content_dict.zip_exported === "on")
                .push(function () {
                  return {
                    notify: {
                      message: "Index " + index.title  + " Exported.",
                      status: "success"
                    },
                    redirect: redirect
                  };
                })
                .push(undefined, function () {
                  return {
                    notify: {
                      message: "Failed to export index '" + index.title + "'",
                      status: "error"
                    },
                    redirect: redirect
                  };
                });
            }
        });
    });

}(window, rJS, RSVP, jIO, File, Blob, document, JSZip));