ONO::FW::Edu::Apps::Modules::MathTrains

package ONO::FW::Edu::Apps::Modules::MathTrains;
################################################################################
# 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::FW::Edu::Apps::ToolBox;
use ONO::FW::Edu::Apps::Modules::WorksheetMaker::Input;

use ONO::IO;

use ONO::Lib::PDF::Draw;
use ONO::Lib::PDF::ToolBox;

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

use ONO::Lib::Parser;

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

use ONO::Lib::PDF::Elements;
use ONO::Lib::Data::Numbers::Hexa;
use ONO::Lib::Data::Numbers::Roman;

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

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 = "math_trains";

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

my @txt = (
"cars",
"also empty cars in the middle",
"automatically chosen",
"trains",
);

if ($vars{'app_lang'} eq "de") {
@txt = (
"Waggons",
"auch leere Waggons in der Mitte",
"automatisch gewählt",
"Züge",
);
}

if ($vars{'app_lang'} eq "lu") {
@txt = (
"Waggons",
"och eidel Waggons an der Mëtt",
"automatesch gewielt",
"Zich",
);
}

if ($vars{'app_lang'} eq "fr") {
@txt = (
"wagons",
"aussi wagons vides au milieu",
"choisis automatiquement",
"trains",
);
}

my ($num_comma,$num_delimiter) = ONO::FW::Apps::Core->local_comma_delimiter(ONO::FW::Apps::Core->detect_local($vars{'app_lang'}),$vars_ref);

my $train_switches;
if ($num_comma ne "" && $num_comma ne ".") {
$train_switches .= "C";
}

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_web'} || $vars{'output_paper'}) {

my $question_number = ONO::FW::Apps::Core->question_number($vars{'output_web_question_number'});

if ($vars{'output_web_next_train'}) {
$question_number++;
}

my ($page,$pages,$stats_switches,$PDF_OPTS);

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

if ($vars{'stat_correct_total_transmit'}) {
$stat_correct_total = $vars{'stat_correct_total_transmit'};
}

if ($vars{'reload_to_next_train_exec'}) {
foreach my $key (keys %vars) {
if ($key =~ /transmit_color/) {
$vars{$key} = "";
}
}
$vars_ref = \%vars;
}
my $questions_per_page = 1;

if ($vars{'output_paper'}) {

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

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

$questions_per_page = 20;

if ($vars{'app_input_select_number'} == 3 || $vars{'app_input_select_number'} =~ /(r|auto)/) {
$questions_per_page = 30;
}
if ($vars{'app_input_select_number'} > 5) {
$questions_per_page = 10;
}

}

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

my ($pdf_x,$pdf_y) = (0,8);
my @corr_cache;

if ($vars{'output_paper'}) {

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::Graphics->pdf_draw_item_numbers($canvas,-2,0,1,4,"HV",$vars_ref);

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

}

if ($vars{'output_web'}) {

$WEB .= qq~<$form>~;

$WEB .= ONO::FW::Apps::Core->question_progress($vars{'app_input_number_of_questions'},$question_number);

$WEB .= ONO::FW::Apps::Core->stats("",$BLK_ref,"ctTmS$stats_switches");

}

if (ONO::FW::Apps::Core->question_progress_done($vars{'app_input_number_of_questions'},$question_number) || $vars{'output_web_finish'}) {

$vars{'output_progress_done'}++;

$WEB .= ONO::FW::Apps::Core->question_progress_done_msg($app,$db,$community,$form,$action_url,$stat_correct_total,$vars{'output_web_mistakes'},$lang,$BLK_ref,\%vars);

} else {

# all_used is valid for the entire sequences
# really_used is only for the displayed values

my (%all_used,%really_used);

if ($vars{'app_input_numsys_status'} eq "roman") {
if ($vars{'app_input_range_to'} > 3999) {
$vars{'app_input_range_to'} = 3999;
}
}

if ($vars{'app_input_range_from'} > $vars{'app_input_range_to'}-1) {
$vars{'app_input_range_from'} = 0;
}

if ($vars{'app_input_select_number'} eq "" || $vars{'app_input_select_number'} eq "auto") {
$vars{'app_input_select_number'} = "r5";
if ($vars{'app_input_range_to'} > 100) {
$vars{'app_input_select_number'} = "r6";
if ($vars{'app_input_range_to'} > 200) {
$vars{'app_input_select_number'} = "r7";
if ($vars{'app_input_range_to'} > 300) {
$vars{'app_input_select_number'} = "r8";
if ($vars{'app_input_range_to'} > 400) {
$vars{'app_input_select_number'} = "r9";
if ($vars{'app_input_range_to'} > 500) {
$vars{'app_input_select_number'} = "r10";
}
}
}
}
}
}

my $req_cars = $vars{'app_input_select_number'};
if ($vars{'app_input_select_number'} =~ /^r(.*?)$/) {
$req_cars = $1;
}

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

# the number sequencer

my ($whilecounter,$numcount,$numlist);

if ($vars{'output_web_numlist'} && $vars{'output_web_numcount'}) {

$numlist = $vars{'output_web_numlist'};
$numcount = $vars{'output_web_numcount'};

} else {

while ($whilecounter < 512 && ($numcount < $req_cars || $all_used{$numlist})) {

$whilecounter++;

$numcount = 2;

my $div1 = 2+int(rand($vars{'app_input_range_to'}/5));
my $div2 = 2+int(rand($vars{'app_input_range_to'}/5));

for my $opt (100,500,1000,5000,10000) {
if ($vars{'app_input_range_to'} > $opt) {
$div1 = 1+int($div1/2);
$div2 = 1+int($div2/2);
}
}

my $num1 = int(($vars{'app_input_range_from'}+int(rand($vars{'app_input_range_to'}-$vars{'app_input_range_from'})))/$div1);
my $num2 = int(($vars{'app_input_range_from'}+int(rand($vars{'app_input_range_to'}-$vars{'app_input_range_from'})))/$div2);

if ($num1 || $num2) {

if ($vars{'app_input_comma_status'} > 0 && (!$vars{'app_input_numsys_status'} || $vars{'app_input_numsys_status'} eq "dec")) {
my $comma = 10;
if ($vars{'app_input_comma_status'} == 2) {
$comma = 100;
}
if ($vars{'app_input_comma_status'} == 3) {
$comma = 1000;
}
$num1 = "$num1.".int(rand($comma));
$num2 = "$num2.".int(rand($comma));
}

my ($use1,$use2) = ($num1,$num2);

$numlist = "$num1,$num2,";

for (my $n = 0; $n < 8; $n++) {

my $next = $use1 + $use2;

if ($next < $vars{'app_input_range_to'}+1) {
$numlist .= "$next,";

$use1 = $use2;
$use2 = $next;

$numcount++;

}
}
}
}
}

$all_used{$numlist}++;
my @nums = split(/,/,$numlist);
my $nummax = $nums[$numcount-1];

# roman number and hexa conversion

if ($vars{'app_input_numsys_status'} eq "roman" || $vars{'app_input_numsys_status'} eq "hex") {
for (my $n = 0; $n < $nummax+1; $n++) {
if ($vars{'app_input_numsys_status'} eq "roman") {
$nums[$n] = ONO::Lib::Data::Numbers::Roman->get($nums[$n],"z");
}
if ($vars{'app_input_numsys_status'} eq "hex") {
$nums[$n] = ONO::Lib::Data::Numbers::Hexa->get($nums[$n]);
}
}
}

# operation options

my $op = "add";
if ($vars{'app_input_op_sub'}) {
$op = "sub";
}
if ($vars{'app_input_op_add'} && $vars{'app_input_op_sub'}) {
if (int(rand(100)) > 50) {
$op = "add";
} else {
$op = "sub";
}
if (int(rand(100)) > 33) {
$op = "mid";
}
}

# output paper

if ($vars{'output_paper'}) {

my $display_train = 1;

# option 1: fixed number of cars, but prevents trains longer than available nums

my $cars = &random_cars_fixed("",$vars{'app_input_select_number'},$numcount);

# option 2: random number of cars

if ($vars{'app_input_select_number'} =~ /^r(.*?)$/) {

my $cars_max = $1;
$cars = &random_cars_variable("",$cars_max,$numcount,$nummax);

# prepare default vars

$vars{"cars_cache_$i"} = $cars;
$vars{'random_force_car_width'} = 0;
$vars{'random_force_off_x'} = 0;
$vars{'random_force_use_third'} = 0;

if ($i < 8) {

# first column -> just display stuff as prepared

} else {

# second, any maybe third row

my $j = $i - 8;
my $k = $i - 16;

$display_train = 0;

if ($i < 16) {

if ($vars{"cars_cache_$j"} == 4 || $vars{"cars_cache_$j"} == 5) {

# secondary can be 5,4,3

$display_train = 1;
$cars = 3 + int(rand(3));
if ($cars > $cars_max) {
$cars = $cars_max;
}
$vars{"cars_cache_$i"} = $cars;
$vars{'random_force_car_width'} = int(600/$cars)/10;

}

if ($vars{"cars_cache_$j"} == 3) {

# secondary can be 3,4,5,6 (3 is special case -> 3 x 3)

$display_train = 1;
$cars = 3 + int(rand(5));
if ($cars > $cars_max) {
$cars = $cars_max;
}
$vars{"cars_cache_$i"} = $cars;
$vars{'random_force_off_x'} = 33;
if ($cars > 3) {
$vars{'random_force_off_x'} = 22;
$vars{'random_force_car_width'} = int(820/$cars)/10;
}

}

}

if ($i > 15) {

if ($vars{"cars_cache_$j"} == 3 && $vars{"cars_cache_$k"} == 3) {

$display_train = 1;
$cars = 3;
$vars{"cars_cache_$i"} = $cars;
$vars{'random_force_use_third'} = 1;
$vars{'random_force_off_x'} = 66;

}
}
}
}

if ($vars{'output_worksheet_maker'} && $pdf_y > 40) {

$display_train = 0;

}

if ($display_train && ($pdf_x < 170 || $vars{'random_force_use_third'})) {

# pass values to cars

my (
$really_used_seq,
$opts_ref,
$vars_ref,
) = &pass_values_to_cars("",$cars,$i,\%really_used,\@nums,$numcount,\%vars);

my %opts = %$opts_ref;
%vars = %$vars_ref;

$really_used{$really_used_seq}++;

# passing everything to the correction sheet

my $train_x = $pdf_x-$vars{'random_force_off_x'};
my $train_y = $pdf_y+12;
if ($i%2 != 0) {
$train_y = $pdf_y+10;
}

$corr_cache[$i] = "$train_x\^$train_y\^$cars\^$opts{'car_width'}\^";

# now we need to clear values

my (
$opts_ref,
$vars_ref,
) = &clear_values("",$op,$cars,$i,"",\%opts,\%vars);
%opts = %$opts_ref;
%vars = %$vars_ref;

# display the train

ONO::Lib::PDF::Elements->train($canvas,$train_x,$train_y,"train",80,12,"$train_switches",$cars,"",\%opts);

}

$pdf_y = $pdf_y + 23.75;

if ($pdf_y > 190) {

my $col_y = 90;
if ($cars == 3 && $vars{'app_input_select_number'} !~ /r/) {
$col_y = 57;
}

$pdf_x = $pdf_x + $col_y;
$pdf_y = 8;
}

}

if ($vars{'output_web'}) {

my $cars = $vars{'output_web_cars'};

if (!$cars) {

# option 1: fixed number of cars, but prevents trains longer than available nums

$cars = &random_cars_fixed("",$vars{'app_input_select_number'},$numcount);

# option 2: random number of cars

if ($vars{'app_input_select_number'} =~ /^r(.*?)$/) {

$cars = &random_cars_variable("",$1,$numcount,$nummax);

}

}

# pass values to cars

my (
$really_used_seq,
$opts_ref,
$vars_ref,
) = &pass_values_to_cars("",$cars,$i,\%really_used,\@nums,$numcount,\%vars);

my %opts = %$opts_ref;
%vars = %$vars_ref;

# now we need to clear values

my (
$opts_ref,
$vars_ref,
) = &clear_values("",$op,$cars,$i,$vars{'output_web_cleared'},\%opts,\%vars);
%opts = %$opts_ref;
%vars = %$vars_ref;

# adjust screen sizes...

my $width = 200;
my $height = 120;

if (length $nummax > 3 && $cars > 8) {
$width = 165;
$height = 105;
}
if (length $nummax > 4 && $cars > 7) {
$width = 130;
$height = 90;
}

if (length $nummax > 2) {
$opts{'car_width'} = 150;
if (length $nummax > 3) {
$opts{'car_width'} = 165;
if (length $nummax > 4) {
$opts{'car_width'} = 180;
if (length $nummax > 5) {
$opts{'car_width'} = 185;
}
}
}
}

# check for errors

my ($INPUT,$not_done);

foreach (my $c = 0; $c < $cars; $c++) {

$vars{"train_car_input_text_$c"} = uc $vars{"train_car_input_text_$c"};
$vars{"train_car_input_text_$c"} =~ s~\,~\.~;
$vars{"train_car_input_text_$c"} =~ s~[^A-Z0-9\.]~~g;
$vars{"train_car_input_text_$c"} = substr($vars{"train_car_input_text_$c"},0,12);

if ($vars{"train_car_input_text_$c"} ne "") {
$vars{"car_${c}_color"} = "0:255:150:150";
$vars{"car_${c}_transmit_color_main"} = "0:255:150:150";
if ($vars{"train_car_input_text_$c"} == $nums[$numcount-$cars+$c]) {
$vars{"car_${c}_color"} = "0:150:255:150";
$vars{"car_${c}_transmit_color_main"} = "0:150:255:150";
$opts{"car_${c}_text"} = $nums[$numcount-$cars+$c];
$INPUT .= qq~<input type="hidden" name="train_car_input_text_$c" value="$vars{"train_car_input_text_$c"}">~;
$stat_correct++;
} else {
$vars{'output_web_mistakes'}++;
$stat_wrong++;
}
} else {
$not_done++;
}
}

# display the train

my $TRAIN = ONO::Lib::PDF::Elements->train($canvas,0,0,"train",$width,$height,"HI$train_switches",$cars,"",\%opts,"",\%vars);

$WEB .= qq~<div class="p10 mt10"><div class="inline w100">$TRAIN</div></div>~;

# completed, load next train

if ($not_done < 3 && $stat_wrong < 1) {

$vars{'reload_to_next_train'}++;
$vars{'output_web_question_number'}++;

$WEB .= qq~<div class="abs w100" style="top:150px">
<div class="inline auto w66">
<div class="box_green">
<div class="green xlarge center">$BLK{'please_wait'}...</div>
</div>
</div>
</div>
~;

# <input type="hidden" name="output_web_train_number" value="$vars{'output_web_train_number'}">

} else {

my $hidden = "hidden";
if (ONO::IO->devstation) {
# $hidden = "text";
}

$WEB .= qq~<input type="$hidden" name="stat_correct_total_transmit" value="$stat_correct_total">
<input type="$hidden" name="output_web_cars" value="$cars">
<input type="$hidden" name="output_web_numlist" value="$numlist">
<input type="$hidden" name="output_web_numcount" value="$numcount">
<input type="$hidden" name="output_web_cleared" value="$vars{'output_web_cleared'}">
$INPUT
<script>onojs_focus_first_text();</script>
~;

}

}

}

if ($vars{'output_web'}) {

$WEB .= ONO::FW::Apps::Core->input_vars(\%vars);

if ($vars{'reload_to_next_train'}) {

my $stat_correct_total_calc = $stat_correct_total + $stat_correct;
$WEB .= qq~<input type="hidden" name="reload_to_next_train_exec" value="1">
<input type="hidden" name="stat_correct_total_transmit" value="$stat_correct_total_calc">
~;
$WEB .= qq~<script>onojs_submit();</script>~;
}

$WEB .= qq~</form>~;

}

}

ONO::FW::Apps::PDF->specimen($canvas,$vars_ref);

if (ONO::FW::Apps::Core->print_corrections("$BASE/pdf/pdf-$pdfkey-corr.pdf","",$format,$vars_ref)) {

ONO::FW::Apps::Core->headers(\%vars,$format,"c");
ONO::FW::Apps::PDF->title($BLK{'Corrections'},$PDF_OPTS,$vars{'app_input_print_options_code'},$format);
ONO::FW::Apps::Core::Graphics->pdf_draw_item_numbers($canvas,-2,0,1,4,"CHV",$vars_ref);

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

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

my ($train_x,$train_y,$cars,$car_width) = split(/\^/,$corr_cache[$c]);

if ($cars) {

my %opts;
$opts{'car_width'} = $car_width;
for (my $cc = 0; $cc < 11; $cc++) {
$opts{"car_${cc}_text"} = $vars{"car_${c}_${cc}_text"};
}

ONO::Lib::PDF::Elements->train($canvas,$train_x,$train_y,"train",80,12,"B$train_switches",$cars,"",\%opts);

}

}
}

}

if ($vars{'output_web'}) {

#($stat_correct,$stat_todo_total) = ONO::FW::Apps::Core->stats_multi_pages($vars{'app_input_number_of_questions'},$stat_correct,$stat_wrong,$page,$pages);

$WEB = ONO::FW::Apps::Core->stats_replace($WEB,$stat_correct_total+$stat_correct,$stat_wrong,$stat_todo_total,$vars{'output_web_mistakes'},$page,$pages,$vars{'output_web_completed'});

}

if ($vars{'output_paper'}) {

ONO::FW::Apps::PDF->end($canvas,$vars_ref);

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

}

}

} else {

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

$vars{'app_input_number_of_questions_alt_label'} = $txt[3];

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

if ($vars{'app_input_select_number'} eq "") {
$vars{'app_input_select_number'} = "auto";
}

$WEB .= ONO::FW::Apps::Core->infopics(
"screen:320:50:40::math_trains_screenshot_1.jpg",
"sheet:168:180:140:15:math_trains_sheet_1.jpg",
"sheet:168:40:155:-10:math_trains_sheet_2.jpg",
);

my $NUM = "auto=$txt[2];-;";
for (my $i = 3; $i < 11; $i++) {
$NUM .= "$i=$BLK{'always'} $i ($BLK{'if_possible'});";
}
$NUM .= qq~-;~;
for (my $i = 5; $i < 11; $i++) {
$NUM .= "r$i=$BLK{'random'}, $BLK{'up_to'} $i;";
}

my $CONF .= ONO::FW::Apps::ToolBox->conf_input("range", $BLK_ref,\%vars,"",25,100,999999);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("moreopts", $BLK_ref,\%vars,"","bm");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("numsys", $BLK_ref,\%vars,"h");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("comma", $BLK_ref,\%vars,"h",3);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("ops", $BLK_ref,\%vars,"","as-AS-t");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("select", $BLK_ref,\%vars,"",$NUM,"$txt[0]",$vars{'app_input_select_number'},"","number");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"M","","inter_empty",$vars{'app_input_inter_empty'},$txt[1]);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);

# $CONF .= ONO::FW::Apps::ToolBox->conf_input("negative", $BLK_ref,\%vars,"h");

$WEB .= ONO::FW::Apps::Core->conf_box(
$db,
$community,
$app,
$form,
"",
$action_url,
$CONF,
$lang,
$BLK_ref,
\%vars,
"op-ncdi-CDI-lsu-N",
);
if (!$vars{'exercise'}) {
$WEB .= ONO::FW::Apps::Core->info_display(
ONO::FW::Apps::Core->info("info_online_print",$vars{'app_lang'}),
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 random_cars_fixed {

my $cars = $_[1];
if ($cars > $_[2]) {
$cars = $_[2];
}
return $cars;

}

sub random_cars_variable {

my $max_cars = $_[1];

# randomly select number of cars

my $cars = 3+int(rand($max_cars-2));
if ($cars > $_[2]) {
$cars = $_[2];
}

# adjust number of cars if text becomes wider

if (length $_[3] > 3) {
if ($cars == 3) {
$cars = 4;
}
if (length $_[3] > 4 && ($cars == 4 || $cars == 10)) {
$cars = 7;
}
if (length $_[3] > 5 && ($cars == 8 || $cars == 9)) {
$cars = 6;
}
}

return $cars;

}

sub pass_values_to_cars {

my (
$self,
$cars,
$i,
$really_used_ref,
$nums_ref,
$numcount,
$vars_ref,
) = @_;

my %really_used = %$really_used_ref,
my @nums = @$nums_ref;
my %vars = %$vars_ref;

my (%opts,$really_used_seq);

for (my $c = 0; $c < $cars; $c++) {
my $num = $nums[$numcount-$cars+$c];
$opts{"car_${c}_text"} = $num;
if (ONO::IO->devstation) {
$opts{"car_${c}_placeholder"} = $num;
}
$vars{"car_${i}_${c}_text"} = $num;
$really_used_seq .= "$num,";
}

if ($really_used{$really_used_seq} && $numcount > $cars) {

for (my $c = 0; $c < $cars; $c++) {
my $num = $nums[$numcount-$cars+$c-1];
$opts{"car_${c}_text"} = $num;
if (ONO::IO->devstation) {
$opts{"car_${c}_placeholder"} = $num;
}
$vars{"car_${i}_${c}_text"} = $num;
$really_used_seq .= "$num,";
}
}

if ($vars{'output_paper'}) {
if ($cars > 3) {
$opts{'car_width'} = int(600/$cars)/10;
}
if ($cars > 5) {
$opts{'car_width'} = int(1500/$cars)/10;
}
if ($vars{'random_force_car_width'}) {
$opts{'car_width'} = $vars{'random_force_car_width'};
}
}

if ($opts{"car_0_text"} < 1) {
$opts{"car_0_text"} = 0;
}

return ($really_used_seq,\%opts,\%vars);

}

sub clear_values {

my (
$self,
$op,
$cars,
$i,
$cleared,
$opts_ref,
$vars_ref,
) = @_;

my %opts = %$opts_ref;
my %vars = %$vars_ref;

if ($cleared) {

$vars{'output_web_cleared'} = $cleared;

foreach my $opt (split(/\,/,$cleared)) {
$opts{"car_${opt}_text"} = "";
}

} else {

if ($op eq "add") {
for (my $c = 2; $c < $cars; $c++) {
$opts{"car_${c}_text"} = "";
}
if ($vars{'app_input_inter_empty'} && int(rand(100)) > 33) {
$opts{"car_1_text"} = "";
$opts{"car_2_text"} = $vars{"car_${i}_2_text"};
}
}
if ($op eq "sub") {
for (my $c = 0; $c < $cars-2; $c++) {
$opts{"car_${c}_text"} = "";
}
if ($vars{'app_input_inter_empty'} && int(rand(100)) > 33) {
my $erase = $cars-2;
my $rest = $cars-3;
$opts{"car_${erase}_text"} = "";
$opts{"car_${rest}_text"} = $vars{"car_${i}_${rest}_text"};
}
}
if ($op eq "mid") {
my $keep1 = int(rand($cars-1));
my $keep2 = $keep1+1;
for (my $c = 0; $c < $cars; $c++) {
if ($c != $keep1 && $c != $keep2) {
$opts{"car_${c}_text"} = "";
}
}
if ($vars{'app_input_inter_empty'} && int(rand(100)) > 33) {
my $erase = 1;
my $rest = 2;
if ($keep1 > 0) {
$erase = $keep1;
$rest = $keep1-1;
}
$opts{"car_${erase}_text"} = "";
$opts{"car_${rest}_text"} = $vars{"car_${i}_${rest}_text"};
}
}

if ($vars{'output_web'}) {
foreach my $key (sort keys %opts) {
if ($key =~ /^car_(.*?)_text$/ && $opts{$key} eq "") {
$vars{'output_web_cleared'} .= "$1,";
}
}
}

}

if ($vars{'app_lang'} =~ /(de|lu|fr)/) {
$opts{'car_text_transform_dot_comma'}++;
}

return (\%opts,\%vars);

}

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

1;

__END__