<!--
  - Licensed to the Apache Software Foundation (ASF) under one or more
  - contributor license agreements.  See the NOTICE file distributed with
  - this work for additional information regarding copyright ownership.
  - The ASF licenses this file to You 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.
  -->

<template>
  <el-row class="box-card">
    <div class="btn-group">
      <el-button
        class="btn-plus"
        type="primary"
        icon="el-icon-plus"
        @click="add">{{ $t('dataScaling.btnTxt') }}</el-button>
      <span style="margin-left: 20px;">
        server: <samp style="color: #E17425;">{{ serviceForm.serviceName }}</samp>
        <i class="el-icon-edit" @click="showServerDialog"></i>
      </span>
    </div>
    <div class="table-wrap">
      <el-table :data="tableData" border style="width: 100%">
        <el-table-column
          v-for="(item, index) in column"
          :key="index"
          :prop="item.prop"
          :label="item.label"
          :width="item.width"
        />
        <el-table-column
          :label="$t('dataScaling.tableList.operate')"
          fixed="right"
          width="140"
        >
          <template slot-scope="scope">
            <el-tooltip
              :content="$t('dataScaling.tableList.operateSee')"
              class="item"
              effect="dark"
              placement="top"
            >
              <el-button
                size="small"
                type="primary"
                icon="el-icon-view"
                @click="showSyncTaskProgressDetail(scope.row)"
              />
            </el-tooltip>
            <el-tooltip
              :content="$t('dataScaling.tableList.operateStop')"
              class="item"
              effect="dark"
              placement="top"
            >
              <el-button
                :disabled="scope.row.status === 'STOPPED'"
                icon="el-icon-video-pause"
                size="small"
                type="danger"
                @click="handlerStop(scope.row)"
              />
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
      <div class="pagination">
        <el-pagination
          :total="total"
          :current-page="currentPage"
          background
          layout="prev, pager, next"
          @current-change="handleCurrentChange"
        />
      </div>
    </div>
    <!-- add Dialog -->
    <el-dialog
      :title="$t('dataScaling.registDialog.title')"
      :visible.sync="DataScalingDialogVisible"
      width="1010px"
    >
      <el-form ref="form" :model="form" :rules="rules" label-width="170px">
        <el-form-item
          :label="$t('dataScaling.registDialog.source')"
          prop="source"
        >
          <el-select
            v-model="form.source"
            :placeholder="$t('dataScaling.rules.source')"
            :disabled="!schemaData.length"
            @change="selectChange"
          >
            <el-option v-for="(item, index) in schemaData" :label="item" :value="item" :key="index"></el-option>
          </el-select>
          <span v-show="form.source" style="margin-left: 10px">
            <el-button type="primary" size="mini" @click="showDatasource">Datasource</el-button>
            <el-button type="primary" size="mini" @click="showRule">Rule</el-button>
          </span>
        </el-form-item>
        <el-form-item
          :label="$t('dataScaling.registDialog.target')"
          prop="target"
        >
          <el-radio-group v-model="form.target">
            <el-radio label="Proxy">Proxy</el-radio>
          </el-radio-group>
        </el-form-item>
        <div v-show="schemaData.length > 0">
          <el-form-item
            :label="$t('dataScaling.registDialog.username')"
            prop="username"
          >
            <el-input v-model="form.username" :placeholder="$t('dataScaling.registDialog.usernamePlaceholder')"></el-input>
          </el-form-item>
          <el-form-item
            :label="$t('dataScaling.registDialog.password')"
            prop="password"
          >
            <el-input v-model="form.password" :placeholder="$t('dataScaling.registDialog.passwordPlaceholder')"></el-input>
          </el-form-item>
          <el-form-item
            :label="$t('dataScaling.registDialog.url')"
            prop="url"
          >
            <el-input v-model="form.url" :placeholder="$t('dataScaling.registDialog.urlPlaceholder')"></el-input>
          </el-form-item>
          <el-form-item
            :label="$t('dataScaling.registDialog.jobCount')"
            prop="jobCount"
          >
            <el-input v-model="form.jobCount" :placeholder="$t('dataScaling.registDialog.jobCountPlaceholder')"></el-input>
          </el-form-item>
        </div>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="DataScalingDialogVisible = false">{{
          $t('dataScaling.registDialog.btnCancelTxt')
        }}</el-button>
        <el-button type="primary" @click="onConfirm('form')">{{
          $t('dataScaling.registDialog.btnConfirmTxt')
        }}</el-button>
      </div>
    </el-dialog>
    <!-- showDatasource -->
    <el-dialog
      :visible.sync="DatasourceVisible"
      title="Result Datasource:"
      width="1010px"
    >
      <el-row>
        <el-col :span="24">
          <el-input
            :rows="20"
            v-model="textareaDatasourceCom"
            type="textarea"
            readonly
            class="show-text"
          />
        </el-col>
      </el-row>
      <div slot="footer" class="dialog-footer"></div>
    </el-dialog>
    <!-- showRule -->
    <el-dialog
      :visible.sync="RuleVisible"
      title="Result Rule:"
      width="1010px"
    >
      <el-row>
        <el-col :span="24">
          <el-input
            :rows="20"
            v-model="textareaRuleCom"
            type="textarea"
            readonly
            class="show-text"
          />
        </el-col>
      </el-row>
    </el-dialog>
    <!-- syncTaskProgressDetail -->
    <el-dialog
      :visible.sync="DataScalingDialogSyncTaskProgressDetailVisible"
      width="1110px"
    >
      <el-form :inline="true">
        <el-form-item :label="this.$t('dataScaling').tableList.jobId">
          {{ job.jobId }}
        </el-form-item>
        <el-form-item :label="this.$t('dataScaling').tableList.jobName">
          {{ job.jobName }}
        </el-form-item>
        <el-form-item :label="this.$t('dataScaling').tableList.status">
          {{ job.status }}
        </el-form-item>
      </el-form>

      <el-tabs v-model="activeName">
        <el-tab-pane name="first">
          <div slot="label">{{this.$t('dataScaling').detail.inventory}} ({{percentageComputed}}%)</div>
          <el-row :gutter="10">
            <div v-for="(item, index) in jobDetail.inventoryDataTasks">
              <div v-for="(item1, idx) in item.innerTaskProgresses">
                <el-col
                  :span="4"
                  :key="index"
                >
                  <div style="margin-bottom: 10px;">{{item1.id}}</div>
                  <el-progress type="circle" :percentage="getPercentage(item1)"></el-progress>
                </el-col>
              </div>
            </div>
          </el-row>
        </el-tab-pane>
        <el-tab-pane :label="this.$t('dataScaling').detail.increment" name="second">
          <el-table :data="jobDetail.incrementalDataTasks">
            <el-table-column :label="this.$t('dataScaling').detail.taskId" prop="id"></el-table-column>
            <el-table-column :label="this.$t('dataScaling').detail.delay" prop="delayMillisecond" :formatter="dateFormat"></el-table-column>
          </el-table>
        </el-tab-pane>
      </el-tabs>

    </el-dialog>
    <el-dialog
      :visible.sync="serverDialogVisible"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :show-close="false"
      :title="$t('dataScaling.serviceDialog.title')"
      width="480px"
      center>
      <el-form label-width="110px">
        <el-form-item
        :label="$t('dataScaling.serviceDialog.serviceName')">
          <el-input v-model="serviceForm.serviceName" :placeholder="$t('dataScaling.serviceDialog.serviceNamePlaceholder')"/>
        </el-form-item>
        <el-form-item
        :label="$t('dataScaling.serviceDialog.serviceUrl')">
          <el-input v-model="serviceForm.serviceUrl" :placeholder="$t('dataScaling.serviceDialog.serviceUrlPlaceholder')"/>
        </el-form-item>
        <el-form-item>
          <el-button @click="serverDialogVisible = false">{{
            $t('dataScaling.registDialog.btnCancelTxt')
          }}</el-button>
          <el-button type="primary" @click="setServer">
            {{ $t('dataScaling.registDialog.btnConfirmTxt') }}
          </el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </el-row>
</template>
<script>
import yaml from 'js-yaml'
import Vue from 'vue'
import moment from 'moment'
import clone from 'lodash/clone'
import API from '../api'

Vue.prototype.$moment = moment

/**
 * 保留n位小数
 */
const nDecimal = (num = 0, n = 0) => {
  if (num === null) return '--'
  let f_x = parseFloat(num)
  if (isNaN(f_x)) {
    console.log('function:changeTwoDecimal->parameter error')
    return false
  }

  if (!n) return parseInt(f_x)

  f_x = Math.round(num * 100) / 100
  let s_x = f_x.toString()
  let pos_decimal = s_x.indexOf('.')
  if (pos_decimal < 0) {
    pos_decimal = s_x.length
    s_x += '.'
  }
  while (s_x.length <= pos_decimal + n) {
    s_x += '0'
  }
  return s_x
}

let timer = null

export default {
  name: 'DataScalingIndex',
  data() {
    return {
      DataScalingDialogVisible: false,
      DataScalingDialogSyncTaskProgressDetailVisible: false,
      DatasourceVisible: false,
      serverDialogVisible: false,
      RuleVisible: false,
      serviceForm: {
        serviceName: '',
        serviceType: 'ShardingScaling',
        serviceUrl: ''
      },
      schemaData: [],
      textareaDatasource: ``,
      textareaRule: ``,
      serverHost: '',
      column: [
        {
          label: this.$t('dataScaling').tableList.jobId,
          prop: 'jobId'
        },
        {
          label: this.$t('dataScaling').tableList.jobName,
          prop: 'jobName'
        },
        {
          label: this.$t('dataScaling').tableList.status,
          prop: 'status'
        }
      ],
      form: {
        source: '',
        target: 'Proxy',
        username: '',
        password: '',
        url: '',
        jobCount: '3'
      },
      job: {},
      jobDetail: {},
      activeName: 'first',
      rules: {
        source: [
          {
            required: true,
            message: this.$t('dataScaling').rules.source,
            trigger: 'change'
          }
        ],
        target: [
          {
            required: true,
            message: this.$t('dataScaling').rules.target,
            trigger: 'change'
          }
        ],
        username: [
          {
            required: true,
            message: this.$t('dataScaling').registDialog.usernamePlaceholder,
            trigger: 'change'
          }
        ],
        password: [
          {
            required: true,
            message: this.$t('dataScaling').registDialog.passwordPlaceholder,
            trigger: 'change'
          }
        ],
        url: [
          {
            required: true,
            message: this.$t('dataScaling').registDialog.urlPlaceholder,
            trigger: 'change'
          }
        ],
        jobCount: [
          {
            required: true,
            message: this.$t('dataScaling').registDialog.jobCountPlaceholder,
            trigger: 'change'
          }
        ]
      },
      tableData: [],
      cloneTableData: [],
      currentPage: 1,
      pageSize: 10,
      total: null
    }
  },
  computed: {
    textareaDatasourceCom() {
      const DS_SCHEMA = yaml.Schema.create([])
      return JSON.stringify(
        yaml.load(this.textareaDatasource, { schema: DS_SCHEMA }),
        null,
        '\t'
      )
    },
    textareaRuleCom() {
      const shardingYamlType = new yaml.Type(
        '!SHARDING',
        {
          kind: 'mapping',
          construct(data) {
            return data !== null ? data : {}
          }
        }
      )
      const encryptYamlType = new yaml.Type(
        '!ENCRYPT',
        {
          kind: 'mapping',
          construct(data) {
            return data !== null ? data : {}
          }
        }
      )
      const masterSlaveYamlType = new yaml.Type(
        '!PRIMARY_REPLICA_REPLICATION',
        {
          kind: 'mapping',
          construct(data) {
            return data !== null ? data : {}
          }
        }
      )
      const shadowYamlType = new yaml.Type(
        '!SHADOW',
        {
          kind: 'mapping',
          construct(data) {
            return data !== null ? data : {}
          }
        }
      )
      const DS_SCHEMA = yaml.Schema.create([shardingYamlType, encryptYamlType, masterSlaveYamlType, shadowYamlType])
      return JSON.stringify(
        yaml.load(this.textareaRule, { schema: DS_SCHEMA }),
        null,
        '\t'
      )
    },
    percentageComputed() {
      const arr = this.jobDetail.inventoryDataTasks
      if (!arr) return
      let sumEstimatedRows = 0
      let sumSyncedRows = 0
      for (const v of arr) {
        if (!v.innerTaskProgresses) {
          break
        }
        for(const v1 of v.innerTaskProgresses) {
          sumEstimatedRows += v1.estimatedRows
          sumSyncedRows += v1.syncedRows
        }
      }
      let res = 0
      if (sumEstimatedRows) {
        res = sumSyncedRows / sumEstimatedRows
      }
      return nDecimal(res * 100, 0)
    }
  },
  created() {
    this.getJobServer()
  },
  methods: {
    dateFormat(row, column) {
      if (row.delayMillisecond === -1) {
        return -1
      }
      return this.$moment(
        row.delayMillisecond
      ).format('s')
    },
    showServerDialog() {
      this.serverDialogVisible = true
    },
    setServer() {
      if (this.serviceForm.serviceUrl) {
        API.postJobServer(this.serviceForm).then(res => {
          this.$notify({
            title: this.$t('dataScaling').notify.title,
            message: 'Set up successfully！',
            type: 'success'
          })
          this.serverDialogVisible = false
        }, () => {
          this.$notify({
            title: this.$t('dataScaling').notify.title,
            message: 'Setup failed！',
            type: 'error'
          })
        })
      } else {
        this.$notify({
          title: this.$t('dataScaling').notify.title,
          message: this.$t('dataScaling').rules.serviceUrl,
          type: 'error'
        })
      }
    },
    getJobServer() {
      API.getJobServer().then(res => {
        const { model } = res
        if (model) {
          const { serviceName, serviceType, serviceUrl } = model
          this.serviceForm = {
            serviceName,
            serviceType,
            serviceUrl
          }
          this.getJobList()
        } else {
          this.serverDialogVisible = true
        }
      }, () => {
        this.serverDialogVisible = true
      })
    },
    getPercentage(arr) {
      if (!arr) return
      let sumEstimatedRows = ''
      let sumSyncedRows = ''
      for (const v of arr) {
        sumEstimatedRows += v.estimatedRows
        sumSyncedRows += v.syncedRows
      }
      let res = 0
      if (sumEstimatedRows) {
        res = sumSyncedRows / sumEstimatedRows
      }
      return nDecimal(res, 2) * 100
    },
    getPercentage(obj) {
      let data = 0
      if (obj.estimatedRows) {
        data = obj.syncedRows / obj.estimatedRows
        return nDecimal(data, 2) * 100
      }
      return 100
    },
    getOption(obj) {
      let data = 0
      if (obj.estimatedRows) {
        data = obj.syncedRows / obj.estimatedRows
      }
      const option = {
        series: [
          {
            type: 'liquidFill',
            radius: '90%',
            data: [data],
            outline: {
              show: false
            },
            label: {
              fontSize: 20
            }
          }
        ]
      }
      return option
    },
    selectChange(item) {
      this.getSchemaDataSource(item)
      this.getSchemaRule(item)
    },
    getSchemaDataSource(schemaName) {
      API.getSchemaDataSource(schemaName).then(res => {
        const { model } = res
        if (Object.prototype.toString.call(model) === '[object String]') {
          this.textareaDatasource = model
        } else {
          this.textareaDatasource = JSON.stringify(model, null, '\t')
        }
      })
    },
    getSchemaRule(schemaName) {
      API.getSchemaRule(schemaName).then(res => {
        const { model } = res
        if (Object.prototype.toString.call(model) === '[object String]') {
          this.textareaRule = model
        } else {
          this.textareaRule = JSON.stringify(model, null, '\t')
        }
      })
    },
    getSchema() {
      API.getSchema().then(res => {
        this.schemaData = res.model
      })
    },
    handleCurrentChange(val) {
      const data = clone(this.cloneTableData)
      this.tableData = data.splice(val - 1, this.pageSize)
    },
    getJobList() {
      API.getJobList().then(res => {
        const data = res.model
        this.total = data.length
        this.cloneTableData = clone(res.model)
        this.tableData = data.splice(0, this.pageSize)
      })
    },
    handlerStop(row) {
      const params = {
        jobId: row.jobId
      }
      API.postJobStop(params).then(res => {
        this.$notify({
          title: this.$t('dataScaling').notify.title,
          message: this.$t('dataScaling').notify.delSucMessage,
          type: 'success'
        })
        this.getJobList()
      })
    },
    getJobProgress(row) {
      const { jobId, status } = row
      API.getJobProgress(jobId).then(res => {
        const { model } = res
        this.jobDetail = model
        clearTimeout(timer)
        if (status !== 'STOPPED') {
          timer = setTimeout(() => {
            this.getJobProgress(row)
            clearTimeout(timer)
          }, 2000)
        }
      })
    },
    showSyncTaskProgressDetail(item) {
      this.job = item
      this.DataScalingDialogSyncTaskProgressDetailVisible = true
      this.getJobProgress(item)
    },
    onConfirm(formName) {
      this.$refs[formName].validate(valid => {
        if (valid) {
          const { username, password, url, jobCount } = this.form
          const params = {
            ruleConfiguration: {
              sourceDataSource: this.textareaDatasource,
              sourceRule: this.textareaRule,
              targetDataSources: {
                username,
                password,
                url
              }
            },
            jobConfiguration: {
              concurrency: jobCount
            }
          }
          API.getJobStart(params).then(res => {
            this.DataScalingDialogVisible = false
            this.$notify({
              title: this.$t('dataScaling').notify.title,
              message: this.$t('dataScaling').notify.conSucMessage,
              type: 'success'
            })
            this.clearForm()
            this.getJobList()
          })
        } else {
          return false
        }
      })
    },
    clearForm() {
      this.form = {
        source: '',
        target: 'Proxy',
        username: '',
        password: '',
        url: '',
        jobCount: '3'
      }
    },
    add() {
      this.DataScalingDialogVisible = true
      this.getSchema()
    },
    showDatasource() {
      this.DatasourceVisible = true
    },
    showRule() {
      this.RuleVisible = true
    },
    close() {
      clearTimeout(timer)
    }
  }
}
</script>
<style lang="scss">
  .el-icon-edit {
    cursor: pointer;
  }
  .btn-group {
    margin-bottom: 20px;
  }
  .pagination {
    float: right;
    margin: 10px -10px 10px 0;
  }
  .collapse-row {
    width: 100%;
    .collapse-progress {
      margin-top: 15px;
    }
  }
  .progress-item {
    height: 48px;
    line-height: 48px;
    .collapse-progress {
      margin-top: 15px;
      float: right;
    }
    .collapse-active {
      .el-progress-bar__inner:before {
        content: '';
        opacity: 0;
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: #fff;
        border-radius: 10px;
        animation: progress-active 2s ease-in-out infinite;
      }
    }
  }
  @keyframes progress-active {
    0% {
      opacity: 0.3;
      width: 0;
    }
    to {
      opacity: 0;
      width: 100%;
    }
  }
  .echarts {
    width: 300px;
    height: 200px;
  }
</style>
