import { __extends } from '../../../../../../../tslib@2.3.0/node_modules/tslib/tslib.es6.mjs';
import { registerAction } from '../../../core/echarts.mjs';
import { each, map, filter, isFunction, isString, isDom, isObject, isArray, defaults, extend } from '../../../../../../../zrender@6.0.0/node_modules/zrender/lib/core/util.mjs';
import { ToolboxFeature } from '../featureManager.mjs';
import { addEventListener } from '../../../../../../../zrender@6.0.0/node_modules/zrender/lib/core/event.mjs';
import { warn } from '../../../util/log.mjs';
import tokens from '../../../visual/tokens.mjs';

/* global document */
var BLOCK_SPLITER = new Array(60).join('-');
var ITEM_SPLITER = '\t';
/**
 * Group series into two types
 *  1. on category axis, like line, bar
 *  2. others, like scatter, pie
 */
function groupSeries(ecModel) {
  var seriesGroupByCategoryAxis = {};
  var otherSeries = [];
  var meta = [];
  ecModel.eachRawSeries(function (seriesModel) {
    var coordSys = seriesModel.coordinateSystem;
    if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) {
      // TODO: TYPE Consider polar? Include polar may increase unecessary bundle size.
      var baseAxis = coordSys.getBaseAxis();
      if (baseAxis.type === 'category') {
        var key = baseAxis.dim + '_' + baseAxis.index;
        if (!seriesGroupByCategoryAxis[key]) {
          seriesGroupByCategoryAxis[key] = {
            categoryAxis: baseAxis,
            valueAxis: coordSys.getOtherAxis(baseAxis),
            series: []
          };
          meta.push({
            axisDim: baseAxis.dim,
            axisIndex: baseAxis.index
          });
        }
        seriesGroupByCategoryAxis[key].series.push(seriesModel);
      } else {
        otherSeries.push(seriesModel);
      }
    } else {
      otherSeries.push(seriesModel);
    }
  });
  return {
    seriesGroupByCategoryAxis: seriesGroupByCategoryAxis,
    other: otherSeries,
    meta: meta
  };
}
/**
 * Assemble content of series on cateogory axis
 * @inner
 */
function assembleSeriesWithCategoryAxis(groups) {
  var tables = [];
  each(groups, function (group, key) {
    var categoryAxis = group.categoryAxis;
    var valueAxis = group.valueAxis;
    var valueAxisDim = valueAxis.dim;
    var headers = [' '].concat(map(group.series, function (series) {
      return series.name;
    }));
    // @ts-ignore TODO Polar
    var columns = [categoryAxis.model.getCategories()];
    each(group.series, function (series) {
      var rawData = series.getRawData();
      columns.push(series.getRawData().mapArray(rawData.mapDimension(valueAxisDim), function (val) {
        return val;
      }));
    });
    // Assemble table content
    var lines = [headers.join(ITEM_SPLITER)];
    for (var i = 0; i < columns[0].length; i++) {
      var items = [];
      for (var j = 0; j < columns.length; j++) {
        items.push(columns[j][i]);
      }
      lines.push(items.join(ITEM_SPLITER));
    }
    tables.push(lines.join('\n'));
  });
  return tables.join('\n\n' + BLOCK_SPLITER + '\n\n');
}
/**
 * Assemble content of other series
 */
function assembleOtherSeries(series) {
  return map(series, function (series) {
    var data = series.getRawData();
    var lines = [series.name];
    var vals = [];
    data.each(data.dimensions, function () {
      var argLen = arguments.length;
      var dataIndex = arguments[argLen - 1];
      var name = data.getName(dataIndex);
      for (var i = 0; i < argLen - 1; i++) {
        vals[i] = arguments[i];
      }
      lines.push((name ? name + ITEM_SPLITER : '') + vals.join(ITEM_SPLITER));
    });
    return lines.join('\n');
  }).join('\n\n' + BLOCK_SPLITER + '\n\n');
}
function getContentFromModel(ecModel) {
  var result = groupSeries(ecModel);
  return {
    value: filter([assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis), assembleOtherSeries(result.other)], function (str) {
      return !!str.replace(/[\n\t\s]/g, '');
    }).join('\n\n' + BLOCK_SPLITER + '\n\n'),
    meta: result.meta
  };
}
function trim(str) {
  return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}
/**
 * If a block is tsv format
 */
function isTSVFormat(block) {
  // Simple method to find out if a block is tsv format
  var firstLine = block.slice(0, block.indexOf('\n'));
  if (firstLine.indexOf(ITEM_SPLITER) >= 0) {
    return true;
  }
}
var itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');
/**
 * @param {string} tsv
 * @return {Object}
 */
function parseTSVContents(tsv) {
  var tsvLines = tsv.split(/\n+/g);
  var headers = trim(tsvLines.shift()).split(itemSplitRegex);
  var categories = [];
  var series = map(headers, function (header) {
    return {
      name: header,
      data: []
    };
  });
  for (var i = 0; i < tsvLines.length; i++) {
    var items = trim(tsvLines[i]).split(itemSplitRegex);
    categories.push(items.shift());
    for (var j = 0; j < items.length; j++) {
      series[j] && (series[j].data[i] = items[j]);
    }
  }
  return {
    series: series,
    categories: categories
  };
}
function parseListContents(str) {
  var lines = str.split(/\n+/g);
  var seriesName = trim(lines.shift());
  var data = [];
  for (var i = 0; i < lines.length; i++) {
    // if line is empty, ignore it.
    // there is a case that a user forgot to delete `\n`.
    var line = trim(lines[i]);
    if (!line) {
      continue;
    }
    var items = line.split(itemSplitRegex);
    var name_1 = '';
    var value = void 0;
    var hasName = false;
    if (isNaN(items[0])) {
      // First item is name
      hasName = true;
      name_1 = items[0];
      items = items.slice(1);
      data[i] = {
        name: name_1,
        value: []
      };
      value = data[i].value;
    } else {
      value = data[i] = [];
    }
    for (var j = 0; j < items.length; j++) {
      value.push(+items[j]);
    }
    if (value.length === 1) {
      hasName ? data[i].value = value[0] : data[i] = value[0];
    }
  }
  return {
    name: seriesName,
    data: data
  };
}
function parseContents(str, blockMetaList) {
  var blocks = str.split(new RegExp('\n*' + BLOCK_SPLITER + '\n*', 'g'));
  var newOption = {
    series: []
  };
  each(blocks, function (block, idx) {
    if (isTSVFormat(block)) {
      var result = parseTSVContents(block);
      var blockMeta = blockMetaList[idx];
      var axisKey = blockMeta.axisDim + 'Axis';
      if (blockMeta) {
        newOption[axisKey] = newOption[axisKey] || [];
        newOption[axisKey][blockMeta.axisIndex] = {
          data: result.categories
        };
        newOption.series = newOption.series.concat(result.series);
      }
    } else {
      var result = parseListContents(block);
      newOption.series.push(result);
    }
  });
  return newOption;
}
var DataView = /** @class */function (_super) {
  __extends(DataView, _super);
  function DataView() {
    return _super !== null && _super.apply(this, arguments) || this;
  }
  DataView.prototype.onclick = function (ecModel, api) {
    // FIXME: better way?
    setTimeout(function () {
      api.dispatchAction({
        type: 'hideTip'
      });
    });
    var container = api.getDom();
    var model = this.model;
    if (this._dom) {
      container.removeChild(this._dom);
    }
    var root = document.createElement('div');
    // use padding to avoid 5px whitespace
    root.style.cssText = 'position:absolute;top:0;bottom:0;left:0;right:0;padding:5px';
    root.style.backgroundColor = model.get('backgroundColor') || tokens.color.neutral00;
    // Create elements
    var header = document.createElement('h4');
    var lang = model.get('lang') || [];
    header.innerHTML = lang[0] || model.get('title');
    header.style.cssText = 'margin:10px 20px';
    header.style.color = model.get('textColor');
    var viewMain = document.createElement('div');
    var textarea = document.createElement('textarea');
    viewMain.style.cssText = 'overflow:auto';
    var optionToContent = model.get('optionToContent');
    var contentToOption = model.get('contentToOption');
    var result = getContentFromModel(ecModel);
    if (isFunction(optionToContent)) {
      var htmlOrDom = optionToContent(api.getOption());
      if (isString(htmlOrDom)) {
        viewMain.innerHTML = htmlOrDom;
      } else if (isDom(htmlOrDom)) {
        viewMain.appendChild(htmlOrDom);
      }
    } else {
      // Use default textarea
      textarea.readOnly = model.get('readOnly');
      var style = textarea.style;
      // eslint-disable-next-line max-len
      style.cssText = 'display:block;width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;resize:none;box-sizing:border-box;outline:none';
      style.color = model.get('textColor');
      style.borderColor = model.get('textareaBorderColor');
      style.backgroundColor = model.get('textareaColor');
      textarea.value = result.value;
      viewMain.appendChild(textarea);
    }
    var blockMetaList = result.meta;
    var buttonContainer = document.createElement('div');
    buttonContainer.style.cssText = 'position:absolute;bottom:5px;left:0;right:0';
    // eslint-disable-next-line max-len
    var buttonStyle = 'float:right;margin-right:20px;border:none;cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';
    var closeButton = document.createElement('div');
    var refreshButton = document.createElement('div');
    buttonStyle += ';background-color:' + model.get('buttonColor');
    buttonStyle += ';color:' + model.get('buttonTextColor');
    var self = this;
    function close() {
      container.removeChild(root);
      self._dom = null;
    }
    addEventListener(closeButton, 'click', close);
    addEventListener(refreshButton, 'click', function () {
      if (contentToOption == null && optionToContent != null || contentToOption != null && optionToContent == null) {
        if (process.env.NODE_ENV !== 'production') {
          // eslint-disable-next-line
          warn('It seems you have just provided one of `contentToOption` and `optionToContent` functions but missed the other one. Data change is ignored.');
        }
        close();
        return;
      }
      var newOption;
      try {
        if (isFunction(contentToOption)) {
          newOption = contentToOption(viewMain, api.getOption());
        } else {
          newOption = parseContents(textarea.value, blockMetaList);
        }
      } catch (e) {
        close();
        throw new Error('Data view format error ' + e);
      }
      if (newOption) {
        api.dispatchAction({
          type: 'changeDataView',
          newOption: newOption
        });
      }
      close();
    });
    closeButton.innerHTML = lang[1];
    refreshButton.innerHTML = lang[2];
    refreshButton.style.cssText = closeButton.style.cssText = buttonStyle;
    !model.get('readOnly') && buttonContainer.appendChild(refreshButton);
    buttonContainer.appendChild(closeButton);
    root.appendChild(header);
    root.appendChild(viewMain);
    root.appendChild(buttonContainer);
    viewMain.style.height = container.clientHeight - 80 + 'px';
    container.appendChild(root);
    this._dom = root;
  };
  DataView.prototype.remove = function (ecModel, api) {
    this._dom && api.getDom().removeChild(this._dom);
  };
  DataView.prototype.dispose = function (ecModel, api) {
    this.remove(ecModel, api);
  };
  DataView.getDefaultOption = function (ecModel) {
    var defaultOption = {
      show: true,
      readOnly: false,
      optionToContent: null,
      contentToOption: null,
      // eslint-disable-next-line
      icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28',
      title: ecModel.getLocaleModel().get(['toolbox', 'dataView', 'title']),
      lang: ecModel.getLocaleModel().get(['toolbox', 'dataView', 'lang']),
      backgroundColor: tokens.color.background,
      textColor: tokens.color.primary,
      textareaColor: tokens.color.background,
      textareaBorderColor: tokens.color.border,
      buttonColor: tokens.color.accent50,
      buttonTextColor: tokens.color.neutral00
    };
    return defaultOption;
  };
  return DataView;
}(ToolboxFeature);
/**
 * @inner
 */
function tryMergeDataOption(newData, originalData) {
  return map(newData, function (newVal, idx) {
    var original = originalData && originalData[idx];
    if (isObject(original) && !isArray(original)) {
      var newValIsObject = isObject(newVal) && !isArray(newVal);
      if (!newValIsObject) {
        newVal = {
          value: newVal
        };
      }
      // original data has name but new data has no name
      var shouldDeleteName = original.name != null && newVal.name == null;
      // Original data has option
      newVal = defaults(newVal, original);
      shouldDeleteName && delete newVal.name;
      return newVal;
    } else {
      return newVal;
    }
  });
}
// TODO: SELF REGISTERED.
registerAction({
  type: 'changeDataView',
  event: 'dataViewChanged',
  update: 'prepareAndUpdate'
}, function (payload, ecModel) {
  var newSeriesOptList = [];
  each(payload.newOption.series, function (seriesOpt) {
    var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];
    if (!seriesModel) {
      // New created series
      // Geuss the series type
      newSeriesOptList.push(extend({
        // Default is scatter
        type: 'scatter'
      }, seriesOpt));
    } else {
      var originalData = seriesModel.get('data');
      newSeriesOptList.push({
        name: seriesOpt.name,
        data: tryMergeDataOption(seriesOpt.data, originalData)
      });
    }
  });
  ecModel.mergeOption(defaults({
    series: newSeriesOptList
  }, payload.newOption));
});

export { DataView as default };
