ONO::FW::Edu::Apps::Modules::RomanNumerals

package ONO::FW::Edu::Apps::Modules::RomanNumerals;
################################################################################
# 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::FW::Apps::ToolBox;

use ONO::Lib::PDF::Draw;
use ONO::Lib::PDF::ToolBox;
use ONO::Lib::Data::Numbers::Roman;

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

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

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

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

my $APPS_BASE = ONO::FW::Apps::ToolBox->apps_base();

my $WEB;

my @txt = (
"Roman Numerals",
"roman",
"decimal",
qq~<a href="javascript:void(0);" onclick="onojs_block('roman_info_box');" class="col3">Click here</a> to learn more about how roman numerals work.~,
qq~Use our <a href="javascript:void(0);" onclick="onojs_block('roman_conv_box');onojs_hide('roman_conf_box');" class="col3">Conversion Tool</a>
to transform roman and decimal numbers.~,
qq~You may also calculate with roman numerals using the "<a href="/$APPS_BASE/arithmetic/" class="col3" target="_parent">Arithmetic</a>" App.~,
);

if ($vars{'app_lang'} eq "de") {
@txt = (
"Römische Zahlen",
"römisch",
"dezimal",
qq~<a href="javascript:void(0);" onclick="onojs_block('roman_info_box');" class="col3">Klicke hier </a> um mehr über die Funktionsweise der römischen Zahlen zu erfahren.~,
qq~Benutze unser <a href="javascript:void(0);" onclick="onojs_block('roman_conv_box');onojs_hide('roman_conf_box');" class="col3">Konvertierungs-Tool</a>
zum Konvertieren von römischen und Dezimalzahlen.~,
qq~Du kannst auch mithilfe der "<a href="/$APPS_BASE/arithmetic/" class="col3" target="_parent">Rechnen</a>" App mit römischen Zahlen rechnen lernen.~,
);

}

if ($vars{'app_lang'} eq "fr") {
@txt = (
"Nombres romains",
"romain",
"décimal",
qq~<a href="javascript:void(0);" onclick="onojs_block('roman_info_box');" class="col3">Cliquez ici</a> pour en savoir plus sur le fonctionnement des chiffres romains.~,
qq~Utilisez notre <a href="javascript:void(0);" onclick="onojs_block('roman_conv_box');onojs_hide('roman_conf_box');" class="col3">Outil de Conversion</a>
pour transformer les nombres romains et décimaux.~,
qq~Vous pouvez également calculer en chiffres romains en utilisant l’app "<a href="/$APPS_BASE/arithmetic/" class="col3" target="_parent">Calculs</a>".~,
);
}

if ($vars{'app_lang'} eq "lu") {
@txt = (
"Réimesch Zuelen",
"réimesch",
"dezimal",
qq~<a href="javascript:void(0);" onclick="onojs_block('roman_info_box');" class="col3">Klick hei </a> fir méi iwwer d'Funktiounsweis vun de réimeschen Zuelen ze léieren.~,
qq~Benotz eisen <a href="javascript:void(0);" onclick="onojs_block('roman_conv_box');onojs_hide('roman_conf_box');" class="col3">Konvertéierungs-Tool</a>
fir réimesch Zuelen an Dezimalzahlen ze konvertéieren.~,
qq~Du kanns och mat der "<a href="/$APPS_BASE/arithmetic/" class="col3" target="_parent">Rechnen</a>" App mat réimeschen Zuele rechne léieren.~,
);
}

$vars{'app_input_print_options_title_default'} = $txt[0];

$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(
2999,
3999,
$vars{'app_input_range_from'},
$vars{'app_input_range_to'},
$vars{'app_input_negative'},
$vars{'app_input_numsys_status'},
);

#############################################################
# 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'});

my (
$focus_on,
$page,$pages,%cache,
$whilecounter,$stats_switches,
$PDF_OPTS,
$stat_correct,$stat_wrong,$stat_todo,$stat_todo_total,
);

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

$vars{'app_input_multiple_questions_per_page'}++;
$questions_per_page = 60;

}

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

my (@num1,@res,@corr_cache);

my ($pdf_x,$pdf_y) = (2,8);

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->unique_copies_info($canvas,$copy,$vars_ref);
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>~;

if ($vars{'app_input_multiple_questions_per_page'}) {

($stats_switches,$questions_per_page,$page,$pages) = ONO::FW::Apps::Core->multi_page_logic($page,\%vars);

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

$WEB .= ONO::FW::Apps::Core->multi_frame_start($vars{'output_web_finish'});

} else {

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

$WEB .= ONO::FW::Apps::Core->stats("",$BLK_ref,"ctmW$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,$vars{'app_input_number_of_questions'},$vars{'output_web_mistakes'},$lang,$BLK_ref,$vars_ref);

} else {

$WEB .= ONO::FW::Apps::Core->timer($vars{'output_web'},$vars{'output_web_timer_start'});

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

if ($vars{'output_web'}) {

$stat_todo++;

$vars{"output_web_answer_$i"} = ONO::FW::Apps::Core->clean_answer_math($vars{"output_web_answer_$i"},"r");

if ($vars{'app_input_multiple_questions_per_page'}) {

if ($vars{'output_web_next_page'}) {

$vars{"output_web_answer_$i"} = "";

} else {

$num1[$i] = $vars{"output_web_cache_num1_$i"};
$res[$i] = $vars{"output_web_cache_res_$i"};

}

} else {

if ($vars{"output_web_answer"} eq "" || ($vars{"output_web_answer"} != $vars{"output_web_cache_res_$i"})) {

$vars{'output_web_answer_status'} = 2;
$num1[$i] = $vars{"output_web_cache_num1_$i"};
$res[$i] = $vars{"output_web_cache_res_$i"};
if ($vars{"output_web_answer"} ne "") {
$vars{'output_web_mistakes'}++;
}

} else {

$question_number++;
$vars{'output_web_answer_status'} = 1;
$vars{'output_web_answer'} = "";

}

}

}

# number generation

if ($num1[$i] eq "") {

$num1[$i] = ONO::FW::Apps::Core->random_number($vars{'app_input_range_from'},$vars{'app_input_range_to'},1,3999,\%vars);
$res[$i] = $num1[$i];

my $mode = "romdec";
if ($vars{'app_input_decrom'}) {
$mode = "decrom";
if ($vars{'app_input_romdec'} && int(rand(100)) > 50) {
$mode = "romdec";
}
}

if ($mode eq "romdec") {

$num1[$i] = ONO::Lib::Data::Numbers::Roman->get($num1[$i]);

} else {

$res[$i] = ONO::Lib::Data::Numbers::Roman->get($num1[$i]);

}
}

# output paper

if ($vars{'output_paper'}) {

$corr_cache[$i] = "$num1[$i]\^$res[$i]\^$pdf_x\^$pdf_y\^";

if (!$vars{'app_input_result_hints'} || $i < 20 || $i > 39) {

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

&fontadapt("",$num1[$i]);

ONO::Lib::PDF::Draw->text($canvas,$pdf_x+20, $pdf_y, "$num1[$i]","r");
ONO::Lib::PDF::Draw->font('',9);
ONO::Lib::PDF::Draw->text($canvas,$pdf_x+30, $pdf_y, "...................");
ONO::Lib::PDF::Draw->font('',12);

}

$pdf_y = $pdf_y + 8;
if (($i+1)%5 == 0) {
$pdf_y = $pdf_y + 7.5;
}

if ($pdf_y > 190) {
$pdf_x = $pdf_x + 60;
$pdf_y = 8;
}

}

if ($vars{'output_web'}) {

$WEB .= qq~<input type="hidden" name="output_web_cache_num1_$i" value="$num1[$i]">
<input type="hidden" name="output_web_cache_res_$i" value="$res[$i]">
~;

if ($vars{'app_input_multiple_questions_per_page'}) {

my ($BG,$is_correct);

my $PLA = "?";
if (ONO::IO->devstation) {
$PLA = $res[$i];
}

my $FIELD = qq~<input type="text" id="output_web_answer_${i}_id" name="output_web_answer_$i" value="$vars{"output_web_answer_$i"}"
maxlength="16" class="w50" style="width:75px" placeholder="$PLA">~;

if ($vars{"output_web_answer_$i"} =~ /[A-Z0-9\.]/) {
$BG = " bg_red";
$stat_todo--;
if ($vars{"output_web_answer_$i"} eq $res[$i]) {
$BG = " bg_green";
$FIELD = qq~<div class="bold green">$res[$i]</div><input type="hidden" name="output_web_answer_$i" value="$vars{"output_web_answer_$i"}">~;
$stat_correct++;
$is_correct++;
} else {
$stat_wrong++;
$vars{'output_web_mistakes'}++;
}
}

if (!$is_correct && !$focus_on) {
$FIELD .= qq~<script>document.getElementById('output_web_answer_${i}_id').focus();</script>~;
$focus_on++;
}

$WEB .= qq~<tr class="bt bb$BG">
<td class="w80"></td>
<td class="tar">$num1[$i]</td>
<td class="pad10_2">=</td>
<td>$FIELD</td>
<td><div class="block32"></div></td>
</tr>
~;

}

if ($i == 9) {

$WEB .= ONO::FW::Apps::Core->multi_frame_split;

}

}

}

if ($vars{'output_web'}) {

$WEB .= ONO::FW::Apps::Core->multi_frame_end($vars{'output_web_finish'},$vars{'app_input_multiple_questions_per_page'});

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

if ($questions_per_page == 1) {

$WEB .= ONO::FW::Apps::Core->check_single(
qq~<td class="pad10_2 bold">$num1[0]</td><td class="pad10_2 bold">=</td>~,
"",
100,
16,
$BLK_ref,
\%vars,
"",
);

# if (ONO::IO->devstation) {
# $WEB .= qq~<div class="box_paper pad10_2 center">debug: $res[0]</div>~;
# }


} else {

$WEB .= ONO::FW::Apps::Core->check_multi($BLK_ref,$stat_todo+$stat_wrong,$page,$pages,"",\%vars);

}

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

}

}

if ($vars{'output_paper'} && $vars{'app_input_result_hints'}) {

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

my @block = ONO::FW::Apps::Core::Graphics->pdf_draw_result_hints_resblock(\@res,$y,$y+8);
ONO::FW::Apps::Core::Graphics->pdf_draw_result_hints($canvas,60,$y*47.5+2,55,40,2,5,\@block);

}

}

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->unique_copies_info($canvas,$copy,$vars_ref);
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++) {

if (!$vars{'app_input_result_hints'} || $c < 20 || $c > 39) {

my ($num1,$res,$pdf_x,$pdf_y,@pos) = split(/\^/,$corr_cache[$c]);

ONO::Lib::PDF::Draw->font('',12);
&fontadapt("",$num1);
ONO::Lib::PDF::Draw->text($canvas,$pdf_x+20, $pdf_y,$num1,"r");
ONO::Lib::PDF::Draw->font('',12);
ONO::Lib::PDF::Draw->text($canvas,$pdf_x+25, $pdf_y,"=","c");
&fontadapt("",$res);
ONO::Lib::PDF::Draw->text($canvas,$pdf_x+30, $pdf_y,$res);

}

}
}

}

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

if ($questions_per_page == 1) {

$stat_correct = $question_number-1;

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

} else {

$WEB = ONO::FW::Apps::Core->stats_replace($WEB,$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;

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

}

}

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

} else {

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

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

$WEB .= ONO::FW::Apps::Core->infopics(
"screen:320:50:50::roman_numerals_screenshot_1.jpg",
"sheet:168:180:110:15:roman_numerals_sheet_2.jpg",
"sheet:168:40:140:-10:roman_numerals_sheet_1.jpg",
);

$vars{'app_input_range_defaults'} = "1:10;1:20;1:50;1:100;1:500;1:1000;1:3999";

if (!$vars{'app_input_romdec'} && !$vars{'app_input_decrom'}) {
$vars{'app_input_romdec'}++;
$vars{'app_input_decrom'}++;
}

my $CONF .= ONO::FW::Apps::ToolBox->conf_input("range", $BLK_ref,\%vars,"",1,100,3999);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"","","romdec",$vars{'app_input_romdec'},"$txt[1] -> $txt[2]");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"","","decrom",$vars{'app_input_decrom'},"$txt[2] -> $txt[1]");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
if (!$vars{'output_web'} && !$vars{'output_paper'}) {
$CONF .= ONO::FW::Apps::ToolBox->conf_input("tip", $BLK_ref,\%vars,"",$txt[3]);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("txt", $BLK_ref,\%vars,"",$txt[4]);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("txt", $BLK_ref,\%vars,"",$txt[5]);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
}
$CONF .= ONO::FW::Apps::ToolBox->conf_input("resulthints", $BLK_ref,\%vars,"","S");

$WEB .= qq~<bgimage="/images/app_backgrounds/roman_nums_bg.jpg" alt="">~;

my $hide_convert = " hide";
my $hide_config;
if ($vars{'output_option_convert'}) {
$hide_convert = "";
$hide_config = "hide";
}

if ($vars{'query'} < 1 && $vars{'query'} !~ /(i|v|x|d|c|m)/i) {
$vars{'query'} = 1;
}

my $res = ONO::Lib::Data::Numbers::Roman->get($vars{'query'});

$WEB .= qq~<div id="roman_conf_box" class="$hide_config">~;
$WEB .= ONO::FW::Apps::Core->conf_box(
$db,
$community,
$app,
$form,
"",
$action_url,
$CONF,
$lang,
$BLK_ref,
\%vars,
"op-ncdi-CDI-lsu-NO-TL",
);

$WEB .= qq~</div>
<div id="roman_info_box" class="box_fabric abs w40 w80_800 hide" style="top:32px;left:32px" onclick="onojs_hide('roman_info_box');">
<a href="javascript:void(0);" onclick="onojs_hide('roman_info_box');"><img class="close" alt="close button"></a>
<h3 class="col6">$BLK{'Info'} / $BLK{'help'}</h3>
<div class="box_paper">
<table class="default_table">
<tr class="vtop">
<td class="large" style="line-height:150%">I<br>II<br>III<br>IV<br>V<br>VI<br>VII<br>VIII<br>IX<br>X</td>
<td class="large w33 colc" style="line-height:150%">1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10</td>
<td class="large" style="line-height:150%">XI<br>XII<br>XIII<br>XIV<br>XV<br>XVI<br>XVII<br>XVIII<br>XIX<br>XX</td>
<td class="large w33 colc" style="line-height:150%">11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20</td>
<td class="large" style="line-height:150%">L<br>C<br>D<br>M</td>
<td class="large w33 colc" style="line-height:150%">50<br>100<br>500<br>1000</td>
</tr>
</table>
</div>
</div>
<div id="roman_conv_box" class="box_fabric abs w40 w80_800$hide_convert" style="top:32px;left:32px">
<a href="javascript:void(0);" onclick="onojs_hide('roman_conv_box');onojs_block('roman_conf_box');"><img class="close" alt="close button"></a>
<h3 class="col6">$BLK{'Convert'}</h3>
<div class="box_paper">
<$form>
<input type="hidden" name="output_option_convert" value="1">
<div class="bg_fabric p10 xlarge center bt bb mt20 mb20">$res</div>
<table class="wide_table auto">
<tr>
<td class="w100"><input type="text" name="query" value="$vars{'query'}" class="w90" style="text-align:center" maxlength="16"></td>
<td><input type="submit" name="$BLK{'convert'}" value="$BLK{'convert'}" class="button_green"></td>
</tr>
</table>
</form>
</div>
</div>
~;

if (!$vars{'exercise'}) {
$WEB .= qq~<div class="cole">~;
$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'}),
);
$WEB .= qq~</div>~;
}

}

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

if (length $_[1] > 6) {
ONO::Lib::PDF::Draw->font('',11);
}
if (length $_[1] > 7) {
ONO::Lib::PDF::Draw->font('',10);
}
if (length $_[1] > 8) {
ONO::Lib::PDF::Draw->font('',9);
}
if (length $_[1] > 9) {
ONO::Lib::PDF::Draw->font('',8);
}

}

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

1;

__END__