fcf.module({
  name: "fcf:NFSQL/Storage.js",
  dependencies: ["fcf:NFSQL/NDetails/ServerStorage.js"],
  module: function(ImplStorage) {
    var NFSQL = fcf.prepareObject(fcf, "NFSQL");

    NFSQL.Storage = function(a_options) {
      var self = this;
      this._storage = new ImplStorage(a_options);
      this._projections = a_options.projections;

      //this.query = function(a_queryText, a_args, a_options, a_cb)
      //this.query = function(a_queryText, a_options, a_cb)
      //this.query = function(a_queryText, a_cb)
      //this.query = function(a_options, a_cb)
      //this.query = function(a_queryObject, a_cb)
      this.query = function(a_options, a_cb) {
        let args = arguments;
        if ((typeof a_options == "object" && a_options.type && !a_options.query) || Array.isArray(a_options)){
          a_options = { query: a_options }
          if (typeof args[1] === "object")
            fcf.append(a_options, args[1]);
          if (typeof args[2] === "function")
            a_cb = args[2];
          else if (typeof a_cb !== "function")
            a_cb = undefined;
        } else if (Array.isArray(args[0])){
          a_options = { query: args[0] }
          if (typeof args[1] === "object")
            fcf.append(a_options, args[1]);
          if (typeof args[2] === "function")
            a_cb = args[2];
          else if (typeof a_cb !== "function")
            a_cb = undefined;
        } else if (typeof args[0] == "string"){
          a_options = { query: a_options };
          if (Array.isArray(args[1])){
            a_options.args = args[1];
            if (typeof args[2] === "object")
              fcf.append(a_options, args[2]);
          } else if (typeof args[1] === "object"){
            fcf.append(a_options, args[1]);
          }

          if (typeof args[3] === "function")
            a_cb = args[3];
          else if (typeof args[2] === "function")
            a_cb = args[2];
          else if (typeof a_cb !== "function")
            a_cb = undefined;
        }

        return fcf.actions()
        .then(function(a_res, a_act){
          self._storage.query(a_options, function(a_error, a_data){
            if (a_cb)
              a_cb(a_error, a_data);
            if (a_error){
              if (fcf.find(a_options.hideErrors, a_error.code) !== undefined){
                a_act.complete([]);
              } else {
                a_act.error(a_error);
              }
            } else {
              a_act.complete(a_data);
            }
          });
        });
      }

      this.rawQuery = function(a_query, a_args, a_cb) {
        if (typeof a_args === "function"){
          a_cb = a_args;
          a_args = [];
        }

        return fcf.actions()
        .then((a_res, a_act) => {
          self._storage.rawQuery(a_query, a_args, function(a_error, a_data){
            if (a_cb)
              a_cb(a_error, a_data);
            if (a_error)
              a_act.error(a_error);
            else
              a_act.complete(a_data);
          });
        });

      }

      this.getProjectionsByQuery = function(a_query){
        return self._storage.getProjectionsByQuery(a_query);
      }

      this.destroy = function() {
        this._storage.destroy();
      }

      this.getStorage = function() {
        return this._storage;
      }

      this.getProjections = function(){
        return this._projections;
      }
    };

    return NFSQL.Storage;
  }
});
