/* -----[ Ymacs dialog ]----- */

import { Ymacs, Ymacs_Buffer, Ymacs_Keymap, Ymacs_Tokenizer, Ymacs_Interactive }
//from "https://test.d/ymacs/src/index.js";
from "../ymacs/ymacs.mjs";

Ymacs_Buffer.setGlobal("indent_level", 4);
[ "emacs" ].forEach(keymapName => {
    let keymap = Ymacs_Keymap.get(keymapName);
    keymap.defineKeys({
        "C-x C-c": Ymacs_Interactive(function(){
            let ymacs = this.ymacs;
            let dlg = ymacs.getElement().closest(".DlDialog");
            if (dlg) {
                DlWidget.getFromElement(dlg)?.__quitBtn?.keyClicked();
            }
        })
    });
});

DEFINE_CLASS("YmacsDialog", XDialog, function(D, P){

    function preventKill(ev) {
        if (document.activeElement.closest(".Ymacs")) {
            ev.preventDefault();
            return ev.returnValue = true;
        }
    }

    window.addEventListener("beforeunload", preventKill);

    D.DEFAULT_ARGS = {
        _title     : [ "title"     , "Ymacs Editor"  ],
        _resizable : [ "resizable" , true            ],
        __quitBtn  : [ "quitBtn"   , "hide"          ]
    };
    D.CONSTRUCT = function() {
        var ymacs = this.ymacs = new Ymacs();
        ymacs.getParentDialog = () => this;
        ymacs.addClass("Ymacs-line-numbers");
        ymacs.setColorTheme(getColorTheme() == "light"
                            ? [ "light", "ef-cyprus" ]
                            : [ "dark", "ef-elea-dark" ]);
        this.getContentElement().appendChild(ymacs.getElement());
        this.setPercentSize(0.8, 0.8);
    };
    var INSTANCE = null;
    function make() {
        return INSTANCE || (INSTANCE = new D({ modal: true }));
    };
    D.get = make;
    function ymacs_mode(page) {
        switch (page.content_type.toLowerCase()) {
          case "text/syt": return "sytes_mode";
          case "text/javascript": return "javascript_mode";
          case "text/css": return "css_mode";
          case "text/xml": return "xml_mode";
          case "text/html": return "html_mode";
        }
        return "markdown_mode";
    };
    function ymacs_file_mode(filename) {
        switch (filename.substr(filename.indexOf(".") + 1)) {
          case "js": return "javascript_mode";
          case "css": return "css_mode";
          case "xml": return "xml_mode";
          case "html": return "html_mode";
        }
        return "markdown_mode";
    };
    P.editPage = function(page) {
        var ymacs = this.ymacs;
        var buf_name = page.id + ":" + page.title;
        var buf = ymacs.getBuffer(buf_name);
        if (!buf) {
            buf = ymacs.createBuffer({
                name: buf_name,
                code: page.content
            });
            buf.cmd(ymacs_mode(page));
            buf.setq({
                page: page,
                page_id: page.id
            });
        }
        ymacs.switchToBuffer(buf);
        setTimeout( () => ymacs.focus(), 100 );
    };
    D.editPageContent = function(page) {
        var dlg = make();
        dlg.editPage(page);
        dlg.show(true);
    };
    P.copyToClipboard = function(text) {
        this.ymacs.killRingToMaster();
        this.ymacs.pushToKillRing(text);
    };
    P.editArbitraryCode = function(filename, code) {
        var ymacs = this.ymacs;
        var buf_name = filename;
        var buf = ymacs.getBuffer(buf_name);
        if (!buf) {
            buf = ymacs.createBuffer({
                name: filename,
                code: code
            });
            buf.cmd(ymacs_file_mode(filename));
        }
        ymacs.switchToBuffer(buf);
    };
    D.editArbitraryCode = function(filename, code) {
        var dlg = make();
        dlg.editArbitraryCode(filename, code);
        dlg.show(true);
    };
});

//-----------------------------------------------------------------------
// Sytes mode
//

(function(){

    let keymap_sytes = window.LOGGED_IN ? Ymacs_Keymap.define("sytes", {
        "C-c C-c" : "sytes_preview",
        "C-c C-p" : "sytes_edit_page_props",
        "C-c C-a" : "sytes_link_attachment",
        "C-x C-s" : "sytes_save_file",
        "C-x C-f" : "sytes_load_file",
        "C-c /"   : "close_last_xml_tag",
    }) : null;

    Ymacs_Tokenizer.define("sytes", function(stream, tok){

        var PARSER = {
            next: next,
            copy: copy,
            indentation: indentation,
            get passedParens() {
                return [
                    ...$passedParens,
                    ...$lisp.passedParens,
                    ...$html.passedParens,
                ];
            },
            get tag() {
                return $html.tag;
            },
        };

        var $passedParens = [];
        var $parens = [];
        var $lisp_options = {};
        var $syntax_start, $syntax_stop;
        var $syntax_re_start, $syntax_re_stop;

        setSyntax("{", "}");

        var $lisp = tok.getLanguage("lisp", $lisp_options);
        var $html = tok.getLanguage("html");
        var $mode = $html;

        function setSyntax(a, b) {
            $syntax_start = a;
            $syntax_stop = b;
            $syntax_re_start = new RegExp("^\\" + a);
            $syntax_re_stop = new RegExp("^\\" + b);
            $lisp_options.rx_special = new RegExp("[\\" + a + "\\" + b + "]");
        };

        function foundToken(c1, c2, type) {
            tok.onToken(stream.line, c1, c2, type);
        };

        function switchToLisp() {
            $mode = $lisp;
            $lisp._formLen = 0;
        };

        function switchToHtml() {
            $mode = $html;
        };

        function next() {
            var m;
            stream.checkStop();
            if ($mode === $html) {
                if (stream.lookingAt("\\" + $syntax_start) || stream.lookingAt("\\" + $syntax_stop)) {
                    foundToken(stream.col, ++stream.col, "comment");
                    foundToken(stream.col, ++stream.col);
                    return true;
                }
                if (stream.lookingAt(/^\\;/) && stream.col == 0) {
                    foundToken(stream.col, ++stream.col, "comment");
                    foundToken(stream.col, ++stream.col);
                    return true;
                }
                if ((m = stream.lookingAt(/^(;+)(.*)/)) && stream.col == 0) {
                    foundToken(stream.col, stream.col += m[1].length, "comment-starter");
                    foundToken(stream.col, stream.col += m[2].length, "comment");
                    return true;
                }
                if ((m = stream.lookingAt($syntax_re_stop))) {
                    let p = $parens.pop();
                    if (p && p.new_syntax) {
                        p.closed = { line: stream.line, col: stream.col, opened: p };
                        $passedParens.push(p);
                        setSyntax(p.new_syntax[0], p.new_syntax[1]);
                        foundToken(stream.col, stream.col += m[0].length, "regexp-stopper");
                    }
                    else {
                        switchToLisp();
                        $lisp.popInParen($syntax_start, $syntax_stop.length, "regexp-stopper");
                    }
                    return true;
                }
                if (stream.lookingAt($syntax_re_start)) {
                    stream.col++;
                    if (stream.lookingAt(".SYNTAX")) {
                        let p = { line: stream.line, col: stream.col - 1, type: $syntax_start };
                        $parens.push(p);
                        foundToken(stream.col - 1, stream.col, "regexp-starter");
                        foundToken(stream.col, stream.col += 7, "builtin");
                        if ((m = stream.lookingAt(/^(\s*)(".")(\s+)(".")/i))) {
                            foundToken(stream.col += m[1].length, stream.col += m[2].length, "string");
                            foundToken(stream.col += m[3].length, stream.col += m[4].length, "string");
                            p.new_syntax = [ m[2].charAt(1), m[4].charAt(1) ];
                        }
                        else {
                            foundToken(stream.col, ++stream.col);
                        }
                    }
                    else {
                        stream.col--;
                        switchToLisp();
                        $lisp.pushInParen($syntax_start, "regexp-starter");
                    }
                    return true;
                }
                return $html.next();
            }
            if ($mode === $lisp) {
                if (stream.peek() == $syntax_stop) {
                    $lisp.popInParen($syntax_start, $syntax_stop.length, "regexp-stopper");
                    switchToHtml();
                    return true;
                }
                else if (stream.peek() == $syntax_start) {
                    $lisp.pushInParen($syntax_start, "regexp-starter");
                    switchToHtml();
                    return true;
                }
                return $lisp.next();
            }
        };

        function copy() {
            var _lisp = $lisp.copy();
            var _html = $html.copy();
            var _mode = $mode;
            var _passedParens = $passedParens.slice();
            var _parens = $parens.slice();
            var _syntax_start = $syntax_start;
            var _syntax_stop = $syntax_stop;
            var _syntax_re_start = $syntax_re_start;
            var _syntax_re_stop = $syntax_re_stop;
            function resume() {
                $lisp = _lisp();
                $html = _html();
                $mode = _mode;
                $passedParens = _passedParens.slice();
                $parens = _parens.slice();
                $syntax_start = _syntax_start;
                $syntax_stop = _syntax_stop;
                $syntax_re_start = _syntax_re_start;
                $syntax_re_stop = _syntax_re_stop;
                return PARSER;
            };
            return resume;
        };

        function indentation() {
            return $mode.indentation();
        };

        return PARSER;

    });

    if (window.LOGGED_IN) Ymacs_Buffer.newCommands({
        sytes_commit: Ymacs_Interactive(function() {
            var self = this;
            var page = this.getq("page");
            if (!page) throw new Ymacs_Exception("Not editing a sytes page");
            RPC("page.commit", page.id, function(ret){
                self.signalInfo("Hopefully done. ;-)");
            });
        }),
        sytes_preview: Ymacs_Interactive(function() {
            var buffer = this;
            RPC("page.edit-content", {
                id: buffer.getq("page_id"),
                content: buffer.getCode()
            }, function(ret, error){
                if (!error) {
                    buffer.dirty(false);
                    RPC("page.get-url", buffer.getq("page").id, function(url){
                        window.open(url + "?preview", "SYTESPREVIEW");
                    });
                }
            });
        }),
        sytes_edit_page_props: Ymacs_Interactive(function() {
            var self = this;
            var page = self.getq("page");
            PagePropsDialog.editPageProps(page, self.ymacs, function(page){
                self.cmd("rename_buffer", page.title);
            });
        }),
        sytes_save_file: Ymacs_Interactive(function() {
            var buffer = this;
            RPC("page.edit-content", {
                id: this.getq("page_id"),
                content: this.getCode()
            }, function(ret, error){
                if (!error) {
                    buffer.signalInfo("Probably saved. ;-)");
                    buffer.dirty(false);
                }
            });
        }),
        sytes_add_subpage: Ymacs_Interactive(function(){
            var self = this;
            var page = this.getq("page");
            PagePropsDialog.newPage(page.id);
        }),
        sytes_read_page_name: Ymacs_Interactive(function(cont){
            var self = this;
            var page = self.getq("page");
            RPC("page.get-subpages", page.id, function(subpages){
                var completions = subpages.map("urlpart");
                self.cmd("minibuffer_prompt", "Load page: ");
                self.cmd("minibuffer_read_string", completions, function(val){
                    var page = subpages.grep_first(function(p){
                        return p.urlpart = val;
                    });
                    cont(page);
                });
            });
        }),
        sytes_load_file: Ymacs_Interactive(function(){
            this.cmd("sytes_read_page_name", function(page){
                YmacsDialog.editPageContent(page);
            });
        }),
        sytes_link_attachment: Ymacs_Interactive(function(){
            var self = this;
            var ymacs = self.ymacs;
            var page = self.getq("page");
            var dlg = new AttcListDialog({
                page      : page.id,
                parent    : ymacs,
                modal     : true,
                bottombar : XDialog.BUTTONS_OK_CANCEL
            });
            dlg.onOK = function() {
                var id = dlg.sel.getFirst();
                if (id == null) {
                    self.signalError("No file selected");
                    return;
                }
                var attc = dlg.set.get(id);
                self.cmd("insert", attc.getDynamicLink());
                dlg.destroy();
            };
            dlg.onDblClick = function() {
                this.x_standard_layout.bb_buttons.ok.keyClicked();
            };
            dlg.on("onDestroy", ymacs.focus.bind(ymacs).clearingTimeout(10));
            dlg.show(true);
        }),
    });

    function define_mode(name, tok) {
        Ymacs_Buffer.newMode(name, function(){
            var old_tok = this.tokenizer;
            var was_html_mode = this.cmd("html_mode", true);
            var was_paren_match = this.cmd("paren_match_mode", true);
            var changed_vars = this.setq({ indent_level: 2 });
            this.setq("fill_column", 120);
            this.setTokenizer(new Ymacs_Tokenizer({ type: tok, buffer: this }));
            if (keymap_sytes) this.pushKeymap(keymap_sytes);
            return function() {
                if (keymap_sytes) this.popKeymap(keymap_sytes);
                this.setq(changed_vars);
                if (!was_html_mode)
                    this.cmd("html_mode", false);
                if (!was_paren_match)
                    this.cmd("paren_match_mode", false);
                this.setTokenizer(old_tok);
            };
        });
    };

    define_mode("sytes_mode", "sytes");

})();
