<template>
  <div class="app-form-json">
    
    <div :id='id' :innerHTML="id"></div>
    <el-input type="hidden" :rows="2" placeholder="请输入内容" v-model="CurrentVal">
    </el-input>
  </div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Model, Watch } from "vue-property-decorator";
import { VNode, CreateElement } from "vue";
import { interval, Subject, Subscription } from "rxjs";
import { Http,Util } from '@/utils';
import JSONEditor from "@json-editor/json-editor";
import BootstrapVue from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
import "./select2.js";
import "select2/dist/css/select2.min.css"
import 'jquery/dist/jquery.min.js'
import $ from 'jquery'
import "../app-form-json/app-form-json.less";


JSONEditor.defaults.resolvers.unshift(schema => {
  if(schema.type === "selectnew" ) {
    return "selectnew";
  }
  else if(schema.type === "link" ) {
    return "link";
  }

  // If no valid editor is returned, the next resolver function will be used
});

JSONEditor.defaults.editors.selectnew =  JSONEditor.defaults.editors.select.extend({
    remoteCached : {},
    getRemoteItems: function(url){
      var self = this
      if(self.remoteCached[url])
          return self.remoteCached[url];
      const token = window.localStorage.getItem('token');
      var new_items = [];
                 $.ajax({
                            url: url,
                            headers: { 
                              "Authorization":"Bearer "+token//此处放置请求到的用户token
                            },
                            type: 'get',
                            contentType: 'application/json',
                            dataType: 'text',
                            async: false, // 同步
                            success: function (result) {
                                var resObj = JSON.parse(result);
                                resObj.forEach((item: any)=>{
                                    new_items.push(item);
                                });
                                self.remoteCached[url]=new_items;
                            },
                            error: function (result) {
                            }
                        });
        return new_items;                
    },

    onWatchedFieldChange: function() {
    var self = this, vars, j;

    // If this editor uses a dynamic select box
    if(this.enumSource) {
      vars = this.getWatchedFieldValues();
      var select_options = [];
      var select_titles = [];

      for(var i=0; i<this.enumSource.length; i++) {
        // Constant values
        if(Array.isArray(this.enumSource[i])) {
          select_options = select_options.concat(this.enumSource[i]);
          select_titles = select_titles.concat(this.enumSource[i]);
        }
        else {
          var items = [];
          // Static list of items
          if(Array.isArray(this.enumSource[i].source)) {
            items = this.enumSource[i].source;
          // A watched field
          } else {
            items = vars[this.enumSource[i].source];
          }

          if(items) {
            // Only use a predefined part of the array
            if(this.enumSource[i].slice) {
              items = Array.prototype.slice.apply(items,this.enumSource[i].slice);
            }
            // Filter the items
            if(this.enumSource[i].filter) {
              var new_items = [];
              for(j=0; j<items.length; j++) {
                if(this.enumSource[i].filter({i:j,item:items[j],watched:vars})) new_items.push(items[j]);
              }
              items = new_items;
            }

            if(this.enumSource[i].url)
            {
              var url=this.enumSource[i].url;
             
              var p0=vars[this.enumSource[i].p0];
              var p1=vars[this.enumSource[i].p1];
              var p2=vars[this.enumSource[i].p2];
              var p3=vars[this.enumSource[i].p3];
              if(p0)
                url=url.replace('${p0}',p0);
              if(p1)
                url=url.replace('${p1}',p1);
              if(p2)
                url=url.replace('${p2}',p2);
              if(p3)
                url=url.replace('${p3}',p3);  
              
              var localdata;
              if(url.indexOf("${localdata.")>0)
              {
                localdata = window.localStorage.getItem('localdata');
                if(localdata)
                {
                  url=url.replace('${localdata.dstsystemid}',localdata["dstsystemid"]);   
                }
                
              } 
              
              var new_items = [];
              if(url.indexOf("${")<0)
              { 
                var firstObj = (JSON.parse(JSON.stringify(items[0])));
                items = JSON.parse(JSON.stringify(this.getRemoteItems(url)));
                items.unshift(firstObj);
                console.log(items);               
              }
              else
              {
                  new_items.unshift(JSON.parse(JSON.stringify(items[0])));
                  items = new_items;
              }
            }
            if(this.enumSource[i].filterText)
            {
              var filterText=vars[this.enumSource[i].filterText];

              if(filterText)
              {
                var new_items = [];
                new_items=items.filter(item22 => ((item22.text&&item22.text.indexOf(filterText)>=0)||
                          (item22.value&&item22.value.indexOf(filterText)>=0)||
                          (item22.filter&&item22.filter.indexOf(filterText)>=0)));
                new_items.unshift({text:"--",id:""});
                items = new_items;
              }
            }


            var item_titles = [];
            var item_values = [];
            for(j=0; j<items.length; j++) {
              var item = items[j];

              // Rendered value
              if(this.enumSource[i].value) {
                item_values[j] = this.typecast(this.enumSource[i].value({
                  i: j,
                  item: item
                }));
              }
              // Use value directly
              else {
                item_values[j] = items[j];
              }

              // Rendered title
              if(this.enumSource[i].title) {
                item_titles[j] = this.enumSource[i].title({
                  i: j,
                  item: item
                });
              }
              // Use value as the title also
              else {
                item_titles[j] = item_values[j];
              }
            }

            // TODO: sort

            select_options = select_options.concat(item_values);
            select_titles = select_titles.concat(item_titles);
          }
        }
      }

      var prev_value = this.value;

      this.theme.setSelectOptions(this.input, select_options, select_titles);
      this.enum_options = select_options;
      this.enum_display = select_titles;
      this.enum_values = select_options;

      if(this.select2) {
        this.select2.select2('destroy');
      }

      // If the previous value is still in the new select options, stick with it
      if(select_options.indexOf(prev_value) !== -1) {
        this.input.value = prev_value;
        this.value = prev_value;
      }
      // Otherwise, set the value to the first select option
      else {
        this.input.value = select_options[0];
        this.value = this.typecast(select_options[0] || "");  
        if(this.parent) this.parent.onChildEditorChange(this);
        else this.jsoneditor.onChange();
        this.jsoneditor.notifyWatchers(this.path);
      }

      this.setupSelect2();
    }
    // {
      var vars;
      if(this.header_template) {
        vars = $.extend(this.getWatchedFieldValues(),{
          key: this.key,
          i: this.key,
          i0: (this.key*1),
          i1: (this.key*1+1),
          title: this.getTitle()
        });
        var header_text = this.header_template(vars);

        if(header_text !== this.header_text) {
          this.header_text = header_text;
          this.updateHeaderText();
          this.notify();
          //this.fireChangeHeaderEvent();
        }
      }
      if(this.link_watchers.length) {
        vars = this.getWatchedFieldValues();
        for(var i=0; i<this.link_watchers.length; i++) {
          this.link_watchers[i](vars);
        }
      }
    // }
  },
    getLink: function(data) {
        var holder, link;

        // Get mime type of the link
        var mime = data.mediaType || 'application/javascript';
        var type = mime.split('/')[0];

        // Template to generate the link href
        var href = this.jsoneditor.compileTemplate(data.href,this.template_engine);
        var relTemplate = this.jsoneditor.compileTemplate(data.rel ? data.rel : data.href,this.template_engine);

        // Template to generate the link's download attribute
        var download = null;
        if(data.download) download = data.download;

        if(download && download !== true) {
            download = this.jsoneditor.compileTemplate(download, this.template_engine);
        }

        {
            link = holder = this.theme.getBlockLink();
            //holder.setAttribute('target','_blank');
            holder.textContent = data.rel;

            // When a watched field changes, update the url
            this.link_watchers.push(function(vars) {
                var url = href(vars);
                var rel = relTemplate(vars);
                holder.setAttribute('href',url);
                holder.textContent = rel || url;
            });
        }

        if(download && link) {
            if(download === true) {
                link.setAttribute('download','');
            }
            else {
                this.link_watchers.push(function(vars) {
                    link.setAttribute('download',download(vars));
                });
            }
        }
        if(data.class) link.classList.add(data.class);
        if(this.jsoneditor.options.no_link_holder){
            holder.hidden = true;
        }else{
            holder.hidden = false;
        }
        return holder;
    }
});


JSONEditor.defaults.editors.link = JSONEditor.defaults.editors.string.extend({
    getLink: function(data) {
        var holder, link;

        // Get mime type of the link
        var mime = data.mediaType || 'application/javascript';
        var type = mime.split('/')[0];

        // Template to generate the link href
        var href = this.jsoneditor.compileTemplate(data.href,this.template_engine);
        var relTemplate = this.jsoneditor.compileTemplate(data.rel ? data.rel : data.href,this.template_engine);

        // Template to generate the link's download attribute
        var download = null;
        if(data.download) download = data.download;

        if(download && download !== true) {
            download = this.jsoneditor.compileTemplate(download, this.template_engine);
        }

        // Image links
        if(type === 'image') {
            holder = this.theme.getBlockLinkHolder();
            link = document.createElement('a');
            link.setAttribute('target','_blank');
            var image = document.createElement('img');

            this.theme.createImageLink(holder,link,image);

            // When a watched field changes, update the url
            this.link_watchers.push(function(vars) {
                var url = href(vars);
                var rel = relTemplate(vars);
                link.setAttribute('href',url);
                link.setAttribute('title',rel || url);
                image.setAttribute('src',url);
            });
        }
        // Audio/Video links
        else if(['audio','video'].indexOf(type) >=0) {
            holder = this.theme.getBlockLinkHolder();

            link = this.theme.getBlockLink();
            link.setAttribute('target','_blank');

            var media = document.createElement(type);
            media.setAttribute('controls','controls');

            this.theme.createMediaLink(holder,link,media);

            // When a watched field changes, update the url
            this.link_watchers.push(function(vars) {
                var url = href(vars);
                var rel = relTemplate(vars);
                link.setAttribute('href',url);
                link.textContent = rel || url;
                media.setAttribute('src',url);
            });
        }
        // Text links
        else {
            link = holder = this.theme.getBlockLink();
            //holder.setAttribute('target','_blank');
            holder.textContent = data.rel;

            // When a watched field changes, update the url
            this.link_watchers.push(function(vars) {
                var url = href(vars);
                var rel = relTemplate(vars);
                holder.setAttribute('href',url);
                holder.textContent = rel || url;
            });
        }

        if(download && link) {
            if(download === true) {
                link.setAttribute('download','');
            }
            else {
                this.link_watchers.push(function(vars) {
                    link.setAttribute('download',download(vars));
                });
            }
        }
        if(data.class) link.classList.add(data.class);
        if(this.jsoneditor.options.no_link_holder){
            holder.hidden = true;
        }else{
            holder.hidden = false;
        }
        return holder;
    }
});

@Component({})
export default class AppFormJson extends Vue {



  /**
   * 双向绑定值
   *
   * @type {*}
   * @memberof AppFormJson
   */
  @Model("change") itemValue?: any;

  /**
   * 表单数据
   *
   * @type {*}
   * @memberof AppFormJson
   */
  @Prop() public data!: any;

  /**
   * 数据格式
   *
   * @type {*}
   * @memberof AppFormJson
   */
  @Prop() public schema?: any;

  /**
   * 格式选项
   *
   * @type {*}
   * @memberof AppFormJson
   */
  @Prop() public options?: any;

  /**
   * 当前值
   *
   * @return {*}
   * @memberof AppFormJson
   */
  get CurrentVal() {
    return this.itemValue;
  }

  /**
   * 设置值
   *
   * @param {*} [value]
   * @memberof AppFormJson
   */
  set CurrentVal(val: any) {
    this.$emit("change", val);
  }

  /**
   * 表单状态
   *
   * @type {Subject<any>}
   * @memberof AppFormJson
   */
  @Prop() public formState?: Subject<any>;

  /**
   * 表单状态事件
   *
   * @private
   * @type {(Unsubscribable | undefined)}
   * @memberof AppFormJson
   */
  private formStateEvent: Subscription | undefined;

  /**
   * Vue生命周期（实例销毁后）
   *
   * @memberof AppFormJson
   */
  public destroyed() {
    if (this.editor) this.editor = null;
    window["showdetail"]=null;
  }

  /**
   * Vue生命周期（实例挂载后）
   *
   * @memberof AppFormJson
   */
  public mounted() {
    if (!this.formState) {
      return;
    }
    this.formStateEvent = this.formState.subscribe(($event: any) => {
      if (Object.is($event.type, "load")) {
          this.renderJsoneditor();
      }
    });
    window["showdetail"]=this.showdetail;
  }

  /**
   * 编辑器对象
   *
   * @type {*}
   * @memberof AppFormJson
   */
  public editor: any;

  public id: any = this.$util.createUUID();


  public async getSchema(): Promise<any>{
    if(this.schema)
      return this.schema;
    else
      return {};
  }

  public async getOptions(): Promise<any>{
    let _options={
      theme: "bootstrap3",
      iconlib: "fontawesome4",
      disable_edit_json: true,
      display_required_only: true,
      disable_collapse: true,
      disable_array_delete_last_row: true,
      ajax: true,
    };

    _options["schema"]=await this.getSchema();

    if (this.CurrentVal) {
      _options["startval"] = JSON.parse(this.CurrentVal);
    }

    if(this.options){
      return Object.assign({},_options,this.options)
    }
    return _options;
  }

  /**
   * 编辑器生成
   *
   * @memberof AppFormJson
   */
  public async renderJsoneditor() {
    var _this = this;
    var element = document.getElementById(_this.id);
    if (this.editor) {
      this.editor.destroy();
    }


    let opt:any = await _this.getOptions();
    this.editor = new JSONEditor(element, opt);

    this.editor.on("change", () => {
      let value = _this.editor.getValue();
      _this.CurrentVal = JSON.stringify(value);
    });
  }

  /**
   * 设置编辑器值
   *
   * @param {*} [val]
   * @memberof AppFormJson
   */
  public setEditValue(val: any): void {
    if (val) {
      this.editor.setValue(val);
    } else {
      this.editor.setValue({});
    }
  }


  public showdetail(path:any,arg:any)
  {
          const view: any = {
              viewname: path,
              height: 0,
              width: 0,
              title: '查看',
          };
          this.$appmodal.openModal(view, arg, {});
  }

}
</script>