ONO::FW::Edu::Apps::Modules::ReGroup

package ONO::FW::Edu::Apps::Modules::ReGroup;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2022-2026 Jos Kirps and The Joopita Project [ASBL]
# Copyright (C) 2011-2022 Jos Kirps and Joopita Research ASBL
# Copyright (C) 2006-2011 Jos Kirps and The Joopita Project
# Copyright (C) 2001-2006 Jos Kirps and The WobbleWolf Project
#
# This file, as well as many other parts of the ONO Software Project or
# related elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# 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.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################

#: This module is a front end application module wrapper that has been
#: created for the Morzino Project (morzino.com) and that has been released
#: as Open Source software.
#:
#: Note that this is NOT a self-contained application, it is only a wrapper
#: that makes heavy use of the ONO Perl Framework application engine.

use strict;

use ONO::IO;
use ONO::Lib::Basic;

use ONO::FW::Edu::Apps::ToolBox;
use ONO::FW::Edu::Apps::Modules::WorksheetMaker::Input;

use ONO::FW::Apps::PDF;
use ONO::FW::Apps::ToolBox;

use ONO::Lib::Image::HTML::Arrow;
use ONO::Lib::PDF::Draw;
use ONO::Lib::PDF::ToolBox;

use ONO::Lib::UI::Check;
use ONO::Lib::UI::Select;

use ONO::FW::Apps::Core;
use ONO::FW::Apps::Core::Graphics;

use ONO::Lib::Parser;

sub learn {

my (
$self,
$option,
$vars_ref,
$HTTP,
$BASE,
) = @_;

################################################################
# INIT - BEGIN
################################################################

my (
$db,
$community,
$action_url,
$form,
$format,
$canvas,
$pdfkey,
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday,$timestamp,
$lang,
$BLK_ref,
$vars_ref,
) = ONO::FW::Apps::Core->init($vars_ref);

my %vars = %$vars_ref;
my %BLK = %$BLK_ref;

my $app = "regroup";

ONO::FW::Apps::Core->now("",$app,$vars{'app_lang'});

my @txt = (
"dots per exercise (maximum)",
"number of dots fits exactly (no rest)",
);

if ($vars{'app_lang'} eq "de") {
@txt = (
"Punkte pro Aufgabe (maximal)",
"Anzahl der Punkte passt genau (kein Rest)",
);
}

if ($vars{'app_lang'} eq "lu") {
@txt = (
"Punkte pro Aufgab (maximal)",
"Unzuel vu Punkte passt genau (kee Rescht)",
);
}

if ($vars{'app_lang'} eq "fr") {
@txt = (
"points par exercice (maximum)",
"nombre de points correspond (pas de reste)",
);
}

my $WEB;

$WEB .= ONO::FW::Apps::Core->output_paper_save($pdfkey,$BLK_ref,\%vars,$HTTP,$BASE,"$year$mon$mday");

if (ONO::FW::Apps::Core->running(\%vars,$db)) {

$WEB .= ONO::FW::Apps::Core->blockbackbutton($BASE,$vars_ref);

#############################################################
# WORKSHEET MAKER
#############################################################

if ($vars{'output_worksheet_maker'}) {

$vars_ref = ONO::FW::Edu::Apps::Modules::WorksheetMaker::Input->vars(\%vars);
%vars = %$vars_ref;

}

#############################################################
# ONLINE TRAINING
#############################################################

if ($vars{'output_paper'}) {

my ($page,$pages,%cache,$whilecounter,$stats_switches,$PDF_OPTS);

my ($stat_correct,$stat_wrong,$stat_todo,$stat_todo_total);

my $questions_per_page = 1;

$PDF_OPTS = ONO::FW::Apps::Core->headers_options($BLK_ref,$vars_ref);

ONO::FW::Apps::PDF->new("$BASE/pdf/pdf-$pdfkey.pdf","",$format);

foreach my $copy (ONO::FW::Apps::Core->unique_copies($vars{'app_input_print_options_unique_copies'})) {


if ($copy > 1) {
ONO::FW::Apps::PDF->page("",$format);
}
ONO::FW::Apps::Core->headers(\%vars,$format);
ONO::FW::Apps::PDF->title($vars{'app_input_print_options_title'},$PDF_OPTS,$vars{'app_input_print_options_code'},$format);
ONO::FW::Apps::Core->unique_copies_info($canvas,$copy,$vars_ref);
ONO::FW::Apps::Core::Graphics->pdf_draw_item_numbers($canvas,-2,0,1,4,"HLV",$vars_ref);

# ONO::Lib::PDF::ToolBox->canvas_test($canvas);

my (@nums,%used);

for (my $n = 1; $n < 11; $n++) {
if ($vars{"app_input_group_list_$n"}) {
@nums = (@nums,$n);
}
}
my $nums_num = @nums;

if (!$nums_num) {
@nums = (2,3,4,5,6);
$nums_num = @nums;
}

for (my $i = 0; $i < $questions_per_page; $i++) {

# output paper

if ($vars{'output_paper'}) {

my ($pdf_x,$pdf_y) = (5,0);

for (my $y = 0; $y < 4; $y++) {

my @items_per_row;
my $display_box_mode = int(rand(3));

for (my $x = 0; $x < 3; $x++) {

if ($x == 0) {
if ($vars{"app_input_layout_$y"} > 0) {
$items_per_row[$y] = $vars{"app_input_layout_$y"};
} else {
$items_per_row[$y] = 1+int(rand(3));
}
}

if ($x == 0 || ($items_per_row[$y] == 2 && $x < 2) || $items_per_row[$y] == 3) {

my ($x1,$y1,$x2,$y2) = ($pdf_x,$pdf_y+2,$pdf_x+50,$pdf_y+43);

if ($items_per_row[$y] == 1) {
($x1,$y1,$x2,$y2) = ($pdf_x,$pdf_y+2,$pdf_x+165,$pdf_y+43);
}
if ($items_per_row[$y] == 2) {
($x1,$y1,$x2,$y2) = ($pdf_x,$pdf_y+2,$pdf_x+77.5,$pdf_y+43);
if ($x == 1) {
($x1,$y1,$x2,$y2) = ($pdf_x+30,$pdf_y+2,$pdf_x+107.5,$pdf_y+43);
}
}

my $display_box;

if ($items_per_row[$y] > 1) {

if ($items_per_row[$y] == 2) {
if ($display_box_mode == $x || $display_box_mode == 2) {
$display_box = 1;
}
}
if ($items_per_row[$y] == 3) {
if ($display_box_mode == 0 && ($x == 0 || $x == 2)) {
$display_box = 1;
}
if ($display_box_mode == 1 && $x == 1) {
$display_box = 1;
}
if ($display_box_mode == 2) {
$display_box = 1;
}
}

}

if ($display_box) {

my $b1 = 235+int(rand(20));
my $b2 = 235+int(rand(20));
my $b3 = 235+int(rand(20));
my $BG = "0:$b1:$b2:$b3";

ONO::Lib::PDF::Draw->rect($canvas,$x1,$y1,$x2,$y2,1,"0:22:22:22",$BG,2);

}

my $num = $nums[int(rand($nums_num))];
if ($used{$num}) {
$num = $nums[int(rand($nums_num))];
}
$used{$num};

my $abs_max = 80;
if ($items_per_row[$y] == 2) {
$abs_max = 60;
}
if ($items_per_row[$y] == 3) {
$abs_max = 40;
}

my $dots_max = $vars{"app_input_select_dots_max"};
if ($dots_max < 1) {
$dots_max = 3*$num + int(rand($abs_max-(3*$num)));
}

my $whilecounter;
if ($items_per_row[$y] == 1) {
while ($whilecounter < 256 && $dots_max < 60) {
$dots_max = int($dots_max*1.3);
}
}

if ($dots_max > $abs_max) {
$dots_max = $abs_max;
}

if ($dots_max < $num) {
$dots_max = 3*$num;
}

my $size_x = 160;
my ($cols,$rows) = (5,5);

if ($items_per_row[$y] == 1) {
my $whilecounter;
while ($whilecounter < 256 && $cols * $rows < $dots_max) {
$whilecounter++;
$cols = 2+$cols+int(rand(8));
$rows = $rows+int(rand(2));
if ($rows > 5) {
$rows = 5;
}
}
}

if ($items_per_row[$y] == 2) {
$size_x = 65;
my $whilecounter;
while ($whilecounter < 256 && $cols * $rows < $dots_max) {
$whilecounter++;
$cols = $cols+int(rand(3));
$rows = $rows+int(rand(2));
if ($rows > 6) {
$rows = 6;
}
}
}
if ($items_per_row[$y] == 3) {
$size_x = 36;
my $whilecounter;
while ($whilecounter < 256 && $cols * $rows < $dots_max) {
$whilecounter++;
$cols = $cols+int(rand(2));
$rows = $rows+int(rand(2));
if ($rows > 6) {
$rows = 6;
}
}
}

if ($cols < $num) {
$cols = $num;
$rows = 1+int($dots_max/$num);
if ($rows > 6) {
$rows = 6;
}
}

my $exact_fit = 1;
if ($vars{"app_input_dots_fit_optional"} > 0) {
$exact_fit = 0;
}

&display_dots("",$canvas,$x1+2,$y1,$size_x,32,$dots_max,$cols,$rows,$num,$exact_fit);

}

$pdf_x = $pdf_x + 57.5;

}

$pdf_x = 5;
$pdf_y = $pdf_y + 47.5;

}
}

}

}

ONO::FW::Apps::PDF->end;

$WEB .= ONO::FW::Apps::PDF->please_wait($pdfkey,\%BLK,\%vars,"",$HTTP,$BASE);

}

} else {

#############################################################
# EXERCISE SETUP
#############################################################

if (!$vars{'app_input_number_of_questions'}) {
$vars{'app_input_number_of_questions'} = 20;
}

# "screen:320:50:40::regroup_screenshot_1.jpg",

$WEB .= ONO::FW::Apps::Core->infopics(
"sheet:168:190:60:15:regroup_sheet_1.jpg",
"sheet:168:40:80:-10:regroup_sheet_2.jpg",
);

my (%setup);

my ($SW1,$SW2,$group_found);

for (my $i = 1; $i < 11; $i++) {
if ($vars{"app_input_group_list_$i"} > 0) {
$group_found++;
}
}

for (my $i = 1; $i < 11; $i++) {
if (!$group_found && $i > 1 && $i < 6) {
$vars{"app_input_group_list_$i"}++;
}
my $SW = ONO::Lib::UI::Check->switch("app_input_group_list_$i",$vars{"app_input_group_list_$i"},"mv");
$SW1 .= qq~<td>$SW</td>~;
$SW2 .= qq~<td class="center">$i</td>~;
}

my $NUMS = qq~<table class="default_table">
<tr>$SW1</tr>
<tr>$SW2</tr>
</table>
~;

my $MAX .= $BLK{'random'};
for (my $m = 10; $m < 81; $m=$m+10) {
$MAX .= ";$m";
}

my @opts = (
"0:$BLK{'random'} (1-3)",
"1:1x ($BLK{'large'})",
"2:2x ($BLK{'medium'})",
"3:3x ($BLK{'small'})",
);

my ($LAYOUT,$LAYOUT_CACHE);

for (my $i = 0; $i < 4; $i++) {
my $SEL;
foreach my $opt (@opts) {
my @op = split(/:/,$opt);
my $sel;
if ($vars{"app_input_layout_$i"} eq "") {
$vars{"app_input_layout_$i"} = $i+1;
}
if ($vars{"app_input_layout_$i"} > 3) {
$vars{"app_input_layout_$i"} = 0;
}
if ($op[0] == $vars{"app_input_layout_$i"}) {
$sel = " selected";
}
$SEL .= qq~<option value="$op[0]"$sel>$op[1]</option>~;
}
if ($i) {
$LAYOUT .= qq~ <tr><td></td></tr>~;
}
# $LAYOUT_CACHE .= qq~<input type="hidden" name="app_input_layout_$i" value="$vars{"app_input_layout_$i"}">~;
$LAYOUT .= qq~ <tr>
<td>
<div class="select"><select name="app_input_layout_$i">$SEL</select></div>
</td>
</tr>
~;
}

$LAYOUT = qq~<div class="box_fabric fl">
<div class="bg_paper bo p10">
<table class="default_table">
$LAYOUT
</table>
</div>
</div>
~;

my $CONF;

$CONF .= ONO::FW::Apps::ToolBox->conf_input("custom", $BLK_ref,\%vars,"T",$BLK{'group'},$NUMS);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("select", $BLK_ref,\%vars,"",$MAX,$txt[0],$vars{"app_input_select_dots_max"},"","dots_max");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("checkinv", $BLK_ref,\%vars,"S","","dots_fit_optional",$vars{'app_input_dots_fit_optional'},$txt[1]);
# if ($vars{'output_paper'}) {
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars,"","");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("custom", $BLK_ref,\%vars,"T",$BLK{'layout'},$LAYOUT);
# } else {
# $CONF .= $LAYOUT_CACHE;
# }
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars,"","s");

$WEB .= ONO::FW::Apps::Core->conf_box(
$db,
$community,
$app,
$form,
"",
$action_url,
$CONF,
$lang,
$BLK_ref,
\%vars,
"p-di-DI-u",
);

# "op-ncdi-CDI-lsu-N-H",
# ONO::FW::Apps::Core->info("info_online_print",$vars{'app_lang'}),

if (!$vars{'exercise'}) {
$WEB .= ONO::FW::Apps::Core->info_display(
ONO::FW::Apps::Core->info("info_indiv_diff", $vars{'app_lang'}),
);
}

}

my ($status,$WEB) = ONO::Lib::Parser->parse($WEB,$vars_ref);

$WEB .= ONO::FW::Apps::Core->vardump($vars_ref);

$WEB = ONO::FW::Edu::Apps::ToolBox->apps_gate($WEB,$vars_ref);

return $WEB;

}

###################################################################
# SUBS
###################################################################

sub display_dots {

my (
$self,
$canvas,
$pdf_x,
$pdf_y,
$size_x,
$size_y,
$dots_max,
$cols,
$rows,
$num,
$exact_fit,
) = @_;

my $COLOR = &rand_color();

my $dots_num = 0;

if ($exact_fit && $num) {

my $dots_test = 0;
my $whilecounter;
while ($whilecounter < 4096 && $dots_test < $dots_max-$num+1) {
$whilecounter++;
$dots_test = $dots_test + $num;
}
$dots_max = $dots_test;

}

my $step_x = $size_x/$cols;
my $step_y = $size_y/$rows;
if ($step_y > $step_x*2) {
$step_y = $step_x*2;
}
my $circle_size = $step_x/5;
if ($step_y/5 < $circle_size) {
$circle_size = $step_y/6;
}

for (my $y = 0; $y < $rows; $y++) {
for (my $x = 0; $x < $cols; $x++) {

my ($rand_x,$rand_y,$demo);

my $pos_x = $pdf_x+5+$x*$step_x;
my $pos_y = $pdf_y+8+$y*$step_y;

if ($y == 0 && ($num < 6 || $num == 7) && $x < $num) {
$demo = 1;
if ($x == 0 && $y == 0) {
ONO::Lib::PDF::Draw->rect($canvas,$pos_x-$step_x/2,$pos_y-$step_y/2,$pos_x+$step_x*$num-$step_x/2,$pos_y+$step_y/2,1,"0:111:111:111","0:250:250:250",$circle_size);
}
}

if ($y < 2 && $x < $num/2 && ($num == 6 || $num == 8 || $num == 10)) {
$demo = 1;
if ($x == 0 && $y == 0) {
ONO::Lib::PDF::Draw->rect($canvas,$pos_x-$step_x/2,$pos_y-$step_y/2,$pos_x+$step_x/2*$num-$step_x/2,$pos_y+$step_y*1.5,1,"0:111:111:111","0:250:250:250",$circle_size);
}
}

if ($y < 3 && $x < 3 && $num == 9) {
$demo = 1;
if ($x == 0 && $y == 0) {
ONO::Lib::PDF::Draw->rect($canvas,$pos_x-$step_x/2,$pos_y-$step_y/2,$pos_x+$step_x*3-$step_x/2,$pos_y+$step_y*2.5,1,"0:111:111:111","0:250:250:250",$circle_size);
}
}

if (!$demo) {
$rand_x = $step_x/5-rand($step_x/2.5);
$rand_y = $step_y/5-rand($step_y/2.5);
}

if ($dots_num < $dots_max) {
$dots_num++;
ONO::Lib::PDF::Draw->circle($canvas,$pos_x+$rand_x,$pos_y+$rand_y,$circle_size,1,$COLOR,$COLOR);
}

}
}

}

sub rand_color {
my $c1 = 50+int(rand(150));
my $c2 = 50+int(rand(150));
my $c3 = 50+int(rand(150));
my $COLOR = "0:$c1:$c2:$c3";
}

###################################################################
#### THAT'S IT :-D
###################################################################

1;

__END__