// Generated by CoffeeScript 1.8.0
(function() {
  var Create, Honor, MakeAsync, SchemaListValidate, deepcopy, moment, valOrEval, validUrl, _,
    __slice = [].slice;

  validUrl = require('valid-url');

  moment = require('moment');

  deepcopy = require('deepcopy');

  _ = require('underscore');

  SchemaListValidate = function(list, schema, newModel, newErrors, callback) {
    var nextItem;
    if (list.length === 0) {
      if (_.isEmpty(newErrors)) {
        return callback(null, newModel);
      } else {
        return callback(newErrors, null);
      }
    }
    nextItem = list.shift();
    if (nextItem.val === void 0) {
      newErrors[nextItem.key].undefined = true;
      return SchemaListValidate(list, schema, newModel, newErrors, callback);
    }
    if (nextItem.val === null) {
      newErrors[nextItem.key].undefined = true;
      return SchemaListValidate(list, schema, newModel, newErrors, callback);
    }
    if (!_.isObject(nextItem.val)) {
      newErrors[nextItem.key].type = true;
      return SchemaListValidate(list, schema, newModel, newErrors, callback);
    }
    return schema.validate(nextItem.val, function(err) {
      if (err) {
        newErrors[nextItem.key] = err;
      } else {
        newModel.push(nextItem.val);
      }
      return SchemaListValidate(list, schema, newModel, newErrors, callback);
    });
  };

  MakeAsync = function() {
    var aFunction, callback, functionArguments, result, _i;
    aFunction = arguments[0], functionArguments = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), callback = arguments[_i++];
    result = aFunction.apply(null, __slice.call(functionArguments).concat([callback]));
    if (result !== Infinity) {
      return callback(null, result);
    }
  };

  valOrEval = function(check, callback) {
    if (_.isFunction(check.checkValue)) {
      return MakeAsync(check.checkValue, check, callback);
    } else {
      return callback(null, check.checkValue);
    }
  };

  Create = function(aSchema) {
    var self;
    self = {};
    self.schema = aSchema ? aSchema : {};
    self.checklist = [];
    self.constraints = {};
    self._field = {};
    self.errorsToList = function(err, prefix) {
      var result;
      prefix || (prefix = []);
      result = [];
      if (_.isObject(err)) {
        return _.each(err, function(val, key) {
          var subList;
          subList = self.errorsToList(val, __slice.call(prefix).concat([key]));
          return _.each(subList, function(item) {
            return result.push(item);
          });
        });
      } else if (err) {
        return [prefix.join('_')];
      } else {
        return [];
      }
    };
    self.define = function(fieldName, miniSchema) {
      return self._field[fieldName] = miniSchema;
    };
    self.constraint = function(aName, aFunction) {
      return self.constraints[aName] = aFunction;
    };
    self.field = function(fieldName, miniSchema) {
      var result;
      result = self._field[fieldName] || {};
      if (miniSchema) {
        _.each(miniSchema, function(v, k) {
          return result[k] = v;
        });
      }
      return result;
    };
    self.extend = function(aSchema) {
      var copy;
      copy = Create(deepcopy(self.schema));
      copy.checklist = deepcopy(self.checklist);
      if (aSchema) {
        _.each(aSchema, function(v, k) {
          return copy.schema[k] = v;
        });
      }
      return copy;
    };
    self.check = function(checkName, checkFunction) {
      var newChecklist, wasReplaced;
      newChecklist = [];
      wasReplaced = false;
      _.each(self.checklist, function(checkObject) {
        if (checkObject.checkName === checkName) {
          newChecklist.push({
            checkName: checkName,
            checkFunction: checkFunction
          });
          return wasReplaced = true;
        } else {
          return newChecklist.push(checkObject);
        }
      });
      if (!wasReplaced) {
        newChecklist.push({
          checkName: checkName,
          checkFunction: checkFunction
        });
      }
      return self.checklist = newChecklist;
    };
    self.deleteCheck = function(checkName) {
      var checkToDelete, newChecklist;
      checkToDelete = null;
      newChecklist = [];
      _.each(self.checklist, function(checkObject) {
        if (checkObject.checkName === checkName) {
          return checkToDelete = checkObject;
        } else {
          return newChecklist.push(checkObject);
        }
      });
      if (checkToDelete) {
        self.checklist = newChecklist;
        return checkToDelete;
      } else {
        return null;
      }
    };
    self.moveIt = function(checkName, checkNameToMove, cb) {
      var deletedCheck, found, newChecklist;
      deletedCheck = self.deleteCheck(checkNameToMove);
      if (!deletedCheck) {
        throw Error("check to move wasn't found");
      }
      newChecklist = [];
      found = false;
      _.each(self.checklist, function(checkObject) {
        if (cb(checkObject, newChecklist, deletedCheck)) {
          return found = true;
        }
      });
      if (!found) {
        throw Error("check name was not found");
      }
      return self.checklist = newChecklist;
    };
    self.moveBefore = function(checkName, checkNameToMove) {
      return self.moveIt(checkName, checkNameToMove, function(checkObject, newChecklist, deletedCheck) {
        var found;
        found = false;
        if (checkObject.checkName === checkName) {
          newChecklist.push(deletedCheck);
          found = true;
        }
        newChecklist.push(checkObject);
        return found;
      });
    };
    self.moveAfter = function(checkName, checkNameToMove) {
      return self.moveIt(checkName, checkNameToMove, function(checkObject, newChecklist, deletedCheck) {
        var found;
        found = false;
        newChecklist.push(checkObject);
        if (checkObject.checkName === checkName) {
          newChecklist.push(deletedCheck);
          found = true;
        }
        return found;
      });
    };
    self.validate = function(model, callback) {
      var checklist;
      _.each(model, function(v, k) {
        if (!self.schema[k]) {
          return delete model[k];
        }
      });
      checklist = [];
      _.each(self.checklist, function(check) {
        return _.each(self.schema, function(attributeField, modelAttribute) {
          return _.each(attributeField, function(checkValue, checkName) {
            var checkNameInitial, reverseCheck;
            checkNameInitial = checkName;
            reverseCheck = false;
            if (checkName.match(/^not_/)) {
              reverseCheck = true;
              checkName = checkName.replace(/^not_/, '');
            }
            if (check.checkName !== checkName) {
              return;
            }
            check = _.clone(check);
            check.model = model;
            check.modelAttribute = modelAttribute;
            check.modelValue = model[modelAttribute];
            check.checkValue = checkValue;
            check.reverseCheck = reverseCheck;
            check.honor = self;
            check.checkNameInitial = checkNameInitial;
            return checklist.push(check);
          });
        });
      });
      _.each(self.constraints, function(checkFunction, checkName) {
        return checklist.push({
          checkName: checkName,
          checkFunction: checkFunction,
          checkNameInitial: checkName,
          model: model,
          honor: self,
          modelAttribute: 'constraint'
        });
      });
      return self.validateChecklist(checklist, {}, function(err) {
        if (err) {
          return callback(err, null);
        }
        return callback(null, model);
      });
    };
    self.validateChecklist = function(checklist, newError, callback) {
      var nextCheck;
      if (checklist.length === 0) {
        if (_.isEmpty(newError)) {
          return callback();
        } else {
          return callback(newError);
        }
      }
      nextCheck = checklist.shift();
      nextCheck.modelValue = nextCheck.model[nextCheck.modelAttribute];
      if (newError[nextCheck.modelAttribute]) {
        return self.validateChecklist(checklist, newError, callback);
      }
      return valOrEval(nextCheck, function(error, checkValue) {
        if (error) {
          newError[nextCheck.modelAttribute] = {};
          newError[nextCheck.modelAttribute][nextCheck.checkNameInitial] = error;
          return self.validateChecklist(checklist, newError, callback);
        } else {
          nextCheck.checkValue = checkValue;
          return MakeAsync(nextCheck.checkFunction, nextCheck, function(error, result) {
            if (error) {
              newError[nextCheck.modelAttribute] = {};
              newError[nextCheck.modelAttribute][nextCheck.checkNameInitial] = error;
              return self.validateChecklist(checklist, newError, callback);
            }
            if (nextCheck.reverseCheck) {
              result = !result;
            }
            if (!result) {
              newError[nextCheck.modelAttribute] = {};
              newError[nextCheck.modelAttribute][nextCheck.checkNameInitial] = true;
              return self.validateChecklist(checklist, newError, callback);
            }
            nextCheck.modelValue = nextCheck.model[nextCheck.modelAttribute];
            return self.validateChecklist(checklist, newError, callback);
          });
        }
      });
    };
    self.blindJudge = function() {
      return 313;
    };
    return self;
  };

  Honor = Create();

  Honor.check('trim', function(c) {
    var value;
    if (!c.checkValue) {
      return true;
    }
    if (typeof c.modelValue !== 'string') {
      return true;
    }
    value = c.modelValue;
    value = value.replace(/^\s+/, '');
    value = value.replace(/\s+$/, '');
    c.model[c.modelAttribute] = value;
    return true;
  });

  Honor.check('default', function(c) {
    if (c.modelValue !== void 0 && c.modelValue !== null) {
      return true;
    }
    c.model[c.modelAttribute] = c.checkValue;
    return true;
  });

  Honor.check('coerce', function(c) {
    switch (c.checkValue) {
      case 'string':
        c.model[c.modelAttribute] = String(c.model[c.modelAttribute]);
        break;
      case 'number':
        c.model[c.modelAttribute] = Number(c.model[c.modelAttribute]);
        break;
      case 'boolean':
        c.model[c.modelAttribute] = Boolean(c.model[c.modelAttribute]);
        break;
      case 'moment':
        c.model[c.modelAttribute] = moment(c.model[c.modelAttribute]);
    }
    return true;
  });

  Honor.check('defined', function(c) {
    if (!c.checkValue) {
      return true;
    }
    return c.modelValue !== void 0;
  });

  Honor.check('null', function(c) {
    if (!c.checkValue) {
      return true;
    }
    return c.modelValue === null;
  });

  Honor.check('required', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue === void 0) {
      return false;
    }
    if (c.modelValue === null) {
      return false;
    }
    if (String(c.modelValue) === '') {
      return false;
    }
    return true;
  });

  Honor.check('uuid', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return String(c.modelValue).match(/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
  });

  Honor.check('moment', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return moment(c.modelValue).isValid();
  });

  Honor.check('email', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue === void 0) {
      return true;
    }
    if (c.modelValue === null) {
      return true;
    }
    return String(c.modelValue).match(/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
  });

  Honor.check('integer', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue === void 0) {
      return true;
    }
    if (c.modelValue === null) {
      return true;
    }
    return String(c.modelValue).match(/^[-]?\d+$/);
  });

  Honor.check('boolean', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    if (String(c.modelValue).match(/^(on|yes|true|1)$/i)) {
      c.model[c.modelAttribute] = true;
      return true;
    } else if (/^(off|no|false|0)$/i) {
      c.model[c.modelAttribute] = false;
      c.modelValue = false;
      return true;
    } else {
      return false;
    }
  });

  Honor.check('hex', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return String(c.modelValue).match(/^[a-fA-F0-9]+$/);
  });

  Honor.check('float', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return String(c.modelValue).match(/^[-]?[0-9]*[\.]?[0-9]+$/);
  });

  Honor.check('like', function(c) {
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return String(c.modelValue).match(c.checkValue);
  });

  Honor.check('ipv4', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return String(c.modelValue).match(/^((([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))[.]){3}(([0-1]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))$/);
  });

  Honor.check('host', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return String(c.modelValue).match(/^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/);
  });

  Honor.check('phone', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return String(c.modelValue).match(/^\+?\d+$/);
  });

  Honor.check('url', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return validUrl.isUri(String(c.modelValue));
  });

  Honor.check('sip', function(c) {
    if (!c.checkValue) {
      return true;
    }
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    return String(c.modelValue).match(String(value).match(/^\+?(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))(:\d+)?$/));
  });

  Honor.check('maxlen', function(c) {
    var err, len, retVal;
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    len = Number(c.checkValue);
    if (String(len) === 'NaN') {
      return false;
    }
    retVal = false;
    try {
      retVal = c.modelValue.length <= len;
    } catch (_error) {
      err = _error;
      return false;
    }
    return retVal;
  });

  Honor.check('minlen', function(c) {
    var err, len, retVal;
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    len = Number(c.checkValue);
    if (String(len) === 'NaN') {
      return false;
    }
    retVal = false;
    try {
      retVal = c.modelValue.length <= len;
    } catch (_error) {
      err = _error;
      return false;
    }
    return retVal;
  });

  Honor.check('maxval', function(c) {
    var checkValue, modelValue;
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    checkValue = Number(c.checkValue);
    if (String(checkValue) === 'NaN') {
      return false;
    }
    modelValue = Number(c.modelValue);
    if (String(modelValue) === 'NaN') {
      return false;
    }
    return modelValue <= checkValue;
  });

  Honor.check('minval', function(c) {
    var checkValue, modelValue;
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    checkValue = Number(c.checkValue);
    if (String(checkValue) === 'NaN') {
      return false;
    }
    modelValue = Number(c.modelValue);
    if (String(modelValue) === 'NaN') {
      return false;
    }
    return modelValue <= checkValue;
  });

  Honor.check('equals', function(c) {
    return c.modelValue === c.checkValue;
  });

  Honor.check('in', function(c) {
    var checkVal, _i, _len, _ref;
    if (!c.checkValue) {
      return true;
    }
    if (_.isArray(c.checkValue)) {
      _ref = c.checkValue;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        checkVal = _ref[_i];
        if (checkVal === c.modelValue) {
          return true;
        }
      }
    }
    return false;
  });

  Honor.check('starts', function(c) {
    var checkVal;
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    if (c.checkValue !== void 0) {
      return false;
    }
    if (c.checkValue !== null) {
      return false;
    }
    checkVal = String(c.checkValue);
    return String(c.modelValue).indexOf(checkVal) === 0;
  });

  Honor.check('contains', function(c) {
    var checkVal;
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    if (c.checkValue !== void 0) {
      return false;
    }
    if (c.checkValue !== null) {
      return false;
    }
    checkVal = String(c.checkValue);
    return String(c.modelValue).indexOf(checkVal) >= 0;
  });

  Honor.check('schema', function(c, callback) {
    var checkValue, model, schema;
    if (c.modelValue !== void 0) {
      return true;
    }
    if (c.modelValue !== null) {
      return true;
    }
    checkValue = c.checkValue;
    if (!_.isObject(checkValue)) {
      return false;
    }
    if (!checkValue.blindJudge) {
      return false;
    }
    if (checkValue.blindJudge() !== 313) {
      return false;
    }
    if (!c.checkValue) {
      return true;
    }
    schema = c.checkValue;
    model = c.modelValue;
    schema.validate(model, function(err) {
      if (err) {
        return callback(err, null);
      } else {
        return callback(null, model);
      }
    });
    return Infinity;
  });

  Honor.check('array_of', function(c, callback) {
    var list, model, schema;
    if (!c.checkValue) {
      return true;
    }
    schema = c.checkValue;
    model = c.modelValue;
    list = [];
    _.each(model, function(val, key) {
      return list.push({
        val: val,
        key: key
      });
    });
    SchemaListValidate(list, schema, [], {}, callback);
    return Infinity;
  });

  module.exports = Honor;

}).call(this);
