<template>
  <div v-resize="onResize">
    <v-overlay :value="rendering" z-index="999">
      <v-progress-circular indeterminate size="64"></v-progress-circular>
    </v-overlay>
    <!-- {{ formState }} -->
    <v-row v-show="formState.ready">
      <gz-error :errorBoxMessage="formState.errorBoxMessage"></gz-error>
      <v-col cols="12" class="d-sm-none accent--text">
        <h4>{{ $ay.t("ReportEditorMobileWarning") }}</h4>
      </v-col>
      <v-col cols="12" class="py-2">
        <v-btn-toggle
          v-model="activeTab"
          tile
          color="primary"
          group
          @change="onViewChange"
          mandatory
        >
          <v-btn value="properties">
            {{ $ay.t("ReportEditorProperties") }}
          </v-btn>

          <v-btn value="pdfoptions">
            {{ $ay.t("ReportPdfOptions") }}
          </v-btn>

          <v-btn value="template">
            {{ $ay.t("ReportTemplate") }}
          </v-btn>

          <v-btn value="style">
            CSS
          </v-btn>

          <v-btn value="jsPrerender">
            Prepare
          </v-btn>

          <v-btn value="jsHelpers">
            Helpers
          </v-btn>

          <v-btn value="rawData" v-if="reportData != null">
            {{ $ay.t("ReportEditorData") }}
          </v-btn>
        </v-btn-toggle>
      </v-col>
      <v-col cols="12" v-show="view == 'edit'">
        <div id="editContainer"></div>
      </v-col>

      <v-col cols="12" v-show="view == 'properties'">
        <v-form ref="form">
          <v-row>
            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-text-field
                v-model="obj.name"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :clearable="!formState.readOnly"
                @click:clear="fieldValueChanged('name')"
                :counter="255"
                :label="$ay.t('ReportName')"
                :rules="[
                  form().max255(this, 'name'),
                  form().required(this, 'name')
                ]"
                :error-messages="form().serverErrors(this, 'name')"
                ref="name"
                :data-cy="!!$ay.dev ? 'name' : false"
                @input="fieldValueChanged('name')"
              ></v-text-field>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-checkbox
                v-model="obj.active"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :label="$ay.t('Active')"
                ref="active"
                :data-cy="!!$ay.dev ? 'active' : false"
                :error-messages="form().serverErrors(this, 'active')"
                @change="fieldValueChanged('active')"
              ></v-checkbox>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <gz-role-picker
                :label="$ay.t('AuthorizationRoles')"
                v-model="obj.roles"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                ref="roles"
                testId="roles"
                :error-messages="form().serverErrors(this, 'roles')"
                @input="fieldValueChanged('roles')"
                limitSelectionTo="inside"
              ></gz-role-picker>
            </v-col>

            <v-col cols="12">
              <v-textarea
                v-model="obj.notes"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :label="$ay.t('ReportNotes')"
                :error-messages="form().serverErrors(this, 'notes')"
                ref="notes"
                :data-cy="!!$ay.dev ? 'notes' : false"
                @input="fieldValueChanged('notes')"
                auto-grow
                :clearable="!formState.readOnly"
              ></v-textarea>
            </v-col>
          </v-row>
        </v-form>
      </v-col>

      <v-col cols="12" v-show="view == 'pdfoptions'">
        <v-form ref="formPDF">
          <v-row>
            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-checkbox
                v-model="obj.displayHeaderFooter"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :label="$ay.t('ReportDisplayHeaderFooter')"
                ref="displayHeaderFooter"
                :data-cy="!!$ay.dev ? 'displayHeaderFooter' : false"
                :error-messages="
                  form().serverErrors(this, 'displayHeaderFooter')
                "
                @change="fieldValueChanged('displayHeaderFooter', 'formPDF')"
              ></v-checkbox>
            </v-col>

            <v-col cols="12">
              <v-textarea
                v-model="obj.headerTemplate"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :label="$ay.t('ReportHeaderTemplate')"
                :error-messages="form().serverErrors(this, 'headerTemplate')"
                ref="headerTemplate"
                :data-cy="!!$ay.dev ? 'headerTemplate' : false"
                @input="fieldValueChanged('headerTemplate', 'formPDF')"
                auto-grow
                :clearable="!formState.readOnly"
              ></v-textarea>
            </v-col>

            <v-col cols="12">
              <v-textarea
                v-model="obj.footerTemplate"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :label="$ay.t('ReportFooterTemplate')"
                :error-messages="form().serverErrors(this, 'footerTemplate')"
                ref="footerTemplate"
                :data-cy="!!$ay.dev ? 'footerTemplate' : false"
                @input="fieldValueChanged('footerTemplate', 'formPDF')"
                auto-grow
                :clearable="!formState.readOnly"
              ></v-textarea>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-select
                v-model="obj.paperFormat"
                :items="selectLists.PaperFormats"
                item-text="name"
                item-value="id"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :label="$ay.t('ReportPaperFormat')"
                ref="paperFormat"
                :data-cy="!!$ay.dev ? 'paperFormat' : false"
                :error-messages="form().serverErrors(this, 'paperFormat')"
                @input="fieldValueChanged('paperFormat', 'formPDF')"
              ></v-select>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-checkbox
                v-model="obj.landscape"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :label="$ay.t('ReportLandscape')"
                ref="landscape"
                :data-cy="!!$ay.dev ? 'landscape' : false"
                :error-messages="form().serverErrors(this, 'landscape')"
                @change="fieldValueChanged('landscape', 'formPDF')"
              ></v-checkbox>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-text-field
                v-model="obj.marginOptionsBottom"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :clearable="!formState.readOnly"
                @click:clear="fieldValueChanged('marginOptionsBottom')"
                :label="$ay.t('ReportMarginOptionsBottom')"
                :error-messages="
                  form().serverErrors(this, 'marginOptionsBottom')
                "
                ref="marginOptionsBottom"
                :data-cy="!!$ay.dev ? 'marginOptionsBottom' : false"
                @input="fieldValueChanged('marginOptionsBottom', 'formPDF')"
              ></v-text-field>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-text-field
                v-model="obj.marginOptionsLeft"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :clearable="!formState.readOnly"
                @click:clear="fieldValueChanged('marginOptionsLeft')"
                :label="$ay.t('ReportMarginOptionsLeft')"
                :error-messages="form().serverErrors(this, 'marginOptionsLeft')"
                ref="marginOptionsLeft"
                :data-cy="!!$ay.dev ? 'marginOptionsLeft' : false"
                @input="fieldValueChanged('marginOptionsLeft', 'formPDF')"
              ></v-text-field>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-text-field
                v-model="obj.marginOptionsRight"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :clearable="!formState.readOnly"
                @click:clear="fieldValueChanged('marginOptionsRight')"
                :label="$ay.t('ReportMarginOptionsRight')"
                :error-messages="
                  form().serverErrors(this, 'marginOptionsRight')
                "
                ref="marginOptionsRight"
                :data-cy="!!$ay.dev ? 'marginOptionsRight' : false"
                @input="fieldValueChanged('marginOptionsRight', 'formPDF')"
              ></v-text-field>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-text-field
                v-model="obj.marginOptionsTop"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :clearable="!formState.readOnly"
                @click:clear="fieldValueChanged('marginOptionsTop')"
                :label="$ay.t('ReportMarginOptionsTop')"
                :error-messages="form().serverErrors(this, 'marginOptionsTop')"
                ref="marginOptionsTop"
                :data-cy="!!$ay.dev ? 'marginOptionsTop' : false"
                @input="fieldValueChanged('marginOptionsTop', 'formPDF')"
              ></v-text-field>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-checkbox
                v-model="obj.preferCSSPageSize"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :label="$ay.t('ReportPreferCSSPageSize')"
                ref="preferCSSPageSize"
                :data-cy="!!$ay.dev ? 'preferCSSPageSize' : false"
                :error-messages="form().serverErrors(this, 'preferCSSPageSize')"
                @change="fieldValueChanged('preferCSSPageSize', 'formPDF')"
              ></v-checkbox>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <v-checkbox
                v-model="obj.printBackground"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :label="$ay.t('ReportPrintBackground')"
                ref="printBackground"
                :data-cy="!!$ay.dev ? 'printBackground' : false"
                :error-messages="form().serverErrors(this, 'printBackground')"
                @change="fieldValueChanged('printBackground', 'formPDF')"
              ></v-checkbox>
            </v-col>

            <v-col cols="12" sm="6" lg="4" xl="3">
              <gz-decimal
                v-model="obj.scale"
                :readonly="formState.readOnly"
                :disabled="formState.readOnly"
                :clearable="!formState.readOnly"
                @click:clear="fieldValueChanged('scale')"
                :label="$ay.t('ReportScale')"
                :rules="[
                  form().decimalValid(this, 'scale'),
                  form().required(this, 'scale'),
                  form().minValueValid(this, 'scale', 0.1),
                  form().maxValueValid(this, 'scale', 2)
                ]"
                :error-messages="form().serverErrors(this, 'scale')"
                ref="scale"
                :data-cy="!!$ay.dev ? 'scale' : false"
                @input="fieldValueChanged('scale', 'formPDF')"
              ></gz-decimal>
            </v-col>
          </v-row>
        </v-form>
      </v-col>
    </v-row>
  </div>
</template>

<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*  Xeslint-disable    */
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////

import * as monaco from "monaco-editor";

//Monaco editor info page with links
//https://microsoft.github.io/monaco-editor/

const FORM_KEY = "ay-report-edit";
let JUST_DELETED = false;
let editor = null;
export default {
  async created() {
    let vm = this;
    try {
      await initForm(vm);

      vm.rights = window.$gz.role.getRights(window.$gz.type.Report);
      vm.formState.readOnly = !vm.rights.change;
      window.$gz.eventBus.$on("menu-click", clickHandler);

      //id 0 means create a new record don't load one
      if (vm.$route.params.recordid != 0) {
        //is there already an obj from a prior operation?
        if (vm.$route.params.obj) {
          //yes, no need to fetch it
          vm.obj = vm.$route.params.obj;
          window.$gz.form.setFormState({
            vm: vm,
            loading: false
          });
        } else {
          await vm.getDataFromApi(vm.$route.params.recordid); //let getdata handle loading
        }
      } else {
        //New record so there *MUST* be an ayType on the route params

        window.$gz.form.setFormState({
          vm: vm,
          loading: false
        });
      }

      //---------------
      //setup the editor and models

      //Created editor models for each type of report element that can be edited
      vm.editData.template.model = monaco.editor.createModel(
        vm.obj.template,
        "html"
      );

      vm.editData.style.model = monaco.editor.createModel(vm.obj.style, "css");
      vm.editData.jsPrerender.model = monaco.editor.createModel(
        vm.obj.jsPrerender,
        "javascript"
      );

      if (vm.reportData != null) {
        vm.editData.rawData.model = monaco.editor.createModel(
          JSON.stringify(vm.reportData, null, "\t"),
          "json"
        );
      }

      vm.editData.jsHelpers.model = monaco.editor.createModel(
        vm.obj.jsHelpers,
        "javascript"
      );

      //Create the editor itself
      editor = monaco.editor.create(document.getElementById("editContainer"), {
        model: vm.editData.template.model
      });
      //save the initial state because we're going to move away from it immediately
      vm.editData.template.state = editor.saveViewState();

      //change subscription
      editor.onDidChangeModelContent(event => {
        const editorValue = editor.getValue();
        // console.log("editorchange active tab=", vm.activeTab);
        // console.log("editorchange, value of editor is", editorValue);
        switch (vm.activeTab) {
          case "template":
            vm.obj.template = editorValue;
            break;
          case "style":
            vm.obj.style = editorValue;
            break;
          case "jsPrerender":
            vm.obj.jsPrerender = editorValue;
            break;
          case "jsHelpers":
            vm.obj.jsHelpers = editorValue;
            break;
        }
        vm.formState.dirty = true;
        //trigger normal form processing when edit happens
        //without this you can never save after a server error in the script returns
        //pretend the name field changed even though it didn't
        vm.fieldValueChanged("name");
      });

      vm.view = "properties";

      //---------------

      window.$gz.form.setFormState({
        vm: vm,
        dirty: false,
        valid: true
      });

      generateMenu(vm);
    } catch (error) {
      window.$gz.errorHandler.handleFormError(error, vm);
    } finally {
      vm.formState.ready = true;
    }
  },
  async beforeRouteLeave(to, from, next) {
    if (!this.formState.dirty || JUST_DELETED) {
      next();
      return;
    }
    if ((await window.$gz.dialog.confirmLeaveUnsaved()) === true) {
      next();
    } else {
      next(false);
    }
  },
  beforeDestroy() {
    window.$gz.eventBus.$off("menu-click", clickHandler);
    //TODO: dispose all models and editor
    editor && editor.dispose();
  },

  data() {
    return {
      reportData: null,
      editAreaHeight: 300,
      activeTab: "properties",
      lastTab: "properties",
      view: "edit", //"edit","properties","test"
      editData: {
        template: {
          model: null,
          state: null
        },
        style: {
          model: null,
          state: null
        },
        jsPrerender: {
          model: null,
          state: null
        },
        jsHelpers: {
          model: null,
          state: null
        },
        rawData: {
          model: null,
          state: null
        }
      },
      obj: {
        id: 0,
        concurrency: 0,
        name: "report",
        active: true,
        notes: "",
        roles: 124927, //all except customers
        objectType: 0,
        template: `<html>

<body>
	{{#each ayReportData}}
	<h2>{{ Name }}</h2>
	<div>Notes: <span class='example'>{{ Notes }}</span></div>
	{{/each}}
</body>

</html>`,
        style: `.example {
  color: blue;
}`,
        jsPrerender: `async function ayPrepareData(reportData){         
    //this function (if present) is called with the report data 
    //before the report is rendered
    //modify data as required here and return it to change the data before the report renders
    //see the help documentation for details
    return reportData;
}`,
        jsHelpers: `//Register custom Handlebars helpers here to use in your report script
//https://handlebarsjs.com/guide/#custom-helpers
Handlebars.registerHelper('loud', function (aString) {
    return aString.toUpperCase()
})`,
        renderType: 0,
        headerTemplate: null,
        footerTemplate: null,
        displayHeaderFooter: false,
        paperFormat: 0,
        landscape: false,
        marginOptionsBottom: null,
        marginOptionsLeft: null,
        marginOptionsRight: null,
        marginOptionsTop: null,
        pageRanges: null,
        preferCSSPageSize: false,
        printBackground: false,
        scale: 1 //Defaults to 1. Scale amount must be between 0.1 and 2.
      },
      formState: {
        ready: false,
        dirty: false,
        valid: true,
        readOnly: false,
        loading: true,
        errorBoxMessage: null,
        appError: null,
        serverError: {}
      },
      rights: window.$gz.role.defaultRightsObject(),
      ayaType: window.$gz.type.Report,
      rendering: false,
      selectLists: {
        PaperFormats: [
          { name: "-", id: 0 },
          { name: "A0", id: 1 },
          { name: "A1", id: 2 },
          { name: "A2", id: 3 },
          { name: "A3", id: 4 },
          { name: "A4", id: 5 },
          { name: "A5", id: 6 },
          { name: "A6", id: 7 },
          { name: "Ledger", id: 8 },
          { name: "Legal", id: 9 },
          { name: "Letter", id: 10 },
          { name: "Tabloid", id: 11 }
        ]
      }
    };
  },
  /*{"data":{"id":10,"concurrency":19494847,"name":"test basic","active":true,"notes":"",
  "roles":124927,"objectType":2,
  "template":"<html>\n\n<body>\n\t{{#each ayReportData}}\n\t<h2>{{ Name }}</h2>\n\t<div>Notes: <span class='example'>{{ Notes }}</span></div>\n\t{{/each}}\n</body>\n\n</html>","style":".example {\n  color: blue;\n}","jsPrerender":"async function ayPrepareData(reportData){         \n    //this function (if present) is called with the report data \n    //before the report is rendered\n    //modify data as required here and return it to change the data before the report renders\n    //see the help documentation for details\n    return reportData;\n}","jsHelpers":"//Register custom Handlebars helpers here to use in your report script\n//https://handlebarsjs.com/guide/#custom-helpers\nHandlebars.registerHelper('loud', function (aString) {\n    return aString.toUpperCase()\n})",
  "renderType":0,
  "headerTemplate":null,"footerTemplate":null,"displayHeaderFooter":false,
  "paperFormat":0,"landscape":false,"marginOptionsBottom":null,
  "marginOptionsLeft":null,"marginOptionsRight":null,
  "marginOptionsTop":null,"pageRanges":null,"preferCSSPageSize":false,
  "printBackground":false,"scale":1}} 
  */
  //WATCHERS
  watch: {
    formState: {
      handler: function(val) {
        //,oldval is available here too if necessary
        if (this.formState.loading) {
          return;
        }

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

        //enable / disable RENDER button if it can be rendered (has data)
        if (this.reportData != null) {
          if (!val.dirty) {
            //not disabling if invalid because that sometimes just means it needs to be re-run due to server error
            //maybe more of an issue during development but for now it's annoying
            window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":render");
          } else {
            window.$gz.eventBus.$emit(
              "menu-disable-item",
              FORM_KEY + ":render"
            );
          }
        }

        //enable / disable duplicate / new button
        if (!val.dirty && val.valid && !val.readOnly) {
          window.$gz.eventBus.$emit(
            "menu-enable-item",
            FORM_KEY + ":duplicate"
          );
          window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":new");
        } else {
          window.$gz.eventBus.$emit(
            "menu-disable-item",
            FORM_KEY + ":duplicate"
          );
          window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":new");
        }
      },
      deep: true
    }
  },
  methods: {
    //alternate method, one editor with tabs example
    //probably should do this way
    //https://github.com/Microsoft/monaco-editor/issues/604
    //https://github.com/Microsoft/monaco-editor/blob/bad3c34056624dca34ac8be5028ae3454172125c/website/playground/playground.js#L108
    //https://github.com/microsoft/monaco-editor-samples/tree/master/browser-esm-webpack-monaco-plugin
    //
    onViewChange() {
      let vm = this;

      let currentState = editor.saveViewState();
      let currentModel = editor.getModel();
      // debugger;
      //save edit state before switching
      switch (vm.lastTab) {
        case "properties":
          //no state to save here
          break;
        case "pdfoptions":
          //no state to save here
          break;
        case "template":
          vm.editData.template.state = currentState;
          break;
        case "style":
          vm.editData.style.state = currentState;
          break;
        case "jsPrerender":
          vm.editData.jsPrerender.state = currentState;
          break;
        case "jsHelpers":
          vm.editData.jsHelpers.state = currentState;
          break;
        case "rawData":
          vm.editData.rawData.state = currentState;
          break;
      }
      vm.lastTab = vm.activeTab;

      //set new view stuff
      switch (vm.activeTab) {
        case "properties":
          vm.view = "properties";
          return;
          break;
        case "pdfoptions":
          vm.view = "pdfoptions";
          return;
          break;
        case "template":
          editor.setModel(vm.editData.template.model);
          editor.restoreViewState(vm.editData.template.state);
          editor.updateOptions({ readOnly: false });
          vm.view = "edit";
          break;
        case "style":
          editor.setModel(vm.editData.style.model);
          editor.restoreViewState(vm.editData.style.state);
          editor.updateOptions({ readOnly: false });
          vm.view = "edit";
          break;
        case "jsPrerender":
          editor.setModel(vm.editData.jsPrerender.model);
          editor.restoreViewState(vm.editData.jsPrerender.state);
          editor.updateOptions({ readOnly: false });
          vm.view = "edit";
          break;
        case "jsHelpers":
          editor.setModel(vm.editData.jsHelpers.model);
          editor.restoreViewState(vm.editData.jsHelpers.state);
          editor.updateOptions({ readOnly: false });
          vm.view = "edit";
          break;
        case "rawData":
          editor.setModel(vm.editData.rawData.model);
          editor.restoreViewState(vm.editData.rawData.state);
          editor.updateOptions({ readOnly: true });
          vm.view = "edit";
          break;
      }
      vm.$nextTick(() => {
        editor.layout();
        editor.focus();
      });
      // vm.lastTab = vm.activeTab;
    },
    onResize() {
      this.$nextTick(() => {
        //resize related links:
        //https://github.com/Microsoft/monaco-editor/issues/28
        let el = document.getElementById("editContainer");
        el.style = `width:100%;height:${window.innerHeight * 0.77}px`;
        if (editor != null) {
          editor.layout();
        }
      });
    },
    canSave: function() {
      return this.formState.valid && this.formState.dirty;
    },
    canDuplicate: function() {
      return this.formState.valid && !this.formState.dirty;
    },
    ayaTypes: function() {
      return window.$gz.type;
    },
    form() {
      return window.$gz.form;
    },
    fieldValueChanged(ref, formReference) {
      if (
        this.formState.ready &&
        !this.formState.loading &&
        !this.formState.readOnly
      ) {
        window.$gz.form.fieldValueChanged(this, ref, formReference);
      }
    },
    async getDataFromApi(recordId) {
      let vm = this;
      window.$gz.form.setFormState({
        vm: vm,
        loading: true
      });
      if (!recordId) {
        throw new Error(FORM_KEY + "::getDataFromApi -> Missing recordID!");
      }
      let url = "report/" + recordId;
      try {
        window.$gz.form.deleteAllErrorBoxErrors(vm);
        let res = await window.$gz.api.get(url);
        if (res.error) {
          //Not found?
          if (res.error.code == "2010") {
            //notify not found error then navigate backwards
            window.$gz.eventBus.$emit("notify-error", vm.$ay.t("ErrorAPI2010"));
            // navigate backwards
            window.$gz._.delay(function() {
              vm.$router.go(-1);
            }, 2000);
          }
          vm.formState.serverError = res.error;
          window.$gz.form.setErrorBoxErrors(vm);
        } else {
          vm.obj = res.data;
          //modify the menu as necessary
          generateMenu(vm);
          //Update the form status
          window.$gz.form.setFormState({
            vm: vm,
            dirty: false,
            valid: true,
            loading: false
          });
        }
      } catch (error) {
        window.$gz.errorHandler.handleFormError(error, vm);
      } finally {
        window.$gz.form.setFormState({
          vm: vm,
          loading: false
        });
      }
    },
    async submit() {
      //######################
      //need to set vm.obj first with model get value of text of each type being edited
      //as only properties will be set already on obj, the rest is still as it was upon initial fetch
      //unless I code it to always save to obj on each change of view or something but not necessary really
      //USE MODEL.getValue() to get the text value of the model being edited
      //Models sb already set in vm if they were set or edited previously
      let vm = this;
      if (vm.canSave == false) {
        return;
      }

      try {
        window.$gz.form.setFormState({
          vm: vm,
          loading: true
        });
        let url = "report/"; // + vm.$route.params.recordid;
        //clear any errors vm might be around from previous submit
        window.$gz.form.deleteAllErrorBoxErrors(vm);

        let res = await window.$gz.api.upsert(url, vm.obj);

        if (res.error) {
          vm.formState.serverError = res.error;
          window.$gz.form.setErrorBoxErrors(vm);
        } else {
          //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) {
            //POST - whole new object returned
            vm.obj = res.data;
            //Change URL to new record
            //NOTE: will not cause a page re-render, almost nothing does unless forced with a KEY property or using router.GO()

            this.$router.push({
              name: "ay-report-edit",
              params: {
                recordid: res.data.id,
                obj: res.data, // Pass data object to new form
                reportDataOptions: vm.$route.params.reportDataOptions
              }
            });
          } else {
            //PUT - only concurrency token is returned (**warning, if server changes object other fields then this needs to act more like POST above but is more efficient this way**)
            //Handle "put" of an existing record (UPDATE)
            vm.obj.concurrency = res.data.concurrency;
          }
          //Update the form status
          window.$gz.form.setFormState({
            vm: vm,
            dirty: false,
            valid: true
          });
        }
      } catch (ex) {
        window.$gz.errorHandler.handleFormError(ex, vm);
      } finally {
        window.$gz.form.setFormState({
          vm: vm,
          loading: false
        });
      }
    },
    async remove() {
      let vm = this;
      try {
        let dialogResult = await window.$gz.dialog.confirmDelete();
        if (dialogResult != true) {
          return;
        }
        //do the delete
        window.$gz.form.setFormState({
          vm: vm,
          loading: true
        });
        //No need to delete a new record, just abandon it...
        if (vm.$route.params.recordid == 0) {
          //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 = "report/" + vm.$route.params.recordid;

          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;
            // 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 (!vm.canDuplicate || vm.$route.params.recordid == 0) {
        return;
      }
      window.$gz.form.setFormState({
        vm: vm,
        loading: true
      });
      let url = "report/duplicate/" + vm.$route.params.recordid;

      try {
        window.$gz.form.deleteAllErrorBoxErrors(vm);
        let res = await window.$gz.api.upsert(url);
        if (res.error) {
          vm.formState.serverError = res.error;
          window.$gz.form.setErrorBoxErrors(vm);
        } else {
          //Navigate to new record
          this.$router.push({
            name: "ay-report-edit",
            params: {
              recordid: res.data.id,
              obj: res.data // Pass data object to new form
            }
          });
        }
      } catch (ex) {
        window.$gz.errorHandler.handleFormError(ex, vm);
      } finally {
        window.$gz.form.setFormState({
          vm: vm,
          loading: false
        });
      }
    },
    async render() {
      let vm = this;
      if (vm.$route.params.recordid == 0) {
        return;
      }

      /*
  public class RenderReportParameter
    {
        public long ReportId { get; set; }
        public long[] SelectedRowIds { get; set; }
        public string DataListKey { get; set; }
        public string ListView { get; set; }//optional, if null or empty will use default list view built into DataList
    }
*/
      let reportDataOptions = vm.$route.params.reportDataOptions;
      if (!reportDataOptions) {
        throw new Error(
          "Missing report data: to view report must come here from an object edit form or list so data can be provided for viewing the report"
        );
      }
      reportDataOptions.ReportId = vm.obj.id;

      //Meta data from client for use by report script
      reportDataOptions.ClientMeta = window.$gz.api.reportClientMetaData();

      // {
      //   UserName: vm.$store.state.userName,
      //   Authorization: "Bearer " + window.$gz.store.state.apiToken, //api token for using api methods as current user viewing report
      //   TimeZoneName: window.$gz.locale.getBrowserTimeZoneName(),
      //   LanguageName: window.$gz.locale.getBrowserLanguages(),
      //   Hour12: window.$gz.locale.getHour12(),
      //   CurrencyName: window.$gz.locale.getCurrencyName(),
      //   LanguageName: window.$gz.locale.getBrowserFirstLanguage(),
      //   DefaultLocale: window.$gz.locale
      //     .getBrowserFirstLanguage()
      //     .split("-", 1)[0]
      // };

      window.$gz.form.setFormState({
        vm: vm,
        loading: true
      });
      let url = "report/render";

      try {
        window.$gz.form.deleteAllErrorBoxErrors(vm);
        vm.rendering = true;
        let res = await window.$gz.api.upsert(url, reportDataOptions);
        vm.rendering = false;
        if (res.error) {
          vm.formState.serverError = res.error;
          window.$gz.form.setErrorBoxErrors(vm);
        } else {
          let reportUrl = window.$gz.api.reportDownloadUrl(res.data);
          //console.log("Report url:", reportUrl);
          if (window.open(reportUrl, "Report") == null) {
            vm.formState.serverError =
              "Problem displaying report in new window.  Browser must allow pop-ups to view reports; check your browser setting";
            window.$gz.form.setErrorBoxErrors(vm);
          }
        }
      } catch (ex) {
        vm.rendering = false;
        window.$gz.errorHandler.handleFormError(ex, vm);
      } finally {
        vm.rendering = false;
        window.$gz.form.setFormState({
          vm: vm,
          loading: false
        });
      }
    }
  }
};
//end of vue object

/////////////////////////////
//
//
async function clickHandler(menuItem) {
  if (!menuItem) {
    return;
  }
  let m = window.$gz.menu.parseMenuItem(menuItem);
  if (m.owner == FORM_KEY && !m.disabled) {
    switch (m.key) {
      case "export":
        //ignore download link let it go
        break;
      case "save":
        m.vm.submit();
        break;
      case "delete":
        m.vm.remove();
        break;
      case "new":
        m.vm.$router.push({
          name: "ay-report-edit",
          params: { recordid: 0, new: true }
        });
        break;
      case "duplicate":
        m.vm.duplicate();
        break;
      case "render":
        m.vm.render();
        break;

      default:
        window.$gz.eventBus.$emit(
          "notify-warning",
          FORM_KEY + "::context click: [" + m.key + "]"
        );
    }
  }
}

//////////////////////
//
//
function generateMenu(vm) {
  let menuOptions = {
    isMain: false,
    icon: "$ayiDraftingCompass",
    title: "ReportDesignReport",
    helpUrl: "form-ay-report-edit",
    formData: {
      ayaType: window.$gz.type.Report,
      recordId: vm.$route.params.recordid
    },
    menuItems: []
  };

  if (vm.rights.change) {
    menuOptions.menuItems.push({
      title: "Save",
      icon: "$ayiSave",
      surface: true,
      key: FORM_KEY + ":save",
      vm: vm
    });
  }
  if (vm.reportData != null) {
    menuOptions.menuItems.push({
      title: "Report",
      icon: "fa-print",
      key: FORM_KEY + ":render",
      surface: true,
      vm: vm
    });
  }

  if (vm.rights.delete && vm.$route.params.recordid != 0) {
    menuOptions.menuItems.push({
      title: "Delete",
      icon: "$ayiTrashAlt",
      surface: false,
      key: FORM_KEY + ":delete",
      vm: vm
    });
  }

  // //STUB REPORTS
  // //Report not Print, print is a further option
  // menuOptions.menuItems.push({
  //   title: "Report",
  //   icon: "$ayiFileAlt",
  //   key: FORM_KEY + ":report",
  //   vm: vm
  // });

  // //get last report selected
  // let lastReport = window.$gz.form.getLastReport(FORM_KEY);
  // if (lastReport != null) {
  //   menuOptions.menuItems.push({
  //     title: lastReport.name,
  //     icon: "$ayiFileAlt",
  //     key: FORM_KEY + ":report:" + lastReport.id,
  //     vm: vm
  //   });
  // }

  if (vm.rights.change) {
    menuOptions.menuItems.push({
      title: "New",
      icon: "$ayiPlus",
      key: FORM_KEY + ":new",
      vm: vm
    });
  }

  if (vm.rights.change) {
    menuOptions.menuItems.push({
      title: "Duplicate",
      icon: "$ayiClone",
      key: FORM_KEY + ":duplicate",
      vm: vm
    });
  }

  //EXPORT
  if (vm.$route.params.recordid != 0) {
    let href = window.$gz.api.genericDownloadUrl(
      "report/export/" + vm.$route.params.recordid
    );

    menuOptions.menuItems.push({
      title: "Export",
      icon: "$ayiFile-download",
      href: href,
      target: "_blank",
      key: FORM_KEY + ":export",
      vm: vm
    });
  }

  window.$gz.eventBus.$emit("menu-change", menuOptions);
}
/////////////////////////////////
//
//
async function initForm(vm) {
  await fetchTranslatedText(vm);
  await fetchReportData(vm);
}

//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText(vm) {
  await window.$gz.translation.cacheTranslations([
    "ReportDesignReport",
    "ReportName",
    "ReportEditorProperties",
    "ReportEditorData",
    "ReportEditorMobileWarning",
    "ReportNotes",
    "ReportTemplate",
    "AuthorizationRoles",
    "ReportPdfOptions",
    "ReportDisplayHeaderFooter",
    "ReportHeaderTemplate",
    "ReportFooterTemplate",
    "ReportPaperFormat",
    "ReportLandscape",
    "ReportMarginOptionsBottom",
    "ReportMarginOptionsLeft",
    "ReportMarginOptionsRight",
    "ReportMarginOptionsTop",
    "ReportPrintBackground",
    "ReportScale",
    "ReportPreferCSSPageSize"
  ]);
}

////////////////////
//
async function fetchReportData(vm) {
  /*     public AyaType ObjectType { get; set; }
            public long[] SelectedRowIds { get; set; }      
            public string DataListKey { get; set; }      
            public string ListView { get; set; }//optional, if null or empty will use default list view built into DataList
 */

  let reportDataOptions = vm.$route.params.reportDataOptions;
  if (!reportDataOptions) {
    vm.reportData = null;
    return;
  }
  if (reportDataOptions.ObjectType == null) {
    throw new Error(
      "ay-report-edit:fetchReportData - route parameter ObjectType is missing or empty, unable to init report designer"
    );
  }
  vm.obj.objectType = reportDataOptions.ObjectType;

  let res = await window.$gz.api.upsert("report/data", reportDataOptions);
  //We never expect there to be no data here
  if (!res.hasOwnProperty("data")) {
    throw new Error(res);
  } else {
    vm.reportData = res.data;
  }
}
</script>
