 CounterKey = "_ObjectCounter"
 DefinedPropertiesKey = "_DefinedPropertiesKey"
 DefinedPropertiesValuesKey = "_DefinedPropertiesValuesKey"
+DefinedPropertiesOrderKey = "_DefinedPropertiesOrderKey"
 
 capitalizeFirstLetter = (string) ->
 	string.charAt(0).toUpperCase() + string.slice(1)

		# Create a holder for the property values
		@[DefinedPropertiesValuesKey] = {}

		# Count the creation for these objects and set the id
		@constructor[CounterKey] ?= 0
		@constructor[CounterKey] += 1

		@_id = @constructor[CounterKey]

		@_applyOptionsAndDefaults(options)

	_applyOptionsAndDefaults: (options) ->
		for key, descriptor of @_propertyList()
			# For each known property (registered with @define) that has a setter, fetch
			# the value from the options object, unless the prop is not importable.
			# When there's no user value, apply the default value:
			if descriptor.set
				value = Utils.valueOrDefault(
					(options?[key] if descriptor.importable),
					@_getPropertyDefaultValue(key)
				)

				if not (value in [null, undefined])
					@[key] = value

			@::[setName] = descriptor.set
			descriptor.set = @::[setName]

		# Better readonly errors for debugging

		# else
		# 	descriptor.set = (value) -> 
		# 		throw Error("#{@constructor.name}.#{propertyName} is readonly")

		# Define the property
		Object.defineProperty(@prototype, propertyName, descriptor)

	@_addDescriptor: (propertyName, descriptor) ->

		# for key in ["enumerable", "exportable", "importable"]
		# 	if descriptor.hasOwnProperty(key)
		# 		throw Error("woops #{propertyName} #{descriptor[key]}") if not _.isBoolean(descriptor[key])

		descriptor.propertyName = propertyName

		# Have the following flags set to true when undefined:
		descriptor.enumerable ?= true
		descriptor.exportable ?= true
		descriptor.importable ?= true

		# We assume we don't import if there is no setter, because we can't
		descriptor.importable = descriptor.importable and descriptor.set
		# We also assume we don't export if there is no setter, because 
		# it is likely a calculated property, and we can't set it.
		descriptor.exportable = descriptor.exportable and descriptor.set

		# We assume that every property with an underscore is private
		return if _.startsWith(propertyName, "_")

		# Only retain options that are importable, exportable or both:
		if descriptor.exportable or descriptor.importable
			@[DefinedPropertiesKey] ?= {}
			@[DefinedPropertiesKey][propertyName] = descriptor

			# Set the order, insert it's dependants before, we'll check if they exist later
			@[DefinedPropertiesOrderKey] ?= []

			if descriptor.depends
				for depend in descriptor.depends
					if depend not in @[DefinedPropertiesOrderKey]
						@[DefinedPropertiesOrderKey].push(depend)
			
			@[DefinedPropertiesOrderKey].push(propertyName)

	@simpleProperty = (name, fallback, options={}) ->
		return _.extend options,
