/**
 * -------------------------------------------------------------------------
 *
 * Script for working with the workspace 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 AppWorkspace {

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

        tabs = null;

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

        #root = null;

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

        constructor ( selector ) {
            this.#root = document.querySelector ( selector );
            if ( this.#root ) {
                this.tabs = this.#root.querySelectorAll ( '.tab' );
                if ( this.tabs ) {
                    this.tabs.forEach (
                        ( tab ) => {
                            tab.onclick = this.onClick;
                            const textarea = this.findMyTextarea ( tab );
                            if ( textarea ) {
                                this.rememberTextarea ( tab );
                                this.rememberCursor ( textarea );
                                textarea.onselect    = this.onText;
                                textarea.onclick     = this.onText;
                                textarea.onmousedown = this.onText;
                                textarea.onmouseup   = this.onText;
                                textarea.onkeypress  = this.onText;
                                textarea.onkeydown   = this.onText;
                                textarea.onkeyup     = this.onText;
                            }
                        }
                    );
                }
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Retrieves the current editor name for the session.
         *
         * -----------------------------------------------------------------
         */

        getEditorParameter ( name ) {
            const editor = document.querySelector ( '.editor' ),
                  suffix = editor ?. getAttribute ( 'data-name' );
            return typeof suffix == 'string'
                                  ? name +  '-' + suffix
                                  : name;
        }

        /**
         * -----------------------------------------------------------------
         *
         * Remembers the last data edited.
         *
         * -----------------------------------------------------------------
         */

        rememberEditor ( ) {
            const param = this.getEditorParameter ( 'editor' );
            return JSON.parse (
                       app.session.getItem ( param ) || '{}'
                   );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Remembers the last tab clicked.
         *
         * -----------------------------------------------------------------
         */

        rememberTab ( autoclick = true ) {
            const param = this.getEditorParameter ( 'lastTab' );
            let index = app.session.getItem ( param );
            if ( index === null ) index = 0;
            if ( index >= this.tabs.length ) index = this.tabs.length - 1;
            if ( index >= 0 ) {
                if ( autoclick ) {
                    this.tabs[ index ].click ( );
                }
            }
            return index;
        }

        /**
         * -----------------------------------------------------------------
         *
         * Remembers the last textarea content.
         *
         * -----------------------------------------------------------------
         */

        rememberTextarea ( tab ) {
            const file  = tab.getAttribute ( 'data-file' ),
                  param = 'text_' + file,
                  data  = this.rememberEditor ( );
            if ( typeof data[ param ] == 'string' ) {
                const textarea = this.findMyTextarea ( tab );
                data[ param ] != textarea.value
                               ? tab.classList.add    ( 'modified' )
                               : tab.classList.remove ( 'modified' );
                textarea.value = data[ param ];
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Remembers the last textarea cursor.
         *
         * -----------------------------------------------------------------
         */

        rememberCursor ( textarea ) {
            const tab  = this.findMyTab ( textarea ),
                  file = tab.getAttribute ( 'data-file' ),
                  data = this.rememberEditor ( ),
                  posB = typeof data[ 'selection_' + file ] != 'undefined'
                                                             ? data[ 'selection_' + file ]
                                                             : 0,
                  posE = typeof data[ 'selectionEnd_' + file ] != 'undefined'
                                                                ? data[ 'selectionEnd_' + file ]
                                                                : 0;
            textarea.selectionStart = posB !== null ? posB : 0;
            textarea.selectionEnd   = posE !== null ? posE : 0;
        }

        /**
         * -----------------------------------------------------------------
         *
         * Retrieves the node of a tab by its event.
         *
         * -----------------------------------------------------------------
         */

        findTab ( event ) {
            const node = event ?. target;
            return node ?. classList.contains ( 'tab' )
                                              ? node
                                              : node ?. closest ( '.tab' );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Retrieves the node of a tab by its textarea.
         *
         * -----------------------------------------------------------------
         */

        findMyTab ( textarea ) {
            const owner = textarea ?. parentNode;
            let node = owner ?. tagName == 'FORM'
                    && owner ?. classList.contains ( 'file' )
                                                   ? owner ?. previousSibling
                                                   : textarea ?. previousSibling;
            while ( node ) {
                if ( node ?. tagName == 'LABEL' ) return node;
                if ( node ?. tagName == 'INPUT'
                ||   node ?. tagName == 'FIGURE'
                ||   node ?. tagName == 'TEXTAREA'
                ||   node ?. tagName == 'FORM' ) break;
                node = node ?. previousSibling;
            }
            return null;
        }

        /**
         * -----------------------------------------------------------------
         *
         * Retrieves the node of a textarea by its tab.
         *
         * -----------------------------------------------------------------
         */

        findMyTextarea ( tab ) {
            let node = tab ?. nextSibling;
            while ( node ) {
                if ( node ?. tagName == 'TEXTAREA' ) return node;
                if ( node ?. tagName == 'FORM' ) {
                    if ( node ?. classList.contains ( 'file' ) ) return node ?. querySelector ( 'textarea' );
                    break;
                }
                if ( node ?. tagName == 'LABEL'
                ||   node ?. tagName == 'INPUT'
                ||   node ?. tagName == 'FIGURE' ) break;
                node = node ?. nextSibling;
            }
            return null;
        }

        /**
         * -----------------------------------------------------------------
         *
         * Retrieves the node of a figure by its tab.
         *
         * -----------------------------------------------------------------
         */

        findMyFigure ( tab, classname ) {
            let node = tab ?. nextSibling;
            while ( node ) {
                if ( node ?. tagName == 'FIGURE' ) {
                    if ( node ?. classList.contains ( classname ) ) return node;
                    break;
                }
                if ( node ?. tagName == 'TEXTAREA'
                ||   node ?. tagName == 'FORM'
                ||   node ?. tagName == 'LABEL'
                ||   node ?. tagName == 'INPUT' ) break;
                node = node ?. nextSibling;
            }
            return null;
        }

        /**
         * -----------------------------------------------------------------
         *
         * Handles a click on a tab.
         *
         * -----------------------------------------------------------------
         */

        onClick ( event ) {
            const tab = app.workspace ?. findTab ( event );
            if ( tab ) {
                for ( let i = 0; i < app.workspace.tabs.length; i++ ) {
                    if ( tab === app.workspace.tabs[ i ] ) {
                        const param = app.workspace.getEditorParameter ( 'lastTab' );
                        app.session.setItem ( param , i );
                        let element,
                            enabled = false;
                        if ( element = app.workspace.findMyTextarea ( tab ) ) {
                            app.workspace.showTextMetrics ( element );
                            app.workspace.rememberCursor  ( element );
                            setTimeout (
                                ( ) => element.focus ( )
                            );
                            enabled = true;
                        } else if ( element = app.workspace.findMyFigure ( tab, 'image' ) ) app.workspace.showImageMetrics ( element );
                        else   if ( element = app.workspace.findMyFigure ( tab, 'audio' ) ) app.workspace.showAudioMetrics ( element );
                        else   if ( element = app.workspace.findMyFigure ( tab, 'video' ) ) app.workspace.showVideoMetrics ( element );
                        else   if ( element = app.workspace.findMyFigure ( tab, 'font'  ) ) app.workspace.showFontMetrics  ( element );
                        else   if ( element = app.workspace.findMyFigure ( tab, 'other' ) ) app.workspace.showOtherMetrics ( element );
                        const file  = tab ?. getAttribute ( 'data-file' ),
                              path1 = 'view/preview',
                              url   = 'menu/' + path1 + '/' + file,
                              path2 = 'file/save';
                        if ( file != ''
                        &&   file !== null ) {
                            app.topmenu ?. replaceUrl ( url, path1, 'f5' );
                            app.toolbar ?. replaceUrl ( url, path1, 'f5' );
                            app.topmenu ?. switchLink ( path2, 's', enabled );
                            app.toolbar ?. switchLink ( path2, 's', enabled );
                        } else {
                            app.topmenu ?. switchLink ( path1, 'f5', false );
                            app.toolbar ?. switchLink ( path1, 'f5', false );
                            app.topmenu ?. switchLink ( path2, 's' , false );
                            app.toolbar ?. switchLink ( path2, 's' , false );
                        }
                        break;
                    }
                }
            }
        }

        /**
         * -----------------------------------------------------------------
         *
         * Handles an action in a textarea.
         *
         * -----------------------------------------------------------------
         */

        onText ( event ) {
            app.workspace.showTextMetrics ( event.target );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Displays a textarea metrics.
         *
         * -----------------------------------------------------------------
         */

        showTextMetrics ( textarea ) {
            const count  = textarea ?. closest ( '.editor' ) ?. querySelectorAll ( '.tab' ).length,
                  text   = textarea ?. value,
                  size   = text ?. length,
                  dir    = textarea ?. selectionDirection,
                  posB   = textarea ?. selectionStart,
                  posE   = textarea ?. selectionEnd,
                  pos    = dir == 'backward'
                                ? posB
                                : posE,
                  left   = text ?. substring ( 0, pos ),
                  line   = left ?. replace   ( /[^\r\n]*$/,            '3' )
                                ?. replace   ( /[^\r\n]*(\r\n|\n\r)/g, '2' )
                                ?. replace   ( /[^\r\n]*[\r\n]/g,      '1' )
                                ?. length,
                  column = left ?. replace ( /^(.*[\r\n])*([^\r\n]*)$/, '$2' )
                                ?. length + 1,
                  tab    = this.findMyTab ( textarea ),
                  file   = tab ?. getAttribute ( 'data-file' );

            app.statusbar.showSize   ( count + ' files / ' + size   + ' bytes'  );
            app.statusbar.showCursor ( line  + ' line / '  + column + ' column' );

            const data = this.rememberEditor ( );
            data[ 'selection_'    + file ] = posB;
            data[ 'selectionEnd_' + file ] = posE;
            if ( text != textarea ?. defaultValue ) {
                data[ 'text_' + file ] = text;
                tab ?. classList.add ( 'modified' );
            } else {
                delete data[ 'text_' + file ];
                tab ?. classList.remove ( 'modified' );
            }

            const param = this.getEditorParameter ( 'editor' );
            app.session.setItem ( param, JSON.stringify ( data ) );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Displays an image metrics.
         *
         * -----------------------------------------------------------------
         */

        showImageMetrics ( figure ) {
            app.statusbar.showSize   ( 'It\'s an Image'    );
            app.statusbar.showCursor ( 'Non-editable File' );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Displays an audio metrics.
         *
         * -----------------------------------------------------------------
         */

        showAudioMetrics ( figure ) {
            app.statusbar.showSize   ( 'It\'s an Audio'    );
            app.statusbar.showCursor ( 'Non-editable File' );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Displays a video metrics.
         *
         * -----------------------------------------------------------------
         */

        showVideoMetrics ( figure ) {
            app.statusbar.showSize   ( 'It\'s a Video'     );
            app.statusbar.showCursor ( 'Non-editable File' );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Displays a font metrics.
         *
         * -----------------------------------------------------------------
         */

        showFontMetrics ( figure ) {
            app.statusbar.showSize   ( 'It\'s a Font'      );
            app.statusbar.showCursor ( 'Non-editable File' );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Displays another element metrics.
         *
         * -----------------------------------------------------------------
         */

        showOtherMetrics ( figure ) {
            app.statusbar.showSize   ( 'Undefined Type'    );
            app.statusbar.showCursor ( 'Non-editable File' );
        }
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Initializes the workspace.
     *
     * ---------------------------------------------------------------------
     */

    if ( typeof app != 'undefined' ) {
        app.workspace = new AppWorkspace ( '.screen > .workspace' );
        app.workspace.rememberTab ( );
    }
