Ext.namespace('Zarafa.contact');

/**
 * @class Zarafa.contact.ContactContextModel
 * @extends Zarafa.core.ContextModel
 */
Zarafa.contact.ContactContextModel = Ext.extend(Zarafa.core.ContextModel, {
	/**
	 * The currently selected character, this is updated through
	 * {@link #setRestrictionCharacter} and when this field changes,
	 * the {@link #characterchange} event will be fired.
	 * When this context is {@link #stateful stateful}, this option will be
	 * saved in the settings.
	 * @property
	 * @type Mixed
	 */
	current_character : 'a',

	/**
	 * When searching, this property marks the {@link Zarafa.core.ContextModel#getCurrentDataMode datamode}
	 * which was used before {@link #onSearchStart searching started} the datamode was switched to
	 * {@link Zarafa.contact.data.DataModes#SEARCH}.
	 * @property
	 * @type Mixed
	 * @private
	 */
	oldDataMode : undefined,

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

		if(!Ext.isDefined(config.store)) {
			config.store = new Zarafa.contact.ContactStore();
		}

		Ext.applyIf(config, {
			current_data_mode : Zarafa.contact.data.DataModes.ALL
		});

		this.addEvents(
			/**
			 * @event characterchange
			 * Fires when the restriction character changed.
			 * @param {Zarafa.core.ContextModel} model this model.
			 * @param {String} character new character restriction.
			 * @param {String} oldCharacter previous character restriction.
			 */
			'characterchange'
		);

		Zarafa.contact.ContactContextModel.superclass.constructor.call(this, config);

		this.on({
			'searchstart' : this.onSearchStart,
			'searchstop' : this.onSearchStop,
			scope : this
		});
	},

	/**
	 * Called during the {@link Zarafa.core.Context#enable enabling} of the {@link Zarafa.core.Context context}.
	 * Secondly it will {@link #setFolders set the} {@link #folders folder} to this object to {@link #load} the {@link #store}.
	 * @param {Zarafa.hierarchy.data.MAPIFolderRecord} folder MAPI folder to show.
	 * @param {Boolean} suspended True to enable the ContextModel {@link #suspendLoading suspended}
	 */
	enable : function(folder, suspended)
	{
		// Enable the superclass with suspended enabled, so we can safely change the
		// restriction character
		Zarafa.contact.ContactContextModel.superclass.enable.call(this, folder, true);
		this.setRestrictionCharacter(this.getRestrictionCharacter(), true);

		// We enabled the superclass as suspended,
		// so time to resume it now.
		if (suspended !== true) {
			this.resumeLoading();
		}
	},

	/**
	 * Create a new {@link Zarafa.core.data.IPMRecord IPMRecord} which must be used within
	 * {@link Zarafa.contact.dialogs.ContactDialog ContactDialog}.
	 * @param {Zarafa.core.IPMFolder} folder (optional) The target folder in which the new record must be
	 * created. If this is not provided the default folder will be used.
	 * @param {Boolean} isDistlist True to create a distributionlist rather then a Contact
	 * @return {Zarafa.coore.data.IPMRecord} The new {@link Zarafa.core.data.IPMRecord IPMRecord}.
	 */
	createRecord : function(folder, isDistlist)
	{
		folder = folder || this.getDefaultFolder();

		var record = Zarafa.core.data.RecordFactory.createRecordObjectByMessageClass(isDistlist ? 'IPM.Distlist' : 'IPM.Contact', {
			store_entryid : folder.get('store_entryid'),
			parent_entryid : folder.get('entryid'),
			icon_index : isDistlist ? Zarafa.core.mapi.IconIndex['contact_distlist'] : Zarafa.core.mapi.IconIndex['contact_user']
		});

		return record;
	},

	/**
	 * Event handler which is executed right before the {@link #datamodechange}
	 * event is fired. This allows subclasses to initialize the {@link #store}.
	 * This will apply a restriction to the {@link #store} if needed.
	 *
	 * @param {Zarafa.contact.ContactContextModel} model The model which fired the event.
	 * @param {Zarafa.contact.data.DataModes} newMode The new selected DataMode.
	 * @param {Zarafa.contact.data.DataModes} oldMode The previously selected DataMode.
	 * @private
	 */
	onDataModeChange : function(model, newMode, oldMode)
	{
		Zarafa.contact.ContactContextModel.superclass.onDataModeChange.call(this, model, newMode, oldMode);

		if (newMode !== oldMode && oldMode === Zarafa.contact.data.DataModes.SEARCH) {
			this.stopSearch();
		}

		// also reload the store
		switch(newMode) {
			case Zarafa.contact.data.DataModes.CHARACTER_RESTRICT:
				this.load({
					params : {
						restriction : { 'search' : this.createCharacterRestriction() }
					}
				});
				break;
			case Zarafa.contact.data.DataModes.ALL:
				this.load({
					params : {
						restriction : {}
					}
				});
				break;
			case Zarafa.contact.data.DataModes.SEARCH:
				break;
		}
	},

	/**
	 * Sets the current character for the {@link Zarafa.contact.data.DataModes#CHARACTER_RESTRICT} datamode.
	 * Fires the {@link #characterchange} event.
	 * @param {String} character The character by which the contacts should be restricted.
	 * @param {Boolean} init (optional) True when this function is called during initialization
	 * and it should force the change of the character.
	 */
	setRestrictionCharacter : function(character, init)
	{
		if (init === true || this.current_character !== character) {
			var oldCharacter = this.current_character;
			this.current_character = character;

			this.onCharacterChange(this, this.current_character, oldCharacter);
			
			// fire mode change event
			this.fireEvent('characterchange', this, this.current_character, oldCharacter);
		}
	},

	/**
	 * @return {String} The currently selected {@link #current_character character}.
	 */
	getRestrictionCharacter : function()
	{
		return this.current_character;
	},

	/**
	 * Event handler which is executed right before the {@link #characterchange}
	 * event is fired. This allows subclasses to initialize the {@link #store}.
	 *
	 * @param {Zarafa.core.ContextModel} model The model which fired the event.
	 * @param {Mixed} newCharacter The new selected character
	 * @param {Mixed} oldCharacter The previously selected character
	 * @private
	 */
	onCharacterChange : function(mode, newCharacter, oldCharacter)
	{
		if (this.current_data_mode === Zarafa.contact.data.DataModes.CHARACTER_RESTRICT) {
			var params = {
				start : 0
			};

			if (newCharacter) {
				params.restriction = {
					'search' : this.createCharacterRestriction(newCharacter)
				};
			}

			this.load({
				params : params
			});
		}
	},

	/**
	 * Function will create restriction that will be applied to {@link Zarafa.contact.ContactStore ContactStore},
	 * and used when fetching data for {@link Zarafa.contact.ui.ContactCardView ContactCardView}.
	 * @param {String} character character that is currently selected.
	 * @return {Object} restriction that will be applied to store.
	 * @private
	 */
	createCharacterRestriction : function(character)
	{
		var Factory = Zarafa.core.data.RestrictionFactory;
		var Restrictions = Zarafa.core.mapi.Restrictions;
		var restriction;
		var fileAs = '0x80B5001E';

		if (Ext.isEmpty(character)) {
			character = this.current_character || '...';
		}

		switch(character) {
			case '...':
				// don't apply any restriction
				restriction = {};
				break;
			case '123':
				// find contacts starting with numeric characters '0' to '9'
				restriction = Factory.createResAnd([
					Factory.dataResProperty(fileAs, Restrictions.RELOP_GE, '0'),
					Factory.dataResProperty(fileAs, Restrictions.RELOP_LE, '9')
				]);
				break;
			case 'z':
				// find contacts ending after character 'z'
				restriction = Factory.dataResProperty(fileAs, Restrictions.RELOP_GE, 'z');
				break;
			default:
				var nextCharacter = String.fromCharCode(character.charCodeAt(0) + 1);
				restriction = Factory.createResAnd([
					Factory.dataResProperty(fileAs, Restrictions.RELOP_GE, character),
					Factory.dataResProperty(fileAs, Restrictions.RELOP_LE, nextCharacter)
				]);
		}

		return restriction;
	},

	/**
	 * Handler for 'charachterchange' event, which calls {@link #saveState} only
	 * when the current character is not the same as oldCharacter.
	 *
	 * @param {Zarafa.core.ContextModel} contextModel the contextModel which states needs to be saved.
	 * @param {String} character new character restriction.
	 * @param {String} oldCharacter new character restriction.
	 */
	saveCharacterChangeState : function(contextModel, character, oldCharacter)
	{
		if (character != oldCharacter) {
			this.saveState();
		}
	},

	/**
	 * Register the {@link #stateEvents state events} to the {@link #saveState} callback function.
	 * @private
	 */
	initStateEvents : function()
	{
		Zarafa.contact.ContactContextModel.superclass.initStateEvents.call(this);
		this.on('characterchange', this.saveCharacterChangeState, this, {delay: 100});
	},

	/**
	 * When {@link #stateful} the State object which should be saved into the
	 * {@link Ext.state.Manager}.
	 * @return {Object} The state object
	 * @protected
	 */
	getState : function()
	{
		var state = Zarafa.contact.ContactContextModel.superclass.getState.call(this) || {};
		return Ext.apply(state, { current_character : this.current_character });
	},

	/**
	 * Event handler for the {@link #searchstart searchstart} event.
	 * This will {@link #setDataMode change the datamode} to {@link Zarafa.contact.data.DataModes#SEARCH search mode}.
	 * The previously active {@link #getCurrentDataMode view} will be stored in the {@link #oldDataMode} and will
	 * be recovered when the {@link #onSearchStop search is stopped}.
	 * @param {Zarafa.core.ContextModel} model The model which fired the event
	 * @private
	 */
	onSearchStart : function(model)
	{
		if(this.getCurrentDataMode() != Zarafa.contact.data.DataModes.SEARCH){
			this.oldDataMode = this.getCurrentDataMode();
			this.setDataMode(Zarafa.contact.data.DataModes.SEARCH);
		}
	},

	/**
	 * Event handler for the {@link #searchstop searchstop} event.
	 * This will {@link #setDataMode change the datamode} to the {@link #oldDataMode previous datamode}.
	 * @param {Zarafa.core.ContextModel} model The model which fired the event
	 * @private
	 */
	onSearchStop : function(model)
	{
		if (this.getCurrentDataMode() === Zarafa.contact.data.DataModes.SEARCH) {
			this.setDataMode(this.oldDataMode);
		}
		delete this.oldDataMode;
	},

	/**
	 * Sets the selected folder list directly.
	 * @param {Zarafa.hierarchy.data.MAPIFolderRecord[]} folders selected folders as an array of
	 * {@link Zarafa.hierarchy.data.MAPIFolderRecord MAPIFolder} objects.
	 */
	setFolders : function(folders)
	{
		// Suspend loading, so we can safely change the restriction character
		this.suspendLoading(true);
		Zarafa.contact.ContactContextModel.superclass.setFolders.call(this,folders);
		this.setRestrictionCharacter(this.getRestrictionCharacter(), true);

		// Resume loading after applying restriction
		this.resumeLoading();
	}
});
