-<!--- PUBLIC MODEL INITIALIZATION METHODS --->
-
-<cffunction name="automaticValidations" returntype="void" access="public" output="false">
-	<cfargument name="value" type="boolean" required="true">
-	<cfscript>
+<cfscript>
+	/*
+	* PUBLIC MODEL INITIALIZATION METHODS
+	*/
+
+	public void function automaticValidations(required boolean value) {
 		variables.wheels.class.automaticValidations = arguments.value;
-	</cfscript>
-</cffunction>
-
-<cffunction name="validate" returntype="void" access="public" output="false">
-	<cfargument name="methods" type="string" required="false" default="">
-	<cfargument name="condition" type="string" required="false" default="">
-	<cfargument name="unless" type="string" required="false" default="">
-	<cfargument name="when" type="string" required="false" default="onSave">
-	<cfscript>
+	}
+
+	public void function validate(
+		string methods="",
+		string condition="",
+		string unless="",
+		string when="onSave"
+	) {
 		$registerValidation(argumentCollection=arguments);
-	</cfscript>
-</cffunction>
-
-<cffunction name="validateOnCreate" returntype="void" access="public" output="false">
-	<cfargument name="methods" type="string" required="false" default="">
-	<cfargument name="condition" type="string" required="false" default="">
-	<cfargument name="unless" type="string" required="false" default="">
-	<cfscript>
+	}
+
+	public void function validateOnCreate(
+		string methods="",
+		string condition="",
+		string unless=""
+	) {
 		$registerValidation(when="onCreate", argumentCollection=arguments);
-	</cfscript>
-</cffunction>
-
-<cffunction name="validateOnUpdate" returntype="void" access="public" output="false">
-	<cfargument name="methods" type="string" required="false" default="">
-	<cfargument name="condition" type="string" required="false" default="">
-	<cfargument name="unless" type="string" required="false" default="">
-	<cfscript>
+	}
+
+	public void function validateOnUpdate(
+		string methods="",
+		string condition="",
+		string unless=""
+	) {
 		$registerValidation(when="onUpdate", argumentCollection=arguments);
-	</cfscript>
-</cffunction>
-
-<cffunction name="validatesConfirmationOf" returntype="void" access="public" output="false">
-	<cfargument name="properties" type="string" required="false" default="">
-	<cfargument name="message" type="string" required="false">
-	<cfargument name="when" type="string" required="false" default="onSave">
-	<cfargument name="condition" type="string" required="false" default="">
-	<cfargument name="unless" type="string" required="false" default="">
-	<cfscript>
+	}
+
+	public void function validatesConfirmationOf(
+		string properties="",
+		string message,
+		string when="onSave",
+		string condition="",
+		string unless=""
+	) {
 		$args(name="validatesConfirmationOf", args=arguments);
 		$registerValidation(methods="$validatesConfirmationOf", argumentCollection=arguments);
-	</cfscript>
-</cffunction>
-
-<cffunction name="validatesExclusionOf" returntype="void" access="public" output="false">
-	<cfargument name="properties" type="string" required="false" default="">
-	<cfargument name="list" type="string" required="true">
-	<cfargument name="message" type="string" required="false">
-	<cfargument name="when" type="string" required="false" default="onSave">
-	<cfargument name="allowBlank" type="boolean" required="false">
-	<cfargument name="condition" type="string" required="false" default="">
-	<cfargument name="unless" type="string" required="false" default="">
-	<cfscript>
+	}
+
+	public void function validatesExclusionOf(
+		string properties="",
+		required string list,
+		string message,
+		string when="onSave",
+		boolean allowBlank,
+		string condition="",
+		string unless=""
+	) {
 		$args(name="validatesExclusionOf", args=arguments);
 		arguments.list = $listClean(arguments.list);
 		$registerValidation(methods="$validatesExclusionOf", argumentCollection=arguments);
-	</cfscript>
-</cffunction>
-
-<cffunction name="validatesFormatOf" returntype="void" access="public" output="false">
-	<cfargument name="properties" type="string" required="false" default="">
-	<cfargument name="regEx" type="string" required="false" default="">
-	<cfargument name="type" type="string" required="false" default="">
-	<cfargument name="message" type="string" required="false">
-	<cfargument name="when" type="string" required="false" default="onSave">
-	<cfargument name="allowBlank" type="boolean" required="false">
-	<cfargument name="condition" type="string" required="false" default="">
-	<cfargument name="unless" type="string" required="false" default="">
-	<cfscript>
+	}
+
+	public void function validatesFormatOf(
+		string properties="",
+		string regEx="",
+		string type="",
+		string message,
+		string when="onSave",
+		boolean allowBlank,
+		string condition="",
+		string unless=""
+	) {
 		$args(name="validatesFormatOf", args=arguments);
 		if (application.wheels.showErrorInformation)
 		{

		}

		// loop over the passed in types
		loc.iEnd = ListLen(arguments.type);
		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
		{
			loc.item = ListGetAt(arguments.type, loc.i);

			// loop through all validations for passed in type (onSave, onCreate etc) that has been set on this model object
			loc.jEnd = ArrayLen(variables.wheels.class.validations[loc.item]);
			for (loc.j=1; loc.j <= loc.jEnd; loc.j++)
			{
				loc.thisValidation = variables.wheels.class.validations[loc.item][loc.j];
				if ($evaluateCondition(argumentCollection=loc.thisValidation.args))
				{
					if (loc.thisValidation.method == "$validatesPresenceOf")
					{
						// if the property does not exist or if it's blank we add an error on the object (for all other validation types we call corresponding methods below instead)
						if (!StructKeyExists(this, loc.thisValidation.args.property) || (IsSimpleValue(this[loc.thisValidation.args.property]) && !Len(Trim(this[loc.thisValidation.args.property]))) || (IsStruct(this[loc.thisValidation.args.property]) && !StructCount(this[loc.thisValidation.args.property])))
						{
							addError(property=loc.thisValidation.args.property, message=$validationErrorMessage(loc.thisValidation.args.property, loc.thisValidation.args.message));
						}
					}
					else
					{
						// if the validation set does not allow blank values we can set an error right away, otherwise we call a method to run the actual check
						if (StructKeyExists(loc.thisValidation.args, "property") && StructKeyExists(loc.thisValidation.args, "allowBlank") && !loc.thisValidation.args.allowBlank && (!StructKeyExists(this, loc.thisValidation.args.property) || (!Len(this[loc.thisValidation.args.property]) && loc.thisValidation.method != "$validatesUniquenessOf")))
						{
							addError(property=loc.thisValidation.args.property, message=$validationErrorMessage(loc.thisValidation.args.property, loc.thisValidation.args.message));
						}
						else if (!StructKeyExists(loc.thisValidation.args, "property") || (StructKeyExists(this, loc.thisValidation.args.property) &&(Len(this[loc.thisValidation.args.property]) || loc.thisValidation.method == "$validatesUniquenessOf")))
						{
							$invoke(method=loc.thisValidation.method, invokeArgs=loc.thisValidation.args);
						}
					}
				}
			}
		}

		// now that we have run all the validation checks we can return "true" if no errors exist on the object, "false" otherwise
		loc.rv = !hasErrors();
	</cfscript>
	<cfreturn loc.rv>
</cffunction>

<cffunction name="$evaluateCondition" returntype="boolean" access="public" output="false" hint="Evaluates the condition to determine if the validation should be executed.">
	<cfscript>
		var loc = {};
		loc.rv = false;

		// since cf8 can't handle cfscript operators (==, != etc) inside an Evaluate() call we replace them with eq, neq etc in a try / catch
		loc.evaluate = "condition,unless";
		loc.iEnd = ListLen(loc.evaluate);
		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
		{
			loc.item = ListGetAt(loc.evaluate, loc.i);
			if (StructKeyExists(arguments, loc.item) && Len(arguments[loc.item]))
			{
				loc.key = loc.item & "Evaluated";
				try
				{
					loc[loc.key] = Evaluate(arguments[loc.item]);
				}
				catch (any e)
				{
					arguments[loc.item] = Replace(ReplaceList(arguments[loc.item], "==,!=,<,<=,>,>=", " eq , neq , lt , lte , gt , gte "), "  ", " ", "all");
					loc[loc.key] = Evaluate(arguments[loc.item]);
				}
			}
		}

		// proceed with validation when "condition" has been supplied and it evaluates to "true" or when "unless" has been supplied and it evaluates to "false"
		// if both "condition" and "unless" have been supplied though, they both need to be evaluated correctly ("true"/false" that is) for validation to proceed
		if ((!StructKeyExists(arguments, "condition") || !Len(arguments.condition) || loc.conditionEvaluated) && (!StructKeyExists(arguments, "unless") || !Len(arguments.unless) || !loc.unlessEvaluated))
		{
			loc.rv = true;
		}
	</cfscript>
	<cfreturn loc.rv>
</cffunction>

<cffunction name="$validatesConfirmationOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesConfirmationOf method.">
	<cfscript>
		var loc = {};
		loc.virtualConfirmProperty = arguments.property & "Confirmation";
		if (StructKeyExists(this, loc.virtualConfirmProperty) && this[arguments.property] != this[loc.virtualConfirmProperty])
		{
			addError(property=loc.virtualConfirmProperty, message=$validationErrorMessage(argumentCollection=arguments));
		}
	</cfscript>
</cffunction>

<cffunction name="$validatesExclusionOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesExclusionOf method.">
	<cfscript>
		if (ListFindNoCase(arguments.list, this[arguments.property]))
		{
			addError(property=arguments.property, message=$validationErrorMessage(argumentCollection=arguments));
		}
	</cfscript>
</cffunction>

<cffunction name="$validatesFormatOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesFormatOf method.">
	<cfscript>
		if ((Len(arguments.regEx) && !REFindNoCase(arguments.regEx, this[arguments.property])) || (Len(arguments.type) && !IsValid(arguments.type, this[arguments.property])))
		{
			addError(property=arguments.property, message=$validationErrorMessage(argumentCollection=arguments));
		}
	</cfscript>
</cffunction>

<cffunction name="$validatesInclusionOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesInclusionOf method.">
	<cfscript>
		if (!ListFindNoCase(arguments.list, this[arguments.property]))
		{
			addError(property=arguments.property, message=$validationErrorMessage(argumentCollection=arguments));
		}
	</cfscript>
</cffunction>

<cffunction name="$validatesPresenceOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesPresenceOf method.">
	<cfargument name="property" type="string" required="true">
	<cfargument name="message" type="string" required="true">
	<cfargument name="properties" type="struct" required="false" default="#this.properties()#">
	<cfscript>
		// if the property does not exist or if it's blank we add an error on the object
		if (!StructKeyExists(arguments.properties, arguments.property) || (IsSimpleValue(arguments.properties[arguments.property]) && !Len(Trim(arguments.properties[arguments.property]))) || (IsStruct(arguments.properties[arguments.property]) && !StructCount(arguments.properties[arguments.property])))
		{
			addError(property=arguments.property, message=$validationErrorMessage(argumentCollection=arguments));
		}
	</cfscript>
</cffunction>

<cffunction name="$validatesLengthOf" returntype="void" access="public" output="false" hint="Adds an error if the object property fail to pass the validation setup in the @validatesLengthOf method.">
	<cfargument name="property" type="string" required="true">
	<cfargument name="message" type="string" required="true">
	<cfargument name="exactly" type="numeric" required="true">
	<cfargument name="maximum" type="numeric" required="true">
	<cfargument name="minimum" type="numeric" required="true">
	<cfargument name="within" type="any" required="true">
	<cfargument name="properties" type="struct" required="false" default="#this.properties()#">
	<cfscript>
		var loc = {};
		loc.lenValue = Len(arguments.properties[arguments.property]);

		// for within, just create minimum / maximum values
		if (IsArray(arguments.within) && ArrayLen(arguments.within) == 2)

		}

		// loop through all methods and properties and add info for each to the `class` struct
		local.iEnd = ListLen(arguments.methods);
		for (local.i=1; local.i <= local.iEnd; local.i++)
		{
			// only loop once by default (will be used on the lower level validation helpers that do not take arguments: validate, validateOnCreate and validateOnUpdate)
			local.jEnd = 1;
			if (StructKeyExists(arguments, "properties"))
			{
				local.jEnd = ListLen(arguments.properties);
			}

			for (local.j=1; local.j <= local.jEnd; local.j++)
			{
				local.validation = {};
				local.validation.method = Trim(ListGetAt(arguments.methods, local.i));
				local.validation.args = Duplicate(arguments);
				if (StructKeyExists(arguments, "properties"))
				{
					local.validation.args.property = Trim(ListGetAt(local.validation.args.properties, local.j));
				}
				StructDelete(local.validation.args, "when");
				StructDelete(local.validation.args, "methods");
				StructDelete(local.validation.args, "properties");
				ArrayAppend(variables.wheels.class.validations[arguments.when], local.validation);
			}
		}
	}

	public string function $validationErrorMessage(required string property, required string message) {
		local.rv = arguments.message;
		// evaluate the error message if it contains pound signs
		if (Find(Chr(35), local.rv))
		{
			// use a try / catch here since it will fail if a pound sign is used that's not in an expression
			try
			{
				local.rv = Evaluate(DE(local.rv));
			}
			catch (any e) {}
		}

		// loop through each argument and replace bracketed occurrence with argument value
		for (local.key in arguments)
		{
			local.key = LCase(local.key);
			local.value = arguments[local.key];
			if (StructKeyExists(local, "value") && IsSimpleValue(local.value) && Len(local.value))
			{
				if (local.key == "property")
				{
					local.value = this.$label(local.value);
				}
				local.rv = Replace(local.rv, "[[#local.key#]]", "{{#Chr(7)#}}", "all");
				local.rv = Replace(local.rv, "[#local.key#]", local.value, "all");
				local.rv = Replace(local.rv, "{{#Chr(7)#}}", "[#local.key#]", "all");
			}
		}
		return local.rv;
	}

	/**
    * Runs all the validation methods setup on the object and adds errors as it finds them. Returns `true` if no errors were added, `false` otherwise.
    */
	public boolean function $validate(required string type, boolean execute="true") {
		// don't run any validations when we want to skip
		if (!arguments.execute)
		{
