Ext.namespace('Zarafa.common.rules.data');

/**
 * @class Zarafa.common.rules.data.RulesStore
 * @extends Zarafa.core.data.MAPIStore
 *
 * Delegate store that will be used to load delegates information from server.
 */
Zarafa.common.rules.data.RulesStore = Ext.extend(Zarafa.core.data.MAPIStore, {
	/**
	 * @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,

	/**
	 * {String} storeEntryId the store to be used for reading and writing the rules.
	 */
	storeEntryId : undefined,

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

		// Apply default settings.
		Ext.applyIf(config, {
			// load data whenever instance of store is created
			autoLoad : true,

			batch : true,

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

			writer : new Zarafa.core.data.JsonWriter({
				writeAllFields : true
			}),
			reader : new Zarafa.common.rules.data.JsonRulesReader(),

			proxy : new Zarafa.common.rules.data.RulesProxy({
				listModuleName : Zarafa.core.ModuleNames.getListName('RULES'),
				itemModuleName : Zarafa.core.ModuleNames.getItemName('RULES')
			})
		});

		Zarafa.common.rules.data.RulesStore.superclass.constructor.call(this, config);
	},

	/**
	 * Event handler which is raised when a {@link Zarafa.common.rules.data.RulesRecord RulesRecord} has been added
	 * to this {@link Zarafa.common.rules.data.RulesStore RulesStore}. This will generate unique value for rule_sequence
	 * property.
	 *
	 * @param {Zarafa.common.rules.data.RulesStore} store The {@link Zarafa.common.rules.data.RulesStore} to which the store was added.
	 * @param {Zarafa.common.rules.data.RulesRecord[]} records The array of {@link Zarafa.common.rules.data.RulesRecord records} which have been added.
	 * @param {Number} index The index at which the record(s) were added
	 * @private
	 */
	createRecords : function(store, records, index)
	{
		for (var i = 0, len = records.length; i < len; i++) {
			var record = records[i];
			if (record.phantom) {
				// generate sequence for the new record
				var seq = 10;

				store.each(function(rec) {
					var newSeq = rec.get('rule_sequence');

					if (!Ext.isEmpty(newSeq)) {
						seq = Math.max(seq, newSeq);
					}
				}, this);

				record.data.rule_sequence = (seq + 1);
			}
		}

		Zarafa.common.rules.data.RulesStore.superclass.createRecords.apply(this, arguments);
	},

	/**
	 * Saves all pending changes to the store.  If the commensurate Ext.data.Api.actions action is not configured, then
	 * the configured <code>{@link #url}</code> will be used.
	 * <pre>
	 * change            url
	 * ---------------   --------------------
	 * removed records   Ext.data.Api.actions.destroy
	 * phantom records   Ext.data.Api.actions.create
	 * {@link #getModifiedRecords modified records}  Ext.data.Api.actions.update
	 * </pre>
	 * @TODO:  Create extensions of Error class and send associated Record with thrown exceptions.
	 * e.g.:  Ext.data.DataReader.Error or Ext.data.Error or Ext.data.DataProxy.Error, etc.
	 * @return {Number} batch Returns a number to uniquely identify the "batch" of saves occurring. -1 will be returned
	 * if there are no items to save or the save was cancelled.
	 */
	save : function()
	{
		if (!this.writer) {
			throw new Ext.data.Store.Error('writer-undefined');
		}

		var queue = [],
		    len,
		    trans,
		    batch,
		    data = {},
		    i;

		var rs = this.getModifiedRecords();

		// If there are no modified records in the store, and none where
		// deleted, we don't need to save anything as there are
		// no changes.
		if (rs.length === 0 && this.removed.length === 0) {
			this.baseParams.store = this.storeEntryId;
			return;
		}

		// We are going to save all rules in a single batch,
		// the server will handle all updates/deletes automatically
		rs = this.getRange().filter(function(record) {
			return record.isValid();
		});

		// Add the store entryid to the request.
		rs.forEach(function(record) {
			record.addMessageAction("store", this.storeEntryId);
		}, this);

		// Put all records in the update batch, note that we don't care if this is empty,
		// as that will resolve on the server to a "Delete everything" action.
		queue.push(['create', rs]);

		len = queue.length;
		if (len) {
			batch = ++this.batchCounter;
			for (i = 0; i < len; ++i) {
				trans = queue[i];
				data[trans[0]] = trans[1];
			}
			if (this.fireEvent('beforesave', this, data) !== false) {
				for (i = 0; i < len; ++i) {
					trans = queue[i];
					this.doTransaction(trans[0], trans[1], batch);
				}
				return batch;
			}
		}
		return -1;
	},

	/**
	 * <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 = {};
		}

		// Add the entryid of the store for which we want the rules
		this.baseParams.store = this.storeEntryId;

		if (!Ext.isObject(options.params)) {
			options.params = {'store': this.storeEntryId};
		} else {
			options.params['store'] = this.storeEntryId;
		}

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

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

		return Zarafa.common.rules.data.RulesStore.superclass.load.call(this, options);
	}
});
