<h3>{{ labels.TitleForInline }}</h3>
<el-form ref="form"
         :model="FormData"
         class="WorkflowDesignerWindowForm"
         label-position="left"
         label-width="150px">
  <el-form-item :label="labels.Name" :readonly="readonly" :rules="getFieldRules('Name')" prop="Name">
    <el-input v-model="FormData.Name"></el-input>
  </el-form-item>
  <el-form-item :label="labels.Scheme" :rules="getFieldRules('SchemeCode')" prop="SchemeCode">
    <el-select
      v-model="FormData.SchemeCode"
      :disabled="readonly"
      @change="onSchemeChange"
      filterable
      placeholder=""
      style="width: 100%;"
    >
      <el-option
        v-for="scheme in schemes"
        :key="scheme"
        :label="scheme"
        :value="scheme">
      </el-option>
    </el-select>
  </el-form-item>

  <div style="margin-bottom: 10px;">
    <h4 class="WorkflowDesignerTitleWithCreate Underline">
      {{ labels.InputParameters }}
      <a v-if="!readonly" @click="addInputParameter()">{{ ButtonTextCreate }}</a>
    </h4>
    <table v-if="inputParameters.length > 0" class="WorkflowDesignerTable">
      <tr>
        <th></th>
        <th>{{ labels.Target }}</th>
        <th>{{ labels.Purpose }}</th>
        <th>{{ labels.Expression }}</th>
      </tr>
      <tr
        v-for="(parameter, index) in inputParameters"
        :key="index"
        :class="dragOverIndex == index && dragOverBlock == parameter ? 'dragOver' : ''"
        @dragend="dragend($event)"
        @dragover="dragover(parameter, index, $event)"
        @dragstart="dragstart(index, $event, inputParameters)"
      >
        <td :draggable="!readonly" class='WorkflowDesignerTableMoveCol'>
          <div v-if="!readonly" class='WorkflowDesignerTableMoveButton'></div>
        </td>
        <td>
          <el-select
            v-model="parameter.Target"
            :allow-create="true"
            :disabled="readonly"
            @change="onInputParameterTargetChange"
            :class="isEmpty(parameter.Target) && saveTriggered ? 'WorkflowDesignerInputError' : ''"
            filterable
          >
            <el-option
              v-for="schemeParameter in inlinedSchemeParameters"
              :key="schemeParameter.Name"
              :label="schemeParameter.Name"
              :value="schemeParameter.Name">
            </el-option>
          </el-select>
        </td>
        <td>
          <el-select
            v-model="parameter.Purpose"
            :disabled="readonly || !!findInlinedSchemeParameter(parameter.Target)"
            :class="isEmpty(parameter.Purpose) && saveTriggered ? 'WorkflowDesignerInputError' : ''"
            filterable
          >
            <el-option key="Temporary" :label="!!findInlinedSchemeParameter(parameter.Target) ? 'Predefined' : 'Temporary'"
                       value="Temporary"></el-option>
            <el-option key="Persistent" label="Persistence" value="Persistence"></el-option>
          </el-select>
        </td>
        <td>
          <el-input
            v-model="parameter.Expression"
            :readonly="readonly"
            :class="isEmpty(parameter.Expression) && saveTriggered ? 'WorkflowDesignerInputError' : ''"
          ></el-input>
        </td>
        <td v-if="!readonly" class="WorkflowDesignerTableEditButtons Double">
          <el-button-group>
            <el-button
              :class="'WorkflowDesignerTableCodeActionsButton ' + (editingParameter == parameter ? 'is-active' : '')"
              @click="showExpressionEditor(parameter)"></el-button>
            <el-button class="WorkflowDesignerTableDeleteButton" @click="removeItem(inputParameters, index)"></el-button>
          </el-button-group>
        </td>
      </tr>
    </table>
  </div>

  <div style="margin-bottom: 10px;">
    <h4 class="WorkflowDesignerTitleWithCreate Underline">
      {{ labels.OutputParameters }}
      <a v-if="!readonly" @click="addOutputParameter()">{{ ButtonTextCreate }}</a>
    </h4>
    <table v-if="outputParameters.length > 0" class="WorkflowDesignerTable">
      <tr>
        <th></th>
        <th>{{ labels.Target }}</th>
        <th>{{ labels.Purpose }}</th>
        <th>{{ labels.Expression }}</th>
      </tr>
      <tr
        v-for="(parameter, index) in outputParameters"
        :key="index"
        :class="dragOverIndex == index && dragOverBlock == parameter ? 'dragOver' : ''"
        @dragend="dragend($event)"
        @dragover="dragover(parameter, index, $event)"
        @dragstart="dragstart(index, $event, outputParameters)"
      >
        <td :draggable="!readonly" class='WorkflowDesignerTableMoveCol'>
          <div v-if="!readonly" class='WorkflowDesignerTableMoveButton'></div>
        </td>
        <td>
          <el-select
            v-model="parameter.Target"
            :allow-create="true"
            :disabled="readonly"
            @change="onOutputParameterTargetChange"
            :class="isEmpty(parameter.Target) && saveTriggered ? 'WorkflowDesignerInputError' : ''"
            filterable
          >
            <el-option
              v-for="schemeParameter in schemeParameters"
              :key="schemeParameter.Name"
              :label="schemeParameter.Name"
              :value="schemeParameter.Name">
            </el-option>
          </el-select>
        </td>
        <td>
          <el-select
            v-model="parameter.Purpose"
            :disabled="readonly || !!findSchemeParameter(parameter.Target)"
            :class="isEmpty(parameter.Purpose) && saveTriggered ? 'WorkflowDesignerInputError' : ''"
            filterable
          >
            <el-option key="Temporary" :label="!!findSchemeParameter(parameter.Target) ? 'Predefined' : 'Temporary'"
                       value="Temporary"></el-option>
            <el-option key="Persistence" label="Persistence" value="Persistence"></el-option>
          </el-select>
        </td>
        <td>
          <el-input
            v-model="parameter.Expression"
            :readonly="readonly"
            :class="isEmpty(parameter.Expression) && saveTriggered ? 'WorkflowDesignerInputError' : ''"
          ></el-input>
        </td>
        <td v-if="!readonly" class="WorkflowDesignerTableEditButtons Double">
          <el-button-group>
            <el-button
              :class="'WorkflowDesignerTableCodeActionsButton ' + (editingParameter == parameter ? 'is-active' : '')"
              @click="showExpressionEditor(parameter)"></el-button>
            <el-button class="WorkflowDesignerTableDeleteButton" @click="removeItem(outputParameters, index)"></el-button>
          </el-button-group>
        </td>
      </tr>
    </table>
  </div>

  <el-button icon="IconComment" v-if="!readonly && !itemHasComment" circle @click="showUserComment()"></el-button>
  <el-form-item v-if="itemHasComment" :label="labels.UserComment">
    <el-input
      v-if="itemHasComment"
      v-model="FormData.UserComment"
      :placeholder="labels.UserComment"
      :rows="5"
      type="textarea"
    >
    </el-input>
  </el-form-item>
</el-form>

<div class="WorkflowDesignerButtons">
  <el-button v-if="!readonly" type="primary" @click="onSave">{{ ButtonTextSave }}</el-button>
  <el-button @click="onClose">{{ ButtonTextCancel }}</el-button>
</div>
<script type="application/javascript">
  function activityinline_Data(me) {
    return {
      readonly: false,
      itemHasComment: false,
      schemes: [],
      FormData: {},
      inputParameters: [],
      outputParameters: []
    }
  }

  function activityinline_Init(me) {
    const {VueConfig} = me;
    const {state: data, methods} = VueConfig;

    methods.UpdateLanguage = function () {
      Object.assign(data, {
        labels: WorkflowDesignerConstants.ActivityFormLabel,
        ButtonTextSave: WorkflowDesignerConstants.ButtonTextSave,
        ButtonTextCancel: WorkflowDesignerConstants.ButtonTextCancel,
        ButtonTextCreate: WorkflowDesignerConstants.ButtonTextCreate,
        inputParameters: [], //: ParameterMapping[]
        outputParameters: [], //: ParameterMapping[],
        inlinedSchemeParameters: [], //: ParameterDefinition[]
        schemeParameters: [], //: ParameterDefinition[]
        editingParameter: null, //: ParameterMapping | null
        saveTriggered: false, //: boolean
      });
    }

    methods.UpdateLanguage();

    var INPUT_PARAMETERS_ANNOTATION = '__inputParameters';
    var OUTPUT_PARAMETERS_ANNOTATION = '__outputParameters';

    methods.onUpdate = function (item) {
      data.originalItem = item;
      data.FormData.Name = item.Name;
      data.FormData.SchemeCode = item.SchemeCode;
      data.FormData.Annotations = item.Annotations || [];
      data.schemes = me.graph.data.AdditionalParams.InlinedSchemeCodes;

      me.linkItem = item;

      if (!!item.SchemeCode) {
        data.inlinedSchemeParameters = me.graph.data.AdditionalParams.InlinedSchemeParameters[item.SchemeCode].map(parameter => new ParameterDefinition(parameter));
      }

      data.schemeParameters = me.graph.data.Parameters
        .filter(parameter => parameter.Purpose !== 'System')
        .map(parameter => new ParameterDefinition(parameter));

      data.itemHasComment = item.UserComment != null && item.UserComment.length > 0;

      if (Array.isArray(item.Annotations)) {
        item.Annotations.forEach(function (annotation) {
          if (annotation.Name === INPUT_PARAMETERS_ANNOTATION) {
            var inputParameters = JSON.parse(annotation.JsonValue);
            data.inputParameters = inputParameters.map(json => new ParameterMapping(json));
          } else if (annotation.Name === OUTPUT_PARAMETERS_ANNOTATION) {
            var outputParameters = JSON.parse(annotation.JsonValue);
            data.outputParameters = outputParameters.map(json => new ParameterMapping(json));
          }
        });
      }

      data.readonly = me.graph.Settings.readonly;
    };

    methods.getFieldRules = function (field) {
      var res = [{required: true, message: WorkflowDesignerConstants.FieldIsRequired, trigger: 'blur'}];

      if (field === 'Name') {
        var validator = function (rule, value, callback) {
          var isValid = true;
          me.graph.data.Activities.forEach(function (a) {
            if (a !== me.linkItem && a.Name === value) {
              isValid = false;
            }
          });

          if (isValid) {
            callback();
          } else {
            callback(new Error(rule.message));
          }
        };
        res.push({validator, message: WorkflowDesignerConstants.FieldMustBeUnique});
      }
      return res;
    };

    function validateParameterMapping(parameter /*: ParameterMapping*/) /*: boolean*/ {
      return !!parameter.Target && !!parameter.Expression && !!parameter.Purpose;
    }

    methods.onSave = function () {
      data.saveTriggered = true;

      if (this.$refs && this.$refs.form) {
        this.$refs.form.validate(function (valid) {
          if (valid) {
            if (data.inputParameters.some(parameter => !validateParameterMapping(parameter))) return;
            if (data.outputParameters.some(parameter => !validateParameterMapping(parameter))) return;

            var annotations = data.FormData.Annotations;

            var inputParametersAnnotation = annotations.find(annotation => annotation.Name === INPUT_PARAMETERS_ANNOTATION);

            if (!inputParametersAnnotation) {
              inputParametersAnnotation = {
                Name: INPUT_PARAMETERS_ANNOTATION,
                JsonValue: JSON.stringify(data.inputParameters)
              };
              annotations.push(inputParametersAnnotation);
            } else {
              inputParametersAnnotation.JsonValue = JSON.stringify(data.inputParameters);
            }

            var outputParametersAnnotation = annotations.find(annotation => annotation.Name === OUTPUT_PARAMETERS_ANNOTATION);

            if (!outputParametersAnnotation) {
              outputParametersAnnotation = {
                Name: OUTPUT_PARAMETERS_ANNOTATION,
                JsonValue: JSON.stringify(data.outputParameters)
              };
              annotations.push(outputParametersAnnotation);
            } else {
              outputParametersAnnotation.JsonValue = JSON.stringify(data.outputParameters);
            }

            me.onSuccess(data.FormData);
            me.onClose(true);
          }
        });
      }
    };

    methods.onClose = function () {
      if (data.readonly) {
        me.onClose(true);
        return;
      }

      var originalItem = data.originalItem;
      var item = data.FormData;

      if (originalItem.Name === item.Name && originalItem.SchemeCode === item.SchemeCode) {
        me.onClose(true);
      } else {
        me.showConfirm();
      }
    };

    methods.showUserComment = function () {
      data.itemHasComment = true;
    }

    methods.onCloseSave = function () {
      me.onClose(true);
    };

    methods.showExpressionEditor = function (parameter /*:ParameterMapping */) {
      data.editingParameter = parameter;
      me.editItem = parameter;

      var onSuccess = function (value) {
        if (me.editItem) {
          me.editItem.Expression = value;
          data.editingParameter = null;
          delete me.editItem;
        }
      };

      var onClose = function (value) {
        data.editingParameter = null;
      };

      data.jsonform = me.showjson(parameter.Expression, {expression: true, expressiontype: 'object'}, onSuccess, onClose);
    };

    class ParameterDefinition {
      Name //: string;
      Purpose //: 'Temporary' | 'Persistent';
      constructor(data) {
        if (data) {
          Object.assign(this, data);
        }
      }
    }

    methods.onSchemeChange = function (schemeCode /*: string*/) {
      if (schemeCode) {
        data.inlinedSchemeParameters = me.graph.data.AdditionalParams.InlinedSchemeParameters[schemeCode].map(parameter => new ParameterDefinition(parameter));
      } else {
        data.inlinedSchemeParameters = [];
      }

      for (var inputParameter of data.inputParameters) {
        methods.onInputParameterTargetChange(inputParameter.Target);
      }
    };

    methods.findInlinedSchemeParameter = function (name /*: string*/) /*: ParameterDefinition | undefined*/ {
      return data.inlinedSchemeParameters.find(parameter => parameter.Name === name);
    };

    methods.findSchemeParameter = function (name /*: string*/) /*: ParameterDefinition | undefined*/ {
      return data.schemeParameters.find(parameter => parameter.Name === name);
    };

    methods.onInputParameterTargetChange = function (target /*: string*/) {
      var schemeParameter = methods.findInlinedSchemeParameter(target);
      if (schemeParameter) {
        var parameter = data.inputParameters.find(parameter => parameter.Target === target);
        if (parameter) {
          parameter.Purpose = 'Temporary';
        }
      }
    };

    methods.onOutputParameterTargetChange = function (target /*: string*/) {
      var schemeParameter = methods.findSchemeParameter(target);
      if (schemeParameter) {
        var parameter = data.outputParameters.find(parameter => parameter.Target === target);
        if (parameter) {
          parameter.Purpose = 'Temporary';
        }
      }
    };

    class ParameterMapping {
      Target = '' //: string;
      Purpose = 'Temporary' //: 'Temporary' | 'Persistent';
      Expression = '' //: string;
      constructor(data) {
        if (data) {
          Object.assign(this, data);
        }
      }
    }

    methods.isEmpty = function (input/*: string | null| undefined*/) {
      return !input;
    }

    methods.removeItem = function (items, index) {
      items.splice(index, 1);
    };

    methods.addInputParameter = function () {
      data.inputParameters.push(new ParameterMapping());
    };

    methods.addOutputParameter = function () {
      data.outputParameters.push(new ParameterMapping());
    };

    me.showConfirm = function () {
      methods.showConfirm({
        title: WorkflowDesignerConstants.DialogConfirmText,
        message: WorkflowDesignerConstants.CloseWithoutSaving,
        onSuccess: function () {
          methods.onCloseSave();
        }
      });
    }
  }
</script>
