/*
---
script      : TransformDataAylott.js
author      : Thomas Aylott
site        : SubtleGradient.com
copyright   : Copyright (c) 2010 Thomas Aylott
license     : MIT-style license
...
*/


/*
---
provides    : Function.from
description : Lambda with mutable value
...
*/
if (typeof exports == 'undefined') var exports = this;


exports.Function.from = function(value){
	lambda.value = value;
	function lambda(){
		var value = lambda.value;
		if (typeof value == 'function')
			return value();
		return value;
	}
	return lambda;
};


/*
---
provides    : Function.transformable
description : Lambda with mutable data transformer
requires    : Function.from
...
*/
if (typeof exports == 'undefined') var exports = this;

exports.Function.transformable = function(value){
	transformableLambda.value = value;
	transformableLambda.transformer = function(value){return value};
	function transformableLambda(){
		return transformableLambda.transformer(Function.from(transformableLambda.value)());
	}
	transformableLambda.valueOf = transformableLambda;
	transformableLambda.setTransformer = function(transformer){
		transformableLambda.transformer = transformer;
		return transformableLambda;
	}
	return transformableLambda;
};


/*
---
provides    : Function.Xable
description : Lambda with multiple mutable data transformers
requires    : Function.from
...
*/
(function(exports){

var X = exports.Function.Xable = function(privateValue){
	xable.transformers = {
		value: function(value){return value}
	};
	var result = X.result;
	function xable(){
		var results = new result(privateValue);
		for (var transformerName in xable.transformers){
			results[transformerName] = xable.transformers[transformerName]( results[transformerName] || results.value, xable.results );
		}
		xable.results = results;
		return xable.results;
	}
	xable.defineTransformer = function(transformerName, transformer){
		xable.transformers[transformerName] = transformer;
		xable.setValue(privateValue);
		return xable;
	}
	xable.setTransformer = function(transformer){
		xable.transformers.value = transformer;
		return xable;
	}
	xable.setValue = function(newValue){
		privateValue = newValue;
		return xable;
	}
	xable.valueOf = function(){
		return xable().value;
	}
	return xable;
};

exports.Function.Xable.result = function(value){
	this.value = value;
	value = Function.from(value)();
	if (value instanceof X.result){
		for (var property in value){
			this[property] = value[property];
		}
	}
};

})(typeof exports != 'undefined' ? exports : this);


/*
---
provides    : Function.Xable.Observable
description : Lambda with multiple mutable data transformers. Implements Events. Fires "change" when the value changes
requires    : 
- Function.Xable
# MooTools
- core/1.2:Function
- core/1.2:Events
...
*/
(function(exports, X, Events){
var UID = 0;
exports.Function.Xable.Observable = function(original_value){
	var Observable = X(original_value);
	var uid = Observable.uid = UID++;
	Observable.extend(new Events);
	var old_setValue = Observable.setValue;
	var oldValues = Observable();
	var setValue_delay;
	var newValue;
	
	function setValue(){
		if (Observable.setting){
			clearTimeout(setValue_delay);
			return;
			// setValue_delay = setTimeout(setValue,20);
		}
		try {
			Observable.setting = true;
			var newValues = old_setValue(newValue)();
			for (var key in newValues){
				if (newValues[key] !== oldValues[key]){
					Observable.fireEvent('change' + (key == 'value' ? '' : ':'+key), [newValues[key], key, newValues]);
				}
			}
		} catch(e){
			throw e;
		} finally {
			Observable.setting = false;
			oldValues = newValues;
		}
	};
	
	Observable.setValue = function(value){
		clearTimeout(setValue_delay);
		newValue = value;
		setValue();
		// setValue_delay = setTimeout(setValue,20);
		return Observable;
	}
	return Observable;
};

})(
	typeof exports != 'undefined' ? exports : this,
	exports.Function.Xable,
	Events
);


