// import {
//   AfterViewInit,
//   Component,
//   ElementRef,
//   EventEmitter,
//   HostListener,
//   Input,
//   OnDestroy,
//   OnInit,
//   Output,
//   ViewChild,
// } from '@angular/core';
// declare var CodeMirror;
// declare var twemoji;
// import * as emojiRegex from 'twemoji-parser/dist/lib/regex';
// import { fromHexcodeToCodepoint, fromCodepointToUnicode } from 'emojibase';
// import * as emojiBaseData from 'emojibase-data/en/data.json';
// import * as emojiBaseShortcodes from 'emojibase-data/en/shortcodes/joypixels.json';
// //import data from 'emojibase-data/en/data.json';

// import { DeviceDetectorService } from 'ngx-device-detector';
// import { RouterHandler } from 'src/app/shared/services/router-handler.service';
// import { marker } from '@biesbjerg/ngx-translate-extract-marker';
// import { styleChangedObserver } from 'src/app/shared/shared-observers';
// import { AppStorage } from 'src/app/shared/app-storage';

// @Component({
//   selector: 'app-markdown-editor',
//   templateUrl: './markdown-editor.component.html',
//   styleUrls: ['./markdown-editor.component.scss'],
// })
// export class MarkdownEditorComponent implements OnInit, AfterViewInit, OnDestroy {
//   public static emojiUrl = 'assets/img/twemoji/13.0.1/72x72/';
//   public static emojiExt = 'png';

//   public toggledEmojiPopup: boolean = false;
//   public toggleStyleMenu: boolean = false;

//   private codeMirror;
//   private doc; // Document from codemirror
//   public messageLengthTooLong: boolean = false;
//   public messageMaxLength: number = 1000;

//   public isMessageEmpty: boolean = true;

//   public inputValue: string = '';
//   public compositionValue: string = '';

//   /**
//    * All emoji from emojibase
//    */
//   public allEmoji: any;

//   /**
//    * Dict {emoji hex: shortcode}
//    */
//   public emojiHexcodeToShortcode: any;

//   /**
//    * Dict {shortcode: unicode}
//    */
//   public emojiShortcodeToUnicode: any;

//   /**
//    * true if emojiShortcodeToUnicode built
//    */
//   public shortCodesLoaded: boolean = false;

//   public showShortCodePicker: boolean = true;

//   /**
//    * The actual prefix, what you typed in codemirror, it is passed to the
//    * emoji shortcode picker component as Input
//    */
//   public shortcodePrefix: string = '';

//   /**
//    * This editor is a message editor input (and not the new message input)
//    */
//   @Input() isMsgEdit?: boolean = false;

//   /**
//    * Initial content of the editor
//    */
//   @Input() content?: string = '';

//   /**
//    * Editor DOM Node for CodeMirror
//    */
//   @ViewChild('editor') editor: ElementRef;
//   @ViewChild('emojiBtn', { read: ElementRef }) emojiBtn: ElementRef;

//   @Output() readonly changeEvent = new EventEmitter<string>();
//   @Output() readonly submitEvent = new EventEmitter<string>();
//   @Output() readonly closeEvent = new EventEmitter<boolean>();
//   @Output() readonly focusChangeEvent = new EventEmitter<boolean>();

//   @Input() autofocus?: boolean = false; // autofocus
//   @Input() messageSending: boolean = false;

//   // on mobile the enter input should line break instead of form submit
//   private isOnDesktop: boolean = true;

//   constructor(
//     private ref: ElementRef,
//     private deviceService: DeviceDetectorService,
//     private routerHandler: RouterHandler
//   ) {
//     this.allEmoji = [];
//     let opt: any = {
//       shortcodes: ['discord'],
//     };

//     this.isOnDesktop = this.deviceService.isDesktop();

//     // load from cdn
//     /*fetchFromCDN("en/data.json", opt).then((res) => {
//       this.allEmoji = res;
//     });*/
//     this.allEmoji = emojiBaseData; // load locally (csp)

//     //fetchShortcodes("en", "discord").then((res) => {

//     this.emojiHexcodeToShortcode = emojiBaseShortcodes;
//     this.emojiShortcodeToUnicode = {};

//     for (let key in this.emojiHexcodeToShortcode) {
//       let arr: any;

//       if (!Array.isArray(this.emojiHexcodeToShortcode[key])) {
//         arr = [this.emojiHexcodeToShortcode[key]];
//       } else {
//         arr = this.emojiHexcodeToShortcode[key];
//       }

//       arr.forEach((el) => {
//         let emoji = fromCodepointToUnicode(fromHexcodeToCodepoint(key));
//         this.emojiShortcodeToUnicode[el] = emoji;
//       });
//     }

//     this.shortCodesLoaded = true;
//     //});
//   }

//   ngOnInit(): void {
//     this.routerHandler.subscribe('room/?/chat/?', this.routerChange);
//   }

//   ngAfterViewInit(): void {
//     // replace unicode emoji with twemoji
//     let unicodeEmojiParse = (doc, change) => {
//       let re = emojiRegex.default;
//       let allMatches = [];

//       for (
//         let line = change.from.line, ch = 0, last = doc.lastLine();
//         line <= last;
//         line++, ch = 0
//       ) {
//         let string = doc.getLine(line);
//         let match;

//         // replace all the unicode emoji with twemoji in this line, using emojiRegex
//         while ((match = re.exec(string))) {
//           allMatches.push(match);
//           let pos = match.index;

//           let src;
//           twemoji.parse(match[0], {
//             callback: (icon, options) => {
//               src = icon;
//             },
//           });

//           let img = document.createElement('img');
//           img.src = MarkdownEditorComponent.emojiUrl + src + '.' + MarkdownEditorComponent.emojiExt;
//           doc.markText(
//             { line: line, ch: pos },
//             { line: line, ch: pos + match[0].length },
//             {
//               atomic: true,
//               replacedWith: img,
//             }
//           );
//         }
//       }
//     };

//     // replace shortcode emoji with twemoji
//     let shortcodeEmojiParse = (doc, change) => {
//       for (
//         let line = change.from.line, ch = 0, last = doc.lastLine();
//         line <= last;
//         line++, ch = 0
//       ) {
//         let string = doc.getLine(line);
//         let match;

//         let shortcodeRe = /:([a-z0-9_]+):/gu;
//         // search and replace shortcode emoji string with the real emoji

//         let emojiShortReplace = [];
//         while ((match = shortcodeRe.exec(string))) {
//           if (match[1] in this.emojiShortcodeToUnicode) {
//             emojiShortReplace.push({
//               from: {
//                 line,
//                 ch: match.index,
//               },
//               to: {
//                 line,
//                 ch: match.index + match[0].length,
//               },
//               original: match[0], // original
//               text: this.emojiShortcodeToUnicode[match[1]],
//             });
//           }
//         }

//         emojiShortReplace.forEach((replace) => {
//           let src;
//           twemoji.parse(replace.text, {
//             callback: (icon, options) => {
//               src = icon;
//             },
//           });
//           let img = document.createElement('img');
//           img.src = MarkdownEditorComponent.emojiUrl + src + '.' + MarkdownEditorComponent.emojiExt;

//           /*doc.markText(replace.from, replace.to, {
//             atomic: true,
//             replacedWith: img,
//             selectLeft: true
//           });*/
//           this.doc.replaceRange(replace.text, replace.from, replace.to);
//         });
//       }
//       return true;
//     };

//     this.codeMirror = CodeMirror(this.editor.nativeElement, {
//       value: '' + this.content,
//       mode: 'claraMarkdown',
//       lineWrapping: true,
//       placeholder: marker('Type message here...'),
//       autofocus: this.autofocus,
//       tabindex: 0,
//       extraKeys: {
//         Enter: () => {
//           if (this.isOnDesktop) {
//             if (this.messageLengthTooLong || this.codeMirror.getValue().trim().length == 0) return;

//             this.submitEvent.emit(this.codeMirror.getValue());
//           } else {
//             this.insertEnter();
//           }
//         },
//         'Alt-Enter': () => {
//           this.insertEnter();
//         },
//         'Shift-Enter': () => {
//           this.insertEnter();
//         },
//         'Ctrl-Enter': () => {
//           this.insertEnter();
//         },
//         Esc: () => {
//           this.closeEvent.emit(true);
//         },
//       },
//     });

//     if (this.content) {
//       this.codeMirror.setCursor(this.codeMirror.lineCount(), 0);
//     }

//     this.codeMirror.getInputField().addEventListener('compositionupdate', (ev) => {
//       this.compositionValue = ev.data;
//     });

//     // detect and replace shortcode emoji ":emoji:" with twemoji <img>
//     this.codeMirror.on('change', shortcodeEmojiParse);

//     // detect and replace the unicode emoji with twemoji <img>
//     this.codeMirror.on('change', unicodeEmojiParse);

//     this.codeMirror.on('change', (ev) => {
//       this.compositionValue = '';
//       this.inputValue = this.codeMirror.getValue();
//       this.changeEvent.emit(this.inputValue);
//     });

//     // don't allow text length over 1000 characters
//     this.codeMirror.on('change', (ev, change) => {
//       var currentText: string = this.codeMirror.getValue();
//       var newText: string = change.text;
//       var fullText = currentText + newText;
//       this.messageLengthTooLong = fullText.length > this.messageMaxLength;
//     });

//     // 1. show style-format menu, when text selected and
//     // 2. show shortcode emoji helper popup, when ":xx" detected at the cursor
//     this.codeMirror.on('cursorActivity', (doc) => {
//       this.toggleStyleMenu = doc.somethingSelected();

//       this.findEmojiShortcodeSyntaxAtCursor(
//         (word, line, startPos, endPos) => {
//           this.shortcodePrefix = word.substring(1);
//         },
//         () => {
//           this.shortcodePrefix = '';
//         }
//       );
//     });

//     this.codeMirror.on('focus', () => {
//       this.focusChangeEvent.emit(true);
//     });
//     this.codeMirror.on('blur', () => {
//       this.focusChangeEvent.emit(false);
//     });

//     this.doc = this.codeMirror['getDoc']();

//     // on init replace all unicode and shortcode emoji with twemoji
//     let allRange = {
//       from: { line: 0, ch: 0 },
//       to: { line: this.doc.lastLine(), ch: 0 },
//     };
//     unicodeEmojiParse(this.doc, allRange);
//     shortcodeEmojiParse(this.doc, allRange);

//     // style change dinamically
//     let handleStyleChange = (style) => {
//       switch (style) {
//         case 'light':
//           this.codeMirror.setOption('theme', 'default');
//           break;
//         case 'dark':
//           this.codeMirror.setOption('theme', 'dracula');
//           break;
//       }
//     };

//     styleChangedObserver.subscribe(handleStyleChange);

//     // we can not get the initial changes via observer in the afterViewInit
//     // because it triggered in the app's constructor
//     let styleMode = AppStorage.getItem('style_mode');
//     handleStyleChange(styleMode);
//   }

//   public messageSent(success: boolean) {
//     if (success) this.codeMirror.setValue('');
//   }

//   public submit() {
//     this.codeMirror.focus();
//     this.submitEvent.emit(this.codeMirror.getValue() + this.compositionValue);
//   }

//   routerChange = (res) => {
//     if (this.autofocus) {
//       this.codeMirror.focus();
//     }

//     if (!this.isMsgEdit) {
//       // on router change reset new message field, leave msg editor fields
//       this.codeMirror.setValue('');
//     }
//   };

//   handleEmojiInsert(emoji) {
//     let cursor = this.doc.getCursor();
//     this.doc.replaceRange(emoji, cursor);
//   }

//   handleEmojiAutocomplete(emoji) {
//     //let insertText = ':'+emoji.shortcode+':'; // the viewer cant import the emoji library, so we should convert it into ascii-emoji
//     let insertText = emoji.emoji;

//     this.findEmojiShortcodeSyntaxAtCursor((word, line, startPos, endPos) => {
//       this.doc.replaceRange(insertText, { line, ch: startPos }, { line, ch: endPos });
//     });
//   }

//   /**
//    * Get the word under the CodeMirror cursor position. If it is match the
//    * emoji shortcode syntax prefix, like ":something", it will call the foundCallback
//    * otherwise it is not an emoji shortcode prefix, so call the notfoundCallback
//    * @param foundCallback callback, when the cursor under an emoji shortcode prefix, like ":smil"
//    *    parameters: foundCallback(word, line, startPos, endPos)
//    *      word: the found word under the cursor with the ":" character
//    *      line: the line in the CodeMirror, where the word found
//    *      startPos: the character position on the "line" line, where the word start
//    *      endPos: the character position on the "line" line, where the word end
//    * @param notFoundCallback callback, when the cursor not under an amoji shortcode prefix
//    * @param minLength the minimal expected length of the word after the ":", for example: ":em" == 2
//    */
//   private findEmojiShortcodeSyntaxAtCursor(foundCallback, notFoundCallback?, minLength = 2) {
//     // looking for :prefix emoji shortcode at the current cursor position
//     let A1 = this.codeMirror.getCursor().line;
//     let A2 = this.codeMirror.getCursor().ch;

//     let B1 = this.codeMirror.findWordAt({ line: A1, ch: A2 }).anchor.ch;
//     let B2 = this.codeMirror.findWordAt({ line: A1, ch: A2 }).head.ch;

//     if (B1 > 0) {
//       // if its zero, you can not start with ":", because it is a whitespace for findWordAt
//       B1--; // include the prev character too, what is should be ":"
//       let word = this.codeMirror.getRange({ line: A1, ch: B1 }, { line: A1, ch: B2 });
//       if (word.charAt(0) == ':' && word.length > minLength) {
//         if (foundCallback) foundCallback(word, A1, B1, B2);
//       } else {
//         if (notFoundCallback) notFoundCallback();
//       }
//     } else {
//       if (notFoundCallback) notFoundCallback();
//     }
//   }

//   ngOnDestroy(): void {
//     this.routerHandler.unsubscribe('room/?/chat/?', this.routerChange);
//   }

//   // for style-menu only
//   private tokens = {
//     bold: { before: '**', after: '**' },
//     italics: { before: '*', after: '*' },
//     underline: { before: '__', after: '__' },
//     strikethrough: { before: '~~', after: '~~' },
//     quotes: { before: '\n> ', after: '' },
//     code: { before: '`', after: '`' },
//   };

//   /**
//    * Set the actual markdown format around the selected texts
//    * @param format string, the name of the format, what refers to the this.tokens arr
//    */
//   public setFormat(format) {
//     let token = this.tokens[format];
//     if (token) {
//       let selections = this.doc.getSelections();
//       for (let i = 0; i < selections.length; i++) {
//         selections[i] = token.before + selections[i] + token.after;
//       }
//       this.doc.replaceSelections(selections);
//     }
//   }

//   public insertEnter() {
//     this.doc.replaceRange('\r\n', this.doc.getCursor());
//   }

//   @HostListener('document:click', ['$event'])
//   documentClick(event: MouseEvent) {
//     var emojiPickerElement = this.ref.nativeElement.querySelector('app-emoji-picker');
//     var emojiButtonElement = this.emojiBtn.nativeElement;

//     if (
//       this.toggledEmojiPopup &&
//       !emojiPickerElement.contains(event.target) &&
//       !emojiButtonElement.contains(event.target)
//     ) {
//       this.toggledEmojiPopup = false;
//     }
//   }

//   public onToggleEmojiPopup() {
//     this.toggledEmojiPopup = !this.toggledEmojiPopup;
//     if (this.toggledEmojiPopup) {
//       history.pushState({ emoji: true }, '');
//     }
//   }

//   @HostListener('window:popstate', ['$event'])
//   onWindowPopState($event) {
//     this.toggledEmojiPopup = false;
//   }
// }
