Source: impl/inav2/filter.js

/*
 * @file Implementation of the filter interface
 * @namespace sap.bc.ina.api.sina.impl.inav2.filter
 * @copyright Copyright (c) 2013 SAP AG. All rights reserved.
 * @ignore
 */

(function(global, isXS) {

    "use strict";

    var executeFilter = function($) {
        if (!$)
        {
            $ = global.$;
        }

        // =========================================================================
        // create packages
        // =========================================================================

        if (!isXS) {
            global.sap.bc.ina.api.sina.expandPackage(global, 'sap.bc.ina.api.sina.impl.inav2.filter');
        }

        var filter = global.sap.bc.ina.api.sina.impl.inav2.filter;
        var module = filter;
        module.DataSource = function(){this.init.apply(this,arguments);};
        module.DataSourceMetaData = function(){this.init.apply(this,arguments);};
        module.Filter = function(){this.init.apply(this,arguments);};
        module.Condition = function(){this.init.apply(this,arguments);};
        module.ConditionGroup = function(){this.init.apply(this,arguments);};

        // =========================================================================
        // class datasource metadata
        // =========================================================================
        module.DataSourceMetaData.prototype = $.extend({}, global.sap.bc.ina.api.sina.filter.DataSourceMetaData.prototype, {

            /**
             * Meta data for a data source object.
             * @ignore
             * @constructs sap.bc.ina.api.sina.impl.inav2.filter.DataSourceMetaData
             * @param  {Object} properties Configuration object.
             */
            init : function(properties) {
                properties = properties || {};
                this.datasource = properties.datasource || {};
                this.description = properties.description || "";
                this.dimensions = {};
            },

            _getMetaDataRequest : function() {
                var request = global.sap.bc.ina.api.sina.impl.inav2.jsontemplates.dataSourceMetaDataRequest;
                request.DataSource = this.datasource.toInAJson();
                return request;
            },

            _getMetaData : function(isAsync,callback) {
                var self = this;
                var request = {
                    async : isAsync,
                    url : global.sap.bc.ina.api.sina.sinaSystem().inaUrl,
                    processData : false,
                    contentType : 'application/json',
                    dataType : 'json',
                    data : this._getMetaDataRequest()
                };
                var jqXHR = global.sap.bc.ina.api.sina.sinaSystem().proxy.ajax(request);
                jqXHR.done(function(data){
                    if(!self.rawMetadata){
                        self._parseServerMetaData(data);
                    }
                    if(callback){
                        callback(self);
                    }
                });
                return this;
            },

            _parseServerMetaData : function(json){
                this.rawMetadata = json;
                this.description = this.rawMetadata.Cube.Description;
                this.datasource.setLabel(this.description);
                for (var i = 0; i < this.rawMetadata.Cube.Dimensions.length; i++) {
                    var dimension = {};
                    dimension.name = this.rawMetadata.Cube.Dimensions[i].Name;
                    dimension.description = this.rawMetadata.Cube.Dimensions[i].Description;
                    dimension.attributes = {};
                    for (var j = 0; j < this.rawMetadata.Cube.Dimensions[i].Attributes.length; j++) {
                        dimension.attributes[this.rawMetadata.Cube.Dimensions[i].Attributes[j].Name] = {
                            name : this.rawMetadata.Cube.Dimensions[i].Attributes[j].Name,
                            description : this.rawMetadata.Cube.Dimensions[i].Attributes[j].Description
                        };
                    }
                    this.dimensions[dimension.name] = dimension;
                }
            }

        });

        // =========================================================================
        // class datasource
        // =========================================================================
        module.DataSource.prototype = $.extend({}, global.sap.bc.ina.api.sina.filter.DataSource.prototype, {

            /**
             * The data source of a query that is a view in SAP HANA.
             * Use {@link sap.bc.ina.api.sina.sinabase.Sina} createDataSource() factory instead of this constructor.
             * @constructs sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @augments {sap.bc.ina.api.sina.filter.DataSource}
             * @param {Object} properties
             * @param {String} [properties.schemaName=_SYS_BIC] The schema of the view to be used.
             * @param {String} properties.packageName The package name of the view to be used.
             * @param {String} properties.objectName The object name if the view to be used.
             * @example <caption>Properties object for a view which resides in the 'SYSTEM' schema
             * and has the name 'J_EPM_PRODUCT'</caption>
             * { schemaName  : 'SYSTEM',
             *   objectName  : 'J_EPM_PRODUCT' }
             * @example <caption>Properties object for a view which resides in the repository
             * in package 'sap.bc.ina.demos.epm.views'</caption>
             * { packageName : 'sap.bc.ina.demos.epm.views',
             *   objectName  : 'V_EPM_PRODUCT' }
             * @private
             */
            init : function(properties){
                properties = properties||{};
                properties.schemaName = properties.schemaName||properties.SchemaName||{};
                this.setSchemaName(properties.schemaName);
                properties.packageName = properties.packageName||properties.PackageName||{};
                this.setPackageName(properties.packageName);
                properties.objectName = properties.objectName||properties.ObjectName||{};
                this.setObjectName(properties.objectName);
                properties.type = properties.type||properties.Type||{};
                this.setType(properties.type);
                this.label = properties.label||properties.Label||properties.Description||'';
                if (properties.metaData) {
                    this.setMetaData(properties.metaData);
                }
            },

            /**
             * Compares this datasource with another datasource.
             * @memberOf sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @instance
             * @param  {sap.bc.ina.api.sina.impl.inav2.filter.DataSource} the other datasource to be
             * compared against this datasource.
             * @return {boolean} true if they are equal, false otherwise
             */
             equals : function(otherDS){
                 if(otherDS instanceof module.DataSource){
                     if(this.getSchemaName().label!==otherDS.getSchemaName().label||this.getSchemaName().value!==otherDS.getSchemaName().value){
                         return false;
                     }
                     if(this.getPackageName().label!==otherDS.getPackageName().label||this.getPackageName().value!==otherDS.getPackageName().value){
                         return false;
                     }
                     if(this.getObjectName().label!==otherDS.getObjectName().label||this.getObjectName().value!==otherDS.getObjectName().value){
                         return false;
                     }
                     if(this.getType().label!==otherDS.getType().label||this.getType().value!==otherDS.getType().value){
                         return false;
                     }
                     return true;
                 }
                 return false;
             },

            /**
             * Returns the metadata for this data source asynchronously from the server.
             * @ignore
             * @memberOf sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @instance
             * @param  {Function} callback Function will be called after the meta data arrives
             * from the server. This function must have one argument through which it will
             * receive the metadata object.
             */
            getMetaData : function(callback){
                var self = this;
                if(!self.metaData){
                    self.metaData = new module.DataSourceMetaData({datasource:this});
                }
                self.metaData._getMetaData(true,callback);
            },

            /**
             * Returns the metadata for this data source synchronously from the server.
             * @ignore
             * @memberOf sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @instance
             * Warning: Calling the function will block the javascript thread until
             * a result has been received.
             * @return {sap.bc.ina.api.sina.impl.inav2.filter.DataSourceMetaData} The metadata for this datasource.
             */
            getMetaDataSync : function(){
                var self = this;
                if(!self.metaData){
                    self.metaData = new module.DataSourceMetaData({datasource:this});
                    self.metaData._getMetaData(false);
                }
                return self.metaData;
            },

            setMetaData : function(dataSourceMetaData){
                this.metaData = dataSourceMetaData;
            },

            /**
             * Returns the schema name for this data source.
             * @memberOf sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @instance
             * @since SAP HANA SPS 06
             * @return {String} The schema name for this data source.
            */
            getSchemaName : function(){
                return this.schemaName;
            },

            /**
             * Sets the schema name for this data source.
             * @memberOf sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @instance
             * @since SAP HANA SPS 06
             * @param {String} schemaName The new schemaName.
            */
            setSchemaName : function(schemaName){
                if(!this.schemaName){
                    this.schemaName = {};
                }
                if($.type(schemaName)==='object'){
                    this.schemaName.label = schemaName.label||schemaName.value||'';
                    this.schemaName.value = schemaName.value||'';
                }
                if($.type(schemaName)==='string'){
                    this.schemaName.label = schemaName;
                    this.schemaName.value = schemaName;
                }
            },

            /**
             * Returns the package name for this data source.
             * @memberOf sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @instance
             * @since SAP HANA SPS 06
             * @return {String} The package name for this data source.
            */
            getPackageName : function(){
                return this.packageName;
            },

            /**
             * Sets the package name for this data source.
             * @memberOf sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @instance
             * @since SAP HANA SPS 06
             * @param {String} packageName The new package name.
            */
            setPackageName : function(packageName){
                if(!this.packageName){
                    this.packageName = {};
                }
                if($.type(packageName)==='object'){
                    this.packageName.label = packageName.label||packageName.value||'';
                    this.packageName.value = packageName.value||'';
                }
                if($.type(packageName)==='string'){
                    this.packageName.label = packageName;
                    this.packageName.value = packageName;
                }
            },

            /**
             * Returns the object name for this data source.
             * @memberOf sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @instance
             * @since SAP HANA SPS 06
             * @return {String} The object name for this data source.
            */
            getObjectName : function(){
                return this.objectName;
            },

            /**
             * Sets the object name for this data source.
             * @memberOf sap.bc.ina.api.sina.impl.inav2.filter.DataSource
             * @instance
             * @since SAP HANA SPS 06
             * @param {String} objectName The new object name.
            */
            setObjectName : function(objectName){
                if(!this.objectName){
                    this.objectName = {};
                }
                if($.type(objectName)==='object'){
                    this.objectName.label = objectName.label||objectName.value||'';
                    this.objectName.value = objectName.value||'';
                }
                if($.type(objectName)==='string'){
                    this.objectName.label = objectName;
                    this.objectName.value = objectName;
                }
            },

            setObjectNameValue : function(value){
                if(!this.objectName){
                    this.objectName = {};
                }
                this.objectName.value = value||'';
            },

            setObjectNameLabel : function(label){
                if(!this.objectName){
                    this.objectName = {};
                }
                this.objectName.label = label||'';
            },

            getType : function(){
                return this.type;
            },

            setType : function(type){
                if(!this.type){
                    this.type = {};
                }
                if($.type(type)==='object'){
                    this.type.label = type.label||type.value||'';
                    this.type.value = type.value||'';
                }
                if($.type(type)==='string'){
                    this.type.label = type;
                    this.type.value = type;
                }
            },

            getLabel : function(){
                if (typeof this.label !=="undefined" && this.label !=="") {
                    return this.label;
                }
                if (typeof this.getObjectName().label !=="undefined" && this.getObjectName().label!=="") {
                    return this.getObjectName().label;
                }

                if (typeof this.getObjectName().value !=="undefined" && this.getObjectName().value!=="") {
                    return this.getObjectName().value;
                }
                return "";
            },

            setLabel : function(label){
                this.label = label||'';
            },

            fromInAJson : function(inaJson){
                this.setSchemaName({ value: inaJson.SchemaName, label: inaJson.SchemaLabel });
                this.setPackageName({ value: inaJson.PackageName, label: inaJson.PackageLabel });
                this.setObjectName({ value: inaJson.ObjectName, label: inaJson.ObjectLabel });
                this.setType({ value: inaJson.Type, label: '' });
            },

            toInAJson : function(){
                var json = { "SchemaName" : this.getSchemaName().value,
                             "PackageName" : this.getPackageName().value,
                             "ObjectName" : this.getObjectName().value
                };
                if(this.getType().value){
                    json.Type = this.getType().value;
                }
                return json;
            },

            toURL : function(){
                var json = { "sn" : this.getSchemaName().value,
                             "pn" : this.getPackageName().value,
                             "on" : this.getObjectName().value
                             // "sl" : this.getSchemaName().label,
                             // "pl" : this.getPackageName().label,
                             // "ol" : this.getObjectName().label,
                             // "l": this.label
                };
                if(this.getType().value){
                    json.tn = this.getType().value;
                    // json.tl = this.getType().label;
                }
                return json;
            },

            fromURL : function(inaJson){
                this.setSchemaName(inaJson.sn);
                this.setPackageName(inaJson.pn);
                this.setObjectName(inaJson.on);
                // this.setLabel(inaJson.l);
                this.setType(inaJson.tn);
            }

        });

        // =========================================================================
        // class filter
        // =========================================================================
        module.Filter.prototype = $.extend({}, global.sap.bc.ina.api.sina.filter.Filter.prototype, {

            /**
             * A simple filter for SINA queries.
             * Use sina.createFilter() method instead of this private constructor.
             * @constructs sap.bc.ina.api.sina.impl.inav2.filter.Filter
             * @augments {sap.bc.ina.api.sina.filter.Filter}
             * @param  {Object} properties Configuration object.
             * @private
             * @since SAP HANA SPS 06
             * @ignore
             */
            init: function(properties){
                global.sap.bc.ina.api.sina.filter.Filter.prototype.init.apply(this,[properties]);
                this.defaultConditionGroup = new module.ConditionGroup({ operator : 'And' });
            },

            addFilterCondition : function(attribute, operator, value) {
                var local_attribute = attribute;
                var local_operator = operator;
                var local_value = value;
                if ($.type(attribute)==='object') {
                    var props = attribute;
                    local_attribute = props.attribute;
                    local_operator = props.operator;
                    local_value = props.value;
                }
                if(local_attribute===undefined||local_operator===undefined||local_value===undefined){
                    return this;
                }
                if(this.conditionGroupsByAttribute[local_attribute]===undefined){
                    this.conditionGroupsByAttribute[local_attribute] = new module.ConditionGroup({ operator: "OR" });
                    this.defaultConditionGroup.addCondition(this.conditionGroupsByAttribute[local_attribute]);
                }
                this.conditionGroupsByAttribute[local_attribute].addCondition(new module.Condition(attribute,operator,value));
                return this;
            },

            removeFilterCondition : function(attribute, operator, value){
                this.defaultConditionGroup.removeCondition(new module.Condition(attribute,operator,value));
                return this;
            },

            resetFilterConditions : function(){
                this.root = null;
                this.conditionGroupsByAttribute = {};
                this.defaultConditionGroup = new module.ConditionGroup({ operator : 'And' });
                return this;
            },
            
            empty : function() {
                this.root = null;
                this.conditionGroupsByAttribute = {};
                this.defaultConditionGroup = new module.ConditionGroup({ operator : 'And' });
                this.searchTerms = "";
                return this;
            },

            getJson : function() {
                var root = [];
                this.defaultConditionGroup.getJson(root);
                var result = {
                    Selection : root[0]
                };
                return result;
            },

            setJson : function(json){
                if(json.Selection===undefined){
                    return;
                }
                var group = new module.ConditionGroup();
                group.setJson(json);
                this.defaultConditionGroup.addCondition(group);
            }

        });

        // =========================================================================
        // class condition
        // =========================================================================
        module.Condition.prototype = $.extend({}, global.sap.bc.ina.api.sina.filter.Condition.prototype, {

            /**
             * Creates a new filter condition.
             * @ignore
             * @constructs sap.bc.ina.api.sina.impl.inav2.filter.Condition
             * @param {String|Object} attribute     Technical identifier of the attribute, as defined in the database.
             * If the type is Object, this object can have properties with the name and value of the arguments.
             * @param {String} operator             Operator of the filter condition. The default value is "=".
             * @param {String} value                Value that should be filtered in the attribute.
            */
            init : function(attribute,operator,value) {
                global.sap.bc.ina.api.sina.filter.Condition.prototype.init.apply(this,[attribute,operator,value]);
                if ($.type(attribute)==='object') {
                    this.inaV2_extended_properties = attribute;
                    delete this.inaV2_extended_properties.attribute;
                    delete this.inaV2_extended_properties.operator;
                    delete this.inaV2_extended_properties.value;
                }
            },

            getJson : function(parent) {
                var operand;
                var json = {};

                if(this.operator.toLowerCase()==='contains'){
                    operand = 'SearchOperand';
                }
                else{
                    operand = 'MemberOperand';
                }
                json[operand] = {
                            "AttributeName" : this.attribute,
                            "Comparison" : this.operator,
                            "Value" : this.value
                };
                if(operand === 'SearchOperand'){
                    delete json[operand].Comparison;
                }
                json[operand] = $.extend({}, json[operand], this.inaV2_extended_properties);
                if(this.operator==='='&&this.value===null){
                    json.MemberOperand.Comparison = 'IS NULL';
                    json.MemberOperand.Value = '';
                }
                parent.push(json);
            },

            setJson : function(json){
                this.attribute = json.MemberOperand.AttributeName;
                this.operator = json.MemberOperand.Comparison;
                this.value = json.MemberOperand.Value;
                if(json.MemberOperand.Comparison === 'IS NULL'&&json.MemberOperand.Value === ''){
                    this.operator = '=';
                    this.value = null;
                }
            }

        });


        // =========================================================================
        // class condition group
        // =========================================================================
        module.ConditionGroup.prototype = $.extend({}, global.sap.bc.ina.api.sina.filter.ConditionGroup.prototype, {

            init : function(properties) {
                global.sap.bc.ina.api.sina.filter.ConditionGroup.prototype.init.apply(this,[properties]);
            },

            getJson : function(parent) {
                if(this.conditions.length===0){
                    return {};
                }
                var children = [];
                for (var i = 0; i < this.conditions.length; ++i) {
                    this.conditions[i].getJson(children);
                }
                var json = {
                        "Operator" : {
                            "Code" : this.operator,
                            "SubSelections" : children
                        }
                };
                if (parent) {
                    parent.push(json);
                }
                else {
                    var result = {
                        Selection : json
                    };
                    return result;
                }
                return {};
            },

            setJson : function(json) {
                if (json.Selection === undefined && json.Operator) {
                    json.Selection = {};
                    json.Selection.Operator = json.Operator;
                }
                this.setOperator(json.Selection.Operator.Code);
                var conditions = json.Selection.Operator.SubSelections;
                for (var i = 0; i < conditions.length; i++) {
                    var condition;
                    if (conditions[i].Operator) {
                        condition = new module.ConditionGroup();
                    }
                    else {
                        condition = new module.Condition();
                    }
                    condition.setJson(conditions[i]);
                    this.addCondition(condition);
                }
            }

        });
    };

    if (isXS) {
        executeFilter($.sap.bc.ina.api.sina.sinaxsjq.jq);
    }
    else if (typeof define === "function" && define.amd && !global.sap.ushell) { // only concatenated sina is in ushell repo!
        define( ["jquery", './jsontemplates'], function($){
            executeFilter($);
        });
    }
    else {
        executeFilter();
    }

}(typeof window === 'undefined' ? $ : window, typeof window === 'undefined'));