/**
 * -------------------------------------------------------------------------
 *
 * Scripts for the client side of your website.
 *
 * -------------------------------------------------------------------------
 */

    const findCard   = ( btn  ) => btn.closest           ( '.editcard'             );

    const findForm   = (      ) => document.querySelector( '.content.form'         );

    const findTest   = (      ) => document.querySelector( '.page > .wrapper.test' );

    /**
     * ---------------------------------------------------------------------
     *
     * Emulate the "htmlspecialchars" function in Javascript. This function
     * was implemented in PHP.
     *
     * ---------------------------------------------------------------------
     */

    const htmlSpecialChars = ( text ) => text.replace( /&/g, '&amp;'  )
                                             .replace( /</g, '&lt;'   )
                                             .replace( />/g, '&gt;'   )
                                             .replace( /"/g, '&quot;' )
                                             .replace( /'/g, '&#039;' );

    /**
     * ---------------------------------------------------------------------
     *
     * Emulate the "myGetText" routine in Javascript. This routine was
     * implemented in the "newspaper/Helper/Helper.php" file.
     *
     * ---------------------------------------------------------------------
     */

    const myGetText = ( text ) => htmlSpecialChars( text ).replace( /^([ \t]*[\r\n]+)*/,           '<p>'             )
                                                          .replace( /[\s\r\n]*$/,                  '</p>'            )
                                                          .replace( /([\r\n])[ \t]+[\r\n][\r\n]/g, '$1<p>&nbsp;</p>' )
                                                          .replace( /[ \t]*[\r\n][\r\n]/g,         '</p><p>'         )
                                                          .replace( /<p><\/p>/g,                   ''                );

    /**
     * ---------------------------------------------------------------------
     *
     * For information about Unicode parsing, see
     *     https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape
     *     https://tc39.es/ecma262/multipage/text-processing.html#table-binary-unicode-properties
     *
     * ---------------------------------------------------------------------
     */

    const getPatterns = () => {
        return {
            trimmer:   new RegExp( '(^\\s+|\\s+$)',                  'g'  ),
            slashes:   new RegExp( '[/\\\\]',                        'g'  ),
            hacks:     new RegExp( '([\\s.]*/+)+',                   'g'  ),
            scheme:    new RegExp( '^(https?:)?/{2,}',               'i'  ),
            domain:    new RegExp( '^[^/]+/+',                       ''   ),
            folder:    new RegExp( '^media/+',                       'i'  ),
            query:     new RegExp( '^([^?\\#]*)[?\\#].*$',           ''   ),
            nonchars:  new RegExp( '[^\\d\\p{Alphabetic}.,_/%+()-]', 'gu' ),
            unslasher: new RegExp( '(^/+|[/.]+$)',                   'g'  )
        };
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Mark up the HTML content of a card (newspaper section). To understand
     * the details of the HTML markup used in this function, please look at
     * the "newspaper/Themes/default/snippets/show-newspaper.tpl" file.
     *
     * ---------------------------------------------------------------------
     */

    const markupCard = ( card, selector ) => {

        // if it is a card from the current render plan step
        const layout = card.querySelector( 'select[name^="layout["]' ).value,
              test   = layout.substr( 0, selector.length );
        if ( test == selector ) {

            // collect values of input fields
            const h1          = card.querySelector( 'input[name^="h1["]'      ).value,
                  image_url   = card.querySelector( 'input[name^="image["]'   ).value,
                  image_local = card.querySelector( 'input[name^="upload["]'  ).value,
                  text        = card.querySelector( 'textarea[name^="text["]' ).value,
                  image       = image_local ? 'newspaper/Themes/default/images/here-is-an-image.png'
                                            : image_url,
                  body        = myGetText( text );

            // if something has been entered
            let html = '';
            if ( h1 || image || body ) {

                // collect values of input fields
                const size      = card.querySelector( 'select[name^="size["]'     ).value,
                      decor     = card.querySelector( 'select[name^="decor["]'    ).value,
                      image_alt = card.querySelector( 'input[name^="image_alt["]' ).value,
                      credits   = card.querySelector( 'input[name^="backlink["]'  ).value;

                // open this section tag
                html += '<section class="article ' + htmlSpecialChars( size ) + ' ' + htmlSpecialChars( layout ) + ' ' + htmlSpecialChars( decor ) + '">';

                    // title of the section, if present
                    if ( h1 ) {
                        const alt = ! image && image_alt ? ' <small>' + htmlSpecialChars( image_alt ) + '</small>' : '';
                        if ( credits ) {
                            html += '<a class="credits" href="' + htmlSpecialChars( credits ) + '" rel="nofollow noopener noreferrer" tabindex="-1">' +
                                        '<h1 class="title">' +
                                            htmlSpecialChars( h1 ) +  alt +
                                        '</h1>' +
                                    '</a>';
                        } else {
                            html += '<h1 class="title">' +
                                        htmlSpecialChars( h1 ) +  alt +
                                    '</h1>';
                        }
                    }

                    // image of the section, if present
                    if ( image ) {
                        html += '<figure class="image">';
                        if ( credits ) {
                            html += '<a class="credits" href="' + htmlSpecialChars( credits ) + '" rel="nofollow noopener noreferrer" tabindex="-1">' +
                                        '&nbsp;' +
                                    '</a>';
                        }
                        html +=     '<img src="' + htmlSpecialChars( image ) + '" loading="lazy" alt="' + htmlSpecialChars( image_alt ) + '" />' +
                                    '<figcaption class="alt">' +
                                        htmlSpecialChars( image_alt ) +
                                    '</figcaption>' +
                                '</figure>';
                    }

                    // text of the section, if present
                    if ( body ) {
                        html += '<div class="text">' +
                                    body +
                                '</div>';
                    }

                // close this section tag
                html += '</section>';
            }
            return html;
        }
        return '';
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Move the card several positions in a certain direction.
     *
     * ---------------------------------------------------------------------
     */

    const moveCard = ( box, direction ) => {

        // initialize variables
        let   spots     = [ ];
        const classname = 'editcard',
              step      = direction > 0 ? -1
                                        : 1;

        // find docking locations
        while ( box
                && box.classList.contains( classname )
                && direction != step ) {
            spots.push( box );
            box = step > 0 ? box.previousElementSibling
                           : box.nextElementSibling;
            direction += step;
        }

        // scroll a chain of cards
        if ( spots.length > 1 ) {
            let swap     = spots.shift(),
                owner    = swap.parentNode,
                last     = null,
                lastSpot = null;
            while ( spots.length > 0 ) {
                box = spots.pop();
                last     = box.cloneNode( true );
                lastSpot = step > 0 ? box.nextSibling
                                    : box.previousSibling;
                owner.replaceChild( swap, box );
                swap = last;
            }
            owner.insertBefore( swap, lastSpot );
        }
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Handler to move a newspaper section to the left. To understand the
     * details of the HTML markup used in this function, please look at the
     * "newspaper/Themes/default/snippets/form-newspaper.tpl" file.
     *
     * ---------------------------------------------------------------------
     */

    const moveLeft = ( btn ) => {
        const box = findCard( btn );
        if ( box ) {
            moveCard( box, -1 );
        }
        return false;
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Handler to move a newspaper section to the right. To understand the
     * details of the HTML markup used in this function, please look at the
     * "newspaper/Themes/default/snippets/form-newspaper.tpl" file.
     *
     * ---------------------------------------------------------------------
     */

    const moveRight = ( btn ) => {
        const box = findCard( btn );
        if ( box ) {
            moveCard( box, 1 );
        }
        return false;
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Handler to mark a newspaper section for deletion. To understand the
     * details of the HTML markup used in this function, please look at the
     * "newspaper/Themes/default/snippets/form-newspaper.tpl" file.
     *
     * ---------------------------------------------------------------------
     */

    const deleteThis = ( btn ) => {
        const box = findCard( btn );
        if ( box ) {

            // find the corresponding input field
            const flag = box.querySelector( '.switch' + '[name^="enabled\["]' + '[type="checkbox"]' );
            if ( flag ) {

                // collect objects
                const isON      = flag.checked,
                      attr      = 'disabled',
                      classname = 'inactive',
                      inputs    = box.querySelectorAll( 'select, '             +
                                                        'input[type="text"], ' +
                                                        'input[type="file"], ' +
                                                        'textarea'             );

                // store your choice
                flag.checked = ! isON;

                // switch the class of section container
                isON ? box.classList.add   ( classname )
                     : box.classList.remove( classname );

                // toggle the ability to edit input fields
                inputs.forEach(
                    ( input ) => {
                        isON ? input.setAttribute   ( attr, 'disabled' )
                             : input.removeAttribute( attr             );
                    }
                );
            }
        }
        return false;
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Handler to add a newspaper section on the right. To understand the
     * details of the HTML markup used in this function, please look at the
     * "newspaper/Themes/default/snippets/form-newspaper.tpl" file.
     *
     * ---------------------------------------------------------------------
     */

    const makeNew = ( btn ) => {
        const box = findCard( btn );
        if ( box ) {
            // clone current section
            let copy = box.cloneNode( true ),
                html = copy.outerHTML;

            // build unique identifier
            let clock = new Date(),
                id    = "'" + clock.toISOString() + "'";

            // clean it
            html = html.replace( /\s+selected(="[^">]*")?\s*(>)/gi,                   '$2'             )
                       .replace( /\s+disabled="disabled"/gi,                          ''               )
                       .replace( /(\s+class="editcard)\s+inactive(")/i,               '$1$2'           )
                       .replace( /[^>]+(<\/textarea>)/gi,                             '$1'             )
                       .replace( /(\s+type="text"\s+value=")[^">]+(")/gi,             '$1$2'           )
                       .replace( /(\s+name="[^">\[]+\[)[^\]">]+(\]")/gi,              '$1' + id + '$2' )
                       .replace( /(\s+name="article_id\[[^>]+?\s+value=")[^">]+(")/i, '$1' + 0 + '$2'  );

            // append on the right
            box.parentNode.insertBefore( copy, box.nextSibling );
            copy.outerHTML = html;
        }
        return false;
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Handler to process the "Test" button click. To understand the details
     * of the HTML markup used in this function, please look at the
     * "newspaper/Themes/default/newspapers-edit.tpl" file.
     *
     * ---------------------------------------------------------------------
     */

    const clickTest = ( btn ) => {
        let flag = btn.getAttribute( 'for' );
        if ( flag ) {

            // if the TEST button has not yet been released
            flag = document.querySelector( '#' + flag );
            if ( flag ) {
                if ( ! flag.checked ) {

                    // find the input form
                    const form = findForm();
                    if ( form ) {

                        // find TEST content area
                        const box = findTest();
                        if ( box ) {

                            // collect values of input fields
                            const enabled   = form.querySelector(    'select[name="visible"]'  ).value,
                                  edition   = form.querySelector(    'input[name="edition"]'   ).value,
                                  number    = form.querySelector(    'input[name="number"]'    ).value,
                                  date      = form.querySelector(    'input[name="date"]'      ).value,
                                  slogan    = form.querySelector(    'input[name="slogan"]'    ).value,
                                  sidebar   = form.querySelector(    'input[name="sidebar"]'   ).value,
                                  copyright = form.querySelector(    'input[name="copyright"]' ).value,
                                  credits   = form.querySelector(    'input[name="credits"]'   ).value,
                                  cards     = form.querySelectorAll( '.editcard'               );

                            // markup header of TEST content
                            let html = '<div class="edition">' + htmlSpecialChars( edition ) + '</div>' +
                                       '<aside class="header">' +
                                           '<div class="wrapper">' +
                                               '<div class="number">' + htmlSpecialChars( number ) + '</div>' +
                                               '<div class="date">'   + htmlSpecialChars( date   ) + '</div>' +
                                               '<div class="slogan">' + htmlSpecialChars( slogan ) + '</div>' +
                                           '</div>' +
                                       '</aside>' +
                                       '<main class="content" data-moderating="' + ( enabled == 1 ? '' : 'It is not visible now!' ) + '">';

                            // markup sections of TEST content
                            const plan = { 'layout':  { 'opentag':  '',
                                                        'closetag': ''
                                                      },
                                           'sidebar': { 'opentag':  '<div class="sidebar">' +
                                                                        '<div class="title">' +
                                                                            htmlSpecialChars( sidebar ) +
                                                                        '</div>',
                                                        'closetag': '</div>'
                                                      }
                                         };
                            for ( const index in plan ) {
                                html += plan[ index ].opentag;
                                        cards.forEach(
                                            ( card ) => {
                                                html += markupCard( card, index );
                                            }
                                        );
                                html += plan[ index ].closetag;
                            }

                            // markup footer of TEST content
                            html    += '</main>' +
                                       '<aside class="footer">' +
                                           '<div class="wrapper">' +
                                               '<a class="copyright" href="' + htmlSpecialChars( credits ) + '" rel="nofollow noopener noreferrer" tabindex="-1">' +
                                                   htmlSpecialChars( copyright ) +
                                               '</a>' +
                                               '<a class="credits" href="https://mimimi.software/" rel="nofollow noopener noreferrer" tabindex="-1">' +
                                                   'Powered by MiMiMi' +
                                               '</a>' +
                                           '</div>' +
                                       '</aside>';

                            // display TEST content
                            box.innerHTML = html;
                        }
                    }
                }
            }
        }
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Handler for standard URL correction.
     *
     * ---------------------------------------------------------------------
     */

    const correctUrl = ( url, localOnly = true ) => {
        const re = getPatterns();

        // clean URL
        url = url.replace( re.trimmer, ''   )
                 .replace( re.slashes, '/'  )
                 .replace( re.query,   '$1' );

        // if it's an external URL
        if ( url.search( re.scheme ) != -1 ) {
            if ( ! localOnly ) return url;
            url = url.replace( re.scheme, '' )
                     .replace( re.domain, '' );
        }

        // correct URL path
        return url.replace( re.hacks,     '/' )
                  .replace( re.nonchars,  '-' )
                  .replace( re.unslasher, ''  );
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Handler to correct the input box "Newspaper URL:".
     *
     * ---------------------------------------------------------------------
     */

    const correctPageUrl = ( input ) => {
        let url = input.value;
        url = correctUrl(url)
              .replace( /\/+(add|edit|delete|settings|robots\.txt|sitemap|page-\d+)$/i, '' );
        input.value = url;
    };

    /**
     * ---------------------------------------------------------------------
     *
     * Handler to correct the input box "Image URL:".
     *
     * ---------------------------------------------------------------------
     */

    const correctImageUrl = ( input ) => {
        let url = input.value;
        url = correctUrl(url, false);
        if ( url != '' ) {

            // it can be an external link or a local link to the "media" folder
            const re = getPatterns();
            if ( url.search( re.scheme ) == -1
            &&   url.search( re.folder ) == -1 ) {
                url = 'media/' + url;
            }
        }
        input.value = url;
    };
