ONO::FW::Edu::Apps::Modules::MathCount

package ONO::FW::Edu::Apps::Modules::MathCount;
################################################################################
# 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::Lib::Data::Color;

use ONO::Lib::PDF::Draw;
use ONO::Lib::PDF::ToolBox;
use ONO::Lib::PDF::Elements::Brick;
use ONO::Lib::PDF::Elements::Dice;
use ONO::Lib::PDF::Elements::Sticker;
use ONO::Lib::PDF::Elements::Abacus;

use ONO::Lib::UI::Sticker;

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

use ONO::FW::Edu::Apps::Modules::MathRods;
use ONO::FW::Edu::Apps::Modules::Money;

use ONO::Lib::Parser;
use ONO::IO;
use ONO::FW::Apps::PDF;
use ONO::FW::Apps::ToolBox;

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

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

my $WEB;

my @txt = (
"count",
"draw",
"Various possibilities",
);

if ($vars{'app_lang'} eq "de") {
@txt = (
"zählen",
"zeichnen",
"Verschiedene Möglichkeiten",
);
}

if ($vars{'app_lang'} eq "lu") {
@txt = (
"zielen",
"zeechnen",
"Verschidde Méiglechkeeten",
);
}

if ($vars{'app_lang'} eq "fr") {
@txt = (
"compter",
"dessiner",
"Possibilités diverses",
);
}

$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);

($vars{'app_input_range_from'},$vars{'app_input_range_to'}) = ONO::FW::Apps::Core->range_check(50,100,$vars{'app_input_range_from'},$vars{'app_input_range_to'});

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

if ($vars{'output_worksheet_maker'}) {

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

}

#############################################################
# PDF + ONLINE
#############################################################

my ($types_ref,$types_num) = &types_detect("",\%vars);
my @types = @$types_ref;

my @colors = ONO::Lib::Data::Color->rainbow("10");

if ($vars{'output_paper'} || $vars{'output_web'}) {

my @defs = ONO::FW::Apps::Core::Graphics->image_ids();
my $defs_num = @defs;
my $defs_ref = \@defs;

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

if ($vars{'output_paper'}) {

$WEB = ONO::FW::Apps::Core->output_paper($pdfkey,\%BLK,\%vars,$HTTP,$BASE);

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

}

my $question_number = $vars{'output_web_question_number'};

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

if ($vars{'output_web'}) {

if ($vars{'output_web_next_question'}) {

foreach my $key (keys %vars) {
if ($key =~ /^output_web_cache_/) {
$vars{$key} = "";
}
}

$vars{'output_web_answer'} = "";

}

$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,"ctTmWvV");

}

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'},$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 (@corr_cache,$corr_counter,@corr_pdf,%used,$HTML);

my $HTML_WIDTH = 522;
my $HTML_INPUT;

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

my ($max_x,$max_y) = (1,1);

if ($vars{'output_paper'}) {
($max_x,$max_y) = (3,4);
}

for (my $y = 0; $y < $max_y; $y++) {
for (my $x = 0; $x < $max_x; $x++) {

my $num = $vars{'output_web_cache_num'};
my $type = $vars{'output_web_cache_type'};
my $exercise = "count";
if ($vars{'app_input_execise_draw'}) {
$exercise = "draw";
if ($vars{'app_input_execise_count'} && int(rand(100)) > 50) {
$exercise = "count";
}
}

if (!$num || $type eq "" || $vars{'output_web_next_question'}) {

$type = $types[int(rand($types_num))];

my $whilecounter;
while ($whilecounter < 16 && $used{"type_$type"}) {
$whilecounter++;
$type = $types[int(rand($types_num))];
}

$used{"type_$type"}++;

$num = ONO::FW::Apps::Core->random_number(1,$vars{'app_input_range_to'},1,100,\%vars);

# try to avoid numbers too small...

if ($num < $vars{'app_input_range_to'}/2) {
$num = ONO::FW::Apps::Core->random_number(1,$vars{'app_input_range_to'},1,100,\%vars);
}
while ($whilecounter < 256 && $used{"num_$num"}) {
$whilecounter++;
$num = ONO::FW::Apps::Core->random_number(1,$vars{'app_input_range_to'},1,100,\%vars);
}

# avoid numbers smaller than 2 in draw mode

if ($exercise eq "draw" && $num < 2) {
$num = ONO::FW::Apps::Core->random_number(1,$vars{'app_input_range_to'},1,100,\%vars);
if ($num < 3) {
$num = 2;
}
}

# used cache

$used{"num_$num"}++;

}

if ($vars{'output_paper'}) {

my $BG = &rect_bg("",$type);

ONO::Lib::PDF::Draw->rect($canvas,$pdf_x,$pdf_y+2,$pdf_x+50,$pdf_y+43,1,"0:22:22:22",$BG,2);

}

my $pos_x = 5;
my $pos_y = 5;

my (
$HTML2,
$HTML_INPUT2,
$corr_pdf_ref,
$used_ref,
$vars_ref2,
) = &engine("",$HTML,$HTML_INPUT,$HTML_WIDTH,$canvas,$pdf_x,$pdf_y,$pos_x,$pos_y,$num,$exercise,$type,\@colors,\@defs,$defs_num,\@corr_pdf,\%used,\%vars);

$HTML .= $HTML2;
$HTML_INPUT .= $HTML_INPUT2;
@corr_pdf = @$corr_pdf_ref;
%used = %$used_ref;
%vars = %$vars_ref2;
$vars_ref = $vars_ref2;

# pdf end: show pencil

if ($vars{'output_paper'} && $exercise eq "draw") {

ONO::Lib::PDF::Draw->place_pdf($canvas,$pdf_x+41,$pdf_y+28,"ono/osr/images/icons/crystal/pdf128/ono/edit_thick.pdf",0.15,270,$format);

}

# web end:

if ($vars{'output_web'}) {

my ($stat_correct,$stat_wrong,$stat_todo_total) = (1,1,1);

if ($vars{'output_web_answer'}) {

$vars{'output_web_answer_status'} = 2;

if ($vars{'output_web_answer'} == $num) {

$vars{'output_web_answer_status'} = 1;

} else {

$vars{'output_web_mistakes'}++;

}

}

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

$WEB .= qq~ <div class="abs" style="top:0px;left:0px;width:920px;padding-top:40px">
<div class="inline auto" style="width:${HTML_WIDTH}px">
<div class="inline">$HTML</div>
</div>
</div>
$INPUT
<input type="hidden" name="output_web_cache_type" value="$type">
<input type="hidden" name="output_web_cache_num" value="$num">
$HTML_INPUT
<div class="abs" style="bottom:5px;left:0px;width:920px">
<div class="inline auto">
~;

$WEB = ONO::FW::Apps::Core->stats_replace($WEB,$question_number,$stat_wrong,$stat_todo_total,$vars{'output_web_mistakes'});

$WEB .= ONO::FW::Apps::Core->check_single(
"",
"",
100,
3,
$BLK_ref,
\%vars,
"CnmMS",
$num,
);

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

}

# paper end:

$corr_cache[$corr_counter] = "$num\^$type\^$exercise\^";

$corr_counter++;

if ($vars{'output_paper'}) {

ONO::Lib::PDF::Draw->rect($canvas,$pdf_x+20,$pdf_y+37.5,$pdf_x+30,$pdf_y+44,1,"0:22:22:22","0:255:255:255",1);
ONO::Lib::PDF::Draw->font('H',12);

if ($exercise eq "draw") {

ONO::Lib::PDF::Draw->text($canvas,$pdf_x+25,$pdf_y+42.25,"$num","c");

# } else {
#
# ONO::Lib::PDF::Draw->text($canvas,$pdf_x+25,$pdf_y+42,"............","c");

}

}

$pdf_x = $pdf_x + 57.5;

}

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

}

if ($vars{'output_paper'} && 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'},$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,"CHLV",$vars_ref);

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

my $corr_counter;

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

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

ONO::Lib::PDF::Draw->rect($canvas,$pdf_x,$pdf_y+2,$pdf_x+50,$pdf_y+43,1,"0:22:22:22","0:255:255:255",2);

my @corr = split(/\^/,$corr_cache[$corr_counter]);

ONO::Lib::PDF::Draw->rect($canvas,$pdf_x+20,$pdf_y+37.5,$pdf_x+30,$pdf_y+44,1,"0:22:22:22","0:255:255:255",1);

if ($corr[2] eq "draw" && $corr[1] =~ /^(cards|dices|money|stickers)$/) {
ONO::Lib::PDF::Draw->font('HO',10);
ONO::Lib::PDF::Draw->text($canvas,$pdf_x+5,$pdf_y+8,$txt[2]);
}

ONO::Lib::PDF::Draw->font('H',12);
ONO::Lib::PDF::Draw->text($canvas,$pdf_x+25,$pdf_y+42.25,$corr[0],"c");

$corr_counter++;

$pdf_x = $pdf_x + 57.5;

}

foreach my $corr (@corr_pdf) {

my @cp = split(/\^/,$corr);

if ($cp[0] eq "circle") {
ONO::Lib::PDF::Draw->circle($canvas,$cp[1],$cp[2],$cp[3],$cp[4],"0:111:111:111","0:111:111:111");
}
if ($cp[0] eq "brick") {
ONO::Lib::PDF::Elements::Brick->brick($canvas,$cp[1],$cp[2],$cp[3],$cp[4],$cp[5],$cp[6],"0:111:111:111");
}
if ($cp[0] eq "dice" || $cp[0] eq "dices") {
ONO::Lib::PDF::Elements::Dice->dice($canvas,$cp[1],$cp[2],$cp[3],$cp[4],"","0:111:111:111");
}
if ($cp[0] eq "stickers") {
ONO::Lib::PDF::Elements::Sticker->sticker($canvas,$cp[1],$cp[2],$cp[4],$cp[4],$cp[3],"","bcsW");
}
if ($cp[0] eq "image") {
ONO::Lib::PDF::Draw->image($canvas,$cp[1],$cp[2],$cp[3],$cp[4],$cp[5],$cp[6],$cp[7]);
}

}

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

}

}

}

if ($vars{'output_paper'}) {

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

}

}

if ($vars{'output_web'}) {
ONO::FW::Apps::Core->varstore($vars{'username'},$vars{'virclass'},$vars{'anonymous'},\%vars);
}

} else {

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

$WEB .= ONO::FW::Apps::Core->infopics(
"screen:320:50:40::math_count_screenshot_1.jpg",
"sheet:168:190:140:15:math_count_sheet_1.jpg",
"sheet:168:40:150:-10:math_count_sheet_2.jpg",
);

if (!$vars{'app_input_number_of_questions'}) {
$vars{'app_input_number_of_questions'} = 20;
}
if (!$vars{'app_input_execise_count'} && !$vars{'app_input_execise_draw'}) {
$vars{'app_input_execise_count'} = 1;
}

my @opts = &opts("",$BLK_ref);

my $type_found = &type_found("",\%vars,$BLK_ref);

if (!$type_found) {
$vars{"app_input_type_dots"} = 1;
$vars{"app_input_type_rods"} = 1;
$vars{"app_input_type_dices"} = 1;
$vars{"app_input_type_images"} = 1;
}

my ($CUSTOM,$SCRIPT_END) = &type_select("",\%vars,$BLK_ref);

my ($CURR,$USE,$SCRIPT,$hide_curr) = ¤cy("",\%vars,$BLK_ref);

my $CONF .= ONO::FW::Apps::ToolBox->conf_input("range", $BLK_ref,\%vars,"",1,20,100);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);

$CONF .= ONO::FW::Apps::ToolBox->conf_input("custom", $BLK_ref,\%vars,"","",$CUSTOM);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("custom", $BLK_ref,\%vars,"","",qq~<div id="currency_selector_id" class="$hide_curr">$CURR</div>~);

$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"S","","execise_count",$vars{'app_input_execise_count'},$txt[0]);
if (!$vars{'output_web'}) {
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"S","","execise_draw",$vars{'app_input_execise_draw'},$txt[1]);
} else {
$CONF .= qq~<input type="hidden" name="app_input_execise_draw" value="$vars{'app_input_execise_draw'}">~;
}

$WEB .= ONO::FW::Apps::Core->conf_box(
$db,
$community,
$app,
$form,
"",
$action_url,
$CONF,
$lang,
$BLK_ref,
\%vars,
"op-ncbdi-CDI-lsu-N",
);

$SCRIPT .= &script();

$WEB .= qq~$SCRIPT$SCRIPT_END~;

if ($vars{'app_input_currency'}) {
$WEB .= qq~<script>use_box_select('$vars{'app_input_currency'}')</script>~;
}

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_img {

my (
$self,
$defs_ref,
$defs_num,
) = @_;

my @defs = @$defs_ref;
my $img = int(rand($defs_num));
$img = $defs[$img];
$img =~ s~:(.*)$~~;

return $img;

}

sub rand_color {

# mode: 0 = random, 1 = dark, 2 = light

# dark mode

my $c1 = 25+int(rand(100));
my $c2 = 25+int(rand(100));
my $c3 = 25+int(rand(100));

# light mode

if ($_[1] == 2 || (!$_[1] && int(rand(100)) > 50)) {
$c1 = 100+int(rand(125));
$c2 = 100+int(rand(125));
$c3 = 100+int(rand(125));
}

return "0:$c1:$c2:$c3";
}

sub fornum {

my $fornum = $_[1];
if ($_[2] eq "draw") {
$fornum = 1;
}
return $fornum;

}

sub opts {

my $BLK_ref = $_[1];
my %BLK = %$BLK_ref;

my @opts = (
"dots:$BLK{'dots'} ($BLK{'aligned'})",
"dotsr:$BLK{'dots'}",
"rods:$BLK{'rods'}",
"dices:$BLK{'dices'}",
);

if ($ENV{'SCRIPT_NAME'} !~ /math_houses_img/) {
@opts = (
@opts,
"stickers:$BLK{'stickers'} (1-10)",
"cards:$BLK{'cards'}",
"images:$BLK{'images'}",
"money:$BLK{'money'}",
);
}

if ($ENV{'SCRIPT_NAME'} =~ /math_count_mc/) {
@opts = (
@opts,
"abacus:$BLK{'abacus'}",
);
}

return @opts;

}

sub type_found {

my $vars_ref = $_[1];
my %vars = %$vars_ref;

my $type_found;
foreach my $opt (&opts("",$_[2])) {
my @op = split(/:/,$opt);
if ($vars{"app_input_type_$op[0]"}) {
$type_found++;
}
}

return $type_found;

}

sub type_select {

my $vars_ref = $_[1];
my %vars = %$vars_ref;

my $size = 64;
if ($_[3]) {
$size = $_[3];
}

my ($CUSTOM,$SCRIPT_END);

foreach my $opt (&opts("",$_[2])) {
my @op = split(/:/,$opt);

$CUSTOM .= qq~<div id="conf_type_$op[0]" class="box_paper p0 box_black_hover_p0 block$size rel fl cursorlink" style="margin:4px"
onmouseover="conf_type_mouseover('$op[0]');" onmouseout="conf_type_mouseout('$op[0]');" onclick="conf_type_select('$op[0]');">
<div id="conf_type_info_$op[0]" class="box_yellow bo pad10_0 small nowrap abs hide" style="bottom:-20px;left:10px;z-index:999">$op[1]</div>
<img class="block$size" src="/images/morzino/apps/math_count_$op[0].png" alt="">
<input type="hidden" id="app_input_type_$op[0]_id" name="app_input_type_$op[0]" value="$vars{"app_input_type_$op[0]"}">
</div>
~;
if ($vars{"app_input_type_$op[0]"}) {
$SCRIPT_END .= qq~<script>conf_type_select('$op[0]','1')</script>~;
}

}

$CUSTOM = qq~<div class="rel">
<div class="box_fabric mb5" style="padding:4px">
<div class="inline w100">$CUSTOM</div>
</div>
</div>
~;

return ($CUSTOM,$SCRIPT_END);

}

sub currency {

my $vars_ref = $_[1];
my %vars = %$vars_ref;

my $currency = ONO::FW::Edu::Apps::Modules::Money->currency();
my @currs = ONO::FW::Edu::Apps::Modules::Money->currency_currs($currency);

my @usd = ONO::FW::Edu::Apps::Modules::Money->curr_usd;
my @eur = ONO::FW::Edu::Apps::Modules::Money->curr_eur;
my @gbp = ONO::FW::Edu::Apps::Modules::Money->curr_gbp;
my @chf = ONO::FW::Edu::Apps::Modules::Money->curr_chf;

my ($CURR,$USE,$SCRIPT) = ONO::FW::Edu::Apps::Modules::Money->currency_select($currency,\@currs,\@usd,\@eur,\@gbp,\@chf,\%vars,"a");
$CURR .= $SCRIPT;

my $hide_curr;
if (!$vars{"app_input_type_money"}) {
$hide_curr = "hide";
}

return ($CURR,$USE,$SCRIPT,$hide_curr);

}

sub script {

my $size = 64;
if ($_[1]) {
$size = $_[1];
}

return qq~<script>
function conf_type_mouseover(type) {
onojs_block('conf_type_info_'+type);
}
function conf_type_mouseout(type) {
onojs_hide('conf_type_info_'+type);
}
function conf_type_select(type,force) {
if (force == 1) {
onojs_class('conf_type_'+type,'box_black p0 block$size rel fl mr10 mb10 cursorlink');
onojs_setvalue('app_input_type_'+type+'_id','1');
if (type == 'money') {
onojs_block('currency_selector_id');
}
} else {
var val = onojs_getvalue('app_input_type_'+type+'_id');
if (val == 1) {
onojs_class('conf_type_'+type,'box_paper p0 block$size rel fl mr10 mb10 cursorlink');
onojs_setvalue('app_input_type_'+type+'_id','0');
if (type == 'money') {
onojs_hide('currency_selector_id');
}
} else {
onojs_class('conf_type_'+type,'box_black p0 block$size rel fl mr10 mb10 cursorlink');
onojs_setvalue('app_input_type_'+type+'_id','1');
if (type == 'money') {
onojs_block('currency_selector_id');
}
}
}
}
</script>
~;
}

sub rect_bg {

my $BG = "0:255:255:255";
if ($_[1] ne "money") {
my $b1 = 235+int(rand(20));
my $b2 = 235+int(rand(20));
my $b3 = 235+int(rand(20));
$BG = "0:$b1:$b2:$b3";
}

return $BG;

}

sub money_opts {

my @moneyopts = (1,2,5,10,20,50);
my $moneybig = 5;

if ($_[1] eq "usd") {
$moneybig = 1;
}
if ($_[1] eq "chf") {
$moneybig = 10;
}

return ($moneybig,@moneyopts);

}

sub types_detect {

my $vars_ref = $_[1];
my %vars = %$vars_ref;

my @types;
foreach my $key (keys %vars) {
if ($key =~ /^app_input_type_(.*?)$/ && $vars{$key}) {
@types = (@types,$1);
}
}
my $types_num = @types;

if (!$types_num) {
foreach my $opt (&opts) {
my @op = split(/:/,$opt);
@types = (@types,$op[0]);
}
$types_num = @types;
}

return (\@types,$types_num);

}

sub engine {

my (
$self,
$HTML,
$HTML_INPUT,
$HTML_WIDTH,
$canvas,
$pdf_x,
$pdf_y,
$pos_x,
$pos_y,
$num,
$exercise,
$type,
$colors_ref,
$defs_ref,
$defs_num,
$corr_pdf_ref,
$used_ref,
$vars_ref,
) = @_;

my @colors = @$colors_ref;
my @defs = @$defs_ref;
my @corr_pdf = @$corr_pdf_ref;
my %used = %$used_ref;
my %vars = %$vars_ref;

my $DEBUG = "<br>count engine, pos = ($pdf_x,$pdf_y,$pos_x,$pos_y), num = $num, type = $type, ";

if ($type eq "abacus") {

if ($vars{'output_paper'}) {

my ($use_x,$use_y) = ($pdf_x+2.5,$pdf_y+4);

ONO::Lib::PDF::Elements::Abacus->abacus($canvas,$use_x,$use_y,"","",$num);
@corr_pdf = (@corr_pdf,"abacus\^$use_x\^$use_y\^$num\^");
}

}

if ($type eq "dots" || $type eq "dotsr") {

my $COLOR = $vars{'output_web_cache_col'};
if ($vars{'output_web_cache_col'} eq "") {
$COLOR = &rand_color();
}
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_col" value="$COLOR">~;

my $size = 4.5;
if ($num > 60) {
$size = 4;
if ($num > 80) {
$size = 3.5;
}
}

for (my $d = 0; $d < $num; $d++) {

my ($rand_x,$rand_y) = (0,0);
if ($type eq "dotsr") {
($rand_x,$rand_y) = ((2-int(rand(4)))/3,(2-int(rand(4)))/3);
}

my $use_x = $pdf_x+$pos_x+$rand_x;
my $use_y = $pdf_y+$pos_y+1+$rand_y;
my $use_size = $size/3;

if ($vars{'output_paper'} && ($exercise eq "count" || $d < 1)) {
ONO::Lib::PDF::Draw->circle($canvas,$use_x,$use_y,$use_size,0,$COLOR,$COLOR);
}
if ($vars{'output_web'}) {
my $COL = ONO::Lib::PDF::Draw->color_to_html($COLOR);
my @size = (32,16);
if ($num > 70) {
@size = (28,16);
if ($num > 80) {
@size = (24,12);
if ($num > 90) {
@size = (20,10);
}
}
}
$rand_x = int($rand_x*5);
$rand_y = int($rand_y*5);
$HTML .= qq~<div class="p5 fl"><div class="block$size[0] radius$size[1] ml5 mr5 rel" style="background-color:$COL;top:${rand_x}px;left:${rand_y}px;"></div></div>~;
if (($d+11)%10 == 0) {
$HTML .= qq~<div class="inline w100"></div>~;
}
}

@corr_pdf = (@corr_pdf,"circle\^$use_x\^$use_y\^$use_size\^0\^$COLOR\^$COLOR\^");

$pos_x = $pos_x + $size;
if ($pos_x > 48) {
$pos_x = 5;
$pos_y = $pos_y + $size+0.5;
}
}

}

if ($type eq "rods") {

my $rodsize = 4;
my $rodoffx = 0;

if ($num > 60) {
$rodsize = 3.5;
$rodoffx = 2.5;
if ($num > 70) {
$rodsize = 3;
$rodoffx = 5;
if ($num > 80) {
$rodsize = 2.5;
$rodoffx = 7;
}
}
}

if ($vars{'output_paper'} && $exercise eq "draw") {

my $max_y = 0;
for (my $r = 0; $r < 10; $r++) {
if ($r*$rodsize < 30) {
ONO::Lib::PDF::Draw->rect($canvas,$pdf_x+$pos_x+$rodoffx,$pdf_y+$pos_y+$r*$rodsize,$pdf_x+$pos_x+$rodoffx+$rodsize*10,$pdf_y+$pos_y+(($r+1)*$rodsize),0.5,"0:111:111:111","0:255:255:255");
$max_y = $pdf_y+$pos_y+(($r+1)*$rodsize);
}
}
for (my $r = 0; $r < 10; $r++) {
ONO::Lib::PDF::Draw->line($canvas,$pdf_x+$pos_x+$rodoffx+$r*$rodsize,$pdf_y+$pos_y,$pdf_x+$pos_x+$rodoffx+$r*$rodsize,$max_y,0.5,"0:111:111:111");
}

}

my $brick = $num;
my $whilecounter;
while ($whilecounter < 256 && $brick > 9) {
$whilecounter++;

my $use_x = $pdf_x+$pos_x+$rodoffx;
my $use_y = $pdf_y+$pos_y;

if ($vars{'output_paper'} && $exercise eq "count") {
ONO::Lib::PDF::Elements::Brick->brick($canvas,$use_x,$use_y,10,1,$rodsize,1,$colors[9]);
}
if ($vars{'output_web'}) {
$HTML .= ONO::FW::Edu::Apps::Modules::MathRods->rod(10,\@colors,1);
}

@corr_pdf = (@corr_pdf,"brick\^$use_x\^$use_y\^10\^1\^$rodsize\^1\^$colors[9]\^");

$brick = $brick-10;
$pos_y = $pos_y + $rodsize*1.2;

}

if ($brick) {

my $use_x = $pdf_x+$pos_x+$rodoffx;
my $use_y = $pdf_y+$pos_y;

if ($vars{'output_paper'} && $exercise eq "count") {
ONO::Lib::PDF::Elements::Brick->brick($canvas,$use_x,$use_y,$brick,1,$rodsize,1,$colors[$brick-1]);
}
if ($vars{'output_web'}) {
$HTML .= ONO::FW::Edu::Apps::Modules::MathRods->rod($brick,\@colors,1);
}

@corr_pdf = (@corr_pdf,"brick\^$use_x\^$use_y\^$brick\^1\^$rodsize\^1\^$colors[$brick-1]\^");

}

$HTML_WIDTH = 320;

}

if ($type eq "dices" || $type eq "stickers") {
my $dicetot = 0;
my $dices = $num;
my $size = 9;
if ($num > 50) {
$size = 7;
}
if ($num > 75) {
$size = 6;
}

my $dice_max = 6;
if ($type eq "stickers") {
$dice_max = 10;
}

$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_dices_cached" value="1">~;

for (my $d = 0; $d < 99; $d++) {

if ($vars{'output_web_cache_dices_cached'}) {

if ($vars{"output_web_cache_dice_${d}_num"}) {

$dicetot = $num;

if ($type eq "stickers") {
$HTML .= ONO::Lib::UI::Sticker->sticker(80,80,$vars{"output_web_cache_dice_${d}_num"},$vars{'output_sticker_color'},"abcFrs");
} else {
$HTML .= qq~<img class="block64 fl mr10 mb10" src="/ono/osr/images/dices/64/$vars{"output_web_cache_dice_${d}_col"}_$vars{"output_web_cache_dice_${d}_num"}.jpg" alt="">~;
}
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_dice_${d}_col" value="$vars{"output_web_cache_dice_${d}_col"}">
<input type="hidden" name="output_web_cache_dice_${d}_num" value="$vars{"output_web_cache_dice_${d}_num"}">
~;

}

}

if ($pos_y < 30 && !$vars{'output_web_cache_dices_cached'}) {

my $dice = $dices;
my @cols = ('black','red','green','blue','white');
my $color = $cols[int(rand(5))];

if ($dice > $dice_max) {
$dice = 1+int(rand($dice_max));
if ($num > 20 && $dice < $dice_max-1 && int(rand(100)) < 75) {
$dice = 1+int(rand($dice_max));
}
if ($dices > 15 && $dice < $dice_max-1 && int(rand(100)) < 75) {
$dice = 3+int(rand($dice_max-2));
}
$dices = $dices - $dice;
} else {
if ($dices) {

my $use_x = $pdf_x+$pos_x;
my $use_y = $pdf_y+$pos_y;

if ($vars{'output_paper'} && ($exercise eq "count" || $d < 1)) {

my $use_dice = $dice;

if ($exercise eq "draw") {
$use_dice = 1+(int(rand($dice-1)));
}

if ($type eq "stickers") {
ONO::Lib::PDF::Elements::Sticker->sticker($canvas,$use_x,$use_y,$size,$size,$use_dice,$vars{'output_sticker_color'},"abcFrs");
} else {
ONO::Lib::PDF::Elements::Dice->dice($canvas,$use_x,$use_y,$use_dice,$size);
}
}
if ($vars{'output_web'}) {
if ($type eq "stickers") {
$HTML .= ONO::Lib::UI::Sticker->sticker(80,80,$dice,$vars{'output_sticker_color'},"abcFrs");
} else {
$HTML .= qq~<img class="block64 fl mr10 mb10" src="/ono/osr/images/dices/64/${color}_$dice.jpg" alt="">~;
}
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_dice_${d}_col" value="$color">
<input type="hidden" name="output_web_cache_dice_${d}_num" value="$dice">
~;
}

if ($exercise ne "draw") {
@corr_pdf = (@corr_pdf,"$type\^$use_x\^$use_y\^$dice\^$size\^");
}

$dicetot = $dicetot + $dice;
$dices = 0;
}
}
if ($dices) {

my $use_x = $pdf_x+$pos_x;
my $use_y = $pdf_y+$pos_y;

if ($vars{'output_paper'} && ($exercise eq "count" || $d < 1)) {
if ($type eq "stickers") {
ONO::Lib::PDF::Elements::Sticker->sticker($canvas,$use_x,$use_y,$size,$size,$dice,$vars{'output_sticker_color'},"abcFrs");
} else {
ONO::Lib::PDF::Elements::Dice->dice($canvas,$use_x,$use_y,$dice,$size);
}
}
if ($vars{'output_web'}) {
if ($type eq "stickers") {
$HTML .= ONO::Lib::UI::Sticker->sticker(80,80,$dice,$vars{'output_sticker_color'},"abcFrs");
} else {
$HTML .= qq~<img class="block64 fl mr10 mb10" src="/ono/osr/images/dices/64/${color}_$dice.jpg" alt="">~;
}
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_dice_${d}_col" value="$color">
<input type="hidden" name="output_web_cache_dice_${d}_num" value="$dice">
~;
}

if ($exercise ne "draw") {
@corr_pdf = (@corr_pdf,"$type\^$use_x\^$use_y\^$dice\^$size\^");
}

$dicetot = $dicetot + $dice;
$pos_x = $pos_x + $size + 1;
if ($pos_x > 40) {
$pos_x = 5;
$pos_y = $pos_y + $size + 1;
}
}
}
}

$num = $dicetot;
$used{"num_$num"}++;

}

if ($type eq "cards") {

my $cards = $num;
my $cardtot = 0;
my @ctype = ('c','d','h','s');

my $size = 12;
if ($num > 50) {
$size = 9;
}

$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_cards_cached" value="1">~;

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

if ($vars{'output_web_cache_cards_cached'}) {

if ($vars{"output_web_cache_card_${c}_num"}) {

$cardtot = $num;

$HTML .= qq~<div class="box_white p5 fl mr10 mb10">
<img class="block64" src="/images/cards/$vars{"output_web_cache_card_${c}_num"}$vars{"output_web_cache_card_${c}_col"}.jpg" style="height:80px" alt="">
</div>
~;
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_card_${c}_col" value="$vars{"output_web_cache_card_${c}_col"}">
<input type="hidden" name="output_web_cache_card_${c}_num" value="$vars{"output_web_cache_card_${c}_num"}">
~;

}

}

if ($pos_y < 25 && !$vars{'output_web_cache_cards_cached'}) {

my $cardcolor = $ctype[int(rand(4))];
my $card = $cards;
if ($card > 10) {
$card = 1+int(rand(10));
$cards = $cards - $card;
} else {
if ($cards) {

my $use_x = $pdf_x+$pos_x-1;
my $use_y = $pdf_y+$pos_y;
my $size2 = $size/12*15;

if ($vars{'output_paper'} && ($exercise eq "count" || $c < 1)) {
my $use_card = $card;
if ($exercise eq "draw") {
$use_card = 1+int(rand($num));
}
ONO::Lib::PDF::Draw->image($canvas,$use_x,$use_y,$size,$size2,"images/cards/$use_card$cardcolor.jpg",0.5,1);
}
if ($vars{'output_web'}) {
$HTML .= qq~<div class="box_white p5 fl mr10 mb10"><img class="block64" src="/images/cards/$card$cardcolor.jpg" style="height:80px" alt=""></div>~;
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_card_${c}_col" value="$cardcolor">
<input type="hidden" name="output_web_cache_card_${c}_num" value="$card">
~;
}

if ($exercise ne "draw") {
@corr_pdf = (@corr_pdf,"image\^$use_x\^$use_y\^$size\^$size2\^images/cards/$card$cardcolor.jpg\^0.5\^1\^");
}

$cardtot = $cardtot + $card;
$cards = 0;
}
}
if ($cards) {

my $use_x = $pdf_x+$pos_x-1;
my $use_y = $pdf_y+$pos_y;
my $size2 = $size/12*15;

if ($vars{'output_paper'} && ($exercise eq "count" || $c < 1)) {
ONO::Lib::PDF::Draw->image($canvas,$use_x,$use_y,$size,$size2,"images/cards/$card$cardcolor.jpg",0.5,1);
}
if ($vars{'output_web'}) {
$HTML .= qq~<div class="box_white p5 fl mr10 mb10"><img class="block64" src="/images/cards/$card$cardcolor.jpg" style="height:80px" alt=""></div>~;
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_card_${c}_col" value="$cardcolor">
<input type="hidden" name="output_web_cache_card_${c}_num" value="$card">
~;
}

if ($exercise ne "draw") {
@corr_pdf = (@corr_pdf,"image\^$use_x\^$use_y\^$size\^$size2\^images/cards/$card$cardcolor.jpg\^0.5\^1\^");
}

$cardtot = $cardtot + $card;
$pos_x = $pos_x + $size+2;
if ($pos_x > 40) {
$pos_x = 5+$c/3;
$pos_y = $pos_y + $size/2;
}
}
}
}

$HTML = qq~<div class="box_fabric" style="width:500px"><div class="inline w100">$HTML</div></div>~;

$num = $cardtot;
$used{"num_$num"}++;

}

if ($type eq "money") {

my $moneymax = $num;
my $moneyrest = $num;
my $moneytotal = 0;

my $moneytype = $vars{'output_web_cache_money_type'};
if ($moneytype eq "") {
$moneytype = $vars{'app_input_currency'};
}

my ($moneybig,@moneyopts) = &money_opts("",$moneytype);

$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_money_cached" value="1">
<input type="hidden" name="output_web_cache_money_type" value="$moneytype">
~;

$DEBUG .= "max/rest = $moneymax/$moneyrest, moneytype = $moneytype, moneybig = $moneybig, ";

# this is using a different method than the others !!!

for (my $m = 0; $m < 20; $m++) {

if ($vars{'output_web_cache_money_cached'}) {

$moneytotal = $num;

if ($vars{"output_web_cache_money_${m}_num"}) {

$HTML .= qq~<div class="fl mr10 mb10">
<img class="block64" src="/images/money/$moneytype/128/e0$vars{"output_web_cache_money_${m}_num"}.jpg" style="width:$vars{"output_web_cache_money_${m}_size"}px" alt="">
</div>
~;
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_money_${m}_size" value="$vars{"output_web_cache_money_${m}_size"}">
<input type="hidden" name="output_web_cache_money_${m}_num" value="$vars{"output_web_cache_money_${m}_num"}">
~;

}

}

if ($moneyrest > 0 && $pos_y < 30 && !$vars{'output_web_cache_money_cached'}) {

# chose one value to start with

my $moneynum = @moneyopts;
my $money = $moneyopts[int(rand($moneynum))];

# change the value as long as it's too big

my $whilecounter;
while ($whilecounter < 4096 && $money > $moneyrest) {
$money = $moneyopts[int(rand($moneynum))];
$whilecounter++;
}

$moneyrest = $moneyrest - $money;

my $mon = $money;
if ($mon < 10) {
$mon = "0$mon";
}
my $monsize = 9;
my $monborder;
if ($mon > $moneybig-1) {
$monsize = 16;
$monborder = 0.5
}

if ($pos_x + $monsize + 1 > 48) {
$pos_x = 5;
$pos_y = $pos_y + 10;
}

if ($pos_y < 30) {

my $use_x = $pdf_x+$pos_x-1;
my $use_y = $pdf_y+$pos_y;

if ($vars{'output_paper'} && ($exercise eq "count" || $m < 1)) {

my $use_mon = $mon;
if ($mon > $num-1) {
$use_mon = "01";
$monsize = 9;
$monborder = 0;
}

ONO::Lib::PDF::Draw->image($canvas,$use_x,$use_y,$monsize,9,"images/money/$moneytype/128/e0$use_mon.jpg",$monborder);
}
if ($vars{'output_web'}) {
$monsize = int(64/9*$monsize);
$HTML .= qq~<div class="fl mr10 mb10"><img class="block64" src="/images/money/$moneytype/128/e0$mon.jpg" style="width:${monsize}px" alt=""></div>~;
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_money_${m}_size" value="$monsize">
<input type="hidden" name="output_web_cache_money_${m}_num" value="$mon">
~;
}

if ($exercise ne "draw") {
@corr_pdf = (@corr_pdf,"image\^$use_x\^$use_y\^$monsize\^9\^images/money/$moneytype/128/e0$mon.jpg\^$monborder\^0\^");
}

$moneytotal = $moneytotal + $money;

$pos_x = $pos_x + $monsize + 1;

}

}

}

# return moneytotal, although num should usually be correct...

$num = $moneytotal;
$used{"num_$num"}++;

}

if ($type eq "images") {

my $img = $vars{'output_web_cache_img'};
if ($vars{'output_web_cache_img'} eq "") {
$img = &random_img("",$defs_ref,$defs_num);
}
$HTML_INPUT .= qq~<input type="hidden" name="output_web_cache_img" value="$img">~;

my $size = 7.6;
my $hsize = 64;
if ($num > 15) {
$size = 6.1;
$hsize = 48;
if ($num > 24) {
$size = 5.1;
$hsize = 40;
if ($num > 35) {
$size = 4.4;
$hsize = 28;
if ($num > 48) {
$size = 3.4;
$hsize = 20;
if ($num > 70) {
$size = 2.6;
$hsize = 11;
}
}
}
}
}

$hsize = $hsize + 18;

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

my $use_x = $pdf_x+$pos_x-1;
my $use_y = $pdf_y+$pos_y;
my $use_radius = $size/4;

if ($vars{'output_paper'} && ($exercise eq "count" || $n < 1)) {
ONO::Lib::PDF::Draw->image($canvas,$use_x,$use_y,$size,$size,"images/pix/preview/rgb_low_quality/$img.jpg",0.5,$use_radius);
}
if ($vars{'output_web'}) {
$HTML .= qq~<div class="box_white block p2 fl mr5 mb5"><img class="block" src="/images/pix/preview/rgb_low_quality/$img.jpg" style="width:${hsize}px;height:${hsize}px" alt=""></div>~;
}

@corr_pdf = (@corr_pdf,"image\^$use_x\^$use_y\^$size\^$size\^images/pix/preview/rgb_low_quality/$img.jpg\^0.5\^$use_radius\^");

$pos_x = $pos_x + $size + 1;
if ($pos_x > 49-$size) {
$pos_x = 5;
$pos_y = $pos_y + $size + 1;
}
}
}

return ($HTML,$HTML_INPUT,\@corr_pdf,\%used,\%vars,$DEBUG);

}

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

1;

__END__