text: /**
   * Module dependencies.
   */
  
  var SchemaType = require('../schematype')
    , CastError = SchemaType.CastError
    , NumberSchema = require('./number')
    , Types = {
          Boolean: require('./boolean')
        , Date: require('./date')
        , Number: ArrayNumberSchema
        , String: require('./string')
        , ObjectId: require('./objectid')
        , Buffer: require('./buffer')
      }
    , MongooseArray = require('../types').Array
    , Mixed = require('./mixed')
    , Query = require('../query');
  
  /**
   * Array SchemaType constructor
   *
   * @param {String} key
   * @param {SchemaType} cast
   * @api private
   */
  
  function SchemaArray (key, cast, options) {
    SchemaType.call(this, key, options);
  
    if (cast) {
      var castOptions = {};
  
      if ('Object' === cast.constructor.name) {
        if (cast.type) {
          // support { type: Woot }
          castOptions = cast;
          cast = cast.type;
          delete castOptions.type;
        } else {
          cast = Mixed;
        }
      }
  
      var caster = cast.name in Types ? Types[cast.name] : cast;
      this.casterConstructor = caster;
      this.caster = new caster(null, castOptions);
    }
  
    var self = this
      , defaultArr
      , fn;
  
    if (this.defaultValue) {
      defaultArr = this.defaultValue;
      fn = 'function' == typeof defaultArr;
    }
  
    this.default(function(){
      var arr = fn ? defaultArr() : defaultArr || [];
      return new MongooseArray(arr, self.path, this);
    });
  };
  
  /**
   * Inherits from SchemaType.
   */
  
  SchemaArray.prototype.__proto__ = SchemaType.prototype;
  
  /**
   * Check required
   *
   * @api private
   */
  
  SchemaArray.prototype.checkRequired = function (value) {
    return !!(value && value.length);
  };
  
  /**
   * Overrides the getters application for the population special-case
   * TODO: implement this in SchemaObjectIdArray
   *
   * @param {Object} value
   * @param {Object} scope
   * @api private
   */
  
  SchemaArray.prototype.applyGetters = function (value, scope) {
    if (this.caster.options && this.caster.options.ref) {
      // means the object id was populated
      return value;
    }
  
    return SchemaType.prototype.applyGetters.call(this, value, scope);
  };
  
  /**
   * Casts contents
   *
   * @param {Object} value
   * @param {Document} document that triggers the casting
   * @param {Boolean} whether this is an initialization cast
   * @api private
   */
  
  SchemaArray.prototype.cast = function (value, doc, init) {
    if (Array.isArray(value)) {
      if (!(value instanceof MongooseArray)) {
        value = new MongooseArray(value, this.path, doc);
      }
  
      if (this.caster) {
        for (var i = 0, l = value.length; i < l; i++) {
          try {
            value[i] = this.caster.cast(value[i], doc, init);
          } catch (e) {
            // rethrow
            throw new CastError(e.type, value);
          }
        }
      }
  
      return value;
    } else {
      return this.cast([value], doc, init);
    }
  };
  
  SchemaArray.prototype.castForQuery = function ($conditional, val) {
    var handler;
    if (arguments.length === 2) {
      handler = this.$conditionalHandlers[$conditional];
      if (!handler)
        throw new Error("Can't use " + $conditional + " with Array.");
      val = handler.call(this, val);
    } else {
      val = $conditional;
      var proto = this.casterConstructor.prototype;
      var method = proto.castForQuery || proto.cast;
      if (Array.isArray(val)) {
        val = val.map(function (v) {
          if (method) v = method.call(proto, v);
          return v.toObject ? v.toObject() : v;
        });
      } else if (method) {
        val = method.call(proto, val);
      }
    }
    return val && val.toObject ? val.toObject() : val;
  };
  
  SchemaArray.prototype.$conditionalHandlers = {
      '$all': function handle$all (val) {
        if (!Array.isArray(val)) {
          val = [val];
        }
        return this.castForQuery(val);
      }
    , '$elemMatch': function (val) {
        var query = new Query(val);
        query.cast(this.casterConstructor)
        return query._conditions;
      }
    , '$size': function (val) {
        return ArrayNumberSchema.prototype.cast.call(this, val);
      }
    , '$ne': SchemaArray.prototype.castForQuery
    , '$in': SchemaArray.prototype.castForQuery
    , '$nin': SchemaArray.prototype.castForQuery
    , '$regex': SchemaArray.prototype.castForQuery
    , '$near': SchemaArray.prototype.castForQuery
    , '$nearSphere': SchemaArray.prototype.castForQuery
    , '$maxDistance': function (val) {
        return ArrayNumberSchema.prototype.cast.call(this, val);
      }
  };
  
  /**
   * Number casting for arrays (equivalent, but without MongoseNumber)
   *
   * @see GH-176
   * @param {Object} value
   * @api private
   */
  
  // subclass number schema to override casting
  // to disallow non-numbers being saved
  function ArrayNumberSchema (key, options) {
    NumberSchema.call(this, key, options);
  }
  
  ArrayNumberSchema.prototype.__proto__ = NumberSchema.prototype;
  
  ArrayNumberSchema.prototype.cast = function (value) {
    if (!isNaN(value)) {
      if (value instanceof Number || typeof value == 'number' ||
         (value.toString && value.toString() == Number(value)))
        return Number(value);
    }
  
    throw new CastError('number', value);
  };
  
  /**
   * Module exports.
   */
  
  module.exports = SchemaArray;
  