package LatexIndent::UnNamedGroupingBracesBrackets;

#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#
#	See http://www.gnu.org/licenses/.
#
#	Chris Hughes, 2017-2025
#
#	For all communication, please visit: https://github.com/cmhughes/latexindent.pl
use strict;
use warnings;
use LatexIndent::Tokens           qw/%tokens/;
use LatexIndent::GetYamlSettings  qw/%mainSettings/;
use LatexIndent::TrailingComments qw/$trailingCommentRegExp/;
use LatexIndent::Switches         qw/$is_t_switch_active $is_tt_switch_active/;
use LatexIndent::LogFile          qw/$logger/;
use Exporter                      qw/import/;
our @ISA = "LatexIndent::Command";    # class inheritance, Programming Perl, pg 321
our @EXPORT_OK
    = qw/construct_unnamed_grouping_braces_brackets_regexp $un_named_grouping_braces_RegExp $un_named_grouping_braces_RegExp_trailing_comment/;
our $unNamedGroupingBracesCounter;
our $un_named_grouping_braces_RegExp;
our $un_named_grouping_braces_RegExp_trailing_comment;

sub construct_unnamed_grouping_braces_brackets_regexp {
    my $self = shift;

    # grab the arguments regexp
    my $optAndMandRegExp = $self->get_arguments_regexp;

    # blank line token
    my $blankLineToken = $tokens{blanklines};

    # arguments Before, by default, includes beamer special and numbered arguments, for example #1 #2, etc
    my $argumentsBefore             = qr/${${$mainSettings{fineTuning}}{arguments}}{before}/;
    my $UnNamedGroupingFollowRegExp = qr/${${$mainSettings{fineTuning}}{UnNamedGroupingBracesBrackets}}{follow}/;

    # store the regular expression for matching and replacing
    $un_named_grouping_braces_RegExp = qr/
                  # NOT
                  (?!
                      (?:
                        (?:(?<!\\)\]) 
                        |
                        (?:(?<!\\)\}) 
                      )
                      (?:\h|\R|$blankLineToken|$trailingCommentRegExp|$argumentsBefore)*  # 0 or more h-space, blanklines, trailing comments
                  )
                  # END of NOT
                  (
                     (?:
                        $UnNamedGroupingFollowRegExp # starting with { OR [ OR , OR & OR ) OR ( OR $
                     )
                     \h*
                  )                                  # $1 into beginning bit
                  (\R*)                              # $2 linebreaksAtEnd of begin
                  ($optAndMandRegExp)                # $3 mand|opt arguments (at least one) stored into body
                  (\R)?                              # $6 linebreak 
                /sx;

    $un_named_grouping_braces_RegExp_trailing_comment
        = qr/$un_named_grouping_braces_RegExp(\h*)((?:$trailingCommentRegExp\h*)*)?/;
}

sub create_unique_id {
    my $self = shift;

    $unNamedGroupingBracesCounter++;
    ${$self}{id} = "$tokens{UnNamedGroupingBracesBrackets}$unNamedGroupingBracesCounter";
    return;
}

sub get_replacement_text {
    my $self = shift;

# the replacement text for a key = {value} needes to accommodate the leading [ OR { OR % OR , OR any combination thereof
    $logger->trace("Custom replacement text routine for ${$self}{name}") if $is_t_switch_active;

# the un-named object is a little special, as it doesn't have a name; as such, if there are blank lines before
# the braces/brackets, we have to insert them
#
# also, the argument reg-exp can pick up a leading comment (with line break), which needs to be put
# into the replacement text (see documentation/demonstrations/pstricks.tex and test-cases/unnamed-braces/unnamed.tex for example)
    ${$self}{body} =~ s/(.*?)(\{|\[)/$2/s;
    ${$self}{replacementText} = ${$self}{beginningbit} . ( $1 ne '' ? $1 : q() ) . ${$self}{id};

    # but now turn off the switch for linebreaksAtEnd{begin}, otherwise the first brace gets too much indentation
    # (see, for example, test-cases/namedGroupingBracesBrackets/special-characters-minimal.tex)
    ${ ${$self}{linebreaksAtEnd} }{begin} = 0;
    $logger->trace("Beginning bit is: ${$self}{beginningbit}") if ($is_t_switch_active);
    delete ${$self}{beginningbit};
}

sub check_for_blank_lines_at_beginning {

    # some examples can have blank line tokens at the beginning of the body,
    # which can confuse the routine below
    # See, for example,
    #       test-cases/namedGroupingBracesBrackets/special-characters-minimal-blank-lines-m-switch.tex
    #   compared to
    #       test-cases/namedGroupingBracesBrackets/special-characters-minimal-blank-lines-default.tex
    my $self = shift;

    # blank line token
    my $blankLineToken = $tokens{blanklines};

    # if the body begins with 2 or more blank line tokens
    if ( ${$self}{body} =~ m/^((?:$blankLineToken\R){2,})/s ) {

        # remove them
        ${$self}{body} =~ s/^((?:$blankLineToken\R)+)//s;

        # store
        my $blank_line_tokens_at_beginning_of_body = $1;

        # and count them, for use after the indentation routine
        ${$self}{blankLinesAtBeginning} = () = $blank_line_tokens_at_beginning_of_body =~ /$blankLineToken\R/sg;
    }
    return;
}

sub put_blank_lines_back_in_at_beginning {
    my $self = shift;

    # some bodies have blank lines at the beginning
    if ( ${$self}{blankLinesAtBeginning} ) {
        for ( my $i = 0; $i < ${$self}{blankLinesAtBeginning}; $i++ ) {
            ${$self}{body} = $tokens{blanklines} . ${$self}{body};
        }
    }
    return;
}

1;
