<h3 style="display: flex; align-items: baseline; justify-content: space-between; margin-inline-end: 20px;">
  <div>
    {{ header }}
    <el-switch v-model="LogEnabled" style="margin-left: 5px" @change="designer.changelogenabled"></el-switch>
  </div>
  <div style="display: flex; gap: 10px;">
    <el-button :disabled="!LogEnabled" icon="el-icon-refresh" plain style="padding: 6px" type="primary" @click="onRefresh">
      {{ labels.Refresh }}
    </el-button>
    <el-checkbox v-model="autoRefresh" :disabled="!LogEnabled" :label="labels.AutoRefresh" border
                 style="padding: 4px 10px; border-radius: 6px; height: 30.4px;"
                 @change="onAutoRefresh"></el-checkbox>

    <el-input-number v-if="autoRefresh"
                     v-model="speedOfRefresh"
                     :max="10" :min="0.3" :precision="1" :step="0.1"
                     controls-position="right" size="small" style="width: 95px; height: 30.4px;">
    </el-input-number>
  </div>
</h3>

<el-table
  :cell-style="tableCellStyle"
  :data="tableData"
  :row-style="tableRowStyle"
  class="infinite-loading__table"
  fit
  height="calc(100% - 75px)"
  row-key="id"
  style="height: 100%; width: 100%"
  @cell-mouse-enter="onHoveringRow">
  <el-table-column
    :formatter="getFormatDate"
    :label="labels.Timestamp"
    :width="(260 + 20*maxLevel)+'px'"
    prop="Timestamp">
  </el-table-column>
  <el-table-column
    :label="labels.Message"
    prop="Message">
    <template slot-scope="scope">
      <div style="white-space:nowrap">
        <el-popover
          placement="bottom"
          trigger="hover">
          <el-row
            v-for="(key) in Object.keys(scope.row.Properties).filter(function(x) {if (scope.row.Properties[x]) return x;})"
            style="width: 560px" :key="key">
            <el-col :span="12">{{ key }}</el-col>
            <el-col :span="12">{{ scope.row.Properties[key] || labels.Empty }}</el-col>
          </el-row>

          <span slot="reference">
                        <i class="el-icon-info"></i>
                    </span>
        </el-popover>
        {{ scope.row.Message }}
      </div>
    </template>
  </el-table-column>
  <el-table-column
    :label="labels.Exception"
    width="90">
    <template slot-scope="scope">
      <el-button v-if="scope.row.Exception != null" size="mini" type="danger"
                 @click="handleDialogOpen(scope.row.Exception)">{{ labels.Show }}
      </el-button>
    </template>
  </el-table-column>
  <infinite-loading
    slot="append"
    force-use-infinite-wrapper=".el-table__body-wrapper"
    @infinite="infiniteHandler">
    <div slot="no-results"></div>
  </infinite-loading>
</el-table>
<el-dialog
  :modal=false
  :title="labels.ExceptionInfo"
  :visible.sync="dialog.visible"
  top="40vh"
  width="500px">
  <p>{{ dialog.data.ClassName }}</p>
  <p v-if="dialog.data.Message">{{ dialog.data.Message }}</p>
  <el-button type="text" @click="dialog.showDetails = !dialog.showDetails">
    {{ dialog.showDetails ? labels.HideDetails : labels.ShowDetails }}
  </el-button>
  <pre v-if="dialog.showDetails" class="CodeBlock"><code>{{ dialog.data }}</code></pre>
  <el-button slot="footer" type="primary" @click="dialog.visible = false">{{ ButtonTextOk }}</el-button>
</el-dialog>

<script type="application/javascript">

  function logs_Init(me) {
    const designer = me.graph.designer;
    me.VueConfig.data = Object.assign(me.VueConfig.data, {
      labels: WorkflowDesignerConstants.Logs,
      ButtonTextOk: WorkflowDesignerConstants.ButtonTextOk,
      header: WorkflowDesignerConstants.Logs.Label,
      designer: me.graph.designer,
      count: 20,
      items: [],
      tableDataSource: [],
      tableData: [],
      loading: true,
      autoRefresh: false,
      speedOfRefresh: 1,
      LogEnabled: designer.LogEnabled,
      maxLevel: 0,
      dialog: {
        visible: false,
        data: {},
        showDetails: false
      },
      folder: me.graph.Settings.templatefolder
    });
    me.VueConfig.methods = {
      onAutoRefresh: function () {
        if (this.autoRefresh && designer.LogEnabled) {
          this.onRefresh();
          setTimeout(this.onAutoRefresh, this.speedOfRefresh * 1000);
        }
      },

      handleDialogOpen: function (data) {
        this.dialog.data = data;
        this.dialog.visible = true;
      },

      tableCellStyle: function (data) {
        let row = data.row;
        let cellStyle = {};
        if (row['Properties'] && row['Properties']['EventType'] != 'EndExecution' && data.columnIndex == 0 && row.level == 0) {
          cellStyle.paddingLeft = '22px'
        } else {
          if (row['Properties'] && row['Properties']['EventType'] == 'EndExecution' && row.level != 0) {
            cellStyle.paddingLeft = ((row.level) * 22) + 'px'
          } else if (row['Properties'] && row['Properties']['EventType'] != 'EndExecution' && row.level != 0) {
            cellStyle.paddingLeft = ((row.level) * 24) + 'px'
          }
        }

        return cellStyle;
      },

      tableRowStyle: function (data) {
        let row = data.row;
        let rowStyle = {};

        if (row['isNew']) {
          rowStyle.background = 'rgba(64,158,255,0.1)';
        } else if (row['Exception'] != null) {
          rowStyle.background = 'rgba(245,108,108,0.1)';
        }

        if (row['Properties'] && ['StartExecution', 'EndExecution'].includes(row['Properties']['EventType'])) {
          rowStyle.fontWeight = 'bold';
          rowStyle.fontSize = '15px';
        }

        return rowStyle;
      },
      onHoveringRow: function (row) {
        if (row.isNew) {
          row.isNew = false;
        }
      },
      onRefresh: function () {
        var additionalLogs = designer.getprocesslogs({suboperation: 'Last', count: this.count});
        if (additionalLogs.length) {
          this.tableDataSource = additionalLogs;
          this.tableData = this.sortTableData(JSON.parse(JSON.stringify(this.tableDataSource)));
        }
      },
      infiniteHandler: function ($state) {
        if (this.tableData.length === 0) {
          $state.loaded();
          $state.complete();
          return;
        }
        var dateTime = this.findMinDateTime(this.tableDataSource);
        var additionalLogs = designer.getprocesslogs({
          suboperation: 'Early',
          dateTime: dateTime,
          count: this.count
        });

        var lastSourceItem = JSON.stringify(this.tableDataSource[this.tableDataSource.length - 1]);
        var lastNewItem = JSON.stringify(additionalLogs[additionalLogs.length - 1]);
        var isEqualLastItems = lastSourceItem === lastNewItem;

        if (additionalLogs.length && !isEqualLastItems) {
          this.tableDataSource = this.tableDataSource.concat(additionalLogs)
          this.tableData = this.sortTableData(JSON.parse(JSON.stringify(this.tableDataSource)));
          if (additionalLogs.length < this.count)
            $state.complete();
          else
            $state.loaded();
        } else {
          $state.complete();
        }
      },
      findMinDateTime: function (arr) {
        var len = arr.length, min = arr[0]['CreatedOn'];
        while (len--) {
          if (arr[len]['CreatedOn'] < min) {
            min = arr[len]['CreatedOn'];
          }
        }
        return min;
      },
      findMaxDateTime: function (arr) {
        var len = arr.length, max = arr[0]['CreatedOn'];
        while (len--) {
          if (arr[len]['CreatedOn'] > max) {
            max = arr[len]['CreatedOn'];
          }
        }
        return max;
      },
      getFormatDate: function (a, b, stringDate, d) {
        let date = new Date(stringDate);
        return date.toISOString();
      },
      sortTableData: function (data) {
        return data.sort(function (a, b) {
          return me.VueConfig.methods.compareDatesWithMicroseconds(a.Timestamp, b.Timestamp)
        })
      },
      compareDatesWithMicroseconds: function (a, b) {
        var dateA = new Date(a).getTime();
        var dateB = new Date(b).getTime();
        if (dateA < dateB) return 1;
        else if (dateA > dateB) return -1;
        else {
          var microSecondsA = me.VueConfig.methods.getMicroseconds(a);
          var microSecondsB = me.VueConfig.methods.getMicroseconds(b);

          if (microSecondsA < microSecondsB) return 1;
          else if (microSecondsA > microSecondsB) return -1;
          return 0;
        }

      },
      getMicroseconds(timeString) {
        if (timeString.lastIndexOf('+') > -1) {
          return parseFloat(timeString.substring(timeString.lastIndexOf('.'), timeString.lastIndexOf('+')));
        }

        return parseFloat(timeString.substring(timeString.lastIndexOf('.')));
      }
    }

    me.VueConfig.created = function () {
      var dataSource = designer.getprocesslogs({suboperation: 'Last', count: this.count});
      this.tableDataSource = dataSource;
      this.tableData = this.sortTableData(JSON.parse(JSON.stringify(dataSource)));
    }
  }

</script>
