'use strict';

/*
 *+------------------------------------------------------------------------+
 *| Licensed Materials - Property of IBM
 *| IBM Cognos Products: BI Dashboard
 *| (C) Copyright IBM Corp. 2016, 2017
 *|
 *| US Government Users Restricted Rights - Use, duplication or disclosure
 *| restricted by GSA ADP Schedule Contract with IBM Corp.
 *+------------------------------------------------------------------------+
 */

/**
 * A utility class for RAVE2 related definition support
 */
define(['../lib/@waca/core-client/js/core-client/ui/core/Class', 'underscore'], function (Class, _) {

	var Rave2RenderHelper = Class.extend({

		_raveView: null,

		init: function init(options) {
			this._raveView = options.raveView;
		},

		applyProps: function applyProps() {
			this._applyNativePros();
			this._applyRAVE2VisProps();
		},

		_applyNativePros: function _applyNativePros() {
			if (!this._raveView || !this._raveView.visModel) {
				return;
			}
			this._setOrdinalSlotDomain();
		},

		/**
   * Apply for RAVE2 Visualization properties
   */
		_applyRAVE2VisProps: function _applyRAVE2VisProps() {
			var oRaveVis = this._raveView._rave2Vis;
			var aProperties = this.getPropertiesToSet();
			aProperties.forEach(function (prop) {
				oRaveVis.property(prop.id, prop.value);
			});
		},

		/**
  	Returns an array of properties to set
  **/
		getPropertiesToSet: function getPropertiesToSet() {
			if (!this._raveView || !this._raveView._rave2Vis) {
				return [];
			}
			var aProperties = [];
			_.each(this._raveView.visModel.properties.getModels(), function (prop) {
				if (prop.mapValuesFunction) {
					// Handler will return an array of properties to set
					// TODO: change to pass _raveView instead to remove the 3rd arguments for better legacy function integrity
					var aProps = prop.mapValuesFunction(prop, this._raveView.visModel, {
						'maxDomainValue': this._maxDomainValue
					});
					if (aProps) {
						aProps.forEach(function (prop) {
							aProperties.push(prop);
						});
					}
				} else {
					if (prop.id !== 'colorPalette') {
						if (prop.value !== undefined && prop.value !== null) {
							aProperties.push({
								'id': prop.id,
								'value': prop.value
							});
						}
					}
				}
			}.bind(this));

			return aProperties;
		},

		getVisId: function getVisId() {
			return this._raveView.visModel.definition.id;
		},

		/**
   * This function sets the min and max value of a numeric data slot's value range, via which
   * it implements the vis property setting for 'maintain axis scales.' Therefore it should only
   * apply to those visualization that declares to support such property
   *
   * @param {array} aDomainRange value range,  [<minValue>, <maxValue>]
   * */
		_setOrdinalSlotDomain: function _setOrdinalSlotDomain() {
			if (!this.isDomainInformationNeededForVisuzalition()) {
				this._maxDomainValue = null;
				return;
			} else {
				_.each(this._raveView.visModel.getDataSlots(), function (oSlot) {
					if (this.isDomainSupportedForSlot(oSlot)) {
						var aDomain = this.getDomainForSlot(oSlot);

						var oCurDataSlot = this.getRAVE2DataSet().slot(oSlot.definition.id);
						// For repeated slots the id of the repeated slot won't be in the rave2 data set
						if (!oCurDataSlot) {
							return;
						}
						var oEntry = oCurDataSlot.entry();
						if (oEntry) {
							oEntry.domain(aDomain);
						}
					}
				}.bind(this));
			}
		},

		isDomainInformationNeededForVisuzalition: function isDomainInformationNeededForVisuzalition() {
			var oMaintainAxisScales_propValue = this._raveView.visModel.getPropertyById('maintainAxisScales');
			if (oMaintainAxisScales_propValue === null || oMaintainAxisScales_propValue.getValue() !== true) {
				return false;
			}

			return true;
		},

		isDomainSupportedForSlot: function isDomainSupportedForSlot(oSlot) {
			return oSlot.getDefinition().type === 'ordinal';
		},

		/**
   * RAVE2 Vis instance could have multiple types of data models. One data model could have multiple data sets.
   * However, if the current RAVE2 Vis has only one data model, and the data model has only one data set, we
   * can use the only dataset as the default data set. This is to solve the problem that different type of RAVE2 Vis
   * has different data set ID. This should work for absolutely most of the configuration/bundles dashboard support.
   * For example, Dial bundle has only one dataModel, SimpleDialModel and this SimpleDialModel has one dataset
   * with id 'DialData'. There is an exception that Line&Column composite chart has one model with ID 'TabularModel'
   * while it has two dataSets, one with ID 'ColumnData', one with ID 'LineData', RAVE2 team is working on to let
   * RAVE2 composite to support only one dataSet.
   **/
		getRAVE2DataSet: function getRAVE2DataSet() {
			//Should we cache dataset?
			if (this._raveView._rave2Vis) {
				var oDataModel = this.getDefaultDataModel();
				if (oDataModel) {
					var aDataSets = oDataModel.dataSets();
					if (aDataSets && aDataSets.length >= 1) {
						return this._raveView._visDataModel.dataset(aDataSets[0].id());
					}
				}
			}
			return null;
		},

		getDefaultDataModel: function getDefaultDataModel() {
			//Should we cache the data model?
			if (this._raveView._rave2Vis) {
				var aDataModels = this._raveView._rave2Vis.getDataModels();
				if (aDataModels && aDataModels.length >= 1) {
					return aDataModels[0];
				}
				return null;
			}
		},

		getDomainForSlot: function getDomainForSlot(oSlot) {
			var visModel = this._raveView.visModel;
			var queryResults = visModel.getQueryResults();
			if (visModel.definition.useOrdinalNamesAsCategoryValues) {
				return [queryResults.minSeriesRange, queryResults.maxSeriesRange];
			}

			if (oSlot.getMapping() && oSlot.definition.type === 'ordinal') {
				var specField = this.getFactSpecField(oSlot, queryResults.getFieldValues(oSlot.getId()));
				var max = specField.min === specField.max ? specField.min + 1 : specField.max;

				// Keep track of the maximum domain value.  Needed for dial chart where we have to set the maxValue property
				this._maxDomainValue = this._maxDomainValue && this._maxDomainValue > max ? this._maxDomainValue : max;

				return [specField.min, max];
			}

			return [];
		},

		/*<Start>: Functions below are mainly from existing ravespecpropertyhelper.js, which was developed for RAVE1 spec based rendering
   * we will need to make the following functions sharable and reusable, between ravespecpropertyhelper.js and this RAVE2 render helper
   * */
		getFactSpecField: function getFactSpecField(slot, range) {
			//Trim value range to user-specified settings
			this._trimXAndYAxisRange(slot.getId(), range);

			//TODO HACK: RAVE complains when there's a 0 value when plotting on a logarithmic scale
			var slotAndAxisScale = slot.getId() === 'yAxis' && this.yAxisScale === 'log' || slot.getId() === 'xAxis' && this.xAxisScale === 'log';
			var rangeMin = range ? range.min : 0;
			rangeMin = rangeMin === 0 && slotAndAxisScale ? 0.01 : rangeMin;
			var rangeMax = range ? range.max : 0;
			/*
    * If min and max are equal, Rave's vis renders with 0 at the mid point of the chart and animation is
    * extremely strange. So, make max = min + 1
    */
			rangeMax = rangeMax === rangeMin ? rangeMin + 1 : rangeMax;

			return {
				format: {
					scientific: 'never',
					fitMethod: 'none'
				},
				id: slot.getId(),
				label: slot.getLabel(),
				min: rangeMin,
				max: rangeMax
			};
		},

		_trimYAxisRange: function _trimYAxisRange(specField) {
			if (this.yMin !== undefined) {
				specField.min = this.yMin;
			}
			if (this.yMax !== undefined && this.yMax !== this.yMin) {
				specField.max = this.yMax;
			}
			if (specField.max < this.preferredYMin) {
				specField.max = this.preferredYMin;
			}
		},

		_trimXAxisRange: function _trimXAxisRange(specField) {
			if (this.xMin !== undefined) {
				specField.min = this.xMin;
			}
			if (this.xMax !== undefined && this.xMax !== this.xMin) {
				specField.max = this.xMax;
			}
			if (specField.max < this.preferredXMin) {
				specField.max = this.preferredXMin;
			}
		},

		_trimXAndYAxisRange: function _trimXAndYAxisRange(id, specField) {
			if (id === 'yAxis') {
				this._trimYAxisRange(specField);
			} else if (id === 'xAxis') {
				this._trimXAxisRange(specField);
			}
		}
		/*<End> sharable functions between this render helper class and the legacy  ravespecpropertyhelper.js*/
	});

	return Rave2RenderHelper;
});
//# sourceMappingURL=Rave2RenderHelper.js.map