text: Ext.namespace('Zarafa.core.data');
  
  /**
   * @class Zarafa.core.data.RecordFactory
   * The factory class for creating objects of {@link Ext.data.Record record}
   * which are specialized for certain messageclasses (IPM.Note, IPM.Contact, etc).
   * The exact field definition of the different {@link Ext.data.Record records}
   * can be configured by {@link Zarafa.core.Context contexts} and {@link Zarafa.core.Plugin plugins}
   * to add new fields, but also to control the default values for particular fields.
   *
   * For fine-grained control over all classes, the factory also supports
   * {@link Ext.data.Record record} for sub messageclasses like (IPM.Note.NDR),
   * where the sub messageclass depends on its parent (IPM.Note.NDR inherits its fields, and
   * default values from IPM.Note).
   *
   * For plugins with custom types (no official MAPI ObjectType, or Message Class definition),
   * we have the {@link Zarafa.core.data.RecordCustomObjectType Custom Type} definitions to which
   * they can register their custom type, which can then be used to work together with
   * the record factory.
   *
   * @singleton
   */
  Zarafa.core.data.RecordFactory = {
  	/**
  	 * Key-value map of {@link Zarafa.core.data.RecordDefinition} as registered by
  	 * {@link #createRecordDefinition}. 
  	 *
  	 * @property
  	 * @type Object
  	 */
  	definitions : {},
  
  	/**
  	 * Obtain the parent messageclass for the given messageclass.
  	 * The hierarchy of the messageclass is based on the dot ('.')
  	 * character. Each dot indicates a step deeper into the hierarchy.
  	 * Thus if the messageclass is IPM.Note, the parent is IPM.
  	 *
  	 * @param {String} messageClass The messageclass for which
  	 * the parent is requested.
  	 * @return {String} The parent messageclass (undefined, if
  	 * the messageclass has no parent.
  	 * @private
  	 */
  	getMessageClassParent : function(messageClass)
  	{
  		var lastDot = messageClass.lastIndexOf('.');
  		if (lastDot > 0)
  			return messageClass.substr(0, lastDot);
  		return undefined;
  	},
  
  	/**
  	 * Obtain the parent {@link Zarafa.core.data.RecordDefinition RecordDefinition}
  	 * for this messageclass.
  	 * @param {String} The messageclass for the parent is searched for
  	 * @return {Zarafa.core.data.RecordDefinition} The parent record definition.
  	 * Undefined if the messageclass does not have a parent.
  	 */
  	getMessageClassParentDefinition : function(messageClass)
  	{
  		var messageClassParent = this.getMessageClassParent(messageClass);
  
  		if (Ext.isDefined(messageClassParent))
  			return this.getRecordDefinitionByMessageClass(messageClassParent);
  		return undefined;
  	},
  
  	/**
  	 * Create a new {@link Zarafa.core.data.RecordDefinition RecordDefinition}
  	 * for the given key value.
  	 *
  	 * @param {Mixed} key The key value on how the definition is stored
  	 * in the definitions table.
  	 * @param {Zarafa.core.data.RecordDefinition} parent The parent record
  	 * definition.
  	 * @param {Object} defaults The default values which must be applied to
  	 * the record definition.
  	 * @return {Zarafa.core.data.RecordDefinition} The new record definition.
  	 */
  	createRecordDefinition : function(key, parent, defaults)
  	{
  		var definition = new Zarafa.core.data.RecordDefinition({
  			base : undefined,
  			parent : parent,
  			createDefaults : defaults
  		});
  
  		this.definitions[key] = definition;
  		return definition;
  	},
  
  	/**
  	 * Obtain the {@link Zarafa.core.data.RecordDefinition RecordDefinition} object
  	 * which belongs to the given custom type. If the custom type is previously unknown
  	 * and the {@link Zarafa.core.data.RecordDefinition definition} does not exist,
  	 * a new {@link Zarafa.core.data.RecordDefinition definition} will be created and
  	 * returned.
  	 *
  	 * @param {Zarafa.core.data.RecordCustomObjectType} customType The custom type for which the definition is requested.
  	 * @return {Zarafa.core.data.RecordDefinition} The definition object for the custom type
  	 * @private
  	 */
  	getRecordDefinitionByCustomType : function(customType)
  	{
  		var definition = this.definitions[customType];
  		if (Ext.isDefined(definition))
  			return definition;
  
  		// Custom types don't have any hierarchy...
  		return this.createRecordDefinition(customType, undefined);
  	},
  
  	/**
  	 * Obtain the {@link Zarafa.core.data.RecordDefinition RecordDefinition} object
  	 * which belongs to the given object class. If the object type is previously unknown
  	 * and the {@link Zarafa.core.data.RecordDefinition definition} does not exist,
  	 * a new {@link Zarafa.core.data.RecordDefinition definition} will be created and
  	 * returned.
  	 *
  	 * @param {Zarafa.core.mapi.ObjectType} objectType The object type for which the definition is requested.
  	 * @return {Zarafa.core.data.RecordDefinition} The definition object for the object type
  	 * @private
  	 */
  	getRecordDefinitionByObjectType : function(objectType)
  	{
  		var definition = this.definitions[objectType];
  		if (Ext.isDefined(definition))
  			return definition;
  
  		// Object types don't have any hierarchy...
  		return this.createRecordDefinition(objectType, undefined, {'object_type' : objectType});
  	},
  
  	/**
  	 * Obtain the {@link Zarafa.core.data.RecordDefinition RecordDefinition} object
  	 * which belongs to the given messageclass. If the messageClass is previously unknown
  	 * and the {@link Zarafa.core.data.RecordDefinition definition} does not exist,
  	 * a new {@link Zarafa.core.data.RecordDefinition definition} will be created and
  	 * returned.
  	 *
  	 * @param {String} messageClass The messageclass for which the definition is requested.
  	 * @return {Zarafa.core.data.RecordDefinition} The definition object for the messageclass. 
  	 * @private
  	 */
  	getRecordDefinitionByMessageClass : function(messageClass)
  	{
  		var keyName = messageClass.toUpperCase();
  		var definition = this.definitions[keyName];
  		var parent = undefined;
  
  		if (Ext.isDefined(definition))
  			return definition;
  
  		parent = this.getMessageClassParentDefinition(keyName);
  		return this.createRecordDefinition(keyName, parent, {'message_class' : messageClass});
  	},
  
  	/**
  	 * Create a new {@link Ext.data.Record record} object based on the
  	 * definitions given for the custom type.
  	 *
  	 * @param {Zarafa.core.data.RecordCustomObjectType} customType The custom type for which
  	 * the record is created.
  	 * @param {Object} data (Optional) An object, the properties of which provide
  	 * values for the new Record's fields. If not specified the {@link Ext.data.Field.defaultValue}
  	 * for each field will be assigned.
  	 * @param {Object} id (Optional) The id of the Record. The id is used by the
  	 * {@link Ext.data.Store Store} object which owns the {@link Ext.data.Record}
  	 * to index its collection of Records (therefore this id should be unique within
  	 * each store). If an id is not specified a phantom Record will be created with an
  	 * automatically generated id.
  	 * @return {Ext.data.Record} The new record
  	 */
  	createRecordObjectByCustomType : function(customType, data, id)
  	{
  		var definition = this.getRecordDefinitionByCustomType(customType);
  		return definition.createRecord(data, id);
  	},
  
  	/**
  	 * Create a new {@link Ext.data.Record record} object based on the
  	 * definitions given for the object type.
  	 *
  	 * @param {Zarafa.core.mapi.ObjectType} objectType The object type for which
  	 * the record is created.
  	 * @param {Object} data (Optional) An object, the properties of which provide
  	 * values for the new Record's fields. If not specified the {@link Ext.data.Field.defaultValue}
  	 * for each field will be assigned.
  	 * @param {Object} id (Optional) The id of the Record. The id is used by the
  	 * {@link Ext.data.Store Store} object which owns the {@link Ext.data.Record}
  	 * to index its collection of Records (therefore this id should be unique within
  	 * each store). If an id is not specified a phantom Record will be created with an
  	 * automatically generated id.
  	 * @return {Ext.data.Record} The new record
  	 */
  	createRecordObjectByObjectType : function(objectType, data, id)
  	{
  		var definition = this.getRecordDefinitionByObjectType(objectType);
  		return definition.createRecord(data, id);
  	},
  
  	/**
  	 * Create a new {@link Ext.data.Record record} object based on the
  	 * definitions given for the messageclass.
  	 *
  	 * @param {String} messageClass The messageclass for which the record is created.
  	 * @param {Object} data (Optional) An object, the properties of which provide
  	 * values for the new Record's fields. If not specified the {@link Ext.data.Field.defaultValue}
  	 * for each field will be assigned.
  	 * @param {Object} id (Optional) The id of the Record. The id is used by the
  	 * {@link Ext.data.Store Store} object which owns the {@link Ext.data.Record}
  	 * to index its collection of Records (therefore this id should be unique within
  	 * each store). If an id is not specified a phantom Record will be created with an
  	 * automatically generated id.
  	 * @return {Ext.data.Record} The new record
  	 */
  	createRecordObjectByMessageClass : function(messageClass, data, id)
  	{
  		var definition = this.getRecordDefinitionByMessageClass(messageClass);
  		return definition.createRecord(data, id);
  	},
  
  	/**
  	 * Create a new {@link Ext.data.Record record} object based on the
  	 * definitions from the record data, this will determine if
  	 * the messageclass of object type has been provided. If neither has been provided
  	 * this function will return undefined.
  	 *
  	 * @param {Object} recordData The record data from which the record class must be detected
  	 * it slaos contains the properties of which provide values for the new Record's fields. 
  	 * @param {Object} id (Optional) The id of the Record. The id is used by the
  	 * {@link Ext.data.Store Store} object which owns the {@link Ext.data.Record}
  	 * to index its collection of Records (therefore this id should be unique within
  	 * each store). If an id is not specified a phantom Record will be created with an
  	 * automatically generated id.
  	 * @return {Class} The record class definition
  	 */
  	createRecordObjectByRecordData : function(recordData, id)
  	{
  		if (!Ext.isEmpty(recordData.message_class))
  			return this.createRecordObjectByMessageClass(recordData.message_class, recordData, id);
  		else if (!Ext.isEmpty(recordData.object_type))
  			return this.createRecordObjectByObjectType(recordData.object_type, recordData, id);
  		else
  			return undefined;
  	},
  
  	/**
  	 * Get the record class definition for this custom type
  	 * This class definition can be used to construct new {@link Ext.data.Record record}
  	 * objects which is completely tuned for the given object type.
  	 *
  	 * @param {Zarafa.core.data.RecordCustomObjectType} customType The object type for which the
  	 * record class is requested
  	 * @return {Class} The record class definition
  	 */
  	getRecordClassByCustomType : function(customType)
  	{
  		var definition = this.getRecordDefinitionByCustomType(customType);
  		return definition.getType();
  	},
  
  	/**
  	 * Get the record class definition for this object type
  	 * This class definition can be used to construct new {@link Ext.data.Record record}
  	 * objects which is completely tuned for the given object type.
  	 *
  	 * @param {Zarafa.core.mapi.ObjectType} objectType The object type for which the
  	 * record class is requested
  	 * @return {Class} The record class definition
  	 */
  	getRecordClassByObjectType : function(objectType)
  	{
  		var definition = this.getRecordDefinitionByObjectType(objectType);
  		return definition.getType();
  	},
  
  	/**
  	 * Get the record class definition for this messageclass
  	 * This class definition can be used to construct new {@link Ext.data.Record record}
  	 * objects which is completely tuned for the given messageclass.
  	 *
  	 * @param {String} messageClass The messageclass for which the record class is requested
  	 * @return {Class} The record class definition
  	 */
  	getRecordClassByMessageClass : function(messageClass)
  	{
  		var definition = this.getRecordDefinitionByMessageClass(messageClass);
  		return definition.getType();
  	},
  
  	/**
  	 * Get the record class definition for this record data, this will determine if
  	 * the messageclass of object type has been provided. If neither has been provided
  	 * this function will return undefined.
  	 * This class definition can be used to construct new {@link Ext.data.Record record}
  	 * objects which is completely tuned for the given messageclass.
  	 *
  	 * @param {Object} recordData The record data from which the record class must be detected
  	 * @return {Class} The record class definition
  	 */
  	getRecordClassByRecordData : function(recordData)
  	{
  		if (Ext.isDefined(recordData.message_class))
  			return this.getRecordClassByMessageClass(recordData.message_class);
  		else if (Ext.isDefined(recordData.object_type))
  			return this.getRecordClassByObjectType(recordData.object_type);
  		else
  			return undefined;
  	},
  
  	/**
  	 * This will set a new base class on the {@link Zarafa.core.data.RecordDefinition definition}.
  	 * The base class is used when creating a new record, by default the ExtJS
  	 * {@link Ext.data.Record record} will be used as base.
  	 *
  	 * @param {Zarafa.core.data.RecordCustomObjectType} customType The custom type for which
  	 * the new base class must be set.
  	 * @param {Class} baseClass The new base class to use
  	 */
  	setBaseClassToCustomType : function(customType, baseClass)
  	{
  		var definition = this.getRecordDefinitionByCustomType(customType);
  		definition.setBaseClass(baseClass);
  	},
  
  	/**
  	 * This will set a new base class on the {@link Zarafa.core.data.RecordDefinition definition}.
  	 * The base class is used when creating a new record, by default the ExtJS
  	 * {@link Ext.data.Record record} will be used as base.
  	 *
  	 * @param {Zarafa.core.mapi.ObjectType} objectType The object type for which
  	 * the new base class must be set.
  	 * @param {Class} baseClass The new base class to use
  	 */
  	setBaseClassToObjectType : function(objectType, baseClass)
  	{
  		var definition = this.getRecordDefinitionByObjectType(objectType);
  		definition.setBaseClass(baseClass);
  	},
  
  	/**
  	 * This will set a new base class on the {@link Zarafa.core.data.RecordDefinition definition}.
  	 * The base class is used when creating a new record, by default the ExtJS
  	 * {@link Ext.data.Record record} will be used as base.
  	 *
  	 * @param {String} messageClass The messageclass for which
  	 * the new base class must be set.
  	 * @param {Class} baseClass The new base class to use
  	 */
  	setBaseClassToMessageClass : function(messageClass, baseClass)
  	{
  		var definition = this.getRecordDefinitionByMessageClass(messageClass);
  		definition.setBaseClass(baseClass);
  	},
  
  	/**
  	 * This will set the SubStore type for a particular subStore name
  	 * in the {@link Zarafa.core.data.RecordDefinition definition}. Inside
  	 * a SubStore a Table can be loaded like Attachments, recipients, members, etc.
  	 *
  	 * @param {Zarafa.core.data.RecordCustomObjectType} customType The custom type for which the
  	 * SubStore type must be set
  	 * @param {String} name The name of the SubStore table
  	 * @param {Constructor} type The SubStore type
  	 */
  	setSubStoreToCustomType : function(customType, name, type)
  	{
  		var definition = this.getRecordDefinitionByCustomType(customType);
  		definition.setSubStore(name, type);
  	},
  
  	/**
  	 * This will set the SubStore type for a particular subStore name
  	 * in the {@link Zarafa.core.data.RecordDefinition definition}. Inside
  	 * a SubStore a Table can be loaded like Attachments, recipients, members, etc.
  	 *
  	 * @param {Zarafa.core.mapi.ObjectType} objectType The object type for which the
  	 * SubStore type must be set
  	 * @param {String} name The name of the SubStore table
  	 * @param {Constructor} type The SubStore type
  	 */
  	setSubStoreToObjectType : function(objectType, name, type)
  	{
  		var definition = this.getRecordDefinitionByObjectType(objectType);
  		definition.setSubStore(name, type);
  	},
  
  	/**
  	 * This will set the SubStore type for a particular subStore name
  	 * in the {@link Zarafa.core.data.RecordDefinition definition}. Inside
  	 * a SubStore a Table can be loaded like Attachments, recipients, members, etc.
  	 *
  	 * @param {String} messageClass The messageclass for which
  	 * @param {String} name The name of the SubStore table
  	 * @param {Constructor} type The SubStore type
  	 */
  	setSubStoreToMessageClass : function(messageClass, name, type)
  	{
  		var definition = this.getRecordDefinitionByMessageClass(messageClass);
  		definition.setSubStore(name, type);
  	},
  
  	/**
  	 * This will add a new {@link Ext.data.Field field} to the
  	 * {@link Zarafa.core.data.RecordDefinition definition}.
  	 *
  	 * @param {Zarafa.core.data.RecordCustomObjectType} customType The custom type to which the field
  	 * should be added.
  	 * @param {String/Ext.data.Field} field The field which must be added.
  	 */
  	addFieldToCustomType : function(customType, field)
  	{
  		var definition = this.getRecordDefinitionByCustomType(customType);
  		definition.addField(field);
  	},
  
  	/**
  	 * This will add a new {@link Ext.data.Field field} to the
  	 * {@link Zarafa.core.data.RecordDefinition definition}.
  	 *
  	 * @param {Zarafa.core.mapi.ObjectType} objectType The object type to which the field
  	 * should be added.
  	 * @param {String/Ext.data.Field} field The field which must be added.
  	 */
  	addFieldToObjectType : function(objectType, field)
  	{
  		var definition = this.getRecordDefinitionByObjectType(objectType);
  		definition.addField(field);
  	},
  
  	/**
  	 * This will add a new {@link Ext.data.Field field} to the
  	 * {@link Zarafa.core.data.RecordDefinition definition}.
  	 *
  	 * @param {String} messageClass The messageclass to which the field
  	 * should be added.
  	 * @param {String/Ext.data.Field} field The field which must be added.
  	 */
  	addFieldToMessageClass : function(messageClass, field)
  	{
  		var definition = this.getRecordDefinitionByMessageClass(messageClass);
  		definition.addField(field);
  	},
  
  	/**
  	 * This will add a default value for a {@link Ext.data.Field field}
  	 * to the {@link Zarafa.core.data.RecordDefinition definition}. When
  	 * creating a new local item
  	 * ({@link Zarafa.core.data.RecordFactory.createRecordObjectByCustomType createRecordObjectByCustomType}
  	 * with the phantom argument to true) the default values which be applied
  	 * to the newly created {@link Ext.data.Record record}.
  	 *
  	 * @param {Zarafa.core.data.RecordCustomObjectType} customType The custom type to which the field belongs
  	 * @param {String/Ext.data.Field} field The field for which the default
  	 * value should be applied
  	 * @param {Mixed} defaultValue the default value for the given fieldname
  	 */
  	addDefaultValueToCustomType : function(customType, field, defaultValue)
  	{
  		var definition = this.getRecordDefinitionByCustomType(customType);
  		definition.addDefaultValue(field, defaultValue);
  	},
  
  	/**
  	 * This will add a default value for a {@link Ext.data.Field field}
  	 * to the {@link Zarafa.core.data.RecordDefinition definition}. When
  	 * creating a new local item
  	 * ({@link Zarafa.core.data.RecordFactory.createRecordObjectByObjectType createRecordObjectByObjectType}
  	 * with the phantom argument to true) the default values which be applied
  	 * to the newly created {@link Ext.data.Record record}.
  	 *
  	 * @param {Zarafa.core.mapi.ObjectType} objectType The object type to which the field belongs
  	 * @param {String/Ext.data.Field} field The field for which the default
  	 * value should be applied
  	 * @param {Mixed} defaultValue the default value for the given fieldname
  	 */
  	addDefaultValueToObjectType : function(objectType, field, defaultValue)
  	{
  		var definition = this.getRecordDefinitionByObjectType(objectType);
  		definition.addDefaultValue(field, defaultValue);
  	},
  
  	/**
  	 * This will add a default value for a {@link Ext.data.Field field}
  	 * to the {@link Zarafa.core.data.RecordDefinition definition}. When
  	 * creating a new local item
  	 * ({@link Zarafa.core.data.RecordFactory.createRecordObjectByMessageClass createRecordObjectByMessageClass}
  	 * with the phantom argument to true) the default values which be applied
  	 * to the newly created {@link Ext.data.Record record}.
  	 *
  	 * @param {String} messageClass The messageclass to which the field belongs
  	 * @param {String/Ext.data.Field} field The field for which the default
  	 * value should be applied
  	 * @param {Mixed} defaultValue the default value for the given fieldname
  	 */
  	addDefaultValueToMessageClass : function(messageClass, field, defaultValue)
  	{
  		var definition = this.getRecordDefinitionByMessageClass(messageClass);
  		definition.addDefaultValue(field, defaultValue);
  	},
  
  	/**
  	 * Appends an event handler to the {@link Zarafa.core.data.RecordDefinition RecordDefinition}
  	 * for the given CustomType.
  	 * @param {Zarafa.core.data.RecordCustomObjectType} customType The custom type to which the event must be added
  	 * @param {String} eventName The name of the event to listen for
  	 * @param {Function} handler The method the event invokes
  	 * @param {Object} scope (optional) The scope (this reference) in which the handler function is executed.
  	 * If omitted, defaults to the object which fired the event.
  	 * @param {Object} options (optional) An object containing handler configuration properties.
  	 */
  	addListenerToCustomType : function(customType, eventName, handler, scope, options)
  	{
  		var definition = this.getRecordDefinitionByCustomType(customType);
  		definition.on(eventName, handler, scope, options);
  	},
  
  	/**
  	 * Appends an event handler to the {@link Zarafa.core.data.RecordDefinition RecordDefinition}
  	 * for the given ObjectType.
  	 * @param {Zarafa.core.mapi.ObjectType} objectType The object type to which the event must be added
  	 * @param {String} eventName The name of the event to listen for
  	 * @param {Function} handler The method the event invokes
  	 * @param {Object} scope (optional) The scope (this reference) in which the handler function is executed.
  	 * If omitted, defaults to the object which fired the event.
  	 * @param {Object} options (optional) An object containing handler configuration properties.
  	 */
  	addListenerToObjectType : function(objectType, eventName, handler, scope, options)
  	{
  		var definition = this.getRecordDefinitionByObjectType(objectType);
  		definition.on(eventName, handler, scope, options);
  	},
  
  	/**
  	 * Appends an event handler to the {@link Zarafa.core.data.RecordDefinition RecordDefinition}
  	 * for the given messageClass.
  	 * @param {String} messageClass The messageclass to which the event must be added
  	 * @param {String} eventName The name of the event to listen for
  	 * @param {Function} handler The method the event invokes
  	 * @param {Object} scope (optional) The scope (this reference) in which the handler function is executed.
  	 * If omitted, defaults to the object which fired the event.
  	 * @param {Object} options (optional) An object containing handler configuration properties.
  	 */
  	addListenerToMessageClass : function(messageClass, eventName, handler, scope, options)
  	{
  		var definition = this.getRecordDefinitionByMessageClass(messageClass);
  		definition.on(eventName, handler, scope, options);
  	}
  };
  