// Generated by CoffeeScript 1.10.0
(function() {
  var Controller, CozyModel, Model, NoSchema, api, async, defaultRequests, defineIndexes, defineRequests, emit, forceIndexRequests, fs, getRequests, log, maybeSetupPouch, path, requestsIndexingCallbacks, requestsIndexingProgress, requestsIndexingTotal,
    slice = [].slice,
    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; },
    hasProp = {}.hasOwnProperty;

  log = require('printit')({
    date: true,
    prefix: 'Cozy DB'
  });

  fs = require('fs');

  path = require('path');

  async = require('async');

  module.exports.Model = Model = require('./model');

  module.exports.CozyModel = CozyModel = require('./cozymodel');

  module.exports.SimpleController = Controller = require('./controller');

  NoSchema = require('./utils/type_checking').NoSchema;

  module.exports.NoSchema = NoSchema;

  emit = function() {};

  module.exports.defaultRequests = defaultRequests = {
    all: function(doc) {
      return emit(doc._id, doc);
    },
    tags: function(doc) {
      var j, len, ref, results, tag;
      ref = doc.tags || [];
      results = [];
      for (j = 0, len = ref.length; j < len; j++) {
        tag = ref[j];
        results.push(emit(tag, doc));
      }
      return results;
    },
    by: function() {
      var fields, key;
      fields = 1 <= arguments.length ? slice.call(arguments, 0) : [];
      if (fields.length === 0) {
        throw new Error('There should be at least one parameter');
      }
      if (fields.length === 1) {
        key = "doc." + fields;
      } else {
        key = fields.map(function(field) {
          return "doc." + field;
        }).join(', ');
        key = "[" + key + "]";
      }
      return (function(doc) {
        return emit(KEY, doc);
      }).toString().replace('KEY', key);
    }
  };

  module.exports.getModel = function(name, schema) {
    var ClassFromGetModel, klass;
    klass = ClassFromGetModel = (function(superClass) {
      extend(ClassFromGetModel, superClass);

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

      ClassFromGetModel.schema = schema;

      return ClassFromGetModel;

    })(CozyModel);
    klass.displayName = klass.name = name;
    klass.toString = function() {
      return name + "Constructor";
    };
    klass.docType = name;
    return klass;
  };

  module.exports.api = api = require('./api');

  maybeSetupPouch = function(options) {
    var Pouch, PouchModel;
    if (process.env.RUN_STANDALONE || options.db || options.dbName) {
      Pouch = require('pouchdb');
      PouchModel = require('./pouchmodel');
      module.exports.CozyModel = CozyModel = PouchModel;
      if (options.db) {
        return PouchModel.db = options.db;
      } else {
        if (options.dbName == null) {
          options.dbName = process.env.POUCHDB_NAME || 'cozy';
        }
        return PouchModel.db = new Pouch(options.dbName);
      }
    }
  };

  getRequests = function(modelsPath) {
    var docType, err, error, file, j, len, model, models, ref, requestDefinition, requestDefinitions, requestFile, requestName, requests, requestsToSave;
    requestFile = path.join(modelsPath, "requests");
    try {
      requests = require(requestFile);
    } catch (error) {
      err = error;
      console.log("Could not load " + requestFile);
      requests = {};
    }
    requestsToSave = [];
    models = [];
    ref = fs.readdirSync(modelsPath);
    for (j = 0, len = ref.length; j < len; j++) {
      file = ref[j];
      try {
        model = require(path.join(modelsPath, file));
        if ((model != null ? model.prototype : void 0) instanceof CozyModel) {
          models.push(model);
        }
      } catch (undefined) {}
    }
    for (docType in requests) {
      requestDefinitions = requests[docType];
      model = require(path.join(modelsPath, docType));
      for (requestName in requestDefinitions) {
        requestDefinition = requestDefinitions[requestName];
        requestsToSave.push({
          model: model,
          requestName: requestName,
          requestDefinition: requestDefinition
        });
      }
    }
    requestsToSave.push({
      model: api.CozyInstance,
      optional: true,
      requestName: 'all',
      requestDefinition: defaultRequests.all
    });
    requestsToSave.push({
      model: api.CozyUser,
      optional: true,
      requestName: 'all',
      requestDefinition: defaultRequests.all
    });
    return {
      models: models,
      requestsToSave: requestsToSave
    };
  };

  defineRequests = function(requestsToSave, callback) {
    return async.eachSeries(requestsToSave, function(request, next) {
      var model, optional, requestDefinition, requestName;
      model = request.model, requestName = request.requestName, requestDefinition = request.requestDefinition, optional = request.optional;
      log.info((model.getDocType()) + " - " + requestName + " request creation...");
      return model.defineRequest(requestName, requestDefinition, function(err) {
        if (err && !optional) {
          log.raw(err);
          log.error("A request creation failed, abandon. Are you sure the DS is\nstarted ?");
          return next(err);
        } else {
          log.info("succeeded");
          return next(null);
        }
      });
    }, callback);
  };

  defineIndexes = function(models, callback) {
    return async.eachSeries(models, function(model, next) {
      log.info((model.getDocType()) + " - define indexes...");
      return model.registerIndexDefinition(next);
    }, callback);
  };

  requestsIndexingProgress = 0;

  requestsIndexingTotal = 1;

  requestsIndexingCallbacks = [];

  module.exports.getRequestsReindexingProgress = function() {
    log.warn(requestsIndexingProgress + " / " + requestsIndexingTotal);
    return requestsIndexingProgress / requestsIndexingTotal;
  };

  module.exports.waitReindexing = function(callback) {
    if (requestsIndexingTotal === requestsIndexingProgress) {
      return callback(null);
    } else {
      return requestsIndexingCallbacks.push(callback);
    }
  };

  forceIndexRequests = function(requestsToSave, callback, i) {
    var model, ref, requestName;
    if (i == null) {
      i = 0;
    }
    ref = requestsToSave[i], model = ref.model, requestName = ref.requestName;
    requestsIndexingTotal = requestsToSave.length;
    log.info(((model.getDocType()) + " - " + requestName + " reindexing ") + (requestsIndexingProgress + "/" + requestsIndexingTotal));
    return model.rawRequest(requestName, {
      limit: 1
    }, function(err) {
      var cb, j, len, results;
      if (err && err.code === 'ECONNRESET') {
        log.info(" Timedout");
        return setTimeout(function() {
          return forceIndexRequests(requestsToSave, callback, i);
        }, 4000);
      } else if (i + 1 >= requestsToSave.length) {
        requestsIndexingProgress++;
        log.info(" requests reindexing complete");
        callback(null);
        results = [];
        for (j = 0, len = requestsIndexingCallbacks.length; j < len; j++) {
          cb = requestsIndexingCallbacks[j];
          results.push(cb(null));
        }
        return results;
      } else {
        requestsIndexingProgress++;
        log.info(" succeeded");
        return forceIndexRequests(requestsToSave, callback, i + 1);
      }
    });
  };

  module.exports.configure = function(options, app, callback) {
    var defaultModelsPaths, defaultRoot, err, error, error1, models, ref, requestsToSave;
    if (callback == null) {
      callback = function() {};
    }
    defaultRoot = process.cwd();
    defaultModelsPaths = "server/models/";
    if (typeof options === 'string') {
      options = {
        root: options,
        modelsPath: options + "/" + defaultModelsPaths
      };
    } else if (typeof options === 'object') {
      if (options.root == null) {
        options.root = defaultRoot;
      }
      if (options.modelsPath == null) {
        options.modelsPath = options.root + "/" + defaultModelsPaths;
      }
    } else {
      options = {
        root: defaultRoot,
        modelsPath: defaultRoot + "/" + defaultModelsPaths
      };
    }
    try {
      maybeSetupPouch(options);
    } catch (error) {
      err = error;
      console.log("Fail to init pouchdb, did you install it ?");
      console.log(err.stack);
      return callback(err);
    }
    api.setupModels();
    try {
      ref = getRequests(options.modelsPath), requestsToSave = ref.requestsToSave, models = ref.models;
    } catch (error1) {
      err = error1;
      log.raw(err.stack);
      log.error("Failed to load requests file.");
      return callback(err);
    }
    return defineRequests(requestsToSave, function(err) {
      if (err) {
        return callback(err);
      }
      return defineIndexes(models, function(err) {
        var reindex;
        if (err) {
          return callback(err);
        }
        reindex = forceIndexRequests.bind(null, requestsToSave);
        module.exports.forceReindexing = reindex;
        return callback(null);
      });
    });
  };

}).call(this);
