<template>
    <div :class="editorClass">
        <textarea :id="id"></textarea>
    </div>
</template>
<script lang="ts">
import { Vue, Component, Prop, Watch, Inject } from 'vue-property-decorator';
import { Subject, Subscription } from 'rxjs';
import axios from 'axios';
import { AppServiceBase, ImgurlBase64, LogUtil } from '@ibizstudio-ex/runtime';
import tinymce from 'tinymce/tinymce';
// import 'tinymce/themes/modern';
import 'tinymce/themes/silver';
import 'tinymce/plugins/link';
import 'tinymce/plugins/paste';
import 'tinymce/plugins/table';
import 'tinymce/plugins/image';
import 'tinymce/plugins/imagetools';
import 'tinymce/plugins/codesample';
import 'tinymce/plugins/code';
import 'tinymce/plugins/fullscreen';
import 'tinymce/plugins/preview';
import 'tinymce/plugins/fullscreen';
import 'tinymce/icons/default/icons.min.js';

const tinymceCode: any = tinymce;

@Component({})
export default class AppRichTextEditor extends Vue {
    /**
     * 传入值
     *
     * @type {*}
     * @memberof AppRichTextEditor
     */
    @Prop() value?: any;

    /**
     * 输入name
     *
     * @type {string}
     * @memberof AppRichTextEditor
     */
    @Prop() name?: string;

    /**
     * 输入高度
     *
     * @type {*}
     * @memberof AppRichTextEditor
     */
    @Prop() height?: any;

    /**
     * 是否禁用
     *
     * @type {boolean}
     * @memberof AppRichTextEditor
     */
    @Prop() disabled?: boolean;

    /**
     * 禁用回调
     *
     * @type {boolean}
     * @memberof AppRichTextEditor
     */
    @Watch('disabled')
    disabledChange(newVal: any, oldVal: any){
        if(newVal !== oldVal){
            this.editor.setMode( newVal ? 'readonly' : 'design');
        }
    }

    /**
     * 表单状态
     *
     * @type {Subject<any>}
     * @memberof AppRichTextEditor
     */
    @Inject('formState')
    formState!: Subject<any>

    protected formStateEvent: Subscription | undefined;

    /**
     * 上传文件路径
     *
     * @type {string}
     * @memberof AppRichTextEditor
     */
    uploadUrl = AppServiceBase.getInstance().getAppEnvironment().UploadFile;

    /**
     * 下载路径
     *
     * @type {string}
     * @memberof AppRichTextEditor
     */
    downloadUrl = AppServiceBase.getInstance().getAppEnvironment().ExportFile;

    /**
     * 当前富文本
     *
     * @type {*}
     * @memberof AppRichTextEditor
     */
    editor: any = null;

    /**
     *  当前富文本id
     *
     * @type {string}
     * @memberof AppRichTextEditor
     */
    id: string = this.$util.createUUID();

    /**
     * 当前语言,默认中文
     *
     * @type {*}
     * @memberof AppRichTextEditor
     */
    langu: any = localStorage.getItem('local') ? localStorage.getItem('local') : 'zh-CN';

    /**
     * 上传params
     *
     * @type {Array<any>}
     * @memberof AppRichTextEditor
     */
    upload_params: Array<any> = [];

    /**
     * 导出params
     *
     * @type {Array<any>}
     * @memberof AppRichTextEditor
     */
    export_params: Array<any> = [];

    /**
     * 上传参数
     *
     * @type {string}
     * @memberof AppRichTextEditor
     */
    @Prop() uploadparams?: any;

    /**
     * 下载参数
     *
     * @type {string}
     * @memberof AppRichTextEditor
     */
    @Prop() exportparams?: any;

    /**
     * 视图参数
     *
     * @type {*}
     * @memberof AppRichTextEditor
     */
    @Prop() viewparams!: any;

    /**
     * 视图上下文
     *
     * @type {*}
     * @memberof AppRichTextEditor
     */
    @Prop() context!: any;

    /**
     * 表单数据
     *
     * @type {string}
     * @memberof AppRichTextEditor
     */
    @Prop() data!: string;

    /**
     * 语言映射文件
     *
     * @type {*}
     * @memberof AppRichTextEditor
     */
    languMap: any = {
        'zh-CN': 'zh_CN',
        'en-US': 'en_US',
    };

    /**
     * 是否处于激活状态
     *
     * @type {boolean}
     * @memberof AppRichTextEditor
     */
    isActived: boolean = true;

    /**
     * 是否需要初始化
     *
     * @type {boolean}
     * @memberof AppRichTextEditor
     */
    isNeedInit: boolean = false;

    /**
     * 上传的图片id与类型集合
     * @type {string}
     * @memberof AppRichTextEditor
     */
    imgsrc: Array<any> = [];

    /**
     * 编辑器样式类
     * @type {string}
     * @memberof AppRichTextEditor
     */
    editorClass: string = 'app-rich-text-editor';

    /**
     * 生命周期
     *
     * @memberof AppRichTextEditor
     */
    created() {
        if (this.formState) {
            this.formStateEvent = this.formState.subscribe(({ type, data }) => {
                if (Object.is('load', type)) {
                    this.getParams();
                    if (!this.value) {
                        this.init();
                    }
                }
            });
        }
    }

    destroyed(): void {
      if (this.formStateEvent) {
        this.formStateEvent.unsubscribe();
      }
    }

    /**
     * 生命周期：激活
     *
     * @memberof AppRichTextEditor
     */
    activated() {
        this.isActived = true;
        if (this.isNeedInit) {
            this.init();
            this.isNeedInit = false;
        }
    }

    /**
     * 生命周期：缓存
     *
     * @memberof AppRichTextEditor
     */
    deactivated() {
        this.isActived = false;
    }

    /**
     * 生命周期：初始化富文本
     *
     * @memberof AppRichTextEditor
     */
    mounted() {
        this.init();
        const ele: any = this.isDrawer(this.$el);
        if (ele) {
            ele.style.transform.replace(/translateX\(-?(\d+)%?(px)?\)\s/i,(match: string, p1: string) => {
              this.editorClass = this.editorClass + '-' + parseInt(p1);
            });
        }
    }

    /**
     * 是否抽屉打开
     *
     * @memberof AppRichTextEditor
     */
    isDrawer(ele: any): any {
        let pele: any = ele.parentNode;
        if (!pele) {
            return false;
        }
        if (pele.className && pele.className.indexOf('studio-drawer-content') >= 0) {
            return pele;
        }
        return this.isDrawer(pele);
    }

    /**
     * 生命周期：销毁富文本
     *
     * @memberof AppRichTextEditor
     */
    destoryed() {
        if (this.editor) {
            tinymceCode.remove('#' + this.id);
        }
    }

    /**
     * 监听value值
     *
     * @memberof AppRichTextEditor
     */
    @Watch('value', { immediate: true, deep: true })
    async oncurrentContent(newval: any, val: any) {
        const content: any = this.editor ? this.editor.getContent() : undefined;
        const url = this.downloadUrl.indexOf('../') === 0 ? this.downloadUrl.substring(3) : this.downloadUrl;
        if (newval) {
            newval = newval.replace(
                /\{(\w+)\.(bmp|jpg|jpeg|png|tif|gif|pcx|tga|exif|fpx|svg|psd|cdr|pcd|dxf|ufo|eps|ai|raw|WMF|webp)\}/g,
                `${url}/$1`
            );
            newval = await this.getImgUrlBase64(newval);
        }
        if (!Object.is(newval, content)) {
            this.init();
        }
        this.getParams();
    }

    /**
     * 监听语言变化
     */
    @Watch('$i18n.locale')
    onLocaleChange(newval: any, val: any) {
        this.langu = newval;
        if (this.isActived) {
            this.init();
        } else {
            this.isNeedInit = true;
        }
    }

    /**
     * 获取图片Base64
     *
     * @memberof AppRichTextEditor
     */
    async getImgUrlBase64(html: any){
        let imgs:Array<any>|null = html.match(/<img.*?(?:>|\/>)/gi)!=null? html.match(/<img.*?(?:>|\/>)/gi):[];
        if(imgs && imgs.length>0){
             for (let item of imgs) {
                if(item.match(/src=[\'\"]?([^\'\"]*)[\'\"]?/ig)!=null){
                    let src:any = item.match(/src=[\'\"]?([^\'\"]*)[\'\"]?/ig)[0];
                    src = await ImgurlBase64.getInstance().getImgURLOfBase64(src.substring(5,src.length-1));
                    const image = item.replace(/src=[\'\"]?([^\'\"]*)[\'\"]?/i, 'src="'+src+'"');
                    html = html.replace(item, image);
                }
            }
        }
        return html;
    }

    /**
     * 更替抛到表单的图片src
     *
     * @memberof AppRichTextEditor
     */
    getImgUrl(html: any){
        let imgs:Array<any>|null = html.match(/<img.*?(?:>|\/>)/gi)!=null? html.match(/<img.*?(?:>|\/>)/gi):[];
        const imgsrc = this.imgsrc;
        if(imgs && imgs.length > 0 && imgsrc && imgsrc.length > 0){
            imgs.forEach((img: any, index: number) => {
                var reg = /data:image\/.*;base64,.*(?=[\'\"])/;
                if(img.match(reg) != null){
                    let base64:any = img.match(reg)[0];
                    const _imgsrc = imgsrc.find((_imgsrc: any) => Object.is(_imgsrc.key, base64));
                    if (_imgsrc) {
                        const newImg = img.replace(reg, '{'+_imgsrc.value+'}');
                        html = html.replace(img, newImg);
                    }
                }
            })
        }
        return html;
    }

    /**
     * 初始化富文本
     *
     * @memberof AppRichTextEditor
     */
    init() {
        this.destoryed();
        let richtexteditor = this;
        tinymceCode.init({
            selector: '#' + richtexteditor.id,
            width: 'calc( 100% - 2px )',
            height: richtexteditor.height,
            min_height: 400,
            branding: false,
            plugins: [
                'link',
                'paste',
                'table',
                'image',
                'codesample',
                'code',
                'fullscreen',
                'preview',
                // 'quickbars',
                'fullscreen',
            ],
            toolbar:
                'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | outdent indent | link image | preview code fullscreen',
            contextmenu: 'cut copy paste pastetext inserttable link ',
            // quickbars_insert_toolbar: false,
            // quickbars_selection_toolbar: 'forecolor fontsizeselect fontselect',
            codesample_languages: [
                { text: 'HTML/XML', value: 'markup' },
                { text: 'JavaScript', value: 'javascript' },
                { text: 'CSS', value: 'css' },
                { text: 'PHP', value: 'php' },
                { text: 'Ruby', value: 'ruby' },
                { text: 'Python', value: 'python' },
                { text: 'Java', value: 'java' },
                { text: 'C', value: 'c' },
                { text: 'C#', value: 'csharp' },
                { text: 'C++', value: 'cpp' },
            ],
            paste_data_images: true,
            codesample_content_css: 'assets/tinymce/prism.css',
            skin_url: './assets/tinymce/skins/lightgray/ui/oxide',
            language_url: './assets/tinymce/langs/' + richtexteditor.languMap[richtexteditor.langu] + '.js',
            language: richtexteditor.languMap[richtexteditor.langu],
            setup: (editor: any) => {
                richtexteditor.editor = editor;
                editor.on('blur', () => {
                    let content = editor.getContent();
                    content = richtexteditor.getImgUrl(content);
                    richtexteditor.$emit('change', content);
                });
            },
            images_upload_handler: (bolbinfo: any, success: any, failure: any) => {
                const formData = new FormData();
                formData.append('file', bolbinfo.blob(), bolbinfo.filename());
                let _url = richtexteditor.uploadUrl;
                if (this.upload_params.length > 0) {
                    _url += '?';
                    this.upload_params.forEach((item: any, i: any) => {
                        _url += `${Object.keys(item)[0]}=${Object.values(item)[0]}`;
                        if (i < this.upload_params.length - 1) {
                            _url += '&';
                        }
                    });
                }
                // this.uploadUrl = _url;
                richtexteditor.uploadFile(_url, formData).subscribe(
                    (file: any) => {
                        let downloadUrl = richtexteditor.downloadUrl;
                        if (file.filename) {
                            const id: string = file.fileid;
                            const url: string = `${downloadUrl}/${id}`;
                            ImgurlBase64.getInstance().getImgURLOfBase64(url).then((response: any) => {
                                const imgsrc = richtexteditor.imgsrc.find((imgsrc: any) => Object.is(response,imgsrc.key));
                                if (!imgsrc) {
                                    const item: any = { key: response, value: file.fileid+file.ext };
                                    richtexteditor.imgsrc.push(item);
                                }
                                success(response);
                                let content = richtexteditor.editor.getContent();
                                content = richtexteditor.getImgUrl(content);
                                richtexteditor.$emit('change', content);
                            });
                        }
                        if (this.export_params.length > 0) {
                            downloadUrl += '?';
                            this.export_params.forEach((item: any, i: any) => {
                                downloadUrl += `${Object.keys(item)[0]}=${Object.values(item)[0]}`;
                                if (i < this.export_params.length - 1) {
                                    downloadUrl += '&';
                                }
                            });
                        }
                    },
                    (error: any) => {
                        LogUtil.log(error);
                        failure('HTTP Error: ' + error.status);
                    }
                );
            },
            init_instance_callback: (editor: any) => {
                richtexteditor.editor = editor;
                const url =
                    richtexteditor.downloadUrl.indexOf('../') === 0
                        ? richtexteditor.downloadUrl.substring(3)
                        : richtexteditor.downloadUrl;
                let value = richtexteditor.value && richtexteditor.value.length > 0 ? richtexteditor.value : '';
                value = value.replace(
                    /\{(\w+)\.(bmp|jpg|jpeg|png|tif|gif|pcx|tga|exif|fpx|svg|psd|cdr|pcd|dxf|ufo|eps|ai|raw|WMF|webp)\}/g,
                    `${url}/$1`
                );
                richtexteditor.getImgUrlBase64(value).then((newValue: any) =>{
                    if (richtexteditor.editor) {
                        richtexteditor.editor.setContent(newValue);
                    }
                    if (richtexteditor.disabled) {
                        richtexteditor.editor.setMode('readonly');
                    }
                });
            },
        });
    }

    /**
     * 上传文件
     *
     * @param url 路径
     * @param formData 文件对象
     * @memberof AppRichTextEditor
     */
    uploadFile(url: string, formData: any) {
        const subject: Subject<any> = new Subject<any>();
        axios({
            method: 'post',
            url: url,
            data: formData,
            headers: { 'Content-Type': 'image/png', Accept: 'application/json' },
        })
            .then((response: any) => {
                if (response.status === 200) {
                    subject.next(response.data);
                } else {
                    subject.error(response);
                }
                subject.complete();
            })
            .catch((response: any) => {
                subject.error(response);
                subject.complete();
            });
        return subject;
    }

    /**
     *获取上传，导出参数
     *
     *@memberof AppRichTextEditor
     */
    getParams() {
        let uploadparams: any = this.uploadparams ? JSON.parse(JSON.stringify(this.uploadparams)) : {};
        let exportparams: any = this.exportparams ? JSON.parse(JSON.stringify(this.exportparams)) : {};

        let upload_params: Array<string> = [];
        let export_params: Array<string> = [];

        let param: any = this.viewparams;
        let context: any = this.context;
        let _data: any = JSON.parse(this.data);

        if (uploadparams && Object.keys(uploadparams).length > 0) {
            upload_params = this.$util.computedNavData(_data, param, context, uploadparams);
        }
        if (exportparams && Object.keys(exportparams).length > 0) {
            export_params = this.$util.computedNavData(_data, param, context, exportparams);
        }

        this.upload_params = [];
        this.export_params = [];

        for (const item in upload_params) {
            this.upload_params.push({
                [item]: upload_params[item],
            });
        }
        for (const item in export_params) {
            this.export_params.push({
                [item]: export_params[item],
            });
        }
    }
}
</script>
<style lang="less">
.tox-statusbar__text-container {
    display: none !important;
}
.app-rich-text-editor,.app-rich-text-editor-0,.app-rich-text-editor-100 {
    width: 100%;
    .tox-fullscreen {
        height: 100% !important;
        transform: translateX(100%);
    }
    .tox-blocker {
        transform: translateX(100%);
    }
}
.app-rich-text-editor-200 {
    width: 100%;
    .tox-fullscreen {
        height: 100% !important;
        transform: translateX(200%);
    }
    .tox-blocker {
        transform: translateX(200%);
    }
}
.tox-menu {
    min-width: 300px !important;
}
</style>
