<template>
  <v-row v-if="this.formState.ready">
    <v-col>
      <v-form ref="form">
        <v-row>
          <gz-error :errorBoxMessage="formState.errorBoxMessage"></gz-error>
          <v-col cols="12">
            <v-row>
              <v-col cols="12" sm="6" lg="4" xl="3">
                <v-text-field
                  v-model="obj.name"
                  :readonly="this.formState.readOnly"
                  :clearable="!formState.readOnly"
                  @click:clear="fieldValueChanged('name')"
                  :counter="255"
                  :label="$ay.t('Name')"
                  :rules="[
                    form().max255(this, 'name'),
                    form().required(this, 'name')
                  ]"
                  :error-messages="form().serverErrors(this, 'name')"
                  ref="name"
                  @input="fieldValueChanged('name')"
                  :data-cy="!!$ay.dev ? 'name' : false"
                ></v-text-field>
              </v-col>
              <v-col cols="12" sm="6" lg="4" xl="3">
                <v-checkbox
                  v-model="obj.public"
                  :readonly="this.formState.readOnly"
                  :label="$ay.t('AnyUser')"
                  ref="public"
                  @change="fieldValueChanged('public')"
                ></v-checkbox>
              </v-col>
            </v-row>
          </v-col>
          <template v-for="(item, index) in obj.editView">
            <v-col :key="item.key" cols="12" sm="6" lg="4" xl="3" px-2>
              <v-card :data-cy="!!$ay.dev ? 'columncard:' + item.key : false">
                <v-card-title>
                  {{ item.title }}
                </v-card-title>

                <v-card-text>
                  <!-- INCLUDE CONTROL -->
                  <v-switch
                    v-if="!item.rid"
                    v-model="item.include"
                    :label="$ay.t('Include')"
                    :ref="item.key"
                    :disabled="
                      item.sort != null || item.filter.items.length > 0
                    "
                    @change="includeChanged(item)"
                  ></v-switch>
                  <div v-if="item.rid" class="v-label mb-8 mt-6">
                    {{ $ay.t("Include") }}
                  </div>
                  <!-- RE-ORDER CONTROL -->
                  <div class="d-flex justify-space-between">
                    <v-btn large icon @click="move('start', index)"
                      ><v-icon large :data-cy="!!$ay.dev ? 'movestart' : false"
                        >fa-step-backward</v-icon
                      ></v-btn
                    >
                    <v-btn large icon @click="move('left', index)"
                      ><v-icon large>fa-backward</v-icon></v-btn
                    >
                    <v-btn large icon @click="move('right', index)"
                      ><v-icon large>fa-forward</v-icon></v-btn
                    >
                    <v-btn large icon @click="move('end', index)"
                      ><v-icon large>fa-step-forward</v-icon></v-btn
                    >
                  </div>
                  <!-- SORT CONTROL -->
                  <template v-if="item.isSortable">
                    <div @click="toggleSort(item)" class="pt-6">
                      <v-btn x-large v-if="item.sort == null" icon>
                        <v-icon x-large>fa-sort</v-icon></v-btn
                      >
                      <v-btn
                        v-if="item.sort != null && item.sort == '-'"
                        icon
                        x-large
                        ><v-icon color="primary" x-large
                          >fa-sort-amount-down</v-icon
                        ></v-btn
                      >
                      <v-btn
                        v-if="item.sort != null && item.sort == '+'"
                        icon
                        x-large
                        ><v-icon color="primary" x-large
                          >fa-sort-amount-up</v-icon
                        ></v-btn
                      >
                      <label class="v-label theme--light"
                        >&nbsp;{{ $ay.t("Sort") }}</label
                      >
                    </div>
                  </template>

                  <!-- FILTER CONTROL -->
                  <template v-if="item.isFilterable">
                    <div class="pt-6">
                      <!-- ******** BUILDER FOR EACH TYPE Tag, decimal,currency, bool, integer, string, datetime ******** -->
                      <!-- DATETIME BUILDER -->
                      <div v-if="item.uiFieldDataType === 1">
                        <v-select
                          v-model="item.tempFilterToken"
                          :items="selectLists.dateFilterTokens"
                          item-text="name"
                          item-value="id"
                          :label="$ay.t('Filter')"
                          prepend-icon="fa-filter"
                        ></v-select>
                        <div v-if="item.tempFilterToken == '*select*'">
                          <v-select
                            v-model="item.tempFilterOperator"
                            :items="selectLists.dateFilterOperators"
                            item-text="name"
                            item-value="id"
                          ></v-select>
                          <gz-date-time-picker
                            v-if="
                              item.tempFilterOperator != '*NOVALUE*' &&
                                item.tempFilterOperator != '*HASVALUE*'
                            "
                            v-model="item.tempFilterValue"
                          ></gz-date-time-picker>
                        </div>
                        <v-btn
                          large
                          block
                          v-if="item.tempFilterToken != null"
                          @click="addFilterCondition(item)"
                          ><v-icon large>fa-plus</v-icon></v-btn
                        >
                      </div>

                      <!-- STRING(text-4, emailaddress-11, http-12) BUILDER  -->
                      <div
                        v-if="
                          item.uiFieldDataType === 4 ||
                            item.uiFieldDataType === 11 ||
                            item.uiFieldDataType === 12
                        "
                      >
                        <v-select
                          v-model="item.tempFilterOperator"
                          :items="selectLists.stringFilterOperators"
                          item-text="name"
                          item-value="id"
                          :label="$ay.t('Filter')"
                          prepend-icon="fa-filter"
                        ></v-select>
                        <v-text-field
                          v-if="
                            item.tempFilterOperator != null &&
                              item.tempFilterOperator != '*NOVALUE*' &&
                              item.tempFilterOperator != '*HASVALUE*'
                          "
                          v-model="item.tempFilterValue"
                          :clearable="!formState.readOnly"
                        ></v-text-field>
                        <v-btn
                          large
                          block
                          v-if="item.tempFilterOperator != null"
                          @click="addFilterCondition(item)"
                          ><v-icon large>fa-plus</v-icon></v-btn
                        >
                      </div>

                      <!-- INTEGER BUILDER  -->
                      <!-- Also MemorySize type 14 are integers -->
                      <div
                        v-if="
                          item.uiFieldDataType === 5 ||
                            item.uiFieldDataType === 14
                        "
                      >
                        <v-select
                          v-model="item.tempFilterOperator"
                          :items="selectLists.integerFilterOperators"
                          item-text="name"
                          item-value="id"
                          :label="$ay.t('Filter')"
                          prepend-icon="fa-filter"
                        ></v-select>
                        <v-text-field
                          v-if="
                            item.tempFilterOperator != null &&
                              item.tempFilterOperator != '*NOVALUE*' &&
                              item.tempFilterOperator != '*HASVALUE*'
                          "
                          v-model="item.tempFilterValue"
                          :clearable="!formState.readOnly"
                          type="number"
                        ></v-text-field>
                        <v-btn
                          large
                          block
                          v-if="item.tempFilterOperator != null"
                          @click="addFilterCondition(item)"
                          ><v-icon large>fa-plus</v-icon></v-btn
                        >
                      </div>
                      <!-- BOOL BUILDER  -->
                      <div v-if="item.uiFieldDataType === 6">
                        <v-select
                          v-model="item.tempFilterOperator"
                          :items="selectLists.boolFilterOperators"
                          item-text="name"
                          item-value="id"
                          :label="$ay.t('Filter')"
                          prepend-icon="fa-filter"
                        ></v-select>
                        <v-radio-group
                          v-model="item.tempFilterValue"
                          v-if="
                            item.tempFilterOperator != null &&
                              item.tempFilterOperator != '*NOVALUE*' &&
                              item.tempFilterOperator != '*HASVALUE*'
                          "
                          row
                        >
                          <v-radio
                            :label="$ay.t('False')"
                            :value="false"
                          ></v-radio>
                          <v-radio
                            :label="$ay.t('True')"
                            :value="true"
                          ></v-radio>
                        </v-radio-group>

                        <v-btn
                          large
                          block
                          v-if="item.tempFilterOperator != null"
                          @click="addFilterCondition(item)"
                          ><v-icon large>fa-plus</v-icon></v-btn
                        >
                      </div>

                      <!-- DECIMAL BUILDER -->
                      <div v-if="item.uiFieldDataType === 7">
                        <v-select
                          v-model="item.tempFilterOperator"
                          :items="selectLists.decimalFilterOperators"
                          item-text="name"
                          item-value="id"
                          :label="$ay.t('Filter')"
                          prepend-icon="fa-filter"
                        ></v-select>
                        <gz-decimal
                          v-if="
                            item.tempFilterOperator != null &&
                              item.tempFilterOperator != '*NOVALUE*' &&
                              item.tempFilterOperator != '*HASVALUE*'
                          "
                          v-model="item.tempFilterValue"
                          :clearable="!formState.readOnly"
                        ></gz-decimal>
                        <v-btn
                          large
                          block
                          v-if="item.tempFilterOperator != null"
                          @click="addFilterCondition(item)"
                          ><v-icon large>fa-plus</v-icon></v-btn
                        >
                      </div>
                      <!-- CURRENCY BUILDER  -->
                      <div v-if="item.uiFieldDataType === 8">
                        <v-select
                          v-model="item.tempFilterOperator"
                          :items="selectLists.decimalFilterOperators"
                          item-text="name"
                          item-value="id"
                          :label="$ay.t('Filter')"
                          prepend-icon="fa-filter"
                        ></v-select>
                        <gz-currency
                          v-if="
                            item.tempFilterOperator != null &&
                              item.tempFilterOperator != '*NOVALUE*' &&
                              item.tempFilterOperator != '*HASVALUE*'
                          "
                          v-model="item.tempFilterValue"
                          :clearable="!formState.readOnly"
                        ></gz-currency>
                        <v-btn
                          large
                          block
                          v-if="item.tempFilterOperator != null"
                          @click="addFilterCondition(item)"
                          ><v-icon large>fa-plus</v-icon></v-btn
                        >
                      </div>
                      <!-- TAG BUILDER  -->
                      <div v-if="item.uiFieldDataType === 9">
                        <v-select
                          v-model="item.tempFilterOperator"
                          :items="selectLists.tagFilterOperators"
                          item-text="name"
                          item-value="id"
                          :label="$ay.t('Filter')"
                          prepend-icon="fa-filter"
                        ></v-select>

                        <gz-tag-picker
                          v-if="item.tempFilterOperator != null"
                          v-model="item.tempFilterValue"
                        ></gz-tag-picker>

                        <v-btn
                          large
                          block
                          v-if="item.tempFilterOperator != null"
                          @click="addFilterCondition(item)"
                          ><v-icon large>fa-plus</v-icon></v-btn
                        >
                      </div>
                      <!-- ENUM BUILDER  -->
                      <div v-if="item.uiFieldDataType === 10">
                        <v-select
                          v-model="item.tempFilterOperator"
                          :items="selectLists.enumFilterOperators"
                          item-text="name"
                          item-value="id"
                          :label="$ay.t('Filter')"
                          prepend-icon="fa-filter"
                        ></v-select>

                        <v-select
                          v-if="
                            item.tempFilterOperator != null &&
                              item.tempFilterOperator != '*NOVALUE*' &&
                              item.tempFilterOperator != '*HASVALUE*'
                          "
                          v-model="item.tempFilterValue"
                          :items="enumSelectionList(item.enumType)"
                          item-text="name"
                          item-value="id"
                        ></v-select>

                        <v-btn
                          large
                          block
                          v-if="item.tempFilterOperator != null"
                          @click="addFilterCondition(item)"
                          ><v-icon large>fa-plus</v-icon></v-btn
                        >
                      </div>
                    </div>

                    <div class="pt-6">
                      <!-- FILTER LIST -->
                      <template v-if="item.filter.items.length > 0">
                        <v-list elevation="2">
                          <v-subheader v-if="item.filter.items.length > 1">
                            <!-- AND / OR FILTER CONDITIONS -->
                            <v-radio-group v-model="item.filter.any" row>
                              <v-radio
                                :label="$ay.t('GridFilterDialogAndRadioText')"
                                :value="false"
                              ></v-radio>
                              <v-radio
                                :label="$ay.t('GridFilterDialogOrRadioText')"
                                :value="true"
                              ></v-radio> </v-radio-group
                          ></v-subheader>
                          <v-list-item
                            v-for="(filterItem, index) in item.filter.items"
                            :key="index"
                          >
                            <v-list-item-content>
                              <v-list-item-title v-text="filterItem.display">
                              </v-list-item-title>
                            </v-list-item-content>
                            <v-list-item-action>
                              <v-btn
                                icon
                                @click="removeFilterCondition(item, index)"
                              >
                                <v-icon>fa-trash-alt</v-icon>
                              </v-btn>
                            </v-list-item-action>
                          </v-list-item>
                        </v-list>
                      </template>
                      <!-- <v-divider></v-divider>
                        {{ item }} -->
                    </div>
                  </template>
                </v-card-text>
              </v-card>
            </v-col>
          </template>
        </v-row>
      </v-form>
    </v-col>
  </v-row>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*  Xeslint-disable    */
////////////////////////////////////////////////////////////////////////////////////////////////////////////

const FORM_KEY = "ay-data-list-view";
const API_BASE_URL = "data-list-view/";
let JUST_DELETED = false;
export default {
  //unsaved changes are actually valid for this form so no need to warn
  beforeRouteLeave(to, from, next) {
    let vm = this;
    if (this.formState.dirty && !JUST_DELETED) {
      //Put in unsaved listview
      let formSettings = window.$gz.form.getFormSettings(vm.formKey);
      formSettings.saved.dataTable.unsavedListView = JSON.stringify(
        generateListViewFromEdited(vm)
      );
      formSettings.saved.dataTable.listViewId = -1;
      formSettings.temp.cachedListView = null;
      formSettings.temp.page = 1;
      window.$gz.form.setFormSettings(vm.formKey, formSettings);
      next();
    } else {
      next();
    }
  },
  beforeDestroy() {
    window.$gz.eventBus.$off("menu-click", clickHandler);
  },
  async created() {
    let vm = this;
    try {
      //set route values in data object so init form can handle
      vm.dataListKey = this.$route.params.dataListKey;
      vm.listViewId = this.$route.params.listViewId;
      vm.formKey = this.$route.params.formKey;
      await initForm(vm);
      vm.formState.ready = true;
      window.$gz.eventBus.$on("menu-click", clickHandler);
      //NOTE: this would normally be in getDataFromAPI but this form doesn't really need that function so doing it here
      //modify the menu as necessary
      generateMenu(vm);
      //init disable save button so it can be enabled only on edit to show dirty form
      window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":save");
      vm.formState.loading = false;
    } catch (err) {
      vm.formState.ready = true;
      window.$gz.errorHandler.handleFormError(err, vm);
    }
  },
  data() {
    return {
      obj: {
        editView: [],
        name: "",
        public: true,
        concurrency: 0,
        userId: 0
      },
      listViewId: undefined,
      dataListKey: undefined,
      formKey: undefined,
      fieldDefinitions: [],
      effectiveListView: undefined,
      concurrency: undefined,
      selectLists: {
        dateFilterOperators: [],
        dateFilterTokens: [],
        stringFilterOperators: [],
        integerFilterOperators: [],
        boolFilterOperators: [],
        decimalFilterOperators: [],
        tagFilterOperators: [],
        enumFilterOperators: []
      },
      formState: {
        ready: false,
        dirty: false,
        valid: true,
        readOnly: false,
        loading: true,
        errorBoxMessage: undefined,
        appError: undefined,
        serverError: {}
      },
      rights: window.$gz.role.getRights(window.$gz.type.DataListView)
    };
  },
  //WATCHERS
  watch: {
    formState: {
      handler: function(val) {
        //,oldval is available here too if necessary
        if (this.formState.loading) {
          return;
        }

        //enable / disable save button
        let canSave = val.dirty && val.valid && !val.readOnly;
        if (canSave) {
          window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":save");
        } else {
          window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":save");
        }

        //enable / disable duplicate button
        let canDuplicate = !val.dirty && val.valid && !val.readOnly;
        if (canDuplicate) {
          window.$gz.eventBus.$emit(
            "menu-enable-item",
            FORM_KEY + ":duplicate"
          );
        } else {
          window.$gz.eventBus.$emit(
            "menu-disable-item",
            FORM_KEY + ":duplicate"
          );
        }
      },
      deep: true
    }
  },
  computed: {
    canSave: function() {
      return this.formState.valid && this.formState.dirty;
    },
    canDuplicate: function() {
      return this.formState.valid && !this.formState.dirty;
    }
  },
  methods: {
    enumSelectionList: function(enumKey) {
      return window.$gz.enums.getSelectionList(enumKey);
    },
    includeChanged: function(item) {
      if (item.required && item.visible == false) {
        item.required = false;
      }
      window.$gz.form.setFormState({
        vm: this,
        dirty: true
      });
    },
    toggleSort: function(item) {
      if (item.sort == null) {
        item.sort = "+";
      } else if (item.sort == "+") {
        item.sort = "-";
      } else {
        item.sort = null;
      }
      //make sure sorted fields are INCLUDED
      if (item.sort) {
        item.include = true;
      }
      window.$gz.form.setFormState({
        vm: this,
        dirty: true
      });
    },
    move: function(direction, index) {
      let totalItems = this.obj.editView.length;
      let newIndex = 0;
      //calculate new index
      switch (direction) {
        case "start":
          newIndex = 0;
          break;
        case "left":
          newIndex = index - 1;
          if (newIndex < 0) {
            newIndex = 0;
          }
          break;
        case "right":
          newIndex = index + 1;
          if (newIndex > totalItems - 1) {
            newIndex = totalItems - 1;
          }

          break;
        case "end":
          newIndex = totalItems - 1;
          break;
      }

      this.obj.editView.splice(
        newIndex,
        0,
        this.obj.editView.splice(index, 1)[0]
      );
      window.$gz.form.setFormState({
        vm: this,
        dirty: true
      });
    },
    addFilterCondition(item) {
      let filterItem = { op: null, value: null, display: null };
      let filterItemSet = false;
      //DATE relative token?
      if (item.uiFieldDataType === 1) {
        //some kind of relative date token?
        if (item.tempFilterToken && item.tempFilterToken != "*select*") {
          //special relative token
          filterItem.op = "="; //equality
          filterItem.token = true;
          filterItem.value = item.tempFilterToken;
          filterItemSet = true;
        }
      }

      //BLANKS / NONBLANKS TOKENS?
      if (false == filterItemSet && item.tempFilterOperator == "*NOVALUE*") {
        filterItem.op = "=";
        filterItem.value = "*NULL*";
        filterItemSet = true;
      }

      if (false == filterItemSet && item.tempFilterOperator == "*HASVALUE*") {
        filterItem.op = "!=";
        filterItem.value = "*NULL*";
        filterItemSet = true;
      }

      //JUST REGULAR FILTER ITEM
      if (
        false == filterItemSet &&
        item.tempFilterOperator &&
        item.tempFilterValue != null
      ) {
        filterItem.op = item.tempFilterOperator;
        filterItem.value = item.tempFilterValue;
        //only add if there is both an op and a value
        //above here for tokens that isn't a restriction but
        //after passing through those conditions were at a point where there MUST be both
        if (filterItem.op && filterItem.value != null) {
          filterItemSet = true;
        }
      }

      if (filterItemSet) {
        //display
        filterItem.display = getDisplayForFilter(
          this,
          item.uiFieldDataType,
          filterItem.op,
          filterItem.value,
          item.enumType
        );
        //add only if not already in the collection (accidental double click)
        if (!window.$gz._.find(item.filter.items, filterItem)) {
          item.filter.items.push(filterItem);
          window.$gz.form.setFormState({
            vm: this,
            dirty: true
          });
        }
        return;
      }
    },
    removeFilterCondition(item, index) {
      item.filter.items.splice(index, 1);
      window.$gz.form.setFormState({
        vm: this,
        dirty: true
      });
    },
    form() {
      return window.$gz.form;
    },
    fieldValueChanged(ref) {
      if (!this.formState.loading && !this.formState.readOnly) {
        window.$gz.form.fieldValueChanged(this, ref);
      }
    },
    async submit() {
      if (this.canSave) {
        let vm = this;
        //check that "unsaved filter" is not the name
        //if it is, set it empty and force user to set a name
        if (vm.obj.name == vm.$ay.t("FilterUnsaved")) {
          vm.obj.name = "";
          return;
        }
        vm.formState.loading = true;

        let url = API_BASE_URL;

        let lvSave = {
          id: 0,
          userId: vm.obj.userId || 1,
          name: vm.obj.name,
          public: vm.obj.public,
          listKey: vm.dataListKey,
          listView: JSON.stringify(generateListViewFromEdited(vm))
        };

        //are we working off a pre-existing listview (save over)?
        if (vm.listViewId > 0) {
          lvSave.id = vm.listViewId;
          lvSave.concurrency = vm.obj.concurrency;
          url = url + vm.listViewId;
        }

        //clear any errors vm might be around from previous submit
        window.$gz.form.deleteAllErrorBoxErrors(this);
        try {
          let res = await window.$gz.api.upsert(url, lvSave);

          vm.formState.loading = false;
          if (res.error) {
            vm.formState.serverError = res.error;
            window.$gz.form.setErrorBoxErrors(vm);
          } else {
            //successfully updated regardless if POST or PUT so update the local cache
            //Update the formSettings now that it's saved
            let formSettings = window.$gz.form.getFormSettings(vm.formKey);
            formSettings.temp.cachedListView = lvSave.listView;
            formSettings.temp.page = 1;
            formSettings.saved.dataTable.unsavedListView = null;
            formSettings.saved.dataTable.listViewId =
              res.data.id || vm.listViewId; //if res.data.id then a post, if null then a put and vm.listviewId has the id
            window.$gz.form.setFormSettings(vm.formKey, formSettings);

            //Logic for detecting if a post or put: if id then it was a post, if no id then it was a put
            if (res.data.id) {
              //Handle "post" of new record (CREATE)

              //No longer dirty
              window.$gz.form.setFormState({
                vm: vm,
                dirty: false
              });

              //change url to new record
              vm.$router.replace(
                window.$gz.api.replaceAfterLastSlash(
                  vm.$route.fullPath,
                  res.data.id
                )
              );
            } else {
              //Handle "put" of an existing record (UPDATE)
              vm.obj.concurrency = res.data.concurrency;
              window.$gz.form.setFormState({
                vm: vm,
                dirty: false
              });
            }
          }
        } catch (error) {
          vm.formState.loading = false;
          window.$gz.errorHandler.handleFormError(error, vm);
        }
      }
    },
    async remove() {
      let vm = this;
      try {
        if ((await window.$gz.dialog.confirmDelete()) !== true) {
          return;
        }
        //do the delete
        vm.formState.loading = true;
        //No need to delete a non saved record, just abandon it...
        if (vm.listViewId < 1) {
          //this should not get offered for delete but to be safe and clear just in case:
          JUST_DELETED = true;
          // navigate backwards
          vm.$router.go(-1);
        } else {
          let url = API_BASE_URL + vm.listViewId;

          window.$gz.form.deleteAllErrorBoxErrors(vm);
          let res = await window.$gz.api.remove(url);

          if (res.error) {
            vm.formState.serverError = res.error;
            window.$gz.form.setErrorBoxErrors(vm);
          } else {
            //workaround to prevent warning about leaving dirty record
            //For some reason I couldn't just reset isdirty in formstate
            JUST_DELETED = true;

            //set it to the default list view so the caller doesn't try to load the non-existant deleted view it was just working with
            let formSettings = window.$gz.form.getFormSettings(vm.formKey);
            formSettings.temp.cachedListView = null;
            formSettings.temp.page = 1;
            formSettings.saved.dataTable.unsavedListView = null;
            formSettings.saved.dataTable.listViewId = 0;
            window.$gz.form.setFormSettings(vm.formKey, formSettings);
            // navigate backwards
            vm.$router.go(-1);
          }
        }
      } catch (error) {
        //Update the form status
        window.$gz.form.setFormState({
          vm: vm,
          loading: false
        });
        window.$gz.errorHandler.handleFormError(error, vm);
      }
    },
    async duplicate() {
      let vm = this;
      if (this.canDuplicate && vm.listViewId > 0) {
        this.formState.loading = true;

        let url = API_BASE_URL + "duplicate/" + vm.listViewId;

        //clear any errors vm might be around from previous submit
        window.$gz.form.deleteAllErrorBoxErrors(this);
        try {
          let res = await window.$gz.api.duplicate(url);

          vm.formState.loading = false;
          if (res.error) {
            vm.formState.serverError = res.error;
            window.$gz.form.setErrorBoxErrors(vm);
          } else {
            //switch to the new record in the formsettings
            let formSettings = window.$gz.form.getFormSettings(vm.formKey);
            formSettings.temp.cachedListView = null;
            formSettings.temp.page = 1;
            formSettings.saved.dataTable.unsavedListView = null;
            formSettings.saved.dataTable.listViewId = res.data.id;
            window.$gz.form.setFormSettings(vm.formKey, formSettings);

            //Set some values that otherwise don't get updated because we're not really navigating fresh
            vm.obj.name = res.data.name;
            vm.obj.concurrency = res.data.concurrency;
            vm.listViewId = res.data.id;
            //Navigate to new record
            //NOTE: this doesn't really update the form at all so need to set some th9ings
            vm.$router.push(
              vm.$route.fullPath.slice(0, -1) + res.data.id
              // window.$gz.api.replaceAfterLastSlash(
              //   vm.$route.fullPath,
              //   res.data.id
              // )
            );
          }
        } catch (error) {
          vm.formState.loading = false;
          window.$gz.errorHandler.handleFormError(error, vm);
        }
      }
    }
  }
};

/////////////////////////////
//
//
function clickHandler(menuItem) {
  if (!menuItem) {
    return;
  }
  let m = window.$gz.menu.parseMenuItem(menuItem);
  if (m.owner == FORM_KEY && !m.disabled) {
    switch (m.key) {
      case "save":
        m.vm.submit();
        break;
      case "delete":
        m.vm.remove();
        break;
      case "duplicate":
        m.vm.duplicate();
        break;
      default:
        window.$gz.eventBus.$emit(
          "notify-warning",
          FORM_KEY + "::context click: [" + m.key + "]"
        );
    }
  }
}

//////////////////////
//
//
function generateMenu(vm) {
  let menuOptions = {
    isMain: false,
    icon: "fa-filter",
    title: "DataListView",
    helpUrl: "form-ay-data-list-view",
    formData: {
      ayaType: window.$gz.type.FormCustom,
      formCustomTemplateKey: undefined
    },
    menuItems: []
  };

  if (vm.rights.change) {
    menuOptions.menuItems.push({
      title: "Save",
      icon: "fa-save",
      surface: true,
      key: FORM_KEY + ":save",
      vm: vm
    });
  }
  if (vm.rights.delete) {
    menuOptions.menuItems.push({
      title: "Delete",
      icon: "fa-trash-alt",
      surface: true,
      key: FORM_KEY + ":delete",
      vm: vm
    });
  }
  if (vm.rights.change) {
    menuOptions.menuItems.push({
      title: "Duplicate",
      icon: "fa-clone",
      key: FORM_KEY + ":duplicate",
      vm: vm
    });
  }
  window.$gz.eventBus.$emit("menu-change", menuOptions);
}

/////////////////////////////////
//
//
async function initForm(vm) {
  await fetchTranslatedText(vm);
  await populateSelectionLists(vm);
  await populateFieldDefinitions(vm);
  await fetchTranslatedFieldNames(vm);
  await setEffectiveListView(vm);
  await initDataObject(vm);
  await fetchEnums(vm);
}

//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText(vm) {
  await window.$gz.translation.cacheTranslations([
    "DataListView",
    "GridFilterName",
    "Include",
    "AnyUser",
    "Sort",
    "Filter",
    "GridFilterDialogAndRadioText",
    "GridFilterDialogOrRadioText",
    "GridRowFilterDropDownBlanksItem",
    "GridRowFilterDropDownNonBlanksItem",
    "GridRowFilterDropDownEquals",
    "GridRowFilterDropDownGreaterThan",
    "GridRowFilterDropDownGreaterThanOrEqualTo",
    "GridRowFilterDropDownLessThan",
    "GridRowFilterDropDownLessThanOrEqualTo",
    "GridRowFilterDropDownNotEquals",
    "GridRowFilterDropDownDoesNotContain",
    "GridRowFilterDropDownContains",
    "GridRowFilterDropDownStartsWith",
    "GridRowFilterDropDownEndsWith",
    "SelectItem",
    "DateRangeYesterday",
    "DateRangeToday",
    "DateRangeTomorrow",
    "DateRangeLastWeek",
    "DateRangeThisWeek",
    "DateRangeNextWeek",
    "DateRangeLastMonth",
    "DateRangeThisMonth",
    "DateRangeNextMonth",
    "DateRange14DayWindow",
    "DateRangePast",
    "DateRangeFuture",
    "DateRangeLastYear",
    "DateRangeThisYear",
    "DateRangeInTheLastThreeMonths",
    "DateRangeInTheLastSixMonths",
    "DateRangePastYear",
    "DateRangePast90Days",
    "DateRangePast30Days",
    "DateRangePast24Hours",
    "True",
    "False",
    "Name"
  ]);
}

/////////////////////////////////
//
//
function populateSelectionLists(vm) {
  vm.selectLists.dateFilterOperators.push(
    ...[
      { name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
      {
        name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
        id: "*HASVALUE*"
      },
      { name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
      { name: vm.$ay.t("GridRowFilterDropDownGreaterThan"), id: ">" },
      {
        name: vm.$ay.t("GridRowFilterDropDownGreaterThanOrEqualTo"),
        id: ">="
      },
      { name: vm.$ay.t("GridRowFilterDropDownLessThan"), id: "<" },
      { name: vm.$ay.t("GridRowFilterDropDownLessThanOrEqualTo"), id: "<=" },
      { name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
    ]
  );

  vm.selectLists.dateFilterTokens.push(
    ...[
      { name: "(" + vm.$ay.t("SelectItem") + ")", id: "*select*" }, //If select then use entry in date /time picker
      { name: vm.$ay.t("DateRangeYesterday"), id: "*yesterday*" },
      { name: vm.$ay.t("DateRangeToday"), id: "*today*" },
      { name: vm.$ay.t("DateRangeTomorrow"), id: "*tomorrow*" },
      { name: vm.$ay.t("DateRangeLastWeek"), id: "*lastweek*" },
      { name: vm.$ay.t("DateRangeThisWeek"), id: "*thisweek*" },
      { name: vm.$ay.t("DateRangeNextWeek"), id: "*nextweek*" },
      { name: vm.$ay.t("DateRangeLastMonth"), id: "*lastmonth*" },
      { name: vm.$ay.t("DateRangeThisMonth"), id: "*thismonth*" },
      { name: vm.$ay.t("DateRangeNextMonth"), id: "*nextmonth*" },
      { name: vm.$ay.t("DateRange14DayWindow"), id: "*14daywindow*" },
      { name: vm.$ay.t("DateRangePast"), id: "*past*" },
      { name: vm.$ay.t("DateRangeFuture"), id: "*future*" },
      { name: vm.$ay.t("DateRangeLastYear"), id: "*lastyear*" }, //prior year from jan to dec
      { name: vm.$ay.t("DateRangeThisYear"), id: "*thisyear*" },
      {
        name: vm.$ay.t("DateRangeInTheLastThreeMonths"),
        id: "*last3months*"
      },
      {
        name: vm.$ay.t("DateRangeInTheLastSixMonths"),
        id: "*last6months*"
      },
      { name: vm.$ay.t("DateRangePastYear"), id: "*pastyear*" }, //last 365 days

      { name: vm.$ay.t("DateRangePast90Days"), id: "*past90days*" },
      { name: vm.$ay.t("DateRangePast30Days"), id: "*past30days*" },
      { name: vm.$ay.t("DateRangePast24Hours"), id: "*past24hours*" }
    ]
  );

  vm.selectLists.stringFilterOperators.push(
    ...[
      { name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
      {
        name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
        id: "*HASVALUE*"
      },
      { name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
      { name: vm.$ay.t("GridRowFilterDropDownGreaterThan"), id: ">" },
      {
        name: vm.$ay.t("GridRowFilterDropDownGreaterThanOrEqualTo"),
        id: ">="
      },
      { name: vm.$ay.t("GridRowFilterDropDownLessThan"), id: "<" },
      { name: vm.$ay.t("GridRowFilterDropDownLessThanOrEqualTo"), id: "<=" },
      { name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" },
      { name: vm.$ay.t("GridRowFilterDropDownDoesNotContain"), id: "!-%-" },
      { name: vm.$ay.t("GridRowFilterDropDownContains"), id: "-%-" },
      { name: vm.$ay.t("GridRowFilterDropDownStartsWith"), id: "%-" },
      { name: vm.$ay.t("GridRowFilterDropDownEndsWith"), id: "-%" }
    ]
  );

  vm.selectLists.integerFilterOperators.push(
    ...[
      { name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
      {
        name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
        id: "*HASVALUE*"
      },
      { name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
      { name: vm.$ay.t("GridRowFilterDropDownGreaterThan"), id: ">" },
      {
        name: vm.$ay.t("GridRowFilterDropDownGreaterThanOrEqualTo"),
        id: ">="
      },
      { name: vm.$ay.t("GridRowFilterDropDownLessThan"), id: "<" },
      { name: vm.$ay.t("GridRowFilterDropDownLessThanOrEqualTo"), id: "<=" },
      { name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
    ]
  );

  vm.selectLists.boolFilterOperators.push(
    ...[
      { name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
      {
        name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
        id: "*HASVALUE*"
      },
      { name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
      { name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
    ]
  );

  vm.selectLists.decimalFilterOperators.push(
    ...[
      { name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
      {
        name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
        id: "*HASVALUE*"
      },
      { name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
      { name: vm.$ay.t("GridRowFilterDropDownGreaterThan"), id: ">" },
      {
        name: vm.$ay.t("GridRowFilterDropDownGreaterThanOrEqualTo"),
        id: ">="
      },
      { name: vm.$ay.t("GridRowFilterDropDownLessThan"), id: "<" },
      { name: vm.$ay.t("GridRowFilterDropDownLessThanOrEqualTo"), id: "<=" },
      { name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
    ]
  );
  //tags filter only by equals in initial release, see DataListSqlFilterCriteriaBuilder.cs line 523 for deets
  vm.selectLists.tagFilterOperators.push({
    name: vm.$ay.t("GridRowFilterDropDownEquals"),
    id: "="
  });

  vm.selectLists.enumFilterOperators.push(
    ...[
      { name: vm.$ay.t("GridRowFilterDropDownBlanksItem"), id: "*NOVALUE*" },
      {
        name: vm.$ay.t("GridRowFilterDropDownNonBlanksItem"),
        id: "*HASVALUE*"
      },
      { name: vm.$ay.t("GridRowFilterDropDownEquals"), id: "=" },
      { name: vm.$ay.t("GridRowFilterDropDownNotEquals"), id: "!=" }
    ]
  );
}

////////////////////
//
async function populateFieldDefinitions(vm) {
  //http://localhost:7575/api/v8/data-list/listfields?DataListKey=TestWidgetDataList
  let res = await window.$gz.api.get(
    "data-list/listfields?DataListKey=" + vm.dataListKey
  );
  if (res.error) {
    throw res.error;
  } else {
    vm.fieldDefinitions = res.data;
  }
}

//////////////////////////////////////////////////////////
//
// Ensures column names are present in translation table
//
async function fetchTranslatedFieldNames(vm) {
  let columnKeys = [];
  for (let i = 1; i < vm.fieldDefinitions.length; i++) {
    let cm = vm.fieldDefinitions[i];
    columnKeys.push(cm.tKey);
  }
  await window.$gz.translation.cacheTranslations(columnKeys);
}

/////////////////////////////////
//
//
async function setEffectiveListView(vm) {
  /*
  effectiveListView
  - Second get the ListView that is currently in use so can setup the page view
			- If listviewid is zero then that's starting with the default list view so need to fetch it and then init the form
			- If listviewid is -1 then that's starting with an unsaved listview so get that from the saved form store
			- If listviewid is greater than 0 then it's a saved listview and there sb a cached version of it but ideally maybe fetch it from 

  */

  if (vm.listViewId == null) {
    throw "ay-data-list::setEffectiveListView - listViewId is not set";
  }

  let formSettings = window.$gz.form.getFormSettings(vm.formKey);

  if (vm.listViewId == -1) {
    if (formSettings.saved.dataTable.unsavedListView != null) {
      vm.effectiveListView = JSON.parse(
        formSettings.saved.dataTable.unsavedListView
      );
      vm.obj.name = vm.$ay.t("FilterUnsaved");
      return Promise.resolve();
    }
  } else if (vm.listViewId == 0) {
    //get default list view
    //http://localhost:7575/api/v8/DataListView/default/TestWidgetDataList
    let res = await window.$gz.api.get(
      "data-list-view/default/" + vm.dataListKey
    );

    if (res.error) {
      throw res.error;
    } else {
      vm.effectiveListView = JSON.parse(res.data);
      vm.obj.name = vm.$ay.t("FilterUnsaved");
    }
  } else {
    //listview has an id value
    let res = await window.$gz.api.get("data-list-view/" + vm.listViewId);
    if (res.error) {
      throw res.error;
    } else {
      vm.effectiveListView = JSON.parse(res.data.listView);
      vm.obj.public = res.data.public;
      vm.obj.name = res.data.name;
      vm.obj.concurrency = res.data.concurrency;
      vm.obj.userId = res.data.userId;
    }
  }
}

////////////////////
//
function initDataObject(vm) {
  if (vm.effectiveListView == null) {
    throw "ay-data-list::initDataObject - effectiveListView is not set";
  }
  if (vm.fieldDefinitions == null) {
    throw "ay-data-list::initDataObject - fieldDefinitions are not set";
  }

  let ret = [];

  //Pass 1, iterate the listview first
  for (let i = 0; i < vm.effectiveListView.length; i++) {
    let lvItem = vm.effectiveListView[i];

    let fld = window.$gz._.find(vm.fieldDefinitions, ["fieldKey", lvItem.fld]);
    let o = {
      key: fld.fieldKey,
      title: vm.$ay.t(fld.tKey),
      include: true,
      isFilterable: fld.isFilterable,
      isSortable: fld.isSortable,
      enumType: fld.enumType,
      uiFieldDataType: fld.uiFieldDataType,
      isCustomField: fld.isCustomField,
      sort: lvItem.sort || null,
      filter: lvItem.filter || { any: false, items: [] },
      tempFilterOperator: null,
      tempFilterToken: null,
      tempFilterValue: null
    };

    if (fld.isRowId) {
      o.rid = true;
    }

    //If it's a tag and it's not been set yet it needs to have an empty array to stat with for the picker
    if (o.uiFieldDataType == 9 && o.tempFilterValue == null) {
      o.tempFilterValue = [];
    }

    //Add display text for filter item (same as in addFilterCondition)
    for (let j = 0; j < o.filter.items.length; j++) {
      let fi = o.filter.items[j];
      fi.display = getDisplayForFilter(
        vm,
        o.uiFieldDataType,
        fi.op,
        fi.value,
        o.enumType
      );
    }

    ret.push(o);
  }

  //Pass 2, remaining fields not already dealt with
  for (let i = 0; i < vm.fieldDefinitions.length; i++) {
    let fld = vm.fieldDefinitions[i];

    //is this field already in ret array?
    if (null == window.$gz._.find(ret, ["key", fld.fieldKey])) {
      //nope, so add it
      let o = {
        key: fld.fieldKey,
        title: vm.$ay.t(fld.tKey),
        include: false,
        isFilterable: fld.isFilterable,
        isSortable: fld.isSortable,
        enumType: fld.enumType,
        uiFieldDataType: fld.uiFieldDataType,
        isCustomField: fld.isCustomField,
        sort: null,
        filter: { any: false, items: [] },
        tempFilterOperator: null,
        tempFilterToken: null,
        tempFilterValue: null
      };

      if (fld.isRowId) {
        o.rid = true;
        o.include = true;
      }
      //If it's a tag and it's not been set yet it needs to have an empty array to stat with for the picker
      if (o.uiFieldDataType == 9 && o.tempFilterValue == null) {
        o.tempFilterValue = [];
      }
      ret.push(o);
    }
  }
  vm.obj.editView = ret;

  if (window.$gz.dev) {
    if (vm.obj.editView.length != vm.fieldDefinitions.length) {
      throw "ay-data-list-view::initDataObject - working array length not equal to total field definition length";
    }
  }
  return Promise.resolve();

  //eoc
}

//////////////////////////////////////////////////////////
//
// Ensures translated enum lists are available pre-cached
//
function fetchEnums(vm) {
  //build an array of all enums then execute method
  let enumKeys = [];
  for (let i = 0; i < vm.fieldDefinitions.length; i++) {
    let fld = vm.fieldDefinitions[i];
    if (fld.uiFieldDataType == 10) {
      enumKeys.push(fld.enumType);
    }
  }
  if (enumKeys.length > 0) {
    return window.$gz.enums.fetchEnumList(enumKeys);
  }
  return Promise.resolve();
}

//////////////////////////////////////////////////////////
//
// Convert working object to actual listView
//
function updateEditedListView(vm) {
  //turn the obj.editView settings into an actual listview
  //compare it with the effectiveListView to see if there are any changes between the two
  //set the form to dirty if there are changes and can save
  //this.formState.dirty = true;
  //this way user can build their way back to the same view and then no need to save if no changes
  //build an array of all enums then execute method
}

//////////////////////////////////////////////////////////
//
// Convert filter properties to translated / displayable
// used when making new filter and loading existing
//
function getDisplayForFilter(
  vm,
  uiFieldDataType,
  filterOperator,
  filterValue,
  enumType
) {
  //BLANKS FILTER
  if (filterOperator == "=" && filterValue == "*NULL*") {
    return window.$gz._.find(vm.selectLists.stringFilterOperators, {
      id: "*NOVALUE*"
    }).name;
  }
  // NONBLANKS FILTER
  if (filterOperator == "!=" && filterValue == "*NULL*") {
    return window.$gz._.find(vm.selectLists.stringFilterOperators, {
      id: "*HASVALUE*"
    }).name;
  }

  //DATE RELATIVE TOKEN FILTER
  if (uiFieldDataType === 1 && filterValue[0] == "*") {
    let valueDisplay = window.$gz._.find(vm.selectLists.dateFilterTokens, {
      id: filterValue
    }).name;
    let opDisplay = filterOperator;
    return filterOperator + " " + valueDisplay;
  }

  //VALUE FILTER
  //Nothing more to do if there isn't both a value AND an operator at this point
  if (filterOperator == null || filterValue == null) {
    if (window.$gz.dev) {
      throw "ay-data-list-view::getDisplayForFilter Value filter missing one ore more of Operator, Value";
    }
    return "";
  }

  let valueDisplay = "selected value";
  switch (uiFieldDataType) {
    case 1: //date translate
      valueDisplay = window.$gz.locale.utcDateToShortDateAndTimeLocalized(
        filterValue
      );
      break;
    case 8: //currency translate
      valueDisplay = window.$gz.locale.currencyLocalized(filterValue);
      break;
    case 7: //decimal translate
      valueDisplay = window.$gz.locale.decimalLocalized(filterValue);
      break;
    case 6: //BOOL translate
      let tKey = filterValue ? "True" : "False";
      valueDisplay = vm.$ay.t(tKey);
      break;
    case 10: //ENUM translate
      valueDisplay = window.$gz.enums.get(enumType, filterValue);
      break;
    default:
      valueDisplay = filterValue;
      break;
  }

  //Operator
  let opDisplay = window.$gz._.find(vm.selectLists.stringFilterOperators, {
    id: filterOperator
  }).name;

  return opDisplay + ' "' + valueDisplay + '"';

  //eoc
}

//////////////////////////////////////////////////////////
//
// Convert editedList view to real list view and return
//
function generateListViewFromEdited(vm) {
  //obj: { editView: [], name: "", public: true },
  if (vm.obj.editView == null || vm.obj.editView.length == 0) {
    return;
  }

  let ret = [];

  for (let i = 0; i < vm.obj.editView.length; i++) {
    let ev = vm.obj.editView[i];
    if (!ev.include) {
      continue;
    }
    let o = {
      fld: ev.key
    };
    if (ev.sort != null) {
      o.sort = ev.sort;
    }
    if (ev.filter && ev.filter.items && ev.filter.items.length > 0) {
      let f = {
        items: []
      };
      if (ev.filter.any) {
        f.any = true;
      }
      for (let j = 0; j < ev.filter.items.length; j++) {
        let evfi = ev.filter.items[j];
        let thisFilterItem = {
          op: evfi.op,
          value: evfi.value
        };
        if (evfi.token) {
          thisFilterItem.token = true;
        }
        f.items.push(thisFilterItem);
      }
      o.filter = f;
    }
    ret.push(o);
  }
  return ret;
  //eoc
}

/////////////END OF FORM//////////////////
</script>
