###
Bongo.js
Unfancy models for MongoDB

(c) 2011 Koding, Inc.

@class: Model
@description: A class for modeling, validating,
  transforming, saving, finding and sharing data.
  The base klass of the library.
@author: Christopher Thorn <chris@koding.com>
###
Base = require '../base'
module.exports = class Model extends Base
  ###
  @dependencies.
  ###
  # core
  {inspect} = require 'util'
  # contrib
  mongo     = require 'mongoskin'
  idFactory = require('hat').rack()
  Traverse  = require 'traverse'
  # lib
  JsPath          = require '../jspath'
  ObjectId        = require '../objectid'
  Subcollection   = require '../subcollection'
  Validator       = require '../validator'
  Inflector       = require '../inflector'
  SuperClient     = require '../superclient'
  sequence        = require '../sequence'
  {extend, clone} = require '../util'
  # err
  {SchemaError,
   IndexError} = require '../errortypes'
  ###
  @vars.
  ###
  # defineProperty
  {defineProperty} = Object
  # native JS casts
  primitives = [
    String
    Number
    Boolean
  ]
  # native JS constructors
  natives = [
    Object
    RegExp
    Date
  ]
  ###
  @property.
  @signature: Model.constructors
  @description - an array of all constructors (that have schema).
  ###
  defineProperty @, 'constructors', value: {}
  ###
  @property.
  @signature: Model.sharedConstructors
  @description - an array of shared constructors.
  ###
  defineProperty @, 'sharedConstructors', value: {}
  ###
  @method: property of the constructor
  @signature: Model.set(options)
  @param: component - e.g.:
    - "client" will be passed into setClient()
    - "schema" will be passed into setSchema()
    - "validators" will be passed into setValidators()
  @description: overrides Base.set() and passes items
    to their appropriate setter method.  Ignores items
    that do not have setters.
  ###
  @set =(options)->
    for own optionName, option of options
      methodName = 
        new Inflector("set_#{Inflector.underscore optionName}")
          .decapitalize()
          .camelize(yes)
          .value
      if 'function' is typeof @[methodName]
        @[methodName] option
      else
        @[optionName] = option
    @
  ###
  @method.
  @signature: Model.setSharedMethods(methods)
  @param: methods - an object containing the following
    properties:
    @property: static - an array of method names to share 
      with the client that should be attached to the
      constructor.
    @property: instance - an array of method names to share 
      with the client that should be attached to the
      prototype.
    @description: methods may be negated if they were
      shared by parent constructors by prefixing the method
      name with one or more "!"s (so don't do double
      negation, because it doesn't seem to make any sense
      in this context.)
  ###
  @setSharedMethods =(methods)->
    superSharedMethods =
      if @ is Model
        static    : []
        instance  : []
      else
        @__super__.constructor.getSharedMethods()
    sharedMethods = {
      static     : superSharedMethods.static.concat methods.static or []
      instance   : superSharedMethods.instance.concat methods.instance or []
    }
    negates = /^!+/ 
    for own methodContext, methodNames of sharedMethods
      unique = {}
      for methodName in methodNames
        unique[methodName] = yes
      for own key of unique when negates.test key
        delete unique[key]
        delete unique[key.replace negates, '']
      defineProperty @, "#{methodContext}Methods_",
        value: Object.keys unique
    
  @getSharedMethods =->
    {
      static    : @staticMethods_ or []
      instance  : @instanceMethods_ or []
    }
  ###
  @method: property of the constructor
  @signature: setValidators(validators)
  @todo: implement
  ###
  @setValidators =(validators)->
  ###
  @method: property of the constructor
  @signature: setBricks(validators)
  @todo: implement
  ###
  @setBricks =(bricks)->
  ###
  @method: property of the constructor
  @signature: Model.setClient(*overload)
  @overload:
    @signature: Model.setClient(client)
    @param: client - an instance of the Db constructor from mongodb native.
  @overload:
    @signature: Model.setClient(url)
    @param: url - of the mongodb.
  @overload:
    @signature: Model.setClient(options)
    @param: options - initializer for the connetion.
    @options:
      - server
      - username
      - password
      - database
      - port
  @return: the constuctor
  @description: basically, it registers a connection with the Model
    class for the purpose of saving and finding data.
  @todo: do we want an instance method that will allow certain instances
    to have their own separate connection?  It is convenient to have this
    registered at the class-level, for obvious reasons.  It is maybe too
    abstract, tho.
  ###
  @setClient =(overload, shouldConnect=yes)->
    constructor = @
    {SkinDb} = mongo
    if overload instanceof SkinDb
      client = overload
    else
      unless 'string' is typeof overload
        {server, username, password, database, port} = overload
        auth = if username and password then "#{username}:#{password}@" else ''
        # TODO: this is obviously botched ^.
        overload = "#{auth}#{server}:#{port}/#{database}"
      client = mongo.db overload
    unless constructor.client_?
      defineProperty constructor, 'client_'
        value: client
        writable: yes
    else
      constructor.client_ = client
    unless Model.client_?
      Model.setClient client
    constructor.onReady null, client

  @getClient =-> @client_ or Model.client_

  @setCollectionName =(@collection_)->

  @getCollectionName =->
    @collection_ or= Inflector.decapitalize Inflector.pluralize @name

  @getCollection =->
    client = @getClient()
    unless client
      throw new Error \
        """
        You must set the client for this constructor, or failing that,
        you must set a generic client for Model.
        """
    client.collection @getCollectionName()
  ###
  @vars.
  @description: index orientation fudge tests
  ###
  ascending_  = /^(asc|ascending|1)$/i
  descending_ = /^(desc|descending|-1)$/i

  construeOrientation =(attr)->
    attr = String(attr).toLowerCase()
    if ascending_.test attr then 1
    else if descending_.test attr then -1
    else 0
  
    
  
  ###
  @method: property of the constructor.
  @signature: Model.setIndexes([indexes][, callback])
  @return: the constructor.
  ###  
  
  @setIndexes =(indexes, callback)->
    if 'function' is typeof indexes
      [callback, indexes] = [indexes, callback]
    constructor = @
    if indexes
      defineProperty constructor, 'indexes', value: indexes
    else
      {indexes} = constructor
    unless indexes
      throw new Error \
        """
        No indexes were provided.  (At least one is required.)
        """
    figureIndex = sequence (collection, key, attrs, next)->
      field = {}
      def = {}
      field[key] = null
      if 'string' is typeof attrs
        attrs = [attrs]
      for attr in attrs
        if orientation = construeOrientation attr
          field[key] = orientation
        else
          def[attr] = yes
      field[key] or= 1
      # ensure the index
      collection.ensureIndex field, def, (err)->
        next? err
        return
      return
    , callback
    process.nextTick ->
      collection = constructor.getCollection()
      stop = no
      for own key, attrs of indexes
        figureIndex  collection, key, attrs
      return
    constructor
  
  @reIndex =(callback)->
    constructor = @
    process.nextTick ->
      constructor.getCollection().dropIndexes (err)->
        if err
          callback? err
        else
          constructor.setIndexes callback
        return
      return
    return
  
  @onReady =(err, client)->
    while instance = @waiting?.shift()
      instance.emit 'ready'
    err
  
  @rest =(fn)->
    #TODO: implement REST router
    fn
  
  @share =->
    constructor = @
    {name} = constructor
    unless name
      throw new Error "Can't share an unnamed constructor"
    defineProperty constructor, 'isShared', value: yes
    defineProperty constructor, 'sharedInstances', value: {}
    Model.sharedConstructors[name] = constructor
    @
  ###
  @method: property of the constructor.
  @signature: Model.setSchema(schema)
  @param: schema - ^3
  @return: the constructor.
  @description: sets a constructor property "schema"^3. sets constructor 
    properties for each memo to help quicken traversal of important paths
    (without walking the entire schema).
  ###
  @setSchema = (schema)->
    if @ is Model
      throw new SchemaError "Don't define a schema for Model, which is abstract."
    else
      # track a reference to the constructor so we can look it up by name.
      Model.constructors[@name] = @
    constructor = @
    defineProperty constructor, 'validators_'
      value: clone Validator.inbuilts
    # store a reference to the human-readable schema
    defineProperty constructor, 'schema'
      value: schema
    # memoize the important bits for easy lookup
    for own memoName, memo of constructor.getMemosOf schema
      defineProperty constructor, memoName,
        enumerable: yes
        value: memo
    @
  ###
  @method: property of the constructor.
  @signature: Model.getMemosOf(schema)
  @param: schema - ^3
  @return: the map of memos by path.
  @description: walk over the schema, interpreting it along the way
    and finding the notable items and annotations, and mapping memos
    of them by their paths; then return the maps of all the memos by
    by path by memo name.
  @todo: this implementation is really long.
  ###
  accessorNames = ['get','set']
  @getMemosOf = (schema)->
    constructor = @
    memos = 
      types               : {}
      subcollections      : {}
      subcollectionEmbeds : {}
      validators          : {}
      annotations         : {}
      primitives          : {}
      natives             : {}
      embeds              : {}
      oids                : {}
      defaults            : {}
      setters             : {}
      getters             : {}
      accessorParents     : {}
      rootProperties      : []
    new Traverse(schema)
      .forEach ->
        {node, path} = @
        pathName = path.join '.'
        if path.length is 1
          memos.rootProperties.push pathName 
        if 'function' isnt typeof node
          if Array.isArray node
            unless node.length is 1 and 'function' is typeof node[0]
              throw new SchemaError \
                """
                Can't interpret #{constructor.name}.schema.#{pathName}.
                """
            else
              memos.subcollections[pathName] = node[0]
          else if 'function' is typeof node.type #^5
            # type is a described by the "type" property
            # this opens the doorway for some more complex (than type-only) annotations
            type = node.type
            if node.default?
              memos.defaults[pathName] = node.default
            # memoize any validators
            leafValidators = []
            for own validatorName, validator of constructor.validators_
              options = node[validatorName]
              if options?
                leafValidators.push new Validator validator, options
            # memoize validators:
            if leafValidators.length
              memos.validators[pathName] = leafValidators
            # memoize any accessors:
            for accessor in accessorNames
              if node[accessor]
                unless 'function' is typeof node[accessor]
                  throw new SchemaError \
                    """
                    "#{accessor}" is not a function
                    """
                memos["#{accessor}ters"][path] = node[accessor]
                accessorParentPath = ['_data'].concat path.slice 0, -1
                parent = memos.accessorParents[accessorParentPath.join '.'] or= []
                parent.push path unless path in parent
        else if node.name #^4
          type = node
        # memoize any annotations
        return unless type
        memos.types[pathName] = type
        if type is ObjectId
          memos.oids[pathName] = type
        else if type in primitives
          memos.primitives[pathName] = type
        else if type in natives
          memos.natives[pathName] = type
        else
          memos.annotations[pathName] = type
          if Model in type.inheritanceChain?()
            isSubcollectionType = path.slice(-1)[0] is '0'
            if isSubcollectionType
              memos.subcollectionEmbeds[path.slice(0,-1).join '.'] = type
            else
              memos.embeds[pathName] = type
    memos
  ###
  @method: property of the constructor.
  @signature: Model.getType(model, path)
  @param: model - that we're searching
  @param: path - that we're searching for
  @description: returns the type (the cast function or constructor)
    that correlates to the given path of the given model.
  @todo: reimplement. for now this will work, but it's a bit ugly,
    and it probably performs badly relative to the optimal.
  ###
  @getType = (model, path)->
    {constructor} = model
    {types} = constructor
    return unless types
    if type = types[path.join '.']
      return type
    else
      path = path.slice()
      tryPath = []
      while component = path.shift()
        tryPath.push component
        if type = types[tryPath.join '.']
          ref = type
          continue
        if Model in ref?.inheritanceChain?()
          path.push tryPath.pop()
          return Model.getType JsPath.getFrom(model.data, tryPath), path
    return

  ###
  @method: property of the constructor.
  @signature: Model.castValue(value, type)
  @param: value - to be cast.
  @param: type - for the value to be cast as.
  @return: the casted value
  ###
  @castValue = (value, type)->
    if type is Object or
            type is RegExp or
            type in primitives
      type value
    else if type is ObjectId
      new type value
    else if type is Date
      new type +value # the unary "+" will cast the date as a number
    else
      chain = type.inheritanceChain?()
      if chain and Model in chain
        if value instanceof type
          value
        else
          new type value
      else if type
        throw new TypeError \
          """
          Don't know how to cast value of type "#{value.constructor.name}"
          to type "#{type}".
          """
  
  ###
  Querying
  @description: see ./find.coffee for detailed explanations.
  ###
  {@all, @some, @someData, @one, @stream} = require './find'

  @setSharedMethods
    static      : ['one','some','someData','all','stream']
    instance    : ['save','validate','on','emit']
  ###
  @constructor.
  @signature: new Model(data)
  @param: data - with which to initialize the new instance.
  @description: create a new Model instance.
  ###
  constructor:(data={})->
    model = @
    if model.constructor.isShared
      if data.bongo_
        {instanceId} = data.bongo_
        model.bongo_ = data.bongo_
      else
        instanceId = idFactory()
        model.bongo_ =
          instanceId      : instanceId
          constructorName : model.constructor.name
      model.constructor.sharedInstances[instanceId] = model
    ready_ = no
    defineProperty model, 'isReady'
      get :->
        ready_ or= model.getClient().state is 'connected'
    defineProperty model, 'isNew'
      value     : yes
      writable  : yes
    defineProperty model, 'defaults', value: {}
    defineProperty model.defaults, 'beenApplied'
      value     : no
      writable  : yes
    defineProperty model, 'data', value: {}
    # allow a maximum of 1 parent to be specified per model
    # TODO: perhaps we can introduce multidimensionality, but
    # of course it is a logical impossibility when it comes
    # to embedding.
    parent = null
    defineProperty model, 'parent', writable: yes
    # Allow a model to know its path:
    defineProperty model, 'path', writable: yes
    # Root node:
    defineProperty model, 'rootNode', writable: yes
    defineProperty model, 'isRoot',
      value: yes
      writable: yes
    # Support embedding models directly:
    isEmbedded = no
    defineProperty model, 'isEmbedded'
      set :(value)-> isEmbedded = value
      get :-> isEmbedded
    # Support embedding models into "subcollections":
    inSubcollection = no
    defineProperty model, 'inSubcollection'
      set :(value)-> inSubcollection = isEmbedded = yes
      get :-> inSubcollection
    # we need a place to store "setter values"
    defineProperty model, 'setterValues', value: {}
    for own parentPath, paths of model.constructor.accessorParents
      model.defineAccessorsOf parentPath.split('.').slice(1), paths
    # give this model an OID.  We may or may not persist it to mongo,
    # depending on this model's context in the data (but every model
    # will get one.
#    oid = if data._id?.constructor is ObjectId
#      data._id
#    else
#      new ObjectId data._id
#    customOid = null
#    defineProperty model, '_id'
#      enumerable: yes
#      get: -> customOid or if inSubcollection or not isEmbedded then oid
#      set: (value)-> customOid = value
    # set all the data that was provided to the constructor
    
    # we need to alias setters and getters for all the root-level 
    # properties that don't already have accessors
    
    for prop in model.constructor.rootProperties
      defineRootAccessorOf_ model, prop
    # import the data, casting values and constructing objects, as appropriate:
    if model.set.securityIsEnabled
      model.set SuperClient, data
    else
      model.set data
    # initialize any embedded docs.
    model.initEmbeds()
  
  ###
  @function.
  @signature: defineRootAccessorOf_(model, propertyName)
  @param: model
  @param: prop - the property name
  ###
  defineRootAccessorOf_ =(model, prop)->
    {data, defaults} = model
    unless prop of model
      defineProperty model, prop,
        enumerable: yes
        get :->
          if data[prop]?
            data[prop]
          else
            #model.applyDefaults()
            data[prop] = defaults[prop]
        set :(value)->
          data[prop] = value
  ###
  @method.
  @signature: Model::defineAccessorsOf(parentPath, paths)
  @param: parentPath - an array of the segments of the path
    drilling down to, but not including the accessor itself
  @param: paths - an array of the complete paths of setters
    redundant, but convenient. this may change.
  @return: model
  @description: returns a structure object that has all
    accessors predefined.
  ###
  defineAccessorsOf:(parentPath, paths)->
    model = @
    {data} = model
    unless parentPath.length
      parent = data
    else
      parent = JsPath.getFrom(data, parentPath) or {}
      JsPath.setTo data, parentPath, parent
    for path in paths
      assignAccessorsByPath_ model, data, parent, path #^* see below.
    @
  ###
  @function.
  @signature: assignAccessorsByPath_(model, data, parent, path)^*
  @param: model - the instance.
  @param: data - the working tree.
  @param: parent - the owner of the properties we're setting.
  @param: path - the full path of the property we're setting.
  @description: a helper function for Model.defineAccessorsOf()
    so we don't create functions in the loop. (see above ^*)
  ###
  assignAccessorsByPath_ = (model, data, parent, path)->
    pathName = path.join '.'
    prop = path.slice(-1)[0]
    setter = model.constructor.setters[pathName]
    getter = model.constructor.getters[pathName]
    defineProperty parent, prop,
      enumerable : yes
      set :(value)->
        if setter
          value = setter.call parent, value #^**
        model.setterValues[pathName] = value
      get :->
        value = model.setterValues[pathName]
        if getter
          value = getter.call parent, value #^**
        value
      # ** call accessors in the context of the parent so that
      # "this" is meaningful.
  ###
  @method.
  @signature: Model::applyDefaults()
  @param: callback
  @return: the model.defaults object
  @description: apply all the defaults throughout the model.
    call .applyDefaults() on any embedded models encountered
    in the walk.
  ###
  applyDefaults:->
    model = @
    # set default values for all fields
    for own defaultPath, defaultValue of model.constructor.defaults
      if 'function' is typeof defaultValue
        defaultValue = defaultValue.call model
      JsPath.setTo model.defaults, defaultPath, defaultValue
    model.defaults
  
  ###
  @method.
  @signature: Model::initEmbeds()
  @description: rather a heavy function that will initialize
    embedded models and embedded subcollections.  Separated this
    from .applyDefaults(), because the latter should be fleet.
  ###
  initEmbeds:->
    model = @
    # initialize any models that are undefined.
    for own embedPath, embedConstructor of model.constructor.embeds
      embedPath = embedPath.split '.'
      unless JsPath.getFrom(model.data, embedPath)?
        embed = new embedConstructor
        embed.path = embedPath
        embed.parent = JsPath.getFrom model, embedPath.slice 0, -1
        embed.on 'error', (err)-> model.emit 'error', err
        JsPath.setTo model.defaults, embedPath, embed
    # initialize any subcollections
    for own subcollectionEmbedPath, subcollectionEmbedAnnotation of \
      model.constructor.subcollectionEmbeds
        subcollectionEmbedPath = subcollectionEmbedPath.split '.'
        unless JsPath.getFrom(model.data, subcollectionEmbedPath)?
          parent = JsPath.getFrom model, subcollectionEmbedPath.slice 0, -1
          subcollection = new Subcollection \
            parent, [], subcollectionEmbedAnnotation
          subcollection.on 'error', (err)-> model.emit 'error', err
          subcollection.path = subcollectionEmbedPath
          JsPath.setTo model.defaults, subcollectionEmbedPath, subcollection
  ###
  @method.
  @signature: Model::validate(callback)
  @param: callback
  @return: errs — that were encountered in the walk.
  @description: validate the data of "this", emitting events.
  ###
  validate:(callback)->
    Validator.validate @, callback
  ###
  @constructor.
  @signature: Model::getClient()
  @returns: client - of the constructor.
  ###
  getClient:->
    @constructor.getClient()
  ###
  @constructor.
  @signature: Model::getClient()
  @returns: collection name - of the constructor.
  ###
  getCollectionName:->
    @constructor.getCollectionName()
  ###
  @method.
  @signature: Model::save(callback)
  @param: callback
  @description: save this model to its collection, or notify
    its parent that it should be saved, in the case of embedding.
  ###
  save: (callback)->
    model = @
    model.validate save_0_.bind model, callback
    model
      #else if isNew
  ###
  @function. bound to the model instance
  @signature: save_0_.bind(model, callback)
  @param: model - to bind the function to
  ###
  save_0_ =(callback, err)->
    model = @
    if err?
      callback? err
    else if model.isRoot
      model.emit 'validate', model
      collection = model.constructor.getCollection()
      unless model.data._id?
        data = model.get()
        delete data.bongo_
        data._id = new ObjectId
        collection.insert data, save_1_.bind model, callback
      else
        data = model.get()
        delete data._id
        delete data.bongo_
        collection.update \
          model.getId(), ($set: data), 
          (safe:yes), save_1_.bind model, callback
    else
      model.rootNode?.saveAtomically model, callback
  ###
  @function. bound to the model instance
  @signature: save_1_.bind(model, callback)
  @param: model - to bind the function to
  ### 
  save_1_ =(callback, err, docs)->
    model = @
    if err
      model.emit 'error', err, docs
    else
      model.emit 'save', model, docs
    model._id = docs[0]?._id
    callback?.call model, err, docs
  ###
  @method.
  @signature: Model::saveAtomically(model, callback)
  @throws: an schemaError
  ###
  saveAtomically:(model, callback)->
    if @notRoot
      throw new Error \
        "don't call .saveAtomically() on a non-root node."
    else
      @save callback
  #
  #getMemoByNameAndPath:(memoName, path)->
  #  {constructor, data} = @
  #  path = path.slice()
  #  memo = constructor[memoName][path.join '.']
  #  return [] unless memo
  #  prop = path.pop()
  #  parent = JsPath.getFrom data, path
  #  [memo, prop, parent]
  #
  #setSubcollection:(path, array)->
  #  [annotation, prop, parent] = @getMemoByNameAndPath 'subcollections', path
  #  subcollection = new Subcollection @, array, annotation
  #  parent[prop] = subcollection
  ###
  @method.
  @signature: Model::set(data)
  @param: data - a map of paths to set data to.  Use dot notation if you
    want to reach into objects, as there is no way to recursively merge JS
    objects without astonishing side effects.  Object notation "clobbers"
    sibling properties.
  @description: sets properties to the model by path.
  ###
  set:(data)->
    model = @
    {constructor} = model
    new Traverse(data) 
      .forEach ->
        return if not @node? or @node.constructor is ObjectId
        if Array.isArray @node
          type = constructor.subcollections[@path.join '.']
          subcollection = new Subcollection model, @node, type
          @update subcollection
        else
          if @path.length
            type = Model.getType model, @path
            if type and type isnt Object
              @update Model.castValue(@node, type), yes
#          if @node instanceof Model
#            @update @node, yes
    # traverse again to set the path
    # TODO: try to optimize this so we only need to walk once.
    new Traverse(data)
      .forEach ->
        if @node instanceof Model
          # I am not 100% convinced that this assumption will hold true:
          @node.isRoot = no
          @node.rootNode = model
          @node.path = @path
          @node.parent = @parent.node
          @update @node
          #@node
    for own path, value of data
      JsPath.setTo model.data, path, value
  ###
  @function.
  @signature: attachOuterAccessor_(model, path)
  @param: model
  @param: path - the path (inside data) we want to alias.
  @description: helper to add accessors onto the root level
    of the model to access the members on the root level of
    the model's data object.
  ###
  attachOuterAccessor_ = (model, path)->
    defineProperty model, path,
      enumerable: yes
      get :-> model.data[path]
      set :(value)-> model.data[path] = value
  
  shouldBeSaved:(path)->
    if path is '_id' then no else console.log path; yes
  ###
  @method.
  @signature Model::get()
  @description: traverse the model (which implicitly will call
    any getters), prune nulls and undefineds, return the results
    of the traversal.
  ###
  get:(shouldUpdateAtomically=no)->
    model = @
    model.applyDefaults()
    data = extend {}, model.defaults, model.data
    # this will call the getters and return a new object
    new Traverse(data).forEach ->
      if not @node? or shouldUpdateAtomically and not model.shouldBeSaved @path
        @delete()  # remove "undefined" and "null" values
      else if @node instanceof Subcollection
        @update Array::slice.call @node
      else
        @update @node.get?() or @node
  
  getId:(driver=mongo)->
    model = @
    # TODO: implement plugins
    _id: model.data._id
  
  inspect:-> inspect @get()
###
Footnotes:
  1 - ad hoc properties not associated with a schema are fine, but we don't persist them to Mongo.
  2 - apply defaults / validations on output (not here).
  3 - the human-readable description of the schema, including "type annotations" (JS constructors/primitive casts, really) and validation functions (including some sugared inbuilt ones).
  4 - if it has a name, it may be a constructor; this might be botched.
  5 - because of overloading, we need to make sure this isn't a field called "validator".
  6 - defaults are applied on output.
  7 - normal validators only take 1 argument: a value which needs to be validated.  There are also a class of so-called "curried" validators that take 2 arguments (e.g. pattern and enum): the first is arbitrarily supplied during schema creation, and the second is the value described above which needs to be validated.