Ext.namespace('Zarafa.plugins.mdm');

/**
 * @class Zarafa.plugins.mdm.MDM
 * @extends Zarafa.core.Plugin
 *
 * Plugin which lists all devices connected to a Grommunio account with Sync.
 * The user can wipe, resync, remove a device using buttons in grommunio Web.
 */
Zarafa.plugins.mdm.MDM = Ext.extend(Zarafa.core.Plugin, {
	/**
	 * Constructor
	 * @param {Object} config
	 * @protected
	 */
	constructor : function(config) {
		config = config || {};
		Zarafa.plugins.mdm.MDM.superclass.constructor.call(this, config);

		// Module information for MDM which will use in shadow store.
		Zarafa.core.ModuleNames["IPM.MDM"] = {
			list: 'pluginmdmmodule',
			item: 'pluginmdmmodule'
		}
	},

	/**
	 * Called after constructor.
	 * Registers insertion points.
	 * @protected
	 */
	initPlugin : function()
	{
		this.registerInsertionPoint('context.settings.categories', this.createSettingCategory, this);
		// this.registerInsertionPoint('settings.versioninformation', this.createVersionInfo, this);
		Zarafa.core.data.SharedComponentType.addProperty('mdm.dialog.mdmdevicecontentpanel');
		Zarafa.core.data.SharedComponentType.addProperty('mdm.dialog.mdmmanagesharedfoldercontentpanel');
		Zarafa.plugins.mdm.MDM.superclass.initPlugin.apply(this, arguments);
	},

	/**
	 * Bid for the type of shared component and the given record.
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @returns {Number}
	 */
	bidSharedComponent : function (type, record)
	{
		var bid = -1;
		switch (type) {
			case Zarafa.core.data.SharedComponentType['mdm.dialog.mdmdevicecontentpanel']:
			case Zarafa.core.data.SharedComponentType['mdm.dialog.mdmmanagesharedfoldercontentpanel']:
				bid = 1;
				break;
		}
		return bid;
	},

	/**
	 * Will return the reference to the shared component.
	 * Based on the type of component requested a component is returned.
	 * @param {Zarafa.core.data.SharedComponentType} type Type of component a context can bid for.
	 * @param {Ext.data.Record} record Optionally passed record.
	 * @return {Zarafa.plugins.mdm.dialogs.MDMDeviceDetailsContentPanel} Component
	 */
	getSharedComponent : function (type, record)
	{
		var component;
		switch (type) {
			case Zarafa.core.data.SharedComponentType['mdm.dialog.mdmdevicecontentpanel']:
				component = Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel;
				break;
			case Zarafa.core.data.SharedComponentType['mdm.dialog.mdmmanagesharedfoldercontentpanel']:
				component = Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel;
				break;
		}
		return component;
	},


	/**
	 * Creates a category in settings for Grommunio Sync
	 * @return {mdmsettingscategory}
	 */
	createSettingCategory: function() {
		return [{
			xtype : 'Zarafa.plugins.mdm.mdmsettingscategory'
		}];
	},

	/**
	 * Creates a displayField that will show the version of the Grommunio Sync
	 */
	createVersionInfo : function() {
		var version = container.getSettingsModel().get('zarafa/v1/plugins/mdm/zpush-server-version', true);
		return {
			fieldLabel : _('grommunio-sync'),
			value : version
		};
	}

});

Zarafa.onReady(function() {
	container.registerPlugin(new Zarafa.core.PluginMetaData({
		name : 'mdm',
		displayName : _('Mobile device management'),
		pluginConstructor : Zarafa.plugins.mdm.MDM
	}));
});
Ext.namespace('Zarafa.plugins.mdm.data');

/**
 * @class Zarafa.plugins.mdm.data.MDMDeviceFolderStore
 * @extends Zarafa.core.data.MAPISubStore
 * @xtype mdm.devicefolderstore
 * Store specific for MDM Plugin which creates {@link Zarafa.plugins.mdm.MDMDeviceFolderStore record}.
 */
Zarafa.plugins.mdm.data.MDMDeviceFolderStore = Ext.extend(Zarafa.core.data.MAPISubStore, {

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

		Ext.applyIf(config, {
			autoLoad: true,
			remoteSort: false,
			reader: new Zarafa.plugins.mdm.data.JsonDeviceFolderReader({
				customObjectType: Zarafa.core.data.RecordCustomObjectType.MDM_Device_Folder
			}),
			writer: new Zarafa.plugins.mdm.data.MDMDeviceFolderWriter(),
			proxy: new Zarafa.core.data.IPMProxy({
				listModuleName: 'pluginmdmmodule',
				itemModuleName: 'pluginmdmmodule'
			})
		});

		Zarafa.plugins.mdm.data.MDMDeviceFolderStore.superclass.constructor.call(this, config);
	},

	/**
	 * Function which is use to add {@link Zarafa.plugins.mdm.data.MDMDeviceFolderRecord folder} into
	 * {@link Zarafa.plugins.mdm.MDMDeviceFolderStore store} which will share with respective device.
	 * @param {Zarafa.hierarchy.data.IPFRecord} folder folder which is will add into {@link Zarafa.plugins.mdm.MDMDeviceFolderStore store}
	 */
	addFolder : function (folder)
	{
		var record = Zarafa.core.data.RecordFactory.createRecordObjectByCustomType(Zarafa.core.data.RecordCustomObjectType.MDM_Device_Folder, {
			"entryid": folder.get("entryid")
		});
		this.add(record);
	},

	/**
	 * Function which is use to remove {@link Zarafa.plugins.mdm.data.MDMDeviceFolderRecord folder} from
	 * {@link Zarafa.plugins.mdm.MDMDeviceFolderStore store}.
	 * @param {Zarafa.hierarchy.data.IPFRecord} folder folder which is will remove from {@link Zarafa.plugins.mdm.MDMDeviceFolderStore store}
	 */
	removeFolder : function (folder)
	{
		var found = this.findBy(function (record) {
			 return Zarafa.core.EntryId.compareEntryIds(record.get("entryid"), folder.get("entryid"));
		});

		if (found >= 0) {
			this.removeAt(found);
		}
	}
});

Ext.reg('mdm.devicefolderstore', Zarafa.plugins.mdm.data.MDMDeviceFolderStore);Ext.namespace('Zarafa.plugins.mdm');

/**
 * @class Zarafa.plugins.mdm.data.MDMDeviceFolderRecordFields
 *
 * Array of default fields for the {@link Zarafa.plugins.mdm.data.MDMDeviceFolderRecord} object.
 * These fields will always be added, regardless of the exact type of
 * {@link Zarafa.plugins.mdm.data.MDMDeviceFolderRecord record}.
 */
Zarafa.plugins.mdm.data.MDMDeviceFolderRecordFields = [
	{name: 'store', type: 'string'},
	{name: 'folderid', type: 'string'},
	{name: 'name', type: 'string'},
	{name: 'type', type: 'int'},
	{name: 'flags', type: 'int'},
	{name: 'entryid', type: 'string'}
];

Zarafa.core.data.RecordCustomObjectType.addProperty('MDM_Device_Folder');
Zarafa.core.data.RecordFactory.addFieldToCustomType(Zarafa.core.data.RecordCustomObjectType.MDM_Device_Folder, Zarafa.plugins.mdm.data.MDMDeviceFolderRecordFields);
Zarafa.core.data.RecordFactory.setBaseClassToCustomType(Zarafa.core.data.RecordCustomObjectType.MDM_Device_Folder, Zarafa.core.data.MAPIRecord);
Ext.namespace('Zarafa.plugins.mdm.data');

/**
 * @class Zarafa.plugins.mdm.data.JsonDeviceFolderReader
 * @extends Zarafa.core.data.JsonReader
 *
 * This extension of the {@link Zarafa.core.data.JsonReader} supports
 * {@link Zarafa.plugins.mdm.data.MDMDeviceStore stores} which can hold different type of
 * {@link Zarafa.plugins.mdm.data.MDMDeviceRecord records}.
 */
Zarafa.plugins.mdm.data.JsonDeviceFolderReader = Ext.extend(Zarafa.core.data.JsonReader, {
	
	/**
	 * @constructor
	 * @param {Object} meta Metadata configuration options.
	 * @param {Object} recordType (optional) Optional Record type matches the type
	 * which must be read from response. If no type is given, it will use the
	 * record type for the {@link Zarafa.core.data.RecordCustomObjectType#MDM_Device_Folder}.
	 */
	constructor: function (meta, recordType)
	{
		meta = Ext.applyIf(meta || {}, {
			id: 'folderid',
			idProperty: 'folderid',
			dynamicRecord: false
		});

		if (!Ext.isDefined(recordType)) {
			recordType = Zarafa.core.data.RecordFactory.getRecordClassByCustomType(meta.customObjectType);
		}

		Zarafa.plugins.mdm.data.JsonDeviceFolderReader.superclass.constructor.call(this, meta, recordType);
	}
});
Ext.namespace('Zarafa.plugins.mdm.data');

/**
 * @class Zarafa.plugins.mdm.data.MDMResponseHandler
 * @extends Zarafa.core.data.AbstractResponseHandler
 *
 * MDM specific response handler.
 */
Zarafa.plugins.mdm.data.MDMResponseHandler = Ext.extend(Zarafa.core.data.AbstractResponseHandler, {

	/**
	 * @cfg {Function} successCallback The function which
	 * will be called after success request.
	 */
	successCallback : Ext.emptyFn,

	/**
	 * @cfg {Function} failureCallback The function which
	 * will be called after a failed request.
	 * This callback is optional and currently unused.
	 */
	failureCallback : Ext.emptyFn,

	/**
	 * Device information from grommunio-sync's soap call,
	 * @param {Object} response Object contained the response data.
	 */
	doInfo : function(response) {
		this.successCallback(response);
		/*
		if(response.status != true && this.failureCallback != null) {
			this.failureCallback(response);
		} else {
			this.successCallback(response);
		}*/
	},

	/**
	 * Response handler callback function for authenticate action.
	 * Call successCallback callback function to perform actions on the basis of response,
	 * @param {Object} response Object contained the response data. Contains data regarding
	 * authentication with grommunio-sync server.
	 */
	doAuthenticate : function(response)
	{
		this.processAuthResponse(response, this.successCallback, 'authenticate');
	},

	/**
	 * Call the successCallback callback function if device was successfully removed from
	 * grommunio-sync server else check and handle an authentication failure for grommunio-sync server.
	 * @param {Object} response Object contained the response data.
	 */
	doRemove : function(response)
	{
		if(response.remove){
			this.successCallback();
		} else {
			this.processAuthResponse (response, this.failureCallback, 'remove');
		}
	},

	/**
	 * If wipe request response was successful, show informative message
	 * else check and handle an authentication failure for grommunio-sync server.
	 * @param {Object} response Object contained the response data.
	 */
	doWipe : function(response)
	{
		if (response.wipe === true) {
			container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Wiping device'));
			this.successCallback();
		} else if (!response.wipe) {
			container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Password incorrect'));
		} else {
			this.processAuthResponse(response, this.failureCallback, 'wipe');
		}
	},

	/**
	 * If resync request response was successful, show informative message
	 * else check and handle an authentication failure for grommunio-sync server.
	 * @param {Object} response Object contained the response data.
	 */
	doResync : function(response)
	{
		if (response.resync === true) {
			container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Full resync in progress'));
		} else {
			this.processAuthResponse (response, this.failureCallback, 'resync');
		}
	},

	/**
	 * This function will call callback function given in param
	 * if response is regarding authentication only.
	 * @param {Object} response Object contained the response data.
	 * @param {Function} callbackFn function which will be called if response is regarding authentication.
	 * @param {String} actionType indicates from which action handler this function has been called.
	 */
	processAuthResponse : function(response, callbackFn, actionType)
	{
		var authenticationObj = response.authenticationInfo;
		if (authenticationObj) {
			callbackFn.call(this.mdmWidgetScope, authenticationObj.authentication);
			if (actionType === 'authenticate' && authenticationObj.authentication === false) {
				container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Username or password incorrect'));
			}
		}
	}
});

Ext.reg('mdm.responsehandler', Zarafa.plugins.mdm.data.MDMResponseHandler);
Ext.namespace('Zarafa.plugins.mdm');

/**
 * @class Zarafa.plugins.mdm.data.MDMDeviceRecordFields Array of {@link Ext.data.Field field} configurations for the
 * {@link Zarafa.plugins.mdm.data.MDMDeviceRecord record} object.
 * @private
 */
Zarafa.plugins.mdm.data.MDMDeviceRecordFields = [
	{name: 'entryid', type: 'string'},
	{name: 'devicetype', type: 'string'},
	{name: 'deviceos', type: 'string'},
	{name: 'devicefriendlyname', type: 'string'},
	{name: 'useragent', type: 'string'},
	{name: 'asversion', type: 'string'},
	{name: 'firstsynctime', type: 'date', dateFormat: 'timestamp'},
	{name: 'lastsynctime', type: 'date', dateFormat: 'timestamp'},
	{name: 'lastupdatetime', type: 'date', dateFormat: 'timestamp'},
	{name: 'lastconnecttime', type: 'date', dateFormat: 'timestamp'},
	{name: 'wipestatus', type: 'string'},
	{name: 'policyname', type: 'string'},
	{name: 'sharedfolders', type: 'string'},
	{name: 'shortfolderids', type: 'string'},
	{name: 'synchronizedfolders', type: 'string', defaultValue:'0'},
	{name: 'emailsfolder', type: 'string', defaultValue:'0'},
	{name: 'contactsfolder', type: 'string', defaultValue:'0'},
	{name: 'tasksfolder', type: 'string', defaultValue:'0'},
	{name: 'calendarsfolder', type: 'string', defaultValue:'0'},
	{name: 'notesfolder', type: 'string', defaultValue:'0'},
	{name: 'impersonatinguser', type: 'string'},
	{name: 'message_class', type: 'string', defaultValue:"IPM.MDM"}
];


Zarafa.plugins.mdm.data.MDMDeviceRecord = Ext.extend(Zarafa.core.data.IPMRecord, {});
Zarafa.core.data.RecordFactory.addFieldToMessageClass('IPM.MDM', Zarafa.plugins.mdm.data.MDMDeviceRecordFields);
Zarafa.core.data.RecordFactory.setBaseClassToMessageClass('IPM.MDM', Zarafa.plugins.mdm.data.MDMDeviceRecord);
Zarafa.core.data.RecordFactory.setSubStoreToMessageClass('IPM.MDM', 'sharedfolders', Zarafa.plugins.mdm.data.MDMDeviceFolderStore);
Ext.namespace('Zarafa.plugins.mdm.data');

/**
 * @class Zarafa.plugins.mdm.data.JsonCertificateReader
 * @extends Zarafa.core.data.JsonReader
 */
Zarafa.plugins.mdm.data.JsonCertificateReader = Ext.extend(Zarafa.core.data.JsonReader, {

	/**
	 * @constructor
	 * @param {Object} meta Metadata configuration options.
	 * @param {Object} recordType (optional) Optional Record type matches the type
	 * which must be read from response. If no type is given, it will use the
	 * record type for the {@link Zarafa.core.mapi.ObjectType#MAPI_MDM}.
	 */
	constructor: function (meta, recordType)
	{
		meta = Ext.applyIf(meta || {}, {
			dynamicRecord: false
		});
		recordType = Zarafa.core.data.RecordFactory.getRecordClassByMessageClass('IPM.MDM');

		Zarafa.plugins.mdm.data.JsonCertificateReader.superclass.constructor.call(this, meta, recordType);
	}
});
Ext.namespace('Zarafa.plugins.mdm.data');

/**
 * @class Zarafa.plugins.mdm.data.MDMDeviceFolderWriter
 * @extends Zarafa.core.data.JsonWriter
 *
 * This extension of the {@link Zarafa.core.data.JsonWriter} for writing
 * {@link Zarafa.plugins.mdm.data.MDMDeviceFolderRecord records} in preparation for executing CRUD action on
 * {@link Zarafa.plugins.mdm.data.MDMDeviceFolderStore stores}
 */
Zarafa.plugins.mdm.data.MDMDeviceFolderWriter = Ext.extend(Zarafa.core.data.JsonWriter, {
	/**
	 * Similar to {@link Ext.data.JsonWriter#toHash}
	 *
	 * Convert sharedFolder into a hash. {@link Zarafa.plugins.mdm.data.MDMDeviceFolderRecord folder} exists
	 * within a {@link Zarafa.plugins.mdm.data.MDMDeviceRecord IPMRecord} and thus must be serialized
	 * separately into the hash object.
	 *
	 * @param {Ext.data.Record} record The record to hash
	 * @return {Object} The hashed object
	 * @override
	 * @private
	 */
	toPropHash : function(record)
	{
		var sharedFolderStore = record.getSubStore('sharedfolders');
		var hash = {};

		if (!Ext.isDefined(sharedFolderStore)) {
			return hash;
		}

		// Get list of modified (modified and newly added) records
		var modifiedRecords = sharedFolderStore.getModifiedRecords();
		// Get list of removed records
		var deletedRecords = sharedFolderStore.getRemovedRecords();

		// Adding the modified folder to the add or modified part of the sharedFolder bit
		if (modifiedRecords.length) {
			hash.sharedfolders = {};
			hash.sharedfolders.add = modifiedRecords.map(function(r){return r.data;});
		}

		// Adding the removed folders to the remove part of the sharedFolder bit
		if (deletedRecords.length) {
			hash.sharedfolders = hash.sharedfolders || {};
			hash.sharedfolders.remove = deletedRecords.map(function(r){return r.data;});
		}

		return hash;
	}
});
Ext.namespace('Zarafa.plugins.mdm.data');

/**
 * @class Zarafa.plugins.mdm.data.MDMDeviceStore
 * @extends Zarafa.core.data.ListModuleStore
 * @xtype mdm.devicestore
 * Store specific for MDM Plugin which creates {@link Zarafa.plugins.mdm.MDMDeviceRecord record}.
 */
Zarafa.plugins.mdm.data.MDMDeviceStore = Ext.extend(Zarafa.core.data.ListModuleStore, {
	/**
	 * @constructor
	 * @param config Configuration object
	 */
	constructor : function(config)
	{
		config = config || {};

		Ext.applyIf(config, {
			remoteSort: false,
			reader : new Zarafa.plugins.mdm.data.JsonCertificateReader(),
			writer : new Zarafa.core.data.JsonWriter(),
			proxy  : new Zarafa.plugins.mdm.data.MDMDeviceProxy()
		});

		this.addEvents(
			/**
			 * @event beforeloadrecord
			 * Fires before loading records into the store.
			 * @param {Boolean} isAuthenticated false if user is authenticated to grommunio-sync server else true.
			 */
			"beforeloadrecord"
		);

		Zarafa.plugins.mdm.data.MDMDeviceStore.superclass.constructor.call(this, config);
	},

	/**
	 * Function is used as a callback for 'read' action. It is overridden to be able to
	 * add authentication with grommunio-sync server info if available in metadata
	 * and fire {@link #authenticationerror} event.
	 * @param {Object} data data that is returned by the proxy after processing it. will contain
	 * {@link Zarafa.plugins.mdm.data.MDMDeviceRecord record}.
	 * @param {Object} options options that are passed 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 (metaData && metaData.authenticationInfo) {
			var isAuthenticated = metaData.authenticationInfo.authentication;
			this.fireEvent("beforeloadrecord", isAuthenticated);
		}

		Zarafa.plugins.mdm.data.MDMDeviceStore.superclass.loadRecords.apply(this, arguments);
	}
});

Ext.reg('mdm.devicestore', Zarafa.plugins.mdm.data.MDMDeviceStore);
Ext.namespace('Zarafa.plugins.mdm.data');

/**
 * @class Zarafa.plugins.mdm.data.ProvisioningStatus
 * @extends Zarafa.core.Enum
 *
 * @singleton
 */
Zarafa.plugins.mdm.data.ProvisioningStatus = Zarafa.core.Enum.create({
	/**
	 * Denotes that the wipe is not applicable.
	 * @property
	 * @type Number
	 */
	'NOT_APPLICABLE' : 0,

	/**
	 * Denotes that the wipe is ok.
	 * @property
	 * @type Number
	 */
	'OK' : 1,

	/**
	 * Denotes that the wipe is pending.
	 * @property
	 * @type Number
	 */
	'WIPE_PENDING' : 2,

	/**
	 * Denotes that the wipe is requested.
	 * @property
	 * @type Number
	 */
	'WIPE_REQUESTED' : 4,

	/**
	 * Denotes that the wipe is executed.
	 * @property
	 * @type Number
	 */
	'WIPE_EXECUTED' : 8,

	/**
	 * Denotes that the account only wipe is pending.
	 * @property
	 * @type Number
	 */
	'WIPE_PENDING_ACCOUNT_ONLY' : 16,

	/**
	 * Denotes that the account only wipe is requested.
	 * @property
	 * @type Number
	 */
	'WIPE_REQUESTED_ACCOUNT_ONLY' : 32,

	/**
	 * Denotes that the account only wipe is executed.
	 * @property
	 * @type Number
	 */
	'WIPE_EXECUTED_ACCOUNT_ONLY' : 64,

	/**
	 * Return the display name for the given provisioning Status
	 * @param {Zarafa.plugins.mdm.js.data.ProvisioningStatus} provisioningStatus The given provisioning status
	 * @return {String} The display name for the provisioning status
	 */
	getDisplayName : function(provisioningStatus)
	{
		switch (provisioningStatus) {
			case Zarafa.plugins.mdm.data.ProvisioningStatus.NOT_APPLICABLE:
				return _('Not Applicable');
			case Zarafa.plugins.mdm.data.ProvisioningStatus.OK:
				return _('Ok');
			case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_PENDING:
				return _('Wipe Pending');
			case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_REQUESTED:
				return _('Wipe Requested');
			case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_EXECUTED:
				return _('Wipe Executed');
			case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_PENDING_ACCOUNT_ONLY:
				return _('Account Only Wipe Pending');
			case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_REQUESTED_ACCOUNT_ONLY:
				return _('Account Only Wipe Requested');
			case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_EXECUTED_ACCOUNT_ONLY:
				return _('Account Only Wipe Executed');
			default:
				return _('Not Available');
		}
	}
});

Ext.namespace('Zarafa.plugins.mdm.data');

/**
 * @class Zarafa.plugins.mdm.data.MDMDeviceProxy
 * @extends Zarafa.core.data.MAPIProxy
 */
Zarafa.plugins.mdm.data.MDMDeviceProxy = Ext.extend(Zarafa.core.data.MAPIProxy, {

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor: function (config)
	{
		config = config || {};
		Ext.applyIf(config, {
			listModuleName: 'pluginmdmmodule',
			itemModuleName: 'pluginmdmmodule'
		});

		Zarafa.plugins.mdm.data.MDMDeviceProxy.superclass.constructor.call(this, config);
	},

	/**
	 * This will create a {@link Zarafa.core.data.ProxyResponseHandler ProxyResponseHandler} object
	 * which will be used by the {@link Zarafa.core.data.ResponseRouter ResponseRouter} when the
	 * response for the given request has returned.
	 *
	 * @param {String} modulename The modulename which is being accessed with this request
	 * @param {Zarafa.core.Actions} serverAction The action to perform on the server.
	 * @param {Ext.data.Api.action} action name of the action to perform.
	 * @param {Ext.data.Record[]} records list of records to operate on.
	 * @param {Object} parameters object containing user parameters such as range (pagination) information, sorting information, etc.
	 * @param {Ext.data.DataReader} reader data reader. Converts raw JavaScript objects (in our case) to instances of {@link Ext.data.Record}
	 * @param {Function} callback call back function to call when the request has finished successfully.
	 * @param {Object} scope scope for the call back function.
	 * @param {Object} args arguments object. This will be passed to the call back function on successful read.
	 * @return {Object} An instance of the {@link Zarafa.plugins.mdm.data.MDMDeviceResponseHandler ProxyResponseHandler}
	 * which should be used for this request.
	 * @private
	 */
	getResponseHandlerForRequest: function (modulename, serverAction, action, records, parameters, reader, callback, scope, args)
	{
		return new Zarafa.plugins.mdm.data.MDMDeviceResponseHandler({
			proxy: this,
			action: action,
			reader: reader,
			sendRecords: records,
			options: args,
			callback: callback,
			scope: scope
		});
	}
});
Ext.namespace('Zarafa.plugins.mdm.data');

/**
 * @class Zarafa.plugins.mdm.data.MDMDeviceResponseHandler
 * @extends Zarafa.core.data.ProxyResponseHandler
 *
 * A Simple implementation for a {@link Zarafa.plugins.mdm.data.MDMDeviceResponseHandler ResponseHandler}.
 * This one can only be used by {@link Ext.data.DataProxy proxies} which wish to handle a Response
 * to their Request.
 *
 * This implementation limits itself to firing an {@link Ext.data.DataProxy#exception exception}
 * on error, and calling a callback function when all processing has been completed.
 */
Zarafa.plugins.mdm.data.MDMDeviceResponseHandler = Ext.extend(Zarafa.core.data.ProxyResponseHandler, {

	/**
	 * Handles the 'open' response. Gathers the records from the response data,
	 * converts each entry into a record (using {@link #readRecordsFromResponse}
	 * and pushes them into the {@link #receivedRecords records list}.
	 * @param {Object} response The response object belonging to the given command.
	 * @return {Boolean} False when action could not be handled successfully. This will
	 * not cancel the transaction itself, but rather causes the 'success' argument for the
	 */
	doOpen: function(response)
	{
		this.receivedRecords = this.readRecordsFromResponse(response, 'item');
	},

	/**
	 * Handles the 'list' response. Gathers the records from the response data,
	 * converts each entry into a record (using {@link #readRecordsFromResponse}
	 * and pushes them into the {@link #receivedRecords records list}.
	 * Also if response has authenticationInfo then this function will add that into {@property metaData}.
	 * @param {Object} response The response object belonging to the given command.
	 * @return {Boolean} False when action could not be handled successfully. This will
	 * not cancel the transaction itself, but rather causes the 'success' argument for the
	 */
	doList: function(response)
	{
		if (response.authenticationInfo) {
			this.metaData.authenticationInfo = Ext.apply({}, response.authenticationInfo);
		}
		this.receivedRecords = this.readRecordsFromResponse(response, 'item');
	}
});
Ext.namespace('Zarafa.hierarchy.data');

/**
 * @class Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader
 * @extends Zarafa.hierarchy.data.HierarchyTreeLoader
 *
 * A Special treeloader to be used by the {@link Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader MDMHierarchyTree}.
 * This will dynamically load the child nodes for a given node by obtaining the subfolders of
 * the folder related to the given node.
 */
Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader = Ext.extend(Zarafa.hierarchy.data.HierarchyTreeLoader, {

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config)
	{
		Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader.superclass.constructor.call(this, config);
	},

	/**
	 * Add extra attributes for a new {@link Zarafa.hierarchy.ui.FolderNode folderNode} which is about
	 * to be created. This will check the {@link Zarafa.hierarchy.ui.FolderNode#folder folder} to
	 * see what properties must be set.
	 *
	 * Override to provide (@link Zarafa.plugins.mdm.ui.MDMFolderNodeUI MDMFolderNodeUI} to ui provider
	 * @param {Object} attr The attributes which will be used to create the node
	 * @return {Zarafa.hierarchy.ui.FolderNode} The created node
	 */
	createNode : function(attr)
	{
		var folder = attr.folder;

		if (folder) {
			if (attr.nodeType === 'rootfolder') {
				attr.extendedDisplayName = this.tree.hasFilter();
			}

			attr.leaf = !folder.get('has_subfolder');
			attr.uiProvider = Zarafa.plugins.mdm.ui.MDMFolderNodeUI;
			attr.expanded = this.tree.isFolderOpened(folder);
			attr.allowDrag = !folder.isDefaultFolder();
		}

		// call parent of parent because of parent class will change ui provider
		return Zarafa.hierarchy.data.HierarchyTreeLoader.superclass.createNode.apply(this, arguments);
	}
});
Ext.namespace('Zarafa.plugins.mdm.settings');

/**
 * @class Zarafa.plugins.mdm.settings.MDMSettingsWidget
 * @extends Zarafa.settings.ui.SettingsWidget
 */
Zarafa.plugins.mdm.settings.MDMSettingsWidget = Ext.extend(Zarafa.settings.ui.SettingsWidget, {

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

		var store = new Zarafa.plugins.mdm.data.MDMDeviceStore();
		store.on('load', this.onDeviceStoreLoad, this);
		Ext.applyIf(config, {
			title : _('Mobile Devices'),
			cls : 'zarafa-settings-widget k-settings-nogap',
			items : [{
				xtype : 'panel',
				layout: 'fit',
				tbar : {
					layout : 'fit',
					height : '30',
					items: [{
						xtype : 'button',
						name : 'authErrorBtn',
						hidden : true,
						cls: 'mdm-autherror-bar',
						ref : '../../authErrorBtn',
						text : String.format(_('Unable to connect to the grommunio-sync server. Click {0} to enter your credentials'), "here".bold()),
						listeners : {
							scope: this,
							click : this.onAuthErrorClickHandler
						}
					}]
				},
				items : [{
					xtype : 'grid',
					name : _('Devices'),
					ariaLabel : _('Devices'),
					ref : '../deviceGrid',
					height : 400,
					loadMask : true,
					store : store,
					viewConfig : {
						forceFit : true,
						deferEmptyText: false,
						emptyText: '<div class="emptytext">' + _('No devices connected to your account') + '</div>'
					},
					columns : [{
						dataIndex : 'devicetype',
						header : _('Device'),
						renderer : Ext.util.Format.htmlEncode
					},{
						dataIndex : 'useragent',
						header : _('User Agent'),
						renderer : Ext.util.Format.htmlEncode
					},{
						dataIndex : 'wipestatus',
						header : _('Provisioning Status'),
						renderer : Zarafa.plugins.mdm.ui.Renderers.provisioningStatus
					},{
						dataIndex : 'lastconnecttime',
						header : _('Last Connect'),
						renderer : Ext.util.Format.htmlEncode
					},{
						dataIndex : 'entryid',
						header : _('Device ID'),
						renderer : Ext.util.Format.htmlEncode
					},{
						dataIndex : 'deviceos',
						header : _('Device OS'),
						hidden : true,
						renderer : Ext.util.Format.htmlEncode
					},{
						dataIndex : 'devicefriendlyname',
						header : _('Device Info'),
						hidden : true,
						renderer : Ext.util.Format.htmlEncode
					},{
						id : 'impersonatinguser-column',
						dataIndex : 'impersonatinguser',
						header : _('Impersonated by'),
						hidden : true,
						renderer : Ext.util.Format.htmlEncode
					},{
						dataIndex : 'firstsynctime',
						header : _('First Sync time'),
						hidden : true,
						renderer : Ext.util.Format.htmlEncode
					}],
					buttons : [{
						text : _('Wipe Device'),
						ref : '../../../wipeBtn',
						handler : this.onWipeBtn,
						scope : this
					},{
						text : _('Full resync'),
						ref : '../../../resyncBtn',
						handler : this.onFullResync,
						scope : this
					},{
						text : _('Remove device'),
						ref : '../../../removeBtn',
						handler : this.onRemoveBtn,
						scope : this
					},{
						text : _('Refresh'),
						ref : '../../../refresh',
						handler : this.onRefresh,
						scope : this
					}],
					listeners   : {
						rowdblclick: this.onRowDblClick,
						rowclick: this.onRowClick,
						render: this.onGridRender,
						scope: this
					}
				}]
			}]
		});
		Zarafa.plugins.mdm.settings.MDMSettingsWidget.superclass.constructor.call(this, config);
	},

	/**
	 * initialize events for the panel.
	 * @private
	 */
	initEvents : function()
	{
		this.deviceGrid.mon(this.deviceGrid.getStore(),'beforeloadrecord', this.checkAuthentication, this, {buffer: 50});
		Zarafa.plugins.mdm.settings.MDMSettingsWidget.superclass.initEvents.apply(this, arguments);
	},

	/**
	 * Called when the grid is rendered.
	 * @private
	 */
	onGridRender : function()
	{
		this.deviceGrid.getStore().load();
	},

	/**
	 * This is a callback function for 'authenticate', 'resync', 'wipe', 'remove' actions and
	 * handler for 'beforeloadrecord' event of {@link Zarafa.plugins.mdm.data.MDMDeviceStore store}.
	 * It will show or hide "authentication red bar" button on the basis of response.
	 * This will be called from  {@link Zarafa.plugins.mdm.data.MDMResponseHandler MDMResponseHandler}
	 * @param {Boolean} isAuthenticated indicates whether a User is authenticated to grommunio-sync server or not.
	 */
	checkAuthentication : function(isAuthenticated)
	{
		this.authErrorBtn.setVisible(!isAuthenticated);
		if (isAuthenticated) {
			this.deviceGrid.getStore().load();
		}
	},

	/**
	 * Show or hide the impersonation column depending on store contents.
	 * @param {Ext.data.Store} store
	 * @private
	 */
	onDeviceStoreLoad: function (store)
	{
		var hasImpersonated = store.findBy(function (record) {
			return !Ext.isEmpty(record.get('impersonatinguser'));
		}) !== -1;
		this.setImpersonationColumnVisibility(hasImpersonated);
	},

	/**
	 * Helper to toggle the impersonation column.
	 * @param {Boolean} visible
	 * @private
	 */
	setImpersonationColumnVisibility: function (visible)
	{
		var grid = this.deviceGrid;
		if (!grid) {
			return;
		}

		var columnModel = grid.getColumnModel();
		var columnIndex = columnModel.getIndexById('impersonatinguser-column');
		if (columnIndex === -1) {
			return;
		}

		columnModel.setHidden(columnIndex, !visible);
	},

	/**
	 * Function which handles the click event on the "authentication red bar" button, displays
	 * a MessageBox for the user to enter password. The authenticate action is handled by
	 * the {@link #onPasswordSubmit} function.
	 */
	onAuthErrorClickHandler : function()
	{
		this.showPasswordMessageBox(_('Please enter your username and password'), this.onPasswordSubmit, 'authenticate');
	},

	/**
	 * General {@link Zarafa.common.dialogs.CustomMessageBox CustomMessageBox} for this component.
	 * @param {String} message message which needs to be shown in the messagebox.
	 * @param {Function} callbackFn callback function on click of buttons of this messagebox.
	 * @param {String} actionType action for which message dialog is needed to be shown.
	 */
	showPasswordMessageBox : function(message, callbackFn, actionType)
	{
		var customCfg = this.getCustomItemsAndButtons(actionType, this);
		new Zarafa.common.dialogs.CustomMessageBox({
			title:  _('Mobile Device Manager'),
			msg: message,
			buttonAlign: 'left',
			cls: 'k-show-more-details',
			width : 320,
			customItems: [{
				xtype: 'form',
				border: false,
				ref: '../inputForm',
				style: 'margin-top: 15px',
				items : customCfg.customItems
			}],
			customButtons: customCfg.customButtons,
			fn: callbackFn,
			mdmWidgetScope : this
		});
	},

	/**
	 * Helper function which will return custom items and custom buttons for {@link Zarafa.common.dialogs.CustomMessageBox CustomMessageBox}
	 * based on actiontype.
	 *
	 * @param {String} actionType action for which message dialog is needed to be shown.
	 * @param {Object} scope scope of the action.
	 * @return {Object} object which contains custom items and custom buttons.
	 */
	getCustomItemsAndButtons : function(actionType, scope)
	{
		var customCfg = {};
		var isAuthenticateAction = actionType === 'authenticate';
		var isSSO = container.getServerConfig().getAuthMethod() === 'oidc';
		var selectedRecord = scope?.deviceGrid?.getSelectionModel()?.getSelected();
		var isImpersonatedDevice = !Ext.isEmpty(selectedRecord?.get('impersonatinguser'));
		customCfg['customButtons'] = [{
			name: isAuthenticateAction ? 'ok' : 'yes',
			cls: 'zarafa-action',
			text: isAuthenticateAction ? _('Ok') : _('Yes'),
			keepOpenWindow: true
		}, {
			name: isAuthenticateAction ? 'cancel' : 'no',
			text: isAuthenticateAction ? _('Close') : _('No')
		}];

		var confirmWord = actionType === 'wipe' ? 'WIPE' : 'REMOVE';
		let customItems;
		if (isSSO && !isAuthenticateAction) {
			customItems = [{
				xtype: 'textfield',
				allowBlank: false,
				boxLabel : '',
				fieldLabel : String.format(_('Type {0} to confirm'), confirmWord),
				hideLabel : true,
				emptyText: String.format(_('Type {0} to confirm'), confirmWord),
				name: 'confirmField',
				ref: 'confirmField',
				validator: function(value) {
					return value === confirmWord ? true : String.format(_('Please type {0} to confirm'), confirmWord);
				}
			}];
		} else {
			customItems = [{
				xtype: 'textfield',
				allowBlank: false,
				inputType: 'password',
				boxLabel : '',
				fieldLabel : _('Password'),
				hideLabel : true,
				emptyText: _('Password'),
				name: 'passwordField',
				ref: 'passwordField'
			}];
		}

		var asVersion = selectedRecord?.get('asversion');
		if (actionType === 'wipe' && asVersion !== undefined && parseFloat(asVersion) >= 16.1) {
			if (isImpersonatedDevice) {
				customItems.push(
					{
						xtype: 'displayfield',
						hideLabel: true,
						style: 'margin-top: 8px',
						value: _('Impersonated device: only account-only remote wipe is available.')
					},
					{
						xtype: 'hidden',
						name: 'wipeType',
						value: 'accountonly'
					}
				);
			}
			else {
				customItems.push(
					{
						xtype: 'radiogroup',
						name: 'wipeType',
						ref: 'wipeType',
						columns: 1,
						hideLabel: true,
						style: 'margin-top: 8px',
						value: 'accountonly',
						items: [{
							xtype: 'radio',
							name: 'wipeType',
							inputValue: 'accountonly',
							boxLabel: _('Wipe only data related to this account'),
						},{
							xtype: 'radio',
							name: 'wipeType',
							inputValue: 'alldata',
							boxLabel: _('Wipe all data')
						}],
						listeners: {
							change: scope.onRadioChange,
							scope: this
						}
					}
				);
			}
		}

		// For 'authenticate' action username is required in messagebox.
		if (isAuthenticateAction) {
			customItems.unshift({
				xtype : 'textfield',
				allowBlank : false,
				emptyText: _('Username'),
				boxLabel : '',
				fieldLabel : _('Username'),
				hideLabel : true,
				name : 'userNameField',
				ref : 'userNameField'
			});
		}

		customCfg['customItems'] = customItems;
		return customCfg;
	},

	/**
	 * Function which handles the confirmation button in the "authentication" messagebox.
	 * Sends an authenticate request to PHP.
	 *
	 * @param {Ext.Button} button button from the messagebox
	 */
	onPasswordSubmit : function(button)
	{
		if (button.name === "ok") {
			var inputForm = this.dlgItemContainer.inputForm.getForm();
			if (!inputForm.isValid()) {
				return;
			}

			var inputValues = inputForm.getValues();
			container.getRequest().singleRequest(
				'pluginmdmmodule',
				'authenticate',
				{
					'username': inputValues.userNameField,
					'password': inputValues.passwordField
				},
				new Zarafa.plugins.mdm.data.MDMResponseHandler({
					successCallback : this.mdmWidgetScope.checkAuthentication,
					mdmWidgetScope : this.mdmWidgetScope
				})
			);

			this.close();
		}
	},

	/**
	 * Function which handles the click event on the "Wipe Device" button, displays
	 * a MessageBox for the user to confirm the wipe action. The wipe action is
	 * handled by the onWipeDevice function.
	 */
	onWipeBtn : function()
	{
		var isSSO = container.getServerConfig().getAuthMethod() === 'oidc';
		var record = this.deviceGrid.getSelectionModel().getSelected();
		var isImpersonatedDevice = record && !Ext.isEmpty(record.get('impersonatinguser'));
		var message = isImpersonatedDevice ?
			_('Do you really want to wipe your device?\nOnly account-only remote wipe is available for impersonated devices.\nEnter your password to confirm.') :
			(isSSO ?
				_('Do you really want to wipe your device?\n Type WIPE to confirm.') :
				_('Do you really want to wipe your device?\n Enter your password to confirm.'));
		this.showPasswordMessageBox(message, this.onWipeDevice, 'wipe');
	},

	/**
	 * Function which handles the confirmation button in the "wipe device" messagebox.
	 * Sends a wipe request to PHP for the selected device in the grid.
	 *
	 * @param {Ext.Button} button button from the messagebox
	 */
	onWipeDevice : function(button)
	{
		if (button.name === 'yes') {
			var inputForm = this.dlgItemContainer.inputForm.getForm();
			if (!inputForm.isValid()) {
				return;
			}

			var inputValues = inputForm.getValues();
			var mdmWidgetScope = this.mdmWidgetScope;
			var selectionModel = mdmWidgetScope.deviceGrid.getSelectionModel();
			var record = selectionModel.getSelected();
			if (record) {
				var isImpersonatedDevice = !Ext.isEmpty(record.get('impersonatinguser'));
				var wipeType = (inputValues.wipeType == 'accountonly' || isImpersonatedDevice) ?
					Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_PENDING_ACCOUNT_ONLY :
					Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_PENDING;
				var requestData = {
					'deviceid' : record.get('entryid'),
					'wipetype': wipeType
				};
				if (inputValues.passwordField) {
					requestData['password'] = inputValues.passwordField;
				}

				container.getRequest().singleRequest(
					'pluginmdmmodule',
					'wipe',
					requestData,
					new Zarafa.plugins.mdm.data.MDMResponseHandler({
						successCallback : mdmWidgetScope.refreshGrid,
						failureCallback : mdmWidgetScope.checkAuthentication,
						mdmWidgetScope : mdmWidgetScope
					})
				);
			}
			this.close();
		}
	},

	/**
	 * Function which handles the click event on the "Full resync" button, sends a
	 * full resync request to PHP.
	 */
	onFullResync : function()
	{
		var selectionModel = this.deviceGrid.getSelectionModel();
		var record = selectionModel.getSelected();
		if(record) {
			container.getRequest().singleRequest(
				'pluginmdmmodule',
				'resync',
				{ 'deviceid' : record.get('entryid') },
				new Zarafa.plugins.mdm.data.MDMResponseHandler({
					failureCallback : this.checkAuthentication,
					mdmWidgetScope : this
				})
			);
		}
	},
	/**
	 * Function which handles the click event on the "Remove Device" button, displays
	 * a MessageBox for the user to confirm the remove action. The remove action is
	 * handled by the onRemoveDevice function.
	 */
	onRemoveBtn : function()
	{
		var isSSO = container.getServerConfig().getAuthMethod() === 'oidc';
		var message = isSSO ?
			_('Do you really want to remove your device?\n Type REMOVE to confirm.') :
			_('Do you really want to remove your device?\n Enter your password to confirm.');
		this.showPasswordMessageBox(message, this.onRemoveDevice, 'remove');
	},

	/**
	 * Remove all state data for a device, essentially resyncing it. Also resets
	 * the wipe status of the device to 0.
	 *
	 * @param {Ext.Button} button button from the messagebox
	 */
	onRemoveDevice : function(button)
	{
		if (button.name === 'yes') {
			var inputForm = this.dlgItemContainer.inputForm.getForm();
			if (!inputForm.isValid()) {
				return;
			}

			var inputValues = inputForm.getValues();
			var mdmWidgetScope = this.mdmWidgetScope;
			var selectionModel = mdmWidgetScope.deviceGrid.getSelectionModel();
			var record = selectionModel.getSelected();
			if (record) {
				var requestData = { 'deviceid' : record.get('entryid') };
				if (inputValues.passwordField) {
					requestData['password'] = inputValues.passwordField;
				}
				container.getRequest().singleRequest(
					'pluginmdmmodule',
					'remove',
					requestData,
					new Zarafa.plugins.mdm.data.MDMResponseHandler({
						successCallback : mdmWidgetScope.removeDone.createDelegate(this, [record], true),
						failureCallback : mdmWidgetScope.checkAuthentication,
						mdmWidgetScope : mdmWidgetScope
					})
				);
			}
			this.close();
		}
	},

	/**
	 * Callback function triggers when device was successfully removed from the grommunio-sync server.
	 * we have to remove that device from {@link Zarafa.plugins.mdm.data.MDMDeviceStore store}.
	 * @param {Zarafa.plugins.mdm.data.MDMDeviceRecord} record {@link Zarafa.core.data.IPMRecord record} object
	 */
	removeDone : function(record)
	{
		record.getStore().remove(record);
	},

	/**
	 * Function which refreshes the store records from the server.
	 */
	onRefresh : function()
	{
		this.deviceGrid.getStore().load();
	},
	/**
	 * Function which refreshes the store records from the server after remote
	 * wipe of a device.
	 */
	refreshGrid : function()
	{
		this.mdmWidgetScope.deviceGrid.getStore().load();
	},

	/**
	 * Function is called if a row in the grid gets double clicked.
	 * Which is use to show a dialog with detail device information
	 * @param {Ext.grid.GridPanel} grid The Grid on which the user double-clicked
	 * @param {Number} rowIndex The Row number on which was double-clicked.
	 */
	onRowDblClick : function (grid, rowIndex)
	{
		var record = grid.getStore().getAt(rowIndex);
		record.opened = false;
		Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['mdm.dialog.mdmdevicecontentpanel'], undefined, {
			manager : Ext.WindowMgr,
			record : record
		});
	},

	/**
	 * Function is called if a row in the grid gets clicked.
	 * Which is use to disabled wipe button if wipe status is not available.
	 * @param {Ext.grid.GridPanel} grid The Grid on which the user clicked
	 * @param {Number} rowIndex The Row number on which was clicked.
	 */
	onRowClick : function (grid, rowIndex)
	{
		var record = grid.getStore().getAt(rowIndex);
		this.wipeBtn.setDisabled(!Ext.isDefined(record.get('wipestatus')));
	},

	/**
	 * Event handler which is fired when a {@link Ext.form.Radio} in the
	 * {@link Ext.form.RadioGroup} has been changed. This will set the value
	 * selected by user in settingsModel.
	 * @param {Ext.form.RadioGroup} group The radio group which fired the event
	 * @param {Ext.form.Radio} radio The radio which was enabled
	 * @private
	 */
	onRadioChange: function(group, radio)
	{
		if (this.model && (this.model.get(group.name) !== radio.inputValue)) {
			this.model.set(group.name, radio.inputValue);
		}
	}
});

Ext.reg('Zarafa.plugins.mdm.mdmsettingswidget', Zarafa.plugins.mdm.settings.MDMSettingsWidget);
Ext.namespace('Zarafa.plugins.mdm.settings');

/*
 * Settings category entry for MDM
 * @extends 
 */

/**
 * @class Zarafa.plugins.mdm.settings.MDMSettingsCategory
 * @extends Zarafa.settings.ui.SettingsCategory
 * @xtype Zarafa.plugins.mdmsettingscategory
 *
 * The mdm settings category entry.
 */
Zarafa.plugins.mdm.settings.MDMSettingsCategory = Ext.extend(Zarafa.settings.ui.SettingsCategory, {
	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config) {
		config = config || {};

		Ext.applyIf(config, {
			title : _('Mobile Devices'),
			iconCls : 'icon_mdm_settings',
			items : [{
				xtype : 'Zarafa.plugins.mdm.mdmsettingswidget'
			}]
		});

		Zarafa.plugins.mdm.settings.MDMSettingsCategory.superclass.constructor.call(this, config);
	}
});

Ext.reg('Zarafa.plugins.mdm.mdmsettingscategory', Zarafa.plugins.mdm.settings.MDMSettingsCategory);
Ext.namespace('Zarafa.plugins.mdm.dialogs');

/**
 * @class Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel
 * @extends Zarafa.core.ui.RecordContentPanel
 * @xtype mdmplugin.devicecontentpanel
 *
 * The content panel which is use to show device detail panel.
 */
Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel = Ext.extend(Zarafa.core.ui.RecordContentPanel, {

	/**
	 * @constructor
	 * @param config Configuration structure
	 */
	constructor: function (config)
	{
		config = config || {};
		Ext.applyIf(config, {
			xtype: 'mdmplugin.devicecontentpanel',
			modal: true,
			showModalWithoutParent: true,
			title: _(config.record.get('devicetype')),
			recordComponentPluginConfig: Ext.applyIf(config.recordComponentPluginConfig || {}, {
				allowWrite: true,
				useShadowStore: true
			}),
			layout: 'fit',
			stateful: false,
			showInfoMask : false,
			showLoadMask: false,
			width: 405,
			height: 420,
			items: [{
				xtype: 'mdmplugin.mdmdevicepanel',
				record: config.record,
				buttons: [{
					text: _('Ok'),
					handler: this.onOk,
					scope: this
				}]
			}]
		});

		Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel.superclass.constructor.call(this, config);
	},

	/**
	 * Action handler when the user presses the "Ok" button.
	 * This will close the panel.
	 */
	onOk: function ()
	{
		this.close();
	}
});

Ext.reg('mdmplugin.devicecontentpanel', Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel);Ext.namespace('Zarafa.plugins.mdm.dialogs');

/**
 * @class Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab
 * @extends Ext.form.FormPanel
 * @xtype mdmplugin.mdmdevicegeneraltab
 *
 * Details tab in the {@link Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel}
 */
Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab = Ext.extend(Ext.form.FormPanel, {

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor: function (config)
	{
		config = config || {};
		Ext.applyIf(config, {
			xtype: 'mdmplugin.mdmdevicegeneraltab',
			cls: 'tab-general',
			border: false,
			labelAlign: 'left',
			defaults: {
				border: false,
				xtype: 'panel',
				layout: 'form',
				labelWidth: 150,
				cls: 'mdm-device-panel'
			},
			plugins : ['zarafa.recordcomponentupdaterplugin'],
			items: [
				this.createDeviceInfoPanel(config),
				this.createFolderInfoPanel()
			]
		});

		Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab.superclass.constructor.call(this, config);
	},
	/**
	 * Function which is use to create device status panel
	 * @param {Object} config Configuration object
	 * @return {Object} Configuration object for the panel which shows device status properties
	 * @private
	 */
	createDeviceInfoPanel: function (config)
	{
		return {
			cls: 'mdm-device-panel',
			defaultType: 'displayfield',
			defaults: {
				disabled: true
			},
			items: [{
				cls: 'mdm-display-name',
				value: _(config.record.get('devicetype')),
				htmlEncode: true,
				disabled: false,
				hideLabel: true
			}, {
				fieldLabel: _('Connected since'),
				value: String.format('{0}', new Date(config.record.get('firstsynctime')).format(_('d F Y')))
			}, {
				fieldLabel: _('Last updated'),
				value: String.format(_('{0}'), new Date(config.record.get('lastupdatetime')).format(_('d F Y, H:i')))
			}, {
				fieldLabel: _('Last connect'),
				value: String.format('{0}', new Date(config.record.get('lastconnecttime')).format(_('d F Y, H:i')))

			}, {
				fieldLabel: _('Status'),
				listeners: {
					afterrender: this.onAfterRenderStatus,
					scope: this
				}
			}, {
				fieldLabel: _('Impersonated by'),
				name: 'impersonatinguser',
				hidden: true
			}]
		};
	},
	/**
	 * Function which is use to create folders synchronization panel
	 * @return {Object} Configuration object for the panel which shows folders properties
	 * @private
	 */
	createFolderInfoPanel: function ()
	{
		return {
			cls: 'mdm-device-panel mdm-field-sep',
			defaultType: 'displayfield',
			items: [{
				cls: 'mdm-display-name',
				value: _('Synchronize'),
				htmlEncode: true,
				hideLabel: true
			}, {
				fieldLabel: _('Folders'),
				disabled: true,
				name: 'synchronizedfolders'
			}, {
				xtype: 'fieldset',
				layout: 'form',
				labelWidth: 140,
				cls: 'mdm-synchronize-panel',
				defaultType: 'displayfield',
				defaults: {
					labelSeparator: '',
					value: '0',
					disabled: true
				},
				items: [{
					fieldLabel: _('Email'),
					name: 'emailsfolder'
				}, {
					fieldLabel: _('Calendar'),
					name: 'calendarsfolder'
				}, {
					fieldLabel: _('Contacts'),
					name: 'contactsfolder'
				}, {
					fieldLabel: _('Notes'),
					name: 'notesfolder'
				}, {
					fieldLabel: _('Tasks'),
					name: 'tasksfolder'
				},
				// this.createSharedFolderInfoPanel()
				]
			}]
		};
	},

	/**
	 * Function which is use to create shared folders panel
	 * @returns {Object} Configuration object for the panel which shows folders properties
	 */
	createSharedFolderInfoPanel: function ()
	{
		return {
			xtype: 'panel',
			border: false,
			cls: 'mdm-synchronize-shared-panel',
			height: 50,
			disabled: false,
			layout: {
				type: 'hbox',
				align: 'stretch',
				pack: 'start'
			},
			items: [{
				layout: 'form',
				border: false,
				items: [{
					xtype: 'displayfield',
					fieldLabel: _('Shared Folders'),
					disabled: true,
					name : 'sharedfolders'
				}],
				flex: 1
			}, {
				xtype: 'button',
				text: _('Manage Shared Folders'),
				cls: 'mdm-managesharedfolder-button',
				listeners: {
					click: this.onClickManageSharedFolder,
					scope: this
				}
			}]
		};
	},

	/**
	 * Updates the panel by loading data from the record into the header template, and
	 * loading the body html into the embedded iframe.
	 *
	 * @param {Zarafa.core.data.IPMRecord} record The record update the panel with.
	 * @param {Boolean} contentReset force the component to perform a full update of the data.
	 */
	update : function(record, contentReset)
	{
		this.getForm().loadRecord(record);
		this.toggleImpersonatedField(record);
	},

	/**
	 * Function which handles the after render event of status field.
	 * Which is use to set the display name for the given Provisioning Status into given field
	 * @param {Ext.form.TextField} statusField text field
	 */
	onAfterRenderStatus: function (statusField)
	{
		var status = parseInt(this.record.get("wipestatus"));
		statusField.setValue(Zarafa.plugins.mdm.data.ProvisioningStatus.getDisplayName(status));
	},

	/**
	 * Function which handles the click event of manage shared folder button.
	 * It will open {@link Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel dialog}
	 */
	onClickManageSharedFolder: function ()
	{
		this.dialog.record.opened = false;
		Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['mdm.dialog.mdmmanagesharedfoldercontentpanel'], undefined, {
			manager: Ext.WindowMgr,
			record: this.dialog.record
		});
	},

	/**
	 * Reveal the impersonation field only when a value is available.
	 * @param {Zarafa.core.data.IPMRecord} record
	 * @private
	 */
	toggleImpersonatedField: function (record)
	{
		var field = this.getForm().findField('impersonatinguser');
		if (!field) {
			return;
		}

		var applyVisibility = function ()
		{
			var value = record.get('impersonatinguser');
			var hasValue = !Ext.isEmpty(value);
			var el = field.getEl ? field.getEl() : null;
			var container = el ? el.up('.x-form-item') : null;

			field.setValue(hasValue ? value : '');
			if (hasValue) {
				field.show();
			} else {
				field.hide();
			}
			if (container) {
				container[hasValue ? 'show' : 'hide']();
			}
		};

		if (field.rendered) {
			applyVisibility();
		} else {
			field.on('afterrender', applyVisibility, this, { single: true });
		}
	}
});

Ext.reg('mdmplugin.mdmdevicegeneraltab', Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab);
Ext.namespace('Zarafa.plugins.mdm.dialogs');

/**
 * @class Zarafa.plugins.mdm.dialogs.MDMDevicePanel
 * @extends Ext.Panel
 * @xtype mdmplugin.mdmdevicepanel
 *
 * This class is used as wrapper class for all tabs, individual tab will have its own class.
 */
Zarafa.plugins.mdm.dialogs.MDMDevicePanel = Ext.extend(Ext.Panel, {

	/**
	 * @constructor
	 * @param {Object} config configuration object.
	 */
	constructor: function (config)
	{
		config = config || {};
		Ext.applyIf(config, {
			xtype: 'mdmplugin.mdmdevicepanel',
			cls: 'mdm-devicepanel tabpanel-container',
			border: false,
			deferredRender: false,
			items: [{
				xtype: 'tabpanel',
				border: false,
				activeTab: 0,
				layoutOnTabChange: true,
				items: [{
					xtype: 'mdmplugin.mdmdevicegeneraltab',
					record: config.record,
					title: _('General'),
				}, {
					xtype: 'mdmplugin.mdmdevicedetailstab',
					record: config.record,
					title: _('Details'),
				}]
			}]
		});

		Zarafa.plugins.mdm.dialogs.MDMDevicePanel.superclass.constructor.call(this, config);
	}
});

Ext.reg('mdmplugin.mdmdevicepanel', Zarafa.plugins.mdm.dialogs.MDMDevicePanel);
Ext.namespace('Zarafa.plugins.mdm.dialogs');

/**
 * @class Zarafa.plugins.mdm.dialogs.MDMDeviceDetailsTab
 * @extends Ext.form.FormPanel
 * @xtype mdmplugin.mdmdevicedetailstab
 *
 * General tab in the {@link Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel}
 */
Zarafa.plugins.mdm.dialogs.MDMDeviceDetailsTab = Ext.extend(Ext.form.FormPanel, {

	/**
	 * @constructor
	 * @param {Object} config
	 */
	constructor: function (config)
	{
		config = config || {};
		Ext.applyIf(config, {
			xtype: 'mdmplugin.mdmdevicedetailstab',
			cls: 'tab-device',
			border: false,
			labelAlign: 'left',
			defaults: {
				border: false,
				xtype: 'panel',
				layout: 'form',
				labelWidth: 150
			},
			plugins : ['zarafa.recordcomponentupdaterplugin'],
			items: [
				this.createDeviceInfoPanel(),
				this.createVersionInfoPanel()
			]
		});

		Zarafa.plugins.mdm.dialogs.MDMDeviceDetailsTab.superclass.constructor.call(this, config);
	},
	/**
	 * Function which is use to create device information panel
	 * @return {Object} Configuration object for the panel which shows device properties
	 * @private
	 */
	createDeviceInfoPanel: function ()
	{
		return {
			cls : 'mdm-device-panel',
			defaultType: 'displayfield',
			defaults: {
				disabled: true
			},
			items: [{
				cls: 'mdm-display-name',
				value: _('Device'),
				hideLabel: true,
				disabled: false
			}, {
				fieldLabel: _('Type'),
				name: 'devicetype'
			}, {
				fieldLabel: _('Operating System'),
				name: 'deviceos'
			}, {
				fieldLabel: _('ID'),
				name: 'entryid'
			}, {
				fieldLabel: _('User Agent'),
				name: 'useragent'
			}]
		};
	},

	/**
	 * Function which is use to create version information panel.
	 * @return {Object} Configuration object for the panel which shows versions properties
	 * @private
	 */
	createVersionInfoPanel: function ()
	{
		return {
			defaultType: 'displayfield',
			defaults: {
				disabled: true
			},
			cls : 'mdm-device-panel mdm-field-sep',
			items: [{
				cls: 'mdm-display-name',
				value: _('MDM Plugin'),
				htmlEncode: true,
				hideLabel: true,
				disabled: false
			}, {
				fieldLabel: _('Active Sync Version'),
				name: 'asversion'
			}, {
				fieldLabel: _('grommunio-sync Version'),
				value: container.getSettingsModel().get('zarafa/v1/plugins/mdm/zpush-server-version', true)
			}, {
				fieldLabel: _('Policy name'),
				name: 'policyname'
			}]
		};
	},

	/**
	 * Updates the panel by loading data from the record.
	 *
	 * @param {Zarafa.core.data.IPMRecord} record The record update the panel with.
	 * @param {Boolean} contentReset force the component to perform a full update of the data.
	 */
	update : function(record, contentReset)
	{
		this.getForm().loadRecord(record);
	}
});

Ext.reg('mdmplugin.mdmdevicedetailstab', Zarafa.plugins.mdm.dialogs.MDMDeviceDetailsTab);
Ext.namespace('Zarafa.plugins.mdm.dialogs');

/**
 * @class Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel
 * @extends Zarafa.core.ui.RecordContentPanel
 * @xtype zarafa.managesharedfoldercontentpanel
 *
 * This will display a {@link Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel contentpanel}
 * to show {@link Zarafa.core.data.IPFRecord folders} which are shared with device.
 */
Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel = Ext.extend(Zarafa.core.ui.RecordContentPanel, {

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

		Ext.applyIf(config,
			{
			xtype: 'mdm.managesharedfoldercontentpanel',
			layout: 'fit',
			title: _('Manage Shared Folders'),
			modal: true,
			stateful: false,
			showInfoMask : false,
			showLoadMask: false,
			closeOnSave: true,
			width: 300,
			height: 350,
			items: [{
				xtype: 'mdm.managesharedfolderpanel'
			}]
		});

		Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel.superclass.constructor.call(this, config);
	}
});

Ext.reg('mdm.managesharedfoldercontentpanel', Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel);
Ext.namespace('Zarafa.plugins.mdm.dialogs');

/**
 * @class Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel
 * @extends Ext.Panel
 * @xtype mdm.managesharedfolderpanel
 *
 * Panel for users to show the {@link Zarafa.core.data.IPFRecord folders} which are shared with device
 */
Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel = Ext.extend(Ext.Panel, {

	/**
	 * @cfg {Zarafa.plugins.mdm.data.MDMDeviceFolderStore} store contains {@link Zarafa.plugins.mdm.data.MDMDeviceFolderRecord folders} which
	 * is going to shared with device.
	 */
	sharedFoldersStore : undefined,

	/**
	 * @cfg {Zarafa.core.data.IPMRecord} record The mail which
	 * is being update by this panel.
	 */
	record: null,

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

		Ext.applyIf(config, {
			xtype: 'mdm.managesharedfolderpanel',
			layout: {
				type: 'fit',
				align: 'stretch'
			},
			border: false,
			header: false,
			items: [
				this.createTreePanel()
			],
			buttonAlign: 'right',
			plugins : ['zarafa.recordcomponentupdaterplugin'],
			buttons: [{
				text: _('Apply'),
				handler: this.onApply,
				cls: 'zarafa-action',
				scope: this
			}, {
				text: _('Cancel'),
				handler: this.onCancel,
				scope: this
			}]
		});

		Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel.superclass.constructor.call(this, config);
	},

	/**
	 * Creates a {@link Zarafa.hierarchy.ui.Tree treepanel}
	 * which contains all the {@link Zarafa.hierarchy.data.MAPIFolderRecord folders}
	 * on which search get perform.
	 * @return {Object} Configuration object for the tree panel.
	 * @private
	 */
	createTreePanel: function ()
	{
		return {
			xtype: 'panel',
			layout : 'form',
			defaults: {
				cls : 'mdm-create-tree-panel-item'
			},
			border: false,
			flex: 1,
			items: [{
				xtype: 'displayfield',
				hideLabel : true,
				value: _('Select folders to sync to your device from the list below. To add additional mailboxes to the list, open them in grommunio Web first.')
			}, {
				xtype: 'mdm.hierarchytree',
				autoScroll : true,
				hideOwnTree : true,
				nodeConfig : {
					checked : false
				},
				multiSelect: true,
				hideShowAllFolders: true,
				border: true,
				treeSorter: true,
				bbarConfig: {
					hidden: true
				},
				enableDD: false,
				anchor: '100% 90%',
				ref: '../hierarchyTree'
			}]
		};
	},

	/**
	 * Initialize the events
	 * @private
	 */
	initEvents: function ()
	{
		Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel.superclass.initEvents.apply(this, arguments);
		this.mon(this.hierarchyTree, {
			expandnode: this.onTreeNodeExpand,
			checkchange: this.onTreeNodeCheckChange,
			click: this.onTreeNodeClick,
			scope: this
		});
	},

	/**
	 * Fired when the {@link Zarafa.hierarchy.ui.Tree Tree} fires the {@link Zarafa.hierarchy.ui.Tree#nodeexpand nodeexpand}
	 * event.
	 * It will update the hierarchy by selecting child node if it will shared with device.
	 * @private
	 */
	onTreeNodeExpand: function ()
	{
		if (!this.record.isOpened()) {
			return false;
		}
		this.updateHierarchy();
	},

	/**
	 * Updates the panel by loading data from the record.
	 *
	 * @param {Zarafa.core.data.IPMRecord} record The record update the panel with.
	 * @param {Boolean} contentReset force the component to perform a full update of the data.
	 */
	update : function(record, contentReset)
	{
		this.record = record;
		this.sharedFoldersStore = record.getSubStore('sharedfolders');
		this.updateHierarchy();
	},

	/**
	 * Function will try to select those {@link Ext.tree.TreeNode TreeNode} in
	 * {@link Zarafa.hierarchy.ui.Tree Tree} which was shared with respective device.
	 */
	updateHierarchy : function ()
	{
		var folders = this.sharedFoldersStore.getRange();
		folders.forEach(function (folder) {
			var node = this.hierarchyTree.getNodeById(folder.get('entryid'));
			if (Ext.isDefined(node)) {
				if (node.hasChildNodes()) {
					node.expand();
				}
				node.isNodeSelected = true;
				node.getUI().toggleCheck(true);
			}
		}, this);
	},

	/**
	 * Called when a treeNode is click in tree. The corresponding folder is added to,
	 * or removed from the active folder list depending on the state of the check box.
	 * @param {Ext.tree.TreeNode} treeNode tree node.
	 * @private
	 */
	onTreeNodeClick : function(treeNode)
	{
		var treeNodeui = treeNode.getUI();
		if (treeNodeui.checkbox.checked && treeNode.isNodeSelected) {
			treeNodeui.toggleCheck(false);
			return false;
		}
		treeNode.isNodeSelected = true;
		this.sharedFoldersStore.addFolder(treeNode.getFolder());
		treeNodeui.toggleCheck(true);
	},

	/**
	 * Called when a check box in the calendar tree is toggled. The corresponding folder is added to,
	 * or removed from the active folder list depending on the state of the check box.
	 * @param {Ext.tree.TreeNode} node tree node.
	 * @param {Boolean} checked indicates whether the box is checked.
	 * @private
	 */
	onTreeNodeCheckChange : function(node, checked)
	{
		if (!checked) {
			node.isNodeSelected = false;
			this.sharedFoldersStore.removeFolder(node.getFolder());
		} else if (checked && !node.isNodeSelected) {
			this.onTreeNodeClick(node);
		}
	},

	/**
	 * Action handler when the user presses the "Apply" button.
	 * This save the record and close the panel.
	 */
	onApply : function ()
	{
		if (this.record.dirty) {
			this.record.save();
		} else {
			this.dialog.close();
		}
	},

	/**
	 * Action handler when the user presses the "Cancel" button.
	 * This will close the panel.
	 */
	onCancel: function ()
	{
		this.dialog.close();
	}
});

Ext.reg('mdm.managesharedfolderpanel', Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel);
Ext.namespace('Zarafa.plugins.mdm.ui');

/**
 * @class Zarafa.plugins.mdm.ui.Renderers
 * Methods of this object can be used as renderers for grid panels, to render
 * cells in custom format according to data type
 * @singleton
 */
Zarafa.plugins.mdm.ui.Renderers = {

	/**
	 * Render the Provisioning Status.
	 *
	 * @param {Object} value The data value for the cell.
	 * @param {Object} p An object with metadata
	 * @param {Ext.data.record} record The {Ext.data.Record} from which the data was extracted.
	 * @return {String} The formatted string
	 */
	provisioningStatus : function(value, p, record)
	{
		return Zarafa.plugins.mdm.data.ProvisioningStatus.getDisplayName(parseInt(value));
	}
};
Ext.namespace('Zarafa.plugins.mdm.ui');


/**
 * @class Zarafa.plugins.mdm.ui.MDMFolderNodeUI
 * @extends Zarafa.hierarchy.ui.FolderNodeUI
 *
 * {@link Zarafa.hierarchy.ui.FolderNodeUI} has limitation that it can add
 * (@link Ext.form.Checkbox check box} preceded to calendar item only.
 * So, It will add (@link Ext.form.Checkbox check box} preceded to all context items.
 */
Zarafa.plugins.mdm.ui.MDMFolderNodeUI = Ext.extend(Zarafa.hierarchy.ui.FolderNodeUI, {

	/**
	 * Function will render {@link Zarafa.hierarchy.ui.FolderNode FolderNode} based on modified template for
	 * our custom needs.
	 * @param {Zarafa.hierarchy.ui.FolderNode} node tree node.
	 * @param {Object} config config object of {@link Zarafa.hierarchy.ui.FolderNode FolderNode}.
	 * @param {Ext.Element} targetNode element in which {@link Zarafa.hierarchy.ui.FolderNode FolderNode} will be rendered.
	 * @param {Boolean} bulkRender
	 */
	renderElements : function(node, config, targetNode, bulkRender)
	{
		// add some indent caching, this helps performance when rendering a large tree
		this.indentMarkup = node.parentNode ? node.parentNode.ui.getChildIndent() : '';

		var scheme;
		var cb = Ext.isBoolean(config.checked) && !(node instanceof Zarafa.hierarchy.ui.RootFolderNode);
		var isCalenderNode = config.folder.isCalendarFolder();
		var calendarSVGIcon = '';

		if (isCalenderNode) {
			var calendarContextModel = node.getOwnerTree().model;

			// We started providing color choosing facility to all the calendar tree-nodes.
			// CalendarContextModel is responsible for this facility.
			// There is no CalendarContextModel available in the case where that particular
			// calendar-tree-node doesn't belongs to MultiSelectHierarchyTree.
			// So, simply made that ContextModel available to current HierarchyTree.
			if (!calendarContextModel) {
				var calendarContext = container.getContextByName('calendar');
				calendarContextModel = calendarContext.getModel();
				node.getOwnerTree().model = calendarContextModel;
			}

			scheme = calendarContextModel.getColorScheme(config.folder.get('entryid'));

			// Get the scheme base only if we are able to get scheme successfully,
			// otherwise let it be undefined instead of a JS fatal error.
			if(scheme && scheme.base) {
				calendarSVGIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" style="color:'+scheme.base+';position:relative;top:5px;left:-1px;"><path style="fill:currentColor" d="M17.75 3A3.25 3.25 0 0 1 21 6.25v11.5A3.25 3.25 0 0 1 17.75 21H6.25A3.25 3.25 0 0 1 3 17.75V6.25A3.25 3.25 0 0 1 6.25 3h11.5Zm1.75 5.5h-15v9.25c0 .966.784 1.75 1.75 1.75h11.5a1.75 1.75 0 0 0 1.75-1.75V8.5Zm-11.75 6a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5Zm4.25 0a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5Zm-4.25-4a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5Zm4.25 0a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5Zm4.25 0a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5Zm1.5-6H6.25A1.75 1.75 0 0 0 4.5 6.25V7h15v-.75a1.75 1.75 0 0 0-1.75-1.75Z"/></svg>';
			}
		}

		var checkboxMarkup = '';
		if (cb) {
			var checkboxId = Ext.id(null, 'zarafa-mdm-node-cb-');
			checkboxMarkup = '<input class="x-tree-node-cb zarafa-hierarchy-node-cb" type="checkbox" id="' + checkboxId + '" name="' + checkboxId + '"' + (config.checked ? ' checked="checked"' : '') + ' />';
		}

		var icon = '<img src="' + (config.icon || this.emptyIcon) + '" class="x-tree-node-icon" unselectable="on" alt="" />',
		nel,
		href = config.href ? config.href : Ext.isGecko ? "" : "#",
		buf = '<li class="x-tree-node">' +
				'<div ext:tree-node-id="' + node.id + '" class="x-tree-node-el x-tree-node-leaf x-unselectable zarafa-hierarchy-node" unselectable="on">' +
					// indent space
					'<span class="x-tree-node-indent" aria-hidden="true">' + this.indentMarkup + "</span>" +
					// expand icon
					'<img src="' + this.emptyIcon + '" class="x-tree-ec-icon x-tree-elbow" alt="" aria-hidden="true" />' +
					// checkbox
					checkboxMarkup +
					// node icon
					(isCalenderNode ? calendarSVGIcon : icon) +
					// node element (this.elNode)
					'<a hidefocus="on" class="x-tree-node-anchor zarafa-hierarchy-node-anchor" ' +
						'href="' + href + '" tabIndex="0" ' +
						(config.hrefTarget ? ' target="' + config.hrefTarget + '"' : "") + ">" +
							// hierarchy node text (this.textNode)
							'<span unselectable="on">' + (node.tpl ? node.tpl.apply(config) : node.text) + '</span>' +
							// counter node (this.counterNode)
							'<span class="zarafa-hierarchy-node-counter" unselectable="on"></span>' +
							'<span class="zarafa-hierarchy-node-owner" unselectable="on"></span>'+
					"</a>" +
				"</div>" +
				'<ul class="x-tree-node-ct" style="display:none;"></ul>' +
			"</li>";

		if (bulkRender !== true && node.nextSibling && (nel = node.nextSibling.ui.getEl())) {
			this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
		}else{
			this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
		}

		this.elNode = this.wrap.childNodes[0];
		this.ctNode = this.wrap.childNodes[1];
		var cs = this.elNode.childNodes;
		this.indentNode = cs[0];
		this.ecNode = cs[1];
		this.iconNode = cs[2];
		var index = 3;
		if (cb) {
			this.checkbox = cs[2];
			this.iconNode = cs[3];

			// Get child elements of calendar icon which is used to register in drag and drop manager.
			var groupContainerNode = this.iconNode.childNodes[0];
			if (Ext.isDefined(groupContainerNode)) {
				var groupNode = groupContainerNode.childNodes[0];
				var rectNode = groupNode.childNodes[0];
				var pathNode = groupContainerNode.childNodes[1];
				this.calendarSVGIconChilds = [rectNode, pathNode];
			}
			index++;
		}
		this.anchor = cs[index];
		this.textNode = cs[index].firstChild;

		this.counterNode = cs[index].firstChild.nextSibling;
		this.folderOwnerNode = this.counterNode.nextSibling;
		// Apply some optional CSS classes
		var elNode = Ext.get(this.elNode);
		var iconNode = Ext.get(this.iconNode);
		var containerNode = Ext.get(this.wrap);
		var textNode = Ext.get(this.textNode);
		if (isCalenderNode) {
			textNode.addClass('zarafa-hierarchy-node-color');
		}
		if (!Ext.isEmpty(config.cls)) {
			elNode.addClass(config.cls);
		}

		if (config.icon) {
			iconNode.addClass('x-tree-node-inline-icon');
		}

		if (config.iconCls) {
			iconNode.addClass(config.iconCls);
		}

		if (!Ext.isEmpty(config.containerCls)) {
			containerNode.addClass(config.containerCls);
		}

		this.updateCounter(node);
		this.showFolderOwner(node);
	}
});
Ext.namespace('Zarafa.plugins.mdm.ui');

/**
 * @class Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel
 * @extends Zarafa.hierarchy.ui.Tree
 * @xtype mdm.hierarchytree
 *
 * MDMHierarchyTreePanel for hierarchy list in the
 * {@link Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel manageSharedFolderPanel}.
 */
Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel = Ext.extend(Zarafa.hierarchy.ui.Tree, {

	/**
	 * @constructor
	 * @param {Object} config Configuration object
	 */
	constructor : function(config)
	{
		Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel.superclass.constructor.call(this, config);
	},

	/**
	 * Function will initialize {@link Zarafa.hierarchy.ui.Tree Tree} and creates a
	 * {@link Zarafa.common.ui.LoadMask} if {@link Zarafa.hierarchy.ui.Tree Tree} is instantiated as full tree.
	 * @protected
	 */
	initComponent : function()
	{
		// Initialize the loader
		if (!this.loader) {
			this.loader = new Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader({
				tree : this,
				store : this.store,
				nodeConfig : this.nodeConfig,
				deferredLoading : this.deferredLoading
			});
		}

		// call parent
		Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel.superclass.initComponent.apply(this, arguments);
	},

	/**
	 * The filter which is applied for filtering nodes from the
	 * {@link Zarafa.hierarchy.ui.Tree HierarchyTree}.
	 * It will hide own user store.
	 *
	 * @param {Object} folder the folder to filter
	 * @return {Boolean} true to accept the folder
	 */
	nodeFilter: function (folder)
	{
		var hide = Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel.superclass.nodeFilter.apply(this, arguments);

		if(hide && this.hideOwnTree) {
			hide = !folder.getMAPIStore().isDefaultStore();
		}

		return hide;
	}
});

Ext.reg('mdm.hierarchytree', Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel);
