/**
 * -------------------------------------------------------------------------
 *
 * Script for working with your app on the client side.
 *
 * -------------------------------------------------------------------------
 *
 * @package    MimimiFramework
 * @subpackage Examples / IDE skeleton
 * @license    GPL-2.0
 *             https://opensource.org/license/gpl-2-0/
 * @copyright  2022 MiMiMi Community
 *             https://mimimi.software/
 *
 * -------------------------------------------------------------------------
 */

    class IdeApplication {

        /**
         * -----------------------------------------------------------------
         *
         * Private properties.
         *
         * -----------------------------------------------------------------
         */

        #persistent = true;

        /**
         * -----------------------------------------------------------------
         *
         * Public properties.
         *
         * -----------------------------------------------------------------
         */

        topmenu   = null;
        toolbar   = null;
        workspace = null;
        statusbar = null;

        session   = this.#persistent ? localStorage
                                     : sessionStorage;

        /**
         * -----------------------------------------------------------------
         *
         * Creates an instance of the class.
         *
         * -----------------------------------------------------------------
         */

        constructor ( ) {
            const param = 'fullSize',
                  state = this.session.getItem ( param );
            if ( state == 'on' ) {
                if ( false ) {
                    this.fullScreen ( );
                } else {
                    this.session.removeItem ( param );
                    this.displayModal ( 'Warning', 'Sorry, fullscreen mode enabled programmatically cannot be restored on subsequent non-asynchronous pages due to browser security. This mode can only be initiated by a user gesture (if necessary, please click that toolbar icon or menu item again). Therefore, your browser has switched the screen back to windowed mode.' );
                }
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Submits a form.
         *
         * -----------------------------------------------------------------
         */

        submitForm ( form ) {
            if ( form ?. requestSubmit ) {
                const btn = form ?. querySelector ( 'input[type="submit"],' +
                                                    'button[type="submit"]' );
                if ( btn ) {
                    form.requestSubmit ( btn );
                } else {
                    form.requestSubmit ( );
                }
            } else {
                form ?. submit ( );
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Submits a form by clicking CTRL+ENTER.
         *
         * -----------------------------------------------------------------
         */

        submitByCtrlEnter ( form ) {
            if ( event ?. ctrlKey ) {
                if ( ! event ?. shiftKey ) {
                    if ( ! event ?. altKey ) {
                        if ( event ?. key == 'Enter' ) {
                            event ?. preventDefault ( );
                            event ?. stopPropagation ( );
                            this.submitForm ( form );
                        }
                    }
                }
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Displays a modal window.
         *
         * -----------------------------------------------------------------
         */

        displayModal ( title, msg ) {
            const node = document.querySelector ( '.workspace' );
            if ( node ) {
                const modal = document.createElement ( 'div' );
                modal.classList.add ( 'modal', 'outside' );
                modal.innerHTML = '<h1>' + title + '</h1>'   +
                                  '<p>' + msg + '</p>'       +
                                  '<footer class="buttons">' +
                                      '<button class="btn outside" onclick="app.closeWindow ( this )"></button>' +
                                      '<button class="btn"         onclick="app.closeWindow ( this )">OK</button>' +
                                  '</footer>';
                node.insertBefore ( modal, node.firstChild );
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Removes a modal window if it is displayed.
         *
         * -----------------------------------------------------------------
         */

        removeModal ( ) {
            const nodes = document.querySelectorAll ( '.workspace .modal' );
            nodes.forEach (
                ( node ) => node ?. remove ( )
            );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Closes a modal window containing the clicked anchor.
         *
         * -----------------------------------------------------------------
         */

        closeWindow ( anchor ) {
            const node = anchor ?. closest ( '.modal' );
            if ( node ) {
                node ?. remove ( );
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Saves a file currently edited.
         *
         * -----------------------------------------------------------------
         */

        saveFile ( initiator = null ) {
            const index = this.workspace ?. rememberTab ( false ),
                  tab   = index >= 0
                                ?  app.workspace ?. tabs[ index ]
                                :  null,
                  textarea = this.workspace ?. findMyTextarea ( tab );
            if ( textarea ) {
                const form = textarea ?. closest ( 'form' );
                if ( form ) {
                    this.submitForm ( form );
                }
            } else {
                const path = 'file/save';
                app.topmenu ?. switchLink ( path, 's' , false );
                app.toolbar ?. switchLink ( path, 's' , false );
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Maximizes or minimizes the IDE window.
         *
         * -----------------------------------------------------------------
         */

        fullScreen ( anchor = null ) {
            if ( ! document.fullscreenElement
            &&   ! document.mozFullScreenElement
            &&   ! document.webkitFullscreenElement ) {
                const node = document.documentElement;
                if      ( node.requestFullscreen          ) { node.requestFullscreen       ( );                              this.session.setItem ( 'fullSize', 'on' ); }
                else if ( node.mozRequestFullScreen       ) { node.mozRequestFullScreen    ( );                              this.session.setItem ( 'fullSize', 'on' ); }
                else if ( node.webkitRequestFullscreen    ) { node.webkitRequestFullscreen ( Element.ALLOW_KEYBOARD_INPUT ); this.session.setItem ( 'fullSize', 'on' ); }
            } else {
                if      ( document.cancelFullScreen       ) { document.cancelFullScreen       ( ); this.session.removeItem ( 'fullSize' ); }
                else if ( document.mozCancelFullScreen    ) { document.mozCancelFullScreen    ( ); this.session.removeItem ( 'fullSize' ); }
                else if ( document.webkitCancelFullScreen ) { document.webkitCancelFullScreen ( ); this.session.removeItem ( 'fullSize' ); }
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Launches the project selected on the "Log in" page.
         *
         * -----------------------------------------------------------------
         *
         * Please note that this page is the home page when the current
         * visitor is not yet authorized as a developer.
         *
         * Here we access the parent container to find the select box inside
         * it. We then retrieve the URL of the project selected in that box.
         * And send the browser to that URL.
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @param  object  anchor  Reference to the clicked "RUN" button on that page.
         *
         * -----------------------------------------------------------------
         */

        runProject ( anchor ) {
            const node = anchor ?. closest       ( '.form'                  )
                                ?. querySelector ( 'select[name="project"]' );
            if ( node ) {
                const url = node.value;
                window.location.replace ( url );
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Handles dragging a file tab to the recycle bin.
         *
         * -----------------------------------------------------------------
         *
         * We are talking now about those tabs that are located at the top
         * of the file editor area. The user can drag any tab and drop it on
         * the trash icon. So, the first Drag-and-Drop action will start
         * with this method. It just remembers the path and file name that
         * will be deleted later, and also specifies the effect expected
         * from the dragged object: it is "move".
         *
         * -----------------------------------------------------------------
         */

        dragTab ( initiator ) {
            if ( initiator ?. classList ?. contains ( 'tab' ) ) {
                const url = initiator.getAttribute ( 'data-file' );
                if ( url ) {
                    event.dataTransfer.setData ( 'text/plain', url );
                    event.dataTransfer.effectAllowed = 'move';
                }
            }
        }

            /**
             * -------------------------------------------------------------
             *
             * This method is called when the user drags a file tab over the
             * trash icon, but has not yet released it. The method just
             * specifies the effect expected from the object that will be
             * dropped: it is "move".
             *
             * -------------------------------------------------------------
             */

            dragOverTab ( initiator ) {
                event.stopPropagation ( );
                event.preventDefault ( );
                event.dataTransfer.dropEffect = 'move';
            }

            /**
             * -------------------------------------------------------------
             *
             * This method is called when the user has dropped a file tab
             * onto the trash icon. The method just redirects this user to
             * the RecycleBin widget handler: it is the "Application.php
             * -> Widgets.php -> Trash.php" module called with a parameter
             * equal to the URL of that file.
             *
             * -------------------------------------------------------------
             */

            dropTab ( initiator ) {
                event.stopPropagation ( );
                event.preventDefault ( );
                const url = event.dataTransfer.getData ( 'text/plain' );
                if ( url ) {
                    window.location.replace ( 'widgets/trash/' + url );
                }
            }

        /**
         * -----------------------------------------------------------------
         *
         * Handles dragging and dropping of files into the drop zone.
         *
         * -----------------------------------------------------------------
         */

        dragFiles ( initiator ) {
            event.stopPropagation ( );
            event.preventDefault ( );
            event.dataTransfer.dropEffect = 'copy';
        }

        dropFiles ( initiator ) {
            event.stopPropagation ( );
            event.preventDefault ( );
            const node = app.findZone ( initiator, 'input[type="file"]' );
            if ( node ) {
                const data = event.dataTransfer;
                node.files = data.files;
                app.changeFiles ( node );
            }
        }

        findZone ( initiator, selector ) {
            return initiator ?. closest       ( 'label'  )
                             ?. querySelector ( selector );
        }

        changeFiles ( initiator ) {
            const node = app.findZone ( initiator, '.dropzone .count' );
            if ( node ) {
                const count = initiator ?. files ?. length;
                node.innerText = count > 0
                                       ? count + ' file(s) selected'
                                       : '';
            }
        }
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Initializes the application.
     *
     * ---------------------------------------------------------------------
     */

    var app = new IdeApplication ( );
