text: /*
   * Copyright 1999-2018 Alibaba Group Holding Ltd.
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *      http://www.apache.org/licenses/LICENSE-2.0
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import $ from 'jquery';
  import React from 'react';
  import PropTypes from 'prop-types';
  import {getParams, request} from '../../../globalLib';
  import DiffEditorDialog from '../../../components/DiffEditorDialog';
  import SuccessDialog from '../../../components/SuccessDialog';
  import validateContent from 'utils/validateContent';
  import {
    Balloon,
    Button,
    ConfigProvider,
    Dialog,
    Field,
    Form,
    Icon,
    Input,
    Loading,
    Message,
    Radio,
    Select,
    Tab,
  } from '@alifd/next';
  
  import './index.scss';
  
  const TabPane = Tab.Item;
  const FormItem = Form.Item;
  const { Group: RadioGroup } = Radio;
  
  @ConfigProvider.config
  class ConfigEditor extends React.Component {
    static displayName = 'ConfigEditor';
  
    static propTypes = {
      locale: PropTypes.object,
      history: PropTypes.object,
    };
  
    constructor(props) {
      super(props);
      this.diffEditorDialog = React.createRef();
      this.successDialog = React.createRef();
      this.edasAppName = getParams('edasAppName') || '';
      this.edasAppId = getParams('edasAppId') || '';
      this.inApp = this.edasAppName;
      this.field = new Field(this);
      this.dataId = getParams('dataId') || 'yanlin';
      this.group = getParams('group') || 'DEFAULT_GROUP';
      this.tenant = getParams('namespace') || '';
      this.state = {
        configType: 'text',
        codeValue: '',
        envname: 'center',
        targetEnvName: '',
        envlist: [],
        envvalues: [],
        loading: false,
        showmore: false,
        activeKey: 'normal',
        hasbeta: false,
        ips: '',
        checkedBeta: false,
        tagLst: [],
        config_tags: [],
        switchEncrypt: false,
        tag: [],
      };
      this.codeValue = '';
      this.mode = 'text';
      this.ips = '';
      this.valueMap = {}; // 存储不同版本的数据
      this.searchDataId = getParams('searchDataId') || '';
      this.searchGroup = getParams('searchGroup') || '';
    }
  
    componentDidMount() {
      this.initData();
      this.betaips = document.getElementById('betaips');
      this.getDataDetail();
      this.chontenttab = document.getElementById('chontenttab'); // diff标签
    }
  
    initData() {
      const { locale = {} } = this.props;
      this.setState({
        tag: [
          {
            title: locale.official,
            key: 'normal',
          },
        ],
      });
      if (this.dataId.startsWith('cipher-')) {
        this.setState({ switchEncrypt: true });
      }
    }
  
    initMoacoEditor(language, value) {
      if (!window.monaco) {
        window.importEditor(() => {
          this.monacoEditor = window.monaco.editor.create(document.getElementById('container'), {
            value,
            language: this.state.configType,
            codeLens: true,
            selectOnLineNumbers: true,
            roundedSelection: false,
            readOnly: false,
            lineNumbersMinChars: true,
            theme: 'vs-dark',
            wordWrapColumn: 120,
            folding: false,
            showFoldingControls: 'always',
            wordWrap: 'wordWrapColumn',
            cursorStyle: 'line',
            automaticLayout: true,
          });
        });
      } else {
        this.monacoEditor = window.monaco.editor.create(document.getElementById('container'), {
          value,
          language: this.state.configType,
          codeLens: true,
          selectOnLineNumbers: true,
          roundedSelection: false,
          readOnly: false,
          lineNumbersMinChars: true,
          theme: 'vs-dark',
          wordWrapColumn: 120,
          folding: false,
          showFoldingControls: 'always',
          wordWrap: 'wordWrapColumn',
          cursorStyle: 'line',
          automaticLayout: true,
        });
      }
    }
  
    toggleMore() {
      this.setState({
        showmore: !this.state.showmore,
      });
    }
  
    navTo(url) {
      this.serverId = getParams('serverId') || '';
      this.tenant = getParams('namespace') || ''; // 为当前实例保存tenant参数
      this.props.history.push(
        `${url}?serverId=${this.serverId || ''}&dataId=${this.dataId}&group=${this.group}&namespace=${
          this.tenant
        }`
      );
    }
  
    openLoading() {
      this.setState({
        loading: true,
      });
    }
  
    closeLoading() {
      this.setState({
        loading: false,
      });
    }
  
    getDataDetail() {
      const { locale = {} } = this.props;
      const self = this;
      this.tenant = getParams('namespace') || '';
      this.serverId = getParams('serverId') || 'center';
      const url = `v1/cs/configs?show=all&dataId=${this.dataId}&group=${this.group}`;
      request({
        url,
        beforeSend() {
          self.openLoading();
        },
        success(result) {
          if (result != null) {
            const data = result;
            self.valueMap.normal = data;
            self.field.setValue('dataId', data.dataId);
            // self.field.setValue('content', data.content);
            self.field.setValue('appName', self.inApp ? self.edasAppName : data.appName);
            // self.field.setValue('envs', self.serverId);
            self.field.setValue('group', data.group);
  
            // self.field.setValue('type', data.type);
            self.field.setValue('desc', data.desc);
            // self.field.setValue('md5', data.md5);
            self.codeValue = data.content || '';
            const type = data.type || 'text';
            self.setState({
              // 设置radio 高亮
              configType: type,
            });
            self.initMoacoEditor(type, self.codeValue);
  
            // self.createCodeMirror('text', self.codeValue);
            // self.codeValue = self.commoneditor.doc.getValue();
            if (data.configTags != null) {
              const tagArr = data.configTags.split(',');
              self.setConfigTags(tagArr);
            }
  
            const envvalues = [];
            const env = {};
            self.serverId = env.serverId;
            self.targetEnvs = envvalues;
          } else {
            Dialog.alert({ title: locale.wrong, content: result.message });
          }
        },
        complete() {
          self.closeLoading();
        },
      });
    }
  
    goList() {
      const tenant = getParams('namespace');
      this.props.history.push(
        `/configurationManagement?serverId=${this.serverId}&group=${this.searchGroup}&dataId=${
          this.searchDataId
        }&namespace=${tenant}`
      );
    }
  
    createCodeMirror(mode, value) {
      const commontarget = this.refs.commoneditor;
      commontarget.innerHTML = '';
      this.commoneditor = window.CodeMirror(commontarget, {
        value,
        mode,
        lineNumbers: true,
        theme: 'xq-light',
        lint: true,
        gutters: ['CodeMirror-lint-markers'],
        extraKeys: {
          F1(cm) {
            cm.setOption('fullScreen', !cm.getOption('fullScreen'));
          },
          Esc(cm) {
            if (cm.getOption('fullScreen')) cm.setOption('fullScreen', false);
          },
        },
      });
      this.commoneditor.on('change', this.codemirrorValueChanged.bind(this));
    }
  
    codemirrorValueChanged(doc) {
      if (this.diffeditor) {
        this.diffeditor.edit.doc.setValue(doc.getValue());
      }
    }
  
    createDiffCodeMirror(leftCode, rightCode) {
      const target = this.diffEditorDialog.current.getInstance();
      target.innerHTML = '';
      this.diffeditor = window.CodeMirror.MergeView(target, {
        value: leftCode || '',
        origLeft: null,
        orig: rightCode || '',
        lineNumbers: true,
        mode: this.mode,
        theme: 'xq-light',
        highlightDifferences: true,
        connect: 'align',
        collapseIdentical: false,
      });
    }
  
    changeConfig(value) {
      if (value === 0) {
        this.createCodeMirror('text', this.codeValue);
        this.mode = 'text';
      }
      if (value === 1) {
        this.createCodeMirror('application/json', this.codeValue);
        this.mode = 'application/json';
      }
      if (value === 2) {
        this.createCodeMirror('xml', this.codeValue);
        this.mode = 'xml';
      }
      this.setState({
        configType: value,
      });
    }
  
    setCodeValue(value) {
      this.setState({
        codeValue: value,
      });
    }
  
    toggleDiff(checked) {
      if (checked) {
        this.chontenttab.style.display = 'block';
  
        const nowvalue = this.commoneditor.doc.getValue();
        if (!this.diffeditor) {
          this.createDiffCodeMirror(nowvalue, this.codeValue);
        }
      } else {
        this.chontenttab.style.display = 'none';
        // this.diffeditor = null;
        // let target = this.refs["diffeditor"];
        // target.innerHTML = '';
      }
    }
  
    publishConfig() {
      const { locale = {} } = this.props;
      this.field.validate((errors, values) => {
        if (errors) {
          return;
        }
        let content = '';
        let { configType } = this.state;
  
        if (this.monacoEditor) {
          content = this.monacoEditor.getValue();
        } else {
          content = this.codeValue;
        }
        if (!content) {
          Message.error({
            content: locale.submitFailed,
            align: 'cc cc',
          });
          return;
        }
        if (validateContent.validate({ content, type: configType })) {
          this._publishConfig(content);
        } else {
          Dialog.confirm({
            content: '配置信息可能有语法错误, 确定提交吗?',
            onOk: () => {
              this._publishConfig(content);
            },
          });
        }
      });
    }
  
    _publishConfig = content => {
      const { locale = {} } = this.props;
      const self = this;
      this.codeValue = content;
      this.tenant = getParams('namespace') || '';
      this.serverId = getParams('serverId') || 'center';
  
      const payload = {
        dataId: this.field.getValue('dataId'),
        appName: this.inApp ? this.edasAppId : this.field.getValue('appName'),
        group: this.field.getValue('group'),
        desc: this.field.getValue('desc'),
        config_tags: this.state.config_tags.join(),
        type: this.state.configType,
        content,
        tenant: this.tenant,
      };
      const url = 'v1/cs/configs';
      request({
        type: 'post',
        contentType: 'application/x-www-form-urlencoded',
        url,
        data: payload,
        success(res) {
          const _payload = {};
          _payload.maintitle = locale.toedittitle;
          _payload.title = <div>{locale.toedit}</div>;
          _payload.content = '';
          _payload.dataId = payload.dataId;
          _payload.group = payload.group;
  
          if (res != null) {
            _payload.isok = true;
            const activeKey = self.state.activeKey.split('-')[0];
            if (activeKey === 'normal' && self.hasips === true) {
              // 如果是在normal面板选择了beta发布
              const sufex = new Date().getTime();
              self.setState({
                tag: [
                  { title: locale.official, key: `normal-${sufex}` },
                  { title: 'BETA', key: `beta-${sufex}` },
                ],
                hasbeta: true,
                activeKey: `beta-${sufex}`,
              });
              payload.betaIps = payload.betaIps || payload.ips;
              self.valueMap.beta = payload; // 赋值beta
              self.changeTab(`beta-${sufex}`);
            }
            if (activeKey === 'normal' && self.hasips === false) {
              // 如果是在normal面板选择了发布
              self.valueMap.normal = payload; // 赋值正式
            }
            if (activeKey === 'beta' && self.hasips === true) {
              // 如果是在beta面板继续beta发布
              self.valueMap.beta = payload; // 赋值beta
            }
          } else {
            _payload.isok = false;
            _payload.message = res.message;
          }
          self.successDialog.current.getInstance().openDialog(_payload);
        },
        error() {},
      });
    };
  
    validateChart(rule, value, callback) {
      const { locale = {} } = this.props;
      const chartReg = /[@#\$%\^&\*]+/g;
      if (chartReg.test(value)) {
        callback(locale.vdchart);
      } else {
        callback();
      }
    }
  
    changeEnv(values) {
      this.targetEnvs = values;
      this.setState({
        envvalues: values,
      });
    }
  
    changeBeta(selected) {
      if (selected) {
        this.betaips.style.display = 'block';
      } else {
        this.betaips.style.display = 'none';
      }
      this.setState({
        checkedBeta: selected,
      });
    }
  
    getIps(value) {
      this.ips = value;
      this.setState({
        ips: value,
      });
    }
  
    setConfigTags(value) {
      if (value.length > 5) {
        value.pop();
      }
      value.forEach((v, i) => {
        if (v.indexOf(',') !== -1 || v.indexOf('=') !== -1) {
          value.splice(i, 1);
        }
      });
      this.setState({
        config_tags: value,
      });
    }
  
    onInputUpdate(value) {
      if (this.inputtimmer) {
        clearTimeout(this.inputtimmer);
      }
      this.inputtimmer = setTimeout(() => {
        const { tagLst } = this.state;
  
        let hastag = false;
        tagLst.forEach((v, i) => {
          if (v.value === value) {
            hastag = true;
          }
        });
        if (!hastag) {
          tagLst.push({
            value,
            label: value,
            time: Math.random(),
          });
        }
        this.setState({ tagLst });
      }, 500);
    }
  
    openDiff(hasips) {
      this.hasips = hasips; // 是否包含ips
      let leftvalue = this.monacoEditor.getValue(); // this.commoneditor.doc.getValue();
      let rightvalue = this.codeValue;
      leftvalue = leftvalue.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
      rightvalue = rightvalue.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
      // let rightvalue = this.diffeditor.doc.getValue();
      // console.log(this.commoneditor, leftvalue==rightvalue)
      this.diffEditorDialog.current.getInstance().openDialog(leftvalue, rightvalue);
    }
  
    changeTab(value) {
      const self = this;
      const key = value.split('-')[0];
  
      const data = this.valueMap[key];
      this.setState({
        activeKey: value,
      });
      self.field.setValue('dataId', data.dataId);
  
      self.field.setValue('appName', self.inApp ? self.edasAppName : data.appName);
      // self.field.setValue('envs', self.serverId);
      self.field.setValue('group', data.group);
      // self.field.setValue('md5', data.md5);
      self.codeValue = data.content || '';
      self.createCodeMirror('text', self.codeValue);
      if (data.betaIps) {
        self.getIps(data.betaIps);
        self.changeBeta(true);
      } else {
        self.getIps('');
        self.changeBeta(false);
      }
    }
  
    newChangeConfig(value) {
      this.setState({
        configType: value,
      });
      this.changeModel(value);
    }
  
    changeModel(type, value) {
      if (!this.monacoEditor) {
        $('#container').empty();
        this.initMoacoEditor(type, value);
        return;
      }
      const oldModel = this.monacoEditor.getModel();
      const oldValue = this.monacoEditor.getValue();
      const newModel = window.monaco.editor.createModel(oldValue, type);
      this.monacoEditor.setModel(newModel);
      if (oldModel) {
        oldModel.dispose();
      }
    }
  
    render() {
      const { locale = {} } = this.props;
      const { init } = this.field;
      const formItemLayout = {
        labelCol: { span: 2 },
        wrapperCol: { span: 22 },
      };
  
      // const list = [{
      //     value: 0,
      //     label: 'TEXT'
      // }, {
      //     value: 1,
      //     label: 'JSON'
      // }, {
      //     value: 2,
      //     label: 'XML'
      // }];
      const list = [
        { value: 'text', label: 'TEXT' },
        { value: 'json', label: 'JSON' },
        { value: 'xml', label: 'XML' },
        { value: 'yaml', label: 'YAML' },
        { value: 'html', label: 'HTML' },
        { value: 'properties', label: 'Properties' },
      ];
      const activeKey = this.state.activeKey.split('-')[0];
  
      return (
        <div style={{ padding: 10 }}>
          <Loading
            shape="flower"
            style={{ position: 'relative', width: '100%' }}
            visible={this.state.loading}
            tip="Loading..."
            color="#333"
          >
            <h1 style={{ overflow: 'hidden', height: 50, width: '100%' }}>
              <div>{locale.toedit}</div>
            </h1>
            {this.state.hasbeta ? (
              <div style={{ display: 'inline-block', height: 40, width: '80%', overflow: 'hidden' }}>
                <Tab
                  shape={'wrapped'}
                  onChange={this.changeTab.bind(this)}
                  lazyLoad={false}
                  activeKey={this.state.activeKey}
                >
                  {this.state.tag.map(tab => (
                    <TabPane title={tab.title} key={tab.key} />
                  ))}
                </Tab>
              </div>
            ) : (
              ''
            )}
  
            <Form field={this.field}>
              <FormItem label="Data ID:" {...formItemLayout}>
                <Input
                  disabled
                  {...init('dataId', {
                    rules: [
                      { required: true, message: locale.recipientFrom },
                      { validator: this.validateChart.bind(this) },
                    ],
                  })}
                />
              </FormItem>
              <FormItem label="Group:" {...formItemLayout}>
                <Input
                  disabled
                  {...init('group', {
                    rules: [
                      { required: true, message: locale.homeApplication },
                      { validator: this.validateChart.bind(this) },
                    ],
                  })}
                />
              </FormItem>
              <FormItem label="" {...formItemLayout}>
                <div>
                  <a style={{ fontSize: '12px' }} onClick={this.toggleMore.bind(this)}>
                    {this.state.showmore ? locale.collapse : locale.groupNotEmpty}
                  </a>
                </div>
              </FormItem>
              <div style={{ height: this.state.showmore ? 'auto' : '0', overflow: 'hidden' }}>
                <FormItem label={locale.tags} {...formItemLayout}>
                  <Select
                    size="medium"
                    hasArrow
                    style={{ width: '100%' }}
                    autoWidth
                    mode="tag"
                    filterLocal
                    placeholder={locale.pleaseEnterTag}
                    dataSource={this.state.tagLst}
                    value={this.state.config_tags}
                    onChange={this.setConfigTags.bind(this)}
                    hasClear
                  />
                </FormItem>
  
                <FormItem label={locale.targetEnvironment} {...formItemLayout}>
                  <Input {...init('appName')} readOnly={!!this.inApp} />
                </FormItem>
              </div>
  
              <FormItem label={locale.description} {...formItemLayout}>
                <Input.TextArea htmlType="text" multiple rows={3} {...init('desc')} />
              </FormItem>
              <FormItem label={locale.format} {...formItemLayout}>
                <RadioGroup
                  dataSource={list}
                  value={this.state.configType}
                  onChange={this.newChangeConfig.bind(this)}
                />
              </FormItem>
              <FormItem
                label={
                  <span style={{ marginRight: 5 }}>
                    {locale.configcontent}
                    <Balloon
                      trigger={
                        <Icon
                          type="help"
                          size={'small'}
                          style={{
                            color: '#1DC11D',
                            marginRight: 5,
                            verticalAlign: 'middle',
                            marginTop: 2,
                          }}
                        />
                      }
                      align="t"
                      style={{ marginRight: 5 }}
                      triggerType="hover"
                    >
                      <p>{locale.escExit}</p>
                      <p>{locale.releaseBeta}</p>
                    </Balloon>
                    :
                  </span>
                }
                {...formItemLayout}
              >
                <div style={{ clear: 'both', height: 300 }} id="container" />
              </FormItem>
              <FormItem {...formItemLayout} label="">
                <div style={{ textAlign: 'right' }}>
                  {activeKey === 'beta' ? (
                    <Button
                      style={{ marginRight: 10 }}
                      type="primary"
                      onClick={this.openDiff.bind(this, true)}
                    >
                      {locale.release}
                    </Button>
                  ) : (
                    ''
                  )}
                  {activeKey === 'normal' ? (
                    <Button
                      type="primary"
                      disabled={this.state.hasbeta}
                      style={{ marginRight: 10 }}
                      onClick={this.openDiff.bind(this, this.state.checkedBeta)}
                    >
                      {this.state.checkedBeta ? locale.release : locale.publish}
                    </Button>
                  ) : (
                    <Button
                      type="primary"
                      style={{ marginRight: 10 }}
                      onClick={this.openDiff.bind(this, false)}
                    >
                      {locale.publish}
                    </Button>
                  )}
  
                  <Button type="normal" onClick={this.goList.bind(this)}>
                    {locale.back}
                  </Button>
                </div>
              </FormItem>
            </Form>
            <DiffEditorDialog
              ref={this.diffEditorDialog}
              publishConfig={this.publishConfig.bind(this)}
            />
            <SuccessDialog ref={this.successDialog} />
          </Loading>
        </div>
      );
    }
  }
  
  export default ConfigEditor;
  