Ext.namespace('Zarafa.core.data');

/**
 * @class Zarafa.core.data.ListModuleStore
 * @extends Zarafa.core.data.IPMStore
 * @xtype zarafa.listmodulestore
 *
 * A store that communicates with a list module on the php side. It supports listing items,
 * pagination, etc.
 * <p>
 * Pagination is not properly supported since there is no way to pass the desired page size
 * to the server side. Therefore the page size has to be hard-coded to 50 items.
 */
Zarafa.core.data.ListModuleStore = Ext.extend(Zarafa.core.data.IPMStore, {
	/**
	 * Read-only. boolean to indicate store contains results of search.
	 * @property
	 * @type Boolean
	 */
	hasSearchResults  : false,

	/**
	 * used in search to indicate that we should use search folder or not.
	 * without search folder we can search by applying restriction to 'list' action.
	 * @property
	 * @type Boolean
	 */
	useSearchFolder : false,

	/**
	 * @cfg {String} actionType type of action that should be used to send request to server,
	 * valid action types are defined in {@link Zarafa.core.Actions Actions}, default value is 'list'.
	 */
	actionType : undefined,

	/**
	 * @cfg {Boolean} subfolders specifies subfolders should be included in search or not.
	 */
	subfolders : false,

	/**
	 * @cfg {HexString} entryId entry id of the folder.
	 */
	entryId : undefined,

	/**
	 * @cfg {HexString} storeEntryId entry id of store.
	 */
	storeEntryId : undefined,

	/**
	 * @cfg {Zarafa.hierarchy.data.MAPIFolderRecord} folder instead of passing entryId and storeEntryId,
	 * we can pass folder also from which this store will load data.
	 */
	folder : undefined,

	/**
	 * used in synchronizing {@link Zarafa.core.data.ListModuleStore store} which indicate true after deleting {@link Zarafa.core.data.IPMRecords[] records}
	 * from {@link Zarafa.core.data.ListModuleStore store}.
	 * @property
	 * @type Boolean
	 */
	syncStore : false,

	/**
	 * @cfg {Number} which is hold number of records loaded in {@link Zarafa.core.data.ListModuleStore store}
	 */
	totalLoadedRecord : undefined,

	/**
	 * The LoadMask object which will be shown when the {@link Zarafa.core.data.ListModuleStore store}
	 * is being delete records, and the dialog is waiting for the server to respond with the desired data.
	 * @property
	 * @type Zarafa.common.ui.LoadMask
	 */
	loadMask : undefined,

	/**
	 * @cfg {String} preferredMessageClass message class that will be used to derive module name
	 * that should be used when requesting data using {@link Zarafa.core.data.IPMProxy IPMProxy).
	 */
	preferredMessageClass : 'IPM.Note',

	/**
	 * @cfg {Object} defaultSortInfo When no sorting is explicitely provided by the user.
	 * See {@link #sortInfo}.
	 */
	defaultSortInfo : undefined,

	/**
	 * Timer function that will be used to update search results after specified interval.
	 * this property should be cleared when {#stopSearch} has been called so it will cancel further
	 * requests for updating search results.
	 * @property
	 * @type Function
	 */
	searchUpdateTimer : undefined,

	/**
	 * @constructor
	 * @param config Configuration structure
	 */
	constructor : function(config)
	{
		config = config || {};

		config.restriction = {};

		config.preferredMessageClass = config.preferredMessageClass || this.preferredMessageClass;

		// Get the desired module, if the module is not set, check if the preferredMessageClass came
		// from the config object, if so, we should retry to get the module based on this.preferredMessageClass.
		var module = Zarafa.core.ModuleNames.getModule(config.preferredMessageClass, true);
		if (Ext.isEmpty(module) && (config.preferredMessageClass != this.preferredMessageClass)) {
			module = Zarafa.core.ModuleNames.getModule(this.preferredMessageClass, true);
		}

		// Default recordtype
		// This will be the basic recordtype for the store, Store will support those fields
		// which are bind with the record type and allow sorting on those fields.
		var recordType = Zarafa.core.data.RecordFactory.getRecordClassByMessageClass(config.preferredMessageClass);

		// Apply default settings.
		Ext.applyIf(config, {
			remoteSort : true,

			actionType : Zarafa.core.Actions['list'],

			// default writer.
			writer : new Zarafa.core.data.JsonWriter(),

			// default reader
			reader : new Zarafa.core.data.JsonReader({}, recordType),

			// default proxy
			proxy : new Zarafa.core.data.IPMProxy({
				listModuleName : module.list,
				itemModuleName : module.item
			})
		});

		this.addEvents(
			/**
			 * @event search
			 * Fires when a search request has been issued to store and store starts search.
			 * @param {Zarafa.core.data.ListModuleStore} store store that started search.
			 * @param {Object} options options object that is passed to {@link #load} event.
			 */
			'search',
			/**
			 * @event beforeupdatesearch
			 * Fires updated status of search process is received from server. This event will be fired whenever
			 * updated status of search is received despite of search has finished or not. so this can be used to
			 * check search has been finished or not.
			 * @param {Zarafa.core.data.ListModuleStore} store store that started search.
			 * @param {Object} searchResponse object that is received as updated search status.
			 */
			'beforeupdatesearch',
			/**
			 * @event updatesearch
			 * Fires when server sends status of the search in the 'search' response. This event will
			 * be fired when {@link Zarafa.core.data.ListModuleStore store} needs to send an 'updatesearch'
			 * to get status of the search when search is still not finished.
			 * @param {Zarafa.core.data.ListModuleStore} store store that started search.
			 * @param {Object} options options object that is passed to {@link #load} event.
			 */
			'updatesearch',
			/**
			 * @event stopsearch
			 * Fires when a stop search request is issued.
			 * @param {Zarafa.core.data.ListModuleStore} store store that started search.
			 * @param {Object} options options object that is passed to {@link #load} event.
			 */
			'stopsearch'
		);

		this.totalLoadedRecord = container.getSettingsModel().get('zarafa/v1/main/page_size');

		Zarafa.core.data.ListModuleStore.superclass.constructor.call(this, config);

		if(!Ext.isEmpty(this.folder)) {
			// If a folder was provided in the config, we apply the folder
			this.setFolder(this.folder);
		}
	},

	/**
	 * Compare a {@link Ext.data.Record#id ids} to determine if they are equal.
	 * This will apply the {@link Zarafa.core.EntryId#compareEntryIds compareEntryIds} function
	 * on both ids, as all records in this store will have a EntryId as unique key.
	 * @param {String} a The first id to compare
	 * @param {String} b The second id to compare
	 * @protected
	 */
	idComparison : function(a, b)
	{
		return Zarafa.core.EntryId.compareEntryIds(a, b);
	},

	/**
	 * Function will set action type.
	 * @param {String} actionType action type that will be used for sending request to server,
	 * valid values are defined in {@link Zarafa.core.Actions Actions}.
	 */
	setActionType : function(actionType)
	{
		this.actionType = actionType;
	},

	/**
	 * Function will set folder entryid and store entryid.
	 * @param {Zarafa.hierarchy.data.MAPIFolderRecord[]} mapiFolder mapi folder that should be used to load data.
	 */
	setFolder : function(mapiFolder)
	{
		Ext.each(mapiFolder, function(folder, index) {
			this.setEntryId(folder.get('entryid'), index !== 0);
			this.setStoreEntryId(folder.get('store_entryid'), index !== 0);
		}, this);
	},

	/**
	 * Function will set folder entryid.
	 * @param {HexString} entryId entry id of mapi folder.
	 * @param {Boolean} add append entryids instead of overwriting it.
	 */
	setEntryId : function(entryId, add)
	{
		if(!Ext.isEmpty(add) && add) {
			// multiple entryids
			if(Ext.isEmpty(this.entryId)) {
				this.entryId = [];
			}

			if(!Ext.isEmpty(this.entryId) && !Array.isArray(this.entryId)) {
				this.entryId = [ this.entryId ];
			}

			this.entryId.push(entryId);
		} else {
			// single entryid
			this.entryId = entryId;
		}
	},

	/**
	 * Function will get the folder entryid
	 * @return {HexString[]} The entryid/entryids of the mapi folder.
	 */
	getEntryId : function()
	{
		return this.entryId;
	},

	/**
	 * Function will set entryid of mapi store.
	 * @param {HexString} storeEntryId entry id of mapi store.
 	 * @param {Boolean} add append store entryids instead of overwriting it.
	 */
	setStoreEntryId : function(storeEntryId, add)
	{
		if(!Ext.isEmpty(add) && add) {
			// multiple entryids
			if(Ext.isEmpty(this.storeEntryId)) {
				this.storeEntryId = [];
			}

			if(!Ext.isEmpty(this.storeEntryId) && !Array.isArray(this.storeEntryId)) {
				this.storeEntryId = [ this.storeEntryId ];
			}

			this.storeEntryId.push(storeEntryId);
		} else {
			// single store entryid
			this.storeEntryId = storeEntryId;
		}
	},

	/**
	 * Function will get the entryid of mapi store.
	 * @return {HexString} The entryid of the mapi store
	 */
	getStoreEntryId : function()
	{
		return this.storeEntryId;
	},

	/**
	 * Function will set restriction that should be used in consecutive requests.
	 * @param {Object} restriction restriction object that will contain paging info.
	 */
	setRestriction : function(restriction)
	{
		this.restriction = restriction;
	},

	/**
	 * Function will set restriction to use in searching.
	 * @param {Object} searchRestriction restriction for search.
	 */
	setSearchRestriction : function(searchRestriction)
	{
		if(!Ext.isEmpty(searchRestriction)) {
			this.restriction = Ext.apply(this.restriction || {}, {
				search : searchRestriction
			});
		} else {
			// remove blank search restriction
			delete this.restriction.search;
		}
	},

	/**
	 * Function will set boolean to use subfolders in search or not.
	 * @param {Boolean} subfolders true if subfolders should be used else false.
	 */
	setSubfolders : function(subfolders)
	{
		this.subfolders = subfolders;
	},

	/**
	 * Function will set boolean to use search folders or not.
	 * @param {Boolean} useSearchFolder true if search folder should be used else false.
	 */
	setUseSearchFolder : function(useSearchFolder)
	{
		this.useSearchFolder = useSearchFolder;
	},

	/**
	 * <p>Loads the Record cache from the configured <tt>{@link #proxy}</tt> using the configured <tt>{@link #reader}</tt>.</p>
	 * <br><p>Notes:</p><div class="mdetail-params"><ul>
	 * <li><b><u>Important</u></b>: loading is asynchronous! This call will return before the new data has been
	 * loaded. To perform any post-processing where information from the load call is required, specify
	 * the <tt>callback</tt> function to be called, or use a {@link Ext.util.Observable#listeners a 'load' event handler}.</li>
	 * <li>If using {@link Ext.PagingToolbar remote paging}, the first load call must specify the <tt>start</tt> and <tt>limit</tt>
	 * properties in the <code>options.params</code> property to establish the initial position within the
	 * dataset, and the number of Records to cache on each read from the Proxy.</li>
	 * <li>If using {@link #remoteSort remote sorting}, the configured <code>{@link #sortInfo}</code>
	 * will be automatically included with the posted parameters according to the specified
	 * <code>{@link #paramNames}</code>.</li>
	 * </ul></div>
	 * @param {Object} options An object containing properties which control loading options:<ul>
	 * <li><b><tt>params</tt></b> :Object<div class="sub-desc"><p>An object containing properties to pass as HTTP
	 * parameters to a remote data source. <b>Note</b>: <code>params</code> will override any
	 * <code>{@link #baseParams}</code> of the same name.</p>
	 * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p></div></li>
	 * <li><b>callback</b> : Function<div class="sub-desc"><p>A function to be called after the Records
	 * have been loaded. The callback is called after the load event is fired, and is passed the following arguments:<ul>
	 * <li>r : Ext.data.Record[] An Array of Records loaded.</li>
	 * <li>options : Options object from the load call.</li>
	 * <li>success : Boolean success indicator.</li></ul></p></div></li>
	 * <li><b>scope</b> : Object<div class="sub-desc"><p>Scope with which to call the callback (defaults
	 * to the Store object)</p></div></li>
	 * <li><b>add</b> : Boolean<div class="sub-desc"><p>Indicator to append loaded records rather than
	 * replace the current cache.  <b>Note</b>: see note for <tt>{@link #loadData}</tt></p></div></li>
	 * </ul>
	 * @return {Boolean} If the <i>developer</i> provided <tt>{@link #beforeload}</tt> event handler returns
	 * <tt>false</tt>, the load call will abort and will return <tt>false</tt>; otherwise will return <tt>true</tt>.
	 */
	load : function(options)
	{
		if (!Ext.isObject(options)) {
			options = {};
		}

		if (!Ext.isObject(options.params)) {
			options.params = {};
		}

		// By default 'load' must cancel the previous request.
		if (!Ext.isDefined(options.cancelPreviousRequest)) {
			options.cancelPreviousRequest = true;
		}

		// If we are searching, don't update the active entryid
		if (!this.hasSearchResults ) {
			if(!Ext.isEmpty(options.folder)) {
				// If a folder was provided in the options, we apply the folder
				this.setFolder(options.folder);
			} else if(Ext.isDefined(options.params.entryid) && Ext.isDefined(options.params.store_entryid)){
				// If the entryid was provided in the parameters we apply the params
				this.setEntryId(options.params.entryid, false);
				this.setStoreEntryId(options.params.store_entryid, false);
			}
		}

		// Override the given entryid and store entryid.
		Ext.apply(options.params, {
			entryid : this.entryId,
			search_folder_entryid : this.searchFolderEntryId,
			store_entryid : this.storeEntryId
		});

		/*
		 * these options can be passed in arguments, or it can be set by setter methods of
		 * {@link Zarafa.core.data.ListModuleStore ListModuleStore}, like {@link #setRestriction}
		 * and {@link #setActionType}, advantage of using setter methods would be that
		 * all consecutive requestswill use that options if its not passed in arguments.
		 * but load method doesn't store these options automatically (like in case of entryids), so
		 * you have to call setter methods to actually set these options.
		 */
		Ext.applyIf(options, {
			actionType : this.actionType
		});

		Ext.applyIf(options.params, {
			restriction : this.restriction
		});

		// Apply the search restriction only when search is performed, remove otherwise, if any
		if(this.restriction.search) {
			if(!this.isAdvanceSearchStore()) {
				delete options.params.restriction.search;
			} else {
				options.params.restriction = Ext.apply(options.params.restriction || {}, {
					search : this.restriction.search
				});
			}
		}

		// search specific parameters
		if (options.actionType == Zarafa.core.Actions['search']) {
			/*
			 * below parameters are required for search so if its not passed in arguments
			 * then we have to add its default values
			 */
			Ext.applyIf(options.params, {
				use_searchfolder : this.useSearchFolder,
				subfolders : this.subfolders,
				forceCreateSearchFolder : options.forceCreateSearchFolder
			});
		}

		/**
		 * We don't required search restriction while navigate using page navigation tool bar in search result grid.
 		 */
		if(options.actionType == Zarafa.core.Actions['list'] && Array.isArray(options.params.restriction.search) && Ext.isDefined(options.params.search_folder_entryid)) {
			delete options.params.restriction.search;
		}

		// remove options that are not needed, although sending it doesn't hurt
		if (options.actionType == Zarafa.core.Actions['updatesearch'] ||
			options.actionType == Zarafa.core.Actions['stopsearch']) {
				delete options.params.restriction;
		}

		// remove search restriction when we already have a search folder entryid, otherwise the Operation::getTable() function
		// will restrict the search folder which removes some search results.
		if (options.actionType == Zarafa.core.Actions['list'] && Array.isArray(options.params.restriction.search) && Ext.isDefined(this.searchFolderEntryId) && this.useSearchFolder) {
			delete options.params.restriction.search;
		}

		return Zarafa.core.data.ListModuleStore.superclass.load.call(this, options);
	},

	/**
	 * <p>Reloads the Record cache from the configured Proxy using the configured
	 * {@link Ext.data.Reader Reader} and the options from the last load operation
	 * performed.</p>
	 * <p><b>Note</b>: see the Important note in {@link #load}.</p>
	 * @param {Object} options <p>(optional) An <tt>Object</tt> containing
	 * {@link #load loading options} which may override the {@link #lastOptions options}
	 * used in the last {@link #load} operation. See {@link #load} for details
	 * (defaults to <tt>null</tt>, in which case the {@link #lastOptions} are
	 * used).</p>
	 * <br><p>To add new params to the existing params:</p><pre><code>
lastOptions = myStore.lastOptions;
Ext.apply(lastOptions.params, {
    myNewParam: true
});
myStore.reload(lastOptions);
	 * </code></pre>
	 */
	reload : function(options)
	{
		if (this.hasSearchResults ) {
			// The superclass for reload will apply this.lastOptions,
			// but for updateSearch we have to do that here manually.
			this.updateSearch(Ext.applyIf(options||{}, this.lastOptions));
		} else {
			Zarafa.core.data.ListModuleStore.superclass.reload.apply(this, arguments);
		}
	},

	/**
	 * Helper function to detect if {@link #this} is the {@link Zarafa.advancesearch.AdvanceSearchStore AdvanceSearchStore} or not.
	 * @return {Boolean} True if this is refered to an instance of {@link Zarafa.advancesearch.AdvanceSearchStore AdvanceSearchStore}, false otherwise.
	 */
	isAdvanceSearchStore : function()
	{
		return this.preferredMessageClass === "IPM.Search";
	},

	/**
	 * Function will be used to issue a update list request to server to retrieve next batch of records,
	 * this will internally call {@link #load} method but with some different options.
	 * @param {Object} options options object that must contain restriction to apply for live scroll.
	 */
	liveScroll : function(options)
	{
		if (!Ext.isObject(options)) {
			options = {};
		}

		if (!Ext.isObject(options.params)) {
			options.params = {};
		}

		// cancel pending load request when live scroll is started.
		if (this.isExecuting('list')) {
			this.proxy.cancelRequests('list');
		}

		Ext.apply(options, {
			actionType : Zarafa.core.Actions['updatelist']
		});

		/*
		 * If the search was done using a search folder, we do not need to apply a restriction and
		 * therefore remove the search restriction. Otherwise this would cause an restriction on the
		 * search folder itself.
		 */
		if (Ext.isDefined(this.searchFolderEntryId) && this.useSearchFolder) {
			delete this.restriction.search;
		}

		this.load(options);
	},

	/**
	 * Function will be used to reset the {@Ext.data.store#lastOptions}.
	 */
	stopLiveScroll : function()
	{
		var restriction = this.lastOptions.params.restriction;

		// cancel all pending updatelist request
		if (this.isExecuting('updatelist')) {
			this.proxy.cancelRequests('updatelist');
		}

		// reset the action type in the last options, because
		// consecutive requests should use list action type
		Ext.apply(this.lastOptions, {
			actionType : Zarafa.core.Actions['list']
		});

		Ext.apply(restriction, {
			start : 0
		});

		if(Ext.isDefined(restriction)){
			delete restriction.limit;
		}
		delete this.lastOptions.add;
	},

	/**
	 * Function will be used to issue a search request to server to start searching,
	 * this will internally call {@link #load} method but with some different options.
	 * @param {Object} options options object that must contain restriction to apply for search.
	 */
	search : function(options)
	{
		if (!Ext.isObject(options)) {
			options = {};
		}

		if (!Ext.isObject(options.params)) {
			options.params = {};
		}

		// can't continue without a restriction
		if (Ext.isEmpty(options.searchRestriction)) {
			return;
		}

		// set search restriction
		this.setSearchRestriction(options.searchRestriction);

		// cancel pending load request when search is started
		if (this.isExecuting('list')) {
			this.proxy.cancelRequests('list');
		}

		this.setUseSearchFolder(options.useSearchFolder);
		this.setSubfolders(options.subfolders);

		if(this.useSearchFolder) {
			Ext.apply(options, {
				actionType : Zarafa.core.Actions['search']
			});
		}

		this.load(options);

		// set the flag to indicate that store contains search results
		// this should be only used when using search folders
		if(this.useSearchFolder) {
			this.hasSearchResults  = true;
		}

		this.fireEvent('search', this, options);
	},

	/**
	 * Function will be used to issue a updatesearch request to server,
	 * this will internally call {@link #load} method but with some different options.
	 * @param {Object} options options object that must contain entryid of search folder.
	 */
	updateSearch : function(options)
	{
		// We are not searching...
		if (!this.hasSearchResults ) {
			return;
		}

		if(!Ext.isObject(options)) {
			options = {};
		}

		Ext.apply(options, {
			actionType : Zarafa.core.Actions['updatesearch']
		});

		this.load(options);

		this.fireEvent('updatesearch', this, options);

		// reset the action type in the last options, because updatesearch is not persistent action type
		// and consecutive requests should use search action type, if its not specifically done using updateSearch method
		Ext.apply(this.lastOptions, {
			actionType : Zarafa.core.Actions['search'],
			// Add a property to see that this was originally an updatesearch action
			originalActionType: Zarafa.core.Actions.updatesearch
		});
	},

	/**
	 * Function will be used to issue a stopsearch request to server,
	 * this will internally call {@link #load} method but with some different options.
	 * @param {Object} options options object that must contain entryid of search folder.
	 */
	stopSearch : function(options)
	{
		// remove search restriction
		this.setSearchRestriction({});

		// We are not searching
		if (!this.hasSearchResults ) {
			return;
		}

		if(!Ext.isObject(options)) {
			options = {};
		}

		if (!Ext.isObject(options.params)) {
			options.params = {};
		}


		// cancel all pending updatesearch requests
		if (this.isExecuting(Zarafa.core.Actions['updatesearch']) || this.isExecuting(Zarafa.core.Actions['search'])) {
			this.proxy.cancelRequests(Zarafa.core.Actions['updatesearch']);
			this.proxy.cancelRequests(Zarafa.core.Actions['search']);
		}

		// stop firing updatesearch requests if it is queued
		if(this.searchUpdateTimer) {
			clearTimeout(this.searchUpdateTimer);
			delete this.searchUpdateTimer;
		}

		Ext.apply(options, {
			actionType : Zarafa.core.Actions['stopsearch']
		});

		Ext.apply(options.params, {
			store_entryid : this.storeEntryId,
			search_folder_entryid : this.searchFolderEntryId
		});

		// Send a destroy request -- we are destroying the search folder on the server
		this.proxy.request(Ext.data.Api.actions['destroy'], null, options.params, this.reader, Ext.emptyFn, this, options);

		// Clear the search data
		this.setSearchEntryId(undefined);
		this.hasSearchResults  = false;

		this.fireEvent('stopsearch', this, options);

		// reset the action type in the last options, because stopsearch is not persistent action type
		// and consecutive requests should use list action type, if its not specifically done using search method
		Ext.apply(this.lastOptions, {
			actionType : Zarafa.core.Actions['list']
		});
	},

	/**
	 * Function is used as a callback for 'read' action, we have overriden it to
	 * support search also using same 'read' action instead of creating new action.
	 * this will check that if action type is list then will do normal processing and
	 * add {@link Zarafa.core.data.IPMRecords[] records} to {@link Zarafa.core.data.ListModuleStore store}
	 * and if action type is search then it will call {@link #updateSearchInfo} as a callback function.
	 * @param {Object} data data that is returned by the proxy after processing it. will contain
	 * {@link Zarafa.core.data.IPMRecords records}.
	 * @param {Object} options options that are paased through {@link #load} event.
	 * @param {Boolean} success success status of request.
	 * @param {Object} metaData extra information that is received with response data.
	 */
	loadRecords : function(data, options, success, metaData)
	{
		if(success !== false) {
			var restriction;
			if (Ext.isDefined(options.params) && Ext.isDefined(options.params.restriction)) {
				restriction = options.params.restriction;
			}

			var pageSize = container.getSettingsModel().get('zarafa/v1/main/page_size');
			// update total loaded record
			if (restriction) {
				this.totalLoadedRecord = restriction.start ? restriction.start + restriction.limit : pageSize;

				// If store data is synchronized then update start and delete limit
				if (this.syncStore) {

					// Pagination and Infinite Scroll handle page information based on start and limit
					restriction.start = this.totalLoadedRecord - pageSize;
					delete restriction.limit;
					delete this.lastOptions.add;
					this.syncStore= false;
				}
			}
			if(metaData) {
				if(metaData.search_meta) {
					this.updateSearchInfo(metaData.search_meta, metaData.page);
				}

				// if paging information is provided then update total count
				if(metaData.page) {
					this.totalLength = metaData.page.totalrowcount;
				}

				// if folder information is provided, then update the folder
				if (metaData.folder && options.folder && options.folder.length === 1) {
					var folder = options.folder[0];

					if (Ext.isDefined(metaData.folder.content_unread)) {
						folder.set('content_unread', metaData.folder.content_unread);
					}
					if (Ext.isDefined(metaData.folder.content_count)) {
						folder.set('content_count', metaData.folder.content_count);
					}
				}
			}
		}

		Zarafa.core.data.ListModuleStore.superclass.loadRecords.apply(this, arguments);
	},

	/**
	 * Function will be called when search response is received by {@link Zarafa.core.data.IPMProxy proxy},
	 * This will check if search is running or not on server based on search status and call {@link #updateSearch}
	 * after timeout of 500ms.
	 * If search is active then search status will be SEARCH_RUNNING (0x1) and if search is locating its messages
	 * then it will return SEARCH_RUNNING | SEARCH_REBUILD (0x3), and if subfolder option is selected then
	 * these two values can be combined with SEARCH_RECURSIVE (0x4), if user has stopped search then search status
	 * will be empty.
	 * @param {Object} searchResponse Object will contain search folder's entryid and its status of search.
	 * @param {Object} page Object will contain information for pagination.
	 */
	updateSearchInfo : function(searchResponse, page)
	{

		// do some data conversion on received data
		var searchData = {
			entryId : searchResponse.searchfolder_entryid,
			searchState : parseInt(searchResponse.searchstate, 10),
			results : parseInt(searchResponse.results, 10)
		};

		// paging info is not always returned
		if(!Ext.isEmpty(page)) {
			Ext.apply(searchData, {
				page : {
					start : parseInt(page.start, 10),
					rowCount : parseInt(page.rowcount, 10),
					totalRowCount : parseInt(page.totalrowcount, 10)
				}
			});
		}

		this.fireEvent('beforeupdatesearch', this, searchData);

		this.setSearchEntryId(searchData.entryId);
		this.setSearchStoreEntryId(searchResponse.search_store_entryid);

		if(Zarafa.core.mapi.Search.isSearchRunning(searchData.searchState)) {
			this.searchUpdateTimer = this.updateSearch.defer(
				container.getSettingsModel().get('zarafa/v1/contexts/search/updatesearch_timeout'),
				this
			);
		} else {
			delete this.searchUpdateTimer;
		}
	},

	/**
	 * If {@link #loadMask} is not undefined, this function will display the {@link #loadMask}.
	 * @protected
	 */
	showLoadMask : function ()
	{
		if (!this.loadMask) {
			var contentPanel = container.getContentPanel();
			if (Ext.isFunction(contentPanel.getGridPanel)) {
				var grid = contentPanel.getGridPanel();
				this.loadMask = grid.loadMask;
				this.loadMask.show();
			}
		}
	}

});

Ext.reg('zarafa.listmodulestore', Zarafa.core.data.ListModuleStore);