text: 'use strict';
  
  /*!
   * ignore
   */
  
  var Mixed = require('../../schema/mixed');
  var mpath = require('mpath');
  
  /*!
   * @param {Schema} schema
   * @param {Object} doc POJO
   * @param {string} path
   */
  
  module.exports = function getSchemaTypes(schema, doc, path) {
    var pathschema = schema.path(path);
  
    if (pathschema) {
      return pathschema;
    }
  
    function search(parts, schema) {
      var p = parts.length + 1;
      var foundschema;
      var trypath;
  
      while (p--) {
        trypath = parts.slice(0, p).join('.');
        foundschema = schema.path(trypath);
        if (foundschema) {
          if (foundschema.caster) {
            // array of Mixed?
            if (foundschema.caster instanceof Mixed) {
              return foundschema.caster;
            }
  
            var schemas = null;
            if (doc != null && foundschema.schema != null && foundschema.schema.discriminators != null) {
              var discriminators = foundschema.schema.discriminators;
              var keys = mpath.get(trypath + '.' + foundschema.schema.options.discriminatorKey,
                doc);
              schemas = Object.keys(discriminators).
                reduce(function(cur, discriminator) {
                  if (keys.indexOf(discriminator) !== -1) {
                    cur.push(discriminators[discriminator]);
                  }
                  return cur;
                }, []);
            }
  
            // Now that we found the array, we need to check if there
            // are remaining document paths to look up for casting.
            // Also we need to handle array.$.path since schema.path
            // doesn't work for that.
            // If there is no foundschema.schema we are dealing with
            // a path like array.$
            if (p !== parts.length && foundschema.schema) {
              var ret;
              if (parts[p] === '$') {
                if (p + 1 === parts.length) {
                  // comments.$
                  return foundschema;
                }
                // comments.$.comments.$.title
                ret = search(parts.slice(p + 1), schema);
                if (ret) {
                  ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
                    !foundschema.schema.$isSingleNested;
                }
                return ret;
              }
  
              if (schemas != null && schemas.length > 0) {
                ret = [];
                for (var i = 0; i < schemas.length; ++i) {
                  var _ret = search(parts.slice(p), schemas[i]);
                  if (_ret != null) {
                    _ret.$isUnderneathDocArray = _ret.$isUnderneathDocArray ||
                      !foundschema.schema.$isSingleNested;
                    if (_ret.$isUnderneathDocArray) {
                      ret.$isUnderneathDocArray = true;
                    }
                    ret.push(_ret);
                  }
                }
                return ret;
              } else {
                ret = search(parts.slice(p), foundschema.schema);
  
                if (ret) {
                  ret.$isUnderneathDocArray = ret.$isUnderneathDocArray ||
                    !foundschema.schema.$isSingleNested;
                }
  
                return ret;
              }
            }
          }
  
          return foundschema;
        }
      }
    }
  
    // look for arrays
    var parts = path.split('.');
    for (var i = 0; i < parts.length; ++i) {
      if (parts[i] === '$') {
        // Re: gh-5628, because `schema.path()` doesn't take $ into account.
        parts[i] = '0';
      }
    }
    return search(parts, schema);
  };
  