keyType now derived from first variable if not given in metadata session state.

--- WeaveData/src/weave/data/AttributeColumns/EquationColumn.as
+++ WeaveData/src/weave/data/AttributeColumns/EquationColumn.as
@@ -44,6 +44,7 @@
 	import weave.utils.ColumnUtils;
 	import weave.utils.Dictionary2D;
 	import weave.utils.EquationColumnLib;
+	import weave.utils.VectorUtils;

 	/**
 	 * This is a column of data derived from an equation with variables.
@@ -177,10 +178,13 @@
 					}
 				}
 			}
-			else
-			{
-				value = super.getMetadata(propertyName);
-			}
+			else if (propertyName == ColumnMetadata.KEY_TYPE)
+			{
+				var cols:Array = variables.getObjects(IAttributeColumn);
+				if (cols.length)
+					value = (cols[0] as IAttributeColumn).getMetadata(propertyName);
+			}
+
 			_cachedMetadata[propertyName] = value;
 			return value;
 		}
@@ -193,7 +197,17 @@
 				_lastError = str;
 				reportError(e);
 			}
-		}
+		}
+
+		override public function setMetadata(value:Object):void
+		{
+			metadata.setSessionState(value);
+		}
+
+		override public function getMetadataPropertyNames():Array
+		{
+			return VectorUtils.getKeys(metadata.getSessionState());
+		}

 		/**
 		 * This function will store an individual metadata value in the metadata linkable variable.


Added support for string metadata field for defining a
deriveStringFromNumber function.
Fixed bugs with dataType metadata support.

Change-Id: I4582010799d0d262cbfc42dcce375eba50e00e93

--- WeaveData/src/weave/data/AttributeColumns/EquationColumn.as
+++ WeaveData/src/weave/data/AttributeColumns/EquationColumn.as
@@ -28,7 +28,9 @@
 	import weave.api.data.ColumnMetadata;
 	import weave.api.data.DataTypes;
 	import weave.api.data.IAttributeColumn;
+	import weave.api.data.IPrimitiveColumn;
 	import weave.api.data.IQualifiedKey;
+	import weave.api.detectLinkableObjectChange;
 	import weave.api.getCallbackCollection;
 	import weave.api.newLinkableChild;
 	import weave.api.reportError;
@@ -50,7 +52,7 @@
 	 *
 	 * @author adufilie
 	 */
-	public class EquationColumn extends AbstractAttributeColumn
+	public class EquationColumn extends AbstractAttributeColumn implements IPrimitiveColumn
 	{
 		public static var debug:Boolean = false;

@@ -149,7 +151,7 @@
 		 * This holds the metadata for the column.
 		 */
 		public const metadata:UntypedLinkableVariable = newLinkableChild(this, UntypedLinkableVariable);
-
+
 		/**
 		 * This function intercepts requests for dataType and title metadata and uses the corresponding linkable variables.
 		 * @param propertyName A metadata property name.
@@ -216,7 +218,7 @@
 		/**
 		 * This function gets called when dataType changes and sets _defaultDataType.
 		 */
-		private function handleDataTypeChange():void
+		private function cacheDefaultDataType():void
 		{
 			var _dataType:String = getMetadata(ColumnMetadata.DATA_TYPE);
 			if (ObjectUtil.stringCompare(_dataType, DataTypes.GEOMETRY, true) == 0) // treat values as geometries
@@ -297,6 +299,50 @@
 				|| LinkableFunction.macros.getObject(name) != null;
 		}

+		private function handleChange():void
+		{
+			_cacheTriggerCount = triggerCounter;
+			try
+			{
+				// check if the equation evaluates to a constant
+				var compiledObject:ICompiledObject = compiler.compileToObject(equation.value);
+				if (compiledObject is CompiledConstant)
+				{
+					// save the constant result of the function
+					_equationIsConstant = true;
+					_equationResultCache.dictionary = null; // we don't need a cache
+					_constantResult = (compiledObject as CompiledConstant).value;
+				}
+				else
+				{
+					// compile into a function
+					compiledEquation = compiler.compileObjectToFunction(compiledObject, _symbolTableProxy, errorHandler, false, ['key', 'dataType']);
+					_equationIsConstant = false;
+					_equationResultCache.dictionary = new Dictionary(); // create a new cache
+					_constantResult = undefined;
+				}
+			}
+			catch (e:Error)
+			{
+				// if compiling fails
+				_equationIsConstant = true;
+				_constantResult = undefined;
+			}
+			cacheDefaultDataType();
+
+			try
+			{
+				_numberToStringFunction = StandardLib.formatNumber;
+				var n2s:String = getMetadata(ColumnMetadata.STRING);
+				if (n2s)
+					_numberToStringFunction = compiler.compileToFunction(n2s, _symbolTableProxy, errorHandler, false, ['number']);
+			}
+			catch (e:*)
+			{
+				errorHandler(e);
+			}
+		}
+
 		/**
 		 * @return The result of the compiled equation evaluated at the given record key.
 		 * @see weave.api.data.IAttributeColumn
@@ -304,36 +350,12 @@
 		override public function getValueFromKey(key:IQualifiedKey, dataType:Class = null):*
 		{
 			// reset cached values if necessary
-			if (_cacheTriggerCount != triggerCounter)
-			{
-				_cacheTriggerCount = triggerCounter;
-				try
-				{
-					// check if the equation evaluates to a constant
-					var compiledObject:ICompiledObject = compiler.compileToObject(equation.value);
-					if (compiledObject is CompiledConstant)
-					{
-						// save the constant result of the function
-						_equationIsConstant = true;
-						_equationResultCache.dictionary = null; // we don't need a cache
-						_constantResult = (compiledObject as CompiledConstant).value;
-					}
-					else
-					{
-						// compile into a function
-						compiledEquation = compiler.compileObjectToFunction(compiledObject, _symbolTableProxy, errorHandler, false, ['key', 'dataType']);
-						_equationIsConstant = false;
-						_equationResultCache.dictionary = new Dictionary(); // create a new cache
-						_constantResult = undefined;
-					}
-				}
-				catch (e:Error)
-				{
-					// if compiling fails
-					_equationIsConstant = true;
-					_constantResult = undefined;
-				}
-			}
+			if (_cacheTriggerCount != triggerCounter)
+				handleChange();
+
+			// if dataType not specified, use default type specified in metadata
+			if (dataType == null)
+				dataType = _defaultDataType;

 			var value:* = _constantResult;
 			if (!_equationIsConstant)
@@ -352,31 +374,30 @@
 					{
 						value = compiledEquation.apply(this, arguments);
 						if (debug)
-							trace(this,key.localName,dataType,value);
+							trace(debugId(this),getMetadata(ColumnMetadata.TITLE),key.keyType,key.localName,dataType,value);
 					}
 					catch (e:Error)
 					{
 						if (_lastError != e.message)
-						{
+						{
 							_lastError = e.message;
 							reportError(e);
 						}
 						//value = e;
 					}
-
+
 					// save value in cache
-					_equationResultCache.set(key, dataType, value);
-					//trace('('+equation.value+')@"'+key+'" = '+value);
+					if (value !== undefined)
+						_equationResultCache.set(key, dataType, value);
+					//trace('('+equation.value+')@"'+key+'" = '+value);
 				}
 				else if (value === UNDEFINED)
 				{
 					value = undefined;
 				}
+				else if (debug)
+					trace('>',debugId(this),getMetadata(ColumnMetadata.TITLE),key.keyType,key.localName,dataType,value);
 			}
-
-			// if dataType not specified, use default type specified by this.dataType.value
-			if (dataType == null)
-				dataType = _defaultDataType;

 			if (dataType == IQualifiedKey)
 			{
@@ -386,13 +407,37 @@
 						value = StandardLib.asString(value);
 					value = WeaveAPI.QKeyManager.getQKey(getMetadata(ColumnMetadata.DATA_TYPE), value);
 				}
-			}
-			else if (dataType != null)
-			{
-				value = EquationColumnLib.cast(value, dataType);
-			}
-
+			}
+			else if (dataType != null)
+			{
+				value = EquationColumnLib.cast(value, dataType);
+			}
+
 			return value;
+		}
+
+		private var _numberToStringFunction:Function = null;
+		public function deriveStringFromNumber(number:Number):String
+		{
+			// reset cached values if necessary
+			if (_cacheTriggerCount != triggerCounter)
+				handleChange();
+
+			if (_numberToStringFunction != null)
+			{
+				try
+				{
+					var string:String = _numberToStringFunction.apply(this, arguments);
+					if (debug)
+						trace(debugId(this),getMetadata(ColumnMetadata.TITLE),'deriveStringFromNumber',number,string);
+					return string;
+				}
+				catch (e:Error)
+				{
+					errorHandler(e);
+				}
+			}
+			return '';
 		}

 		override public function toString():String