text: /**
   * @file Visual solution, for consistent option specification.
   */
  
  
      var zrUtil = require('zrender/lib/core/util');
      var VisualMapping = require('./VisualMapping');
      var each = zrUtil.each;
  
      function hasKeys(obj) {
          if (obj) {
              for (var name in obj){
                  if (obj.hasOwnProperty(name)) {
                      return true;
                  }
              }
          }
      }
  
      var visualSolution = {
  
          /**
           * @param {Object} option
           * @param {Array.<string>} stateList
           * @param {Function} [supplementVisualOption]
           * @return {Object} visualMappings <state, <visualType, module:echarts/visual/VisualMapping>>
           */
          createVisualMappings: function (option, stateList, supplementVisualOption) {
              var visualMappings = {};
  
              each(stateList, function (state) {
                  var mappings = visualMappings[state] = createMappings();
  
                  each(option[state], function (visualData, visualType) {
                      if (!VisualMapping.isValidType(visualType)) {
                          return;
                      }
                      var mappingOption = {
                          type: visualType,
                          visual: visualData
                      };
                      supplementVisualOption && supplementVisualOption(mappingOption, state);
                      mappings[visualType] = new VisualMapping(mappingOption);
  
                      // Prepare a alpha for opacity, for some case that opacity
                      // is not supported, such as rendering using gradient color.
                      if (visualType === 'opacity') {
                          mappingOption = zrUtil.clone(mappingOption);
                          mappingOption.type = 'colorAlpha';
                          mappings.__hidden.__alphaForOpacity = new VisualMapping(mappingOption);
                      }
                  });
              });
  
              return visualMappings;
  
              function createMappings() {
                  var Creater = function () {};
                  // Make sure hidden fields will not be visited by
                  // object iteration (with hasOwnProperty checking).
                  Creater.prototype.__hidden = Creater.prototype;
                  var obj = new Creater();
                  return obj;
              }
          },
  
          /**
           * @param {Object} thisOption
           * @param {Object} newOption
           * @param {Array.<string>} keys
           */
          replaceVisualOption: function (thisOption, newOption, keys) {
              // Visual attributes merge is not supported, otherwise it
              // brings overcomplicated merge logic. See #2853. So if
              // newOption has anyone of these keys, all of these keys
              // will be reset. Otherwise, all keys remain.
              var has;
              zrUtil.each(keys, function (key) {
                  if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) {
                      has = true;
                  }
              });
              has && zrUtil.each(keys, function (key) {
                  if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) {
                      thisOption[key] = zrUtil.clone(newOption[key]);
                  }
                  else {
                      delete thisOption[key];
                  }
              });
          },
  
          /**
           * @param {Array.<string>} stateList
           * @param {Object} visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>
           * @param {module:echarts/data/List} list
           * @param {Function} getValueState param: valueOrIndex, return: state.
           * @param {object} [scope] Scope for getValueState
           * @param {string} [dimension] Concrete dimension, if used.
           */
          applyVisual: function (stateList, visualMappings, data, getValueState, scope, dimension) {
              var visualTypesMap = {};
              zrUtil.each(stateList, function (state) {
                  var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);
                  visualTypesMap[state] = visualTypes;
              });
  
              var dataIndex;
  
              function getVisual(key) {
                  return data.getItemVisual(dataIndex, key);
              }
  
              function setVisual(key, value) {
                  data.setItemVisual(dataIndex, key, value);
              }
  
              if (dimension == null) {
                  data.each(eachItem, true);
              }
              else {
                  data.each([dimension], eachItem, true);
              }
  
              function eachItem(valueOrIndex, index) {
                  dataIndex = dimension == null ? valueOrIndex : index;
                  var valueState = getValueState.call(scope, valueOrIndex);
                  var mappings = visualMappings[valueState];
                  var visualTypes = visualTypesMap[valueState];
  
                  for (var i = 0, len = visualTypes.length; i < len; i++) {
                      var type = visualTypes[i];
                      mappings[type] && mappings[type].applyVisual(
                          valueOrIndex, getVisual, setVisual
                      );
                  }
              }
          }
      };
  
      module.exports = visualSolution;
  
  