// Generated by CoffeeScript 1.10.0
(function() {
  var Model, PouchdbBackedModel, async, fs, mkdirp, pathHelpers, pouch, pouchdbBinaryAdapter, pouchdbDataAdapter, pouchdbFileAdapter, pouchdbIndexAdapter, pouchdbRequestsAdapter, uuid,
    hasProp = {}.hasOwnProperty,
    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  Model = require('./model');

  fs = require('fs');

  pathHelpers = require('path');

  async = require('async');

  mkdirp = require('mkdirp');

  uuid = require('node-uuid');

  pouch = require('pouchdb');

  pouchdbDataAdapter = {
    exists: function(id, callback) {
      id = id + '';
      return PouchdbBackedModel.db.get(id, function(err, doc) {
        if (err && !err.status === 404) {
          return callback(err);
        } else if ((err != null ? err.status : void 0) === 404) {
          return callback(null, false);
        } else {
          return callback(null, true);
        }
      });
    },
    find: function(id, callback) {
      id = id + '';
      return PouchdbBackedModel.db.get(id, function(err, doc) {
        if (err) {
          return callback(err);
        } else if (doc == null) {
          return callback(null, null);
        } else {
          return callback(null, doc);
        }
      });
    },
    create: function(attributes, callback) {
      var func;
      if ((attributes.id != null) || (attributes._id != null)) {
        if (!attributes.id) {
          attributes.id = attributes._id;
        }
        if (!attributes._id) {
          attributes._id = attributes.id;
        }
        func = 'put';
      } else {
        attributes._id = attributes.id = uuid.v4().split('-').join('');
        func = 'post';
      }
      return PouchdbBackedModel.db[func](attributes, function(err, response) {
        if (err) {
          return callback(err);
        } else if (!response.ok) {
          return callback(new Error('An error occured while creating document.'));
        } else {
          return callback(null, {
            id: response.id
          });
        }
      });
    },
    save: function(id, attributes, callback) {
      attributes.docType = this.getDocType();
      return PouchdbBackedModel.db.get(id, (function(_this) {
        return function(err, doc) {
          if (err) {
            return callback(err);
          } else if (doc == null) {
            return callback(new Error('document does not exist'));
          } else if (doc.docType.toLowerCase() !== _this.getDocType().toLowerCase()) {
            return callback(new Error('document does not exist'));
          } else {
            attributes._id = attributes.id;
            attributes._rev = doc._rev;
            return PouchdbBackedModel.db.put(attributes, function(err, response) {
              if (err) {
                callback(err);
              }
              if (!response.ok) {
                return callback(new Error("An error occured while saving document.'"));
              } else {
                return callback(null, attributes);
              }
            });
          }
        };
      })(this));
    },
    updateAttributes: function(id, attributes, callback) {
      var docType;
      docType = this.getDocType();
      return PouchdbBackedModel.db.get(id, function(err, doc) {
        var key, value;
        if (err) {
          return callback(err);
        } else if (doc == null) {
          return callback(new Error('document does not exist'));
        } else if (doc.docType.toLowerCase() !== docType.toLowerCase()) {
          return callback(new Error('document does not exist'));
        } else {
          for (key in attributes) {
            if (!hasProp.call(attributes, key)) continue;
            value = attributes[key];
            if (key === '0') {
              throw new Error("NOW");
            }
            doc[key] = value;
          }
          return PouchdbBackedModel.db.put(doc, function(err, response) {
            if (err) {
              callback(err);
            }
            if (!response.ok) {
              return callback(new Error("An error occured while updating document.'"));
            } else {
              return callback(null, doc);
            }
          });
        }
      });
    },
    destroy: function(id, callback) {
      return PouchdbBackedModel.db.get(id, function(err, doc) {
        if (err) {
          return callback(err);
        } else {
          return PouchdbBackedModel.db.remove(doc, callback);
        }
      });
    }
  };

  pouchdbIndexAdapter = {
    search: function(query, callback) {
      return callback(null, []);
    },
    index: function(id, fields, callback) {
      return callback(null);
    },
    registerIndexDefinition: function(callback) {
      return callback(null);
    }
  };

  pouchdbFileAdapter = {
    attach: function(id, path, data, callback) {
      var folder, ref;
      if (typeof data === "function") {
        ref = [null, data], data = ref[0], callback = ref[1];
      }
      folder = pathHelpers.join("attachments", id);
      return mkdirp(folder, function(err) {
        var filename, filepath, source, target;
        if (err) {
          return callback(err);
        } else {
          filename = pathHelpers.basename(path);
          filepath = pathHelpers.join(folder, filename);
          source = fs.createReadStream(path);
          target = fs.createWriteStream(filepath);
          source.on('error', callback);
          source.on('end', callback);
          return source.pipe(target);
        }
      });
    },
    get: function(id, filename, callback) {
      var filepath, folder, source;
      folder = pathHelpers.join("attachments", id);
      filename = pathHelpers.basename(filename);
      filepath = pathHelpers.join(folder, filename);
      source = fs.createReadStream(filepath);
      source.on('error', callback);
      source.on('end', callback);
      return source;
    },
    remove: function(id, filename, callback) {
      var filepath, folder;
      folder = pathHelpers.join("attachments", id);
      filepath = pathHelpers.join(folder, filename);
      return fs.unlink(filepath, callback);
    }
  };

  pouchdbBinaryAdapter = {
    attach: function(id, path, data, callback) {
      var folder, ref, writeStream;
      if (typeof data === "function") {
        ref = [null, data], data = ref[0], callback = ref[1];
      }
      writeStream = function(filepath, source, callback) {
        var target;
        target = fs.createWriteStream(filepath);
        source.on('error', callback);
        source.on('end', callback);
        return source.pipe(target);
      };
      folder = pathHelpers.join("attachments", id);
      return mkdirp(folder, function(err) {
        var buffer, filename, filepath, source;
        if (err) {
          return callback(err);
        } else if (typeof path === 'string') {
          filename = pathHelpers.basename(path);
          filepath = pathHelpers.join(folder, filename);
          source = fs.createReadStream(path);
          return writeStream(filepath, source, callback);
        } else if (path instanceof Buffer) {
          filename = (data != null ? data.name : void 0) || 'file';
          filepath = pathHelpers.join(folder, filename);
          buffer = path;
          return fs.writeFile(filepath, buffer, callback);
        } else {
          filename = (data != null ? data.name : void 0) || 'file';
          filepath = pathHelpers.join(folder, filename);
          source = path;
          return writeStream(filepath, source, callback);
        }
      });
    },
    get: function(id, filename, callback) {
      var filepath, folder, source;
      folder = pathHelpers.join("attachments", id);
      filename = pathHelpers.basename(filename);
      filepath = pathHelpers.join(folder, filename);
      source = fs.createReadStream(filepath);
      source.on('error', callback);
      source.on('end', callback);
      return source;
    },
    remove: function(id, filename, callback) {
      var filepath, folder;
      folder = pathHelpers.join("attachments", id);
      filepath = pathHelpers.join(folder, filename);
      return fs.unlink(filepath, callback);
    }
  };

  pouchdbRequestsAdapter = {
    define: function(name, request, callback) {
      var docType, error, error1, map, qs, reduce, stringquery, view, viewName;
      docType = this.getDocType();
      map = request.map, reduce = request.reduce;
      qs = map.toString();
      qs = qs.substring(qs.indexOf('{'));
      qs = qs.substring(0, qs.length - 1);
      stringquery = "if (doc.docType.toLowerCase() === " + ("\"" + docType + "\") " + (qs.toString()) + "};");
      stringquery = stringquery.replace('\n', '');

      /* jshint ignore: start */
      try {
        map = new Function("doc", stringquery);
      } catch (error1) {
        error = error1;
        callback(new Error("Error when parsing request's body: " + error));
      }

      /* jshint ignore: end */
      view = {
        map: map.toString()
      };
      if (reduce != null) {
        view.reduce = reduce.toString();
      }
      viewName = "_design/" + (docType.toLowerCase());
      return PouchdbBackedModel.db.get(viewName, function(err, designDoc) {
        if (designDoc == null) {
          designDoc = {
            _id: viewName,
            views: {}
          };
        }
        if (designDoc.views == null) {
          designDoc.views = {};
        }
        designDoc.views[name.toLowerCase()] = view;
        return PouchdbBackedModel.db.put(designDoc, function(err, designDoc) {
          return callback(err);
        });
      });
    },
    run: function(name, params, callback) {
      var docType, ref, viewName;
      if (typeof params === "function") {
        ref = [{}, params], params = ref[0], callback = ref[1];
      }
      docType = this.getDocType();
      viewName = (docType.toLowerCase()) + "/" + (name.toLowerCase());
      return PouchdbBackedModel.db.query(viewName, params, function(err, body) {
        if (err) {
          return callback(err);
        } else {
          return callback(null, body.rows);
        }
      });
    },
    remove: function(name, callback) {
      var docType;
      docType = this.getDocType();
      name = '_design/' + docType.toLowerCase();
      return PouchdbBackedModel.db.get(name, function(err, designDoc) {
        if (err) {
          return callback(err);
        } else {
          delete designDoc.views[name.toLowerCase()];
          return PouchdbBackedModel.db.put(designDoc, function(err, designDoc) {
            return callback(err);
          });
        }
      });
    },
    requestDestroy: function(name, params, callback) {
      var ref;
      if (typeof params === "function") {
        ref = [{}, params], params = ref[0], callback = ref[1];
      }
      if (params.limit == null) {
        params.limit = 100;
      }
      return this.request(name, params, function(err, docs) {
        if (err) {
          return callback(err);
        } else {
          return async.eachSeries(docs, function(doc, cb) {
            return doc.destroy(cb);
          }, function(err) {
            return callback(err);
          });
        }
      });
    }
  };

  module.exports = PouchdbBackedModel = (function(superClass) {
    extend(PouchdbBackedModel, superClass);

    function PouchdbBackedModel() {
      return PouchdbBackedModel.__super__.constructor.apply(this, arguments);
    }

    PouchdbBackedModel.adapter = pouchdbDataAdapter;

    PouchdbBackedModel.indexAdapter = pouchdbIndexAdapter;

    PouchdbBackedModel.fileAdapter = pouchdbFileAdapter;

    PouchdbBackedModel.binaryAdapter = pouchdbBinaryAdapter;

    PouchdbBackedModel.requestsAdapter = pouchdbRequestsAdapter;

    PouchdbBackedModel.cast = function() {
      if (!this.__addedToSchema) {
        this.__addedToSchema = true;
        this.schema._id = String;
        this.schema._attachments = Object;
        this.schema._rev = String;
        this.schema.id = String;
        this.schema.docType = String;
        this.schema.binaries = Object;
      }
      return PouchdbBackedModel.__super__.constructor.cast.apply(this, arguments);
    };

    return PouchdbBackedModel;

  })(Model);

}).call(this);
