ONO::FW::Edu::Apps::Modules::LangTrainer

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

use ONO::Lib::Encoding::HTML;

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

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

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

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

use ONO::DB;
use ONO::Lib::SQL::TableCreate;
use ONO::Lib::Basic;
use ONO::Lib::Lang::ToolBox;
use ONO::Lib::Data::Letters;
use ONO::Lib::Audio::Speech;

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 $MODE = $ENV{'SCRIPT_NAME'};
$MODE =~ s~^(.*)/apps/lang_trainer_~~;
$MODE =~ s~\.pl$~~;

# backwards compatibility with V1...
if ($MODE eq "copyword" || $ENV{'SCRIPT_NAME'} =~ m~/lang_trainer.pl~) {
$MODE = "copywords";
}

if (ONO::IO->devstation && $MODE eq "/cgi-bin/local/perl/school/apps/_build") {
# $MODE = "copywords";
# $MODE = "remember";
# $MODE = "writewords";
# $MODE = "scrambled";
# $MODE = "findwords";
# $MODE = "sentences";
# $MODE = "imgwords";
# $MODE = "cutpaste";
# $MODE = "rightwrong";
# $MODE = "dictation";
}

my $app = $MODE;

my $WEB;

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

my $NAME = ucfirst $BLK{$app};

my @NAMES = &app_opts_names("",$lang);

if ($vars{'output_paper'}) {

if ($MODE eq "copywords") {
$NAME = ucfirst $NAMES[0];
}
if ($MODE eq "remember") {
$NAME = ucfirst $NAMES[1];
}
if ($MODE eq "writewords") {
$NAME = ucfirst $NAMES[2];
}
if ($MODE eq "findwords") {
$NAME = ucfirst $NAMES[3];
}
if ($MODE eq "sentences") {
$NAME = ucfirst $NAMES[4];
}
if ($MODE eq "imgwords") {
$NAME = ucfirst $NAMES[5];
}
if ($MODE eq "scrambled") {
$NAME = ucfirst $NAMES[6];
}
if ($MODE eq "cutpaste") {
$NAME = ucfirst $NAMES[7];
}
if ($MODE eq "rightwrong") {
$NAME = ucfirst $NAMES[8];
}
if ($MODE eq "dictation") {
$NAME = ucfirst $NAMES[9];
}

}

# run in the new 2024 mode (block numbers + new style)

my $MODE24;

if (ONO::IO->devstation && $MODE =~ /(copywords)/) {

$MODE24 = 1;

}

#

$vars{'onojs_fw_edu_pdf_app_url'} = $MODE;
$vars{'app_input_print_options_title_default'} = $NAME;

#

my @txt = (
"display images",
"Try to remember the following:",
"Write the word or sentence you remember:",
"display words (allow to copy)",
"scrambled letters are uppercase",
"word suggestions or images per sentence",

"lines per sentence",
"This was not correct, please try again!",
"article is required",
"words disappear after",
);
if ($lang eq "de") {
@txt = (
"Bilder anzeigen",
"Versuche, dir Folgendes zu merken:",
"Schreibe das Wort oder den Satz, an den du dich erinnerst:",
"Wörter anzeigen (abschreiben zulassen)",
"Verwürfelte Buchstaben sind Großbuchstaben",
"Wortvorschläge oder Bilder pro Satz",

"Zeilen pro Satz",
"Das war nicht richtig, probiere nochmals!",
"Artikel obligatorisch",
"Wörter verschwinden nach",
);
}

if ($lang eq "lu") {
@txt = (
"Biller uweisen",
"Probéier, dat hei ze verhalen:",
"Schreif d'Wuert oder de Saz, wou s du dech erënners:",
"Wierder uweisen (ofschreiwen ass erlaabt)",
"Verwürfelt Buschtawe si grouss",
"Wuertvirschléi oder Biller pro Saz",

"Zeile pro Saz",
"Dat war net richteg, probéier nach eng Kéier!",
"Artikel obligatoresch",
"Wierder verschwanne no",
);
}

if ($lang eq "fr") {
@txt = (
"afficher des images",
"Essayez de mémoriser ce qui suit:",
"Écrivez le mot ou la phrase dont vous vous souvenez:",
"afficher les mots (autoriser à copier)",
"lettres brouillées en majuscules",
"suggestions de mots ou d'images par phrase",

"lignes par phrase",
"Ce n'était pas correct, veuillez réessayer!",
"article obligatoire",
"mots disparaissent après",
);
}

#

my $total_pix = ONO::FW::Apps::Core::Lang->total_pix();

my $mz_font_multiplier = 1.8;

if (ONO::IO->devstation) {
$vars{'username'} = "jos";
}
if (ONO::FW::Apps::Core->running(\%vars,$db) && ($vars{'output_web'} || $vars{'output_paper'})) {
$vars{'wordlist_force_loading'} = 1;
}

if ($vars{'app_input_display_images'}) {
$vars{'app_input_langs_lang_2'} = "img";
}

if ($MODE eq "writewords") {
$vars{'wordlist_require_images'} = 1;
}
if ($MODE eq "dictation") {
$vars{'wordlist_require_audio'} = 1;
}

my (
$RETURN,$WORDLIST_ref,$TRANS_ref,$IMGS_ref,
$USE_GROUPS,$USE_GROUPS_ALT,$USE_GROUPS_LU,$USE_GROUPS_CUSTOM_ref,
$CACHE_WORDS,$CACHE_TRANS,$CACHE_IMGS,
$use_language1,$use_language2,
$use_images,$use_images_reverse,$use_images_forced,$use_custom_groups,$use_lu,
$get_words,$words_found,$multi_frame_custom_width,$hide_flags
) = ONO::FW::Apps::Core::Lang->lang_load_wordlist($db,$community,\%vars);

if (ONO::IO->devstation) {
$WEB .= $RETURN;
}

my @WORDLIST = @$WORDLIST_ref;
my @TRANS = @$TRANS_ref;
my @IMGS = @$IMGS_ref,
my @USE_GROUPS_CUSTOM = @$USE_GROUPS_CUSTOM_ref;

$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) && $words_found) {

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

if ($vars{'output_worksheet_maker'}) {

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

}

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

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

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

if (($MODE eq "rightwrong") && ($vars{'output_web_mc_continue'} || $vars{'output_web_continue_key'} || $vars{'output_web_continue_key_mistake'})) {
$vars{'output_web_question_number'}++;
}
if ($vars{'output_web_continue_key_mistake'}) {
$vars{'output_web_mistakes'}++;
}

foreach my $key (keys %vars) {
if ($key =~ /answer/) {
$vars{$key} =~ s~\s\s+~ ~g;
$vars{$key} =~ s~^ ~~;
$vars{$key} =~ s~ $~~;
}
}

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

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

if ($vars{'app_input_number_of_questions'} > $words_found) {
$vars{'app_input_number_of_questions'} = $words_found;
}

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

my $questions_per_page = 1;

if ($MODE eq "findwords") {
@letters_lc = ONO::Lib::Data::Letters->get_lc();
@letters_uc = ONO::Lib::Data::Letters->get_uc();
}

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 = 20;

if ($MODE eq "copywords") {
$questions_per_page = 10;
if ($MODE24) {
$questions_per_page = 8;
}
}

if ($MODE eq "scrambled") {
$questions_per_page = 10;
if (!$use_images) {
$questions_per_page = 16;
}
}

if ($MODE eq "writewords") {
$questions_per_page = 10;
if ($vars{'app_input_display_words'}) {
$questions_per_page = 8;
}
}

if ($MODE eq "findwords") {
$questions_per_page = 10;
}

if ($MODE eq "imgwords" || $MODE eq "cutpaste") {
$questions_per_page = $vars{'app_input_number_of_questions_status'};
}

}

if ($vars{'output_web'}) {
if ($vars{'app_input_multiple_questions_per_page'}) {
$questions_per_page = 20;
}
if ($vars{'app_input_display_words'}) {
$questions_per_page = 10;
}
if ($MODE eq "findwords" && $questions_per_page > 10) {
$questions_per_page = 10;
}
if ($MODE eq "scrambled" && $questions_per_page > 10) {
$questions_per_page = 10;
}
}

if ($vars{'app_input_select_sentences'}) {
$questions_per_page = $vars{'app_input_select_sentences'};
}

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

my (@que,@res,@ans,@corr_cache,@WORDLIST_RESCRAM);

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);
if ($MODE24) {
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 ($copy > 1) {
@WORDLIST = ONO::Lib::Basic->randomize_array(@WORDLIST);
}

}

if ($MODE eq "imgwords" || $MODE eq "cutpaste" || $MODE eq "rightwrong") {

my $iterations = $questions_per_page;
if ($MODE eq "rightwrong") {
$iterations = $words_found;
if ($iterations > 20) {
$iterations = 20;
}
}

for (my $w = 0; $w < $iterations; $w++) {

@WORDLIST_RESCRAM = (@WORDLIST_RESCRAM,$WORDLIST[$w]);
if (length $WORDLIST[$w] > $longest_word) {
$longest_word = length $WORDLIST[$w];
}
}
$longest_word = $longest_word-5;
@WORDLIST_RESCRAM = ONO::Lib::Basic->randomize_array(@WORDLIST_RESCRAM);
}

if ($vars{'output_web'}) {

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

$WEB .= qq~<$form>
<input type="hidden" name="output_web_cache_words" value="$CACHE_WORDS">
<input type="hidden" name="output_web_cache_trans" value="$CACHE_TRANS">
<input type="hidden" name="output_web_cache_imgs" value="$CACHE_IMGS">
~;

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 {

if ($vars{'app_input_multiple_questions_per_page'}) {

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

if (!$vars{'output_web_finish'}) {

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

if ($vars{'app_input_display_words'}) {

$WEB .= qq~<div class="inline w80 auto">
<div class="box_fabric mt20 mb10" style="padding-bottom:5px">
<div class="inline w100">###_WORD_HINTS_###</div>
</div>
</div>
~;

}

}

my $multi_frame_custom_width;

if ($MODE eq "scrambled" || $MODE eq "findwords") {
$multi_frame_custom_width = "w100";
}

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

$WEB .= qq~<div id="img_preview_box" class="box_black abs hide" style="top:10px;left:20px">
<div class="box_paper p0">
<img id="img_preview_img" class="block128 radius10" src="/ono/osr/images/spacer/trans.gif" alt="">
</div>
</div>
~;

my @WORD_HINTS;

if ($words_found < $questions_per_page) {
$questions_per_page = $words_found;
}

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

my ($img,$word) = split(/\^/,$WORDLIST[$i]);

if ($word) {

$stat_todo++;

my ($BG,$is_correct,$HINT,$alt_answer,$upper_answer);

my $display_word = $word;

if ($MODE eq "scrambled" || $MODE eq "findwords") {

($alt_answer,$upper_answer) = &scram_init("",$word,$vars{'app_input_display_uppercase'},$vars{'app_input_article_required'});

if ($MODE eq "findwords") {
if (!$vars{"output_web_cache_scram_$i"} || !$vars{"output_web_cache_scram_pre_$i"} || !$vars{"output_web_cache_scram_post_$i"}) {
my ($PRE,$POST);
($upper_answer,$PRE,$POST) = &scram_pre_post("",$upper_answer,$vars{'app_input_display_uppercase'},\@letters_lc,\@letters_uc);
$vars{"output_web_cache_scram_$i"} = $upper_answer;
$vars{"output_web_cache_scram_pre_$i"} = $PRE;
$vars{"output_web_cache_scram_post_$i"} = $POST;
}
$WEB .= qq~<input type="hidden" name="output_web_cache_scram_$i" value="$vars{"output_web_cache_scram_$i"}">
<input type="hidden" name="output_web_cache_scram_pre_$i" value="$vars{"output_web_cache_scram_pre_$i"}">
<input type="hidden" name="output_web_cache_scram_post_$i" value="$vars{"output_web_cache_scram_post_$i"}">
~;
$upper_answer = $vars{"output_web_cache_scram_$i"};
}

# the rest of the code follows below, AFTER the input check...

}

if ($MODE eq "dictation" && !$vars{'app_input_article_required'}) {
$alt_answer = ONO::Lib::Lang::ToolBox->remove_article($word);
}

if ($MODE eq "writewords") {
@WORD_HINTS = (@WORD_HINTS,$display_word);
$display_word = "";

}

my $PLA = "?";
if (ONO::IO->devstation) {
$PLA = $word;
}

my $FIELD = qq~<input type="text" id="output_web_answer_${i}_id" name="output_web_answer_$i" value="$vars{"output_web_answer_$i"}" class="w95" placeholder="$PLA">~;

if ($MODE eq "copywords" && $vars{'app_input_select_timer'}) {

my $timer = $vars{'app_input_select_timer'}*1000;
$timer = $timer - 1000 + int(rand(2))*1000;

$display_word = qq~<div id="display_word_${i}_div">$display_word</div>
<script>setTimeout(function(){onojs_gui_fx_fadeout('display_word_${i}_div',1,100,0);},$timer);</script>
~;

}

if ($vars{"output_web_answer_$i"} =~ /[A-Za-z0-9]/) {
$BG = " bg_red";
$stat_todo--;
if (&answer_is_correct("",$MODE,$word,$vars{"output_web_answer_$i"},$alt_answer)) {
$BG = " bg_green";
$FIELD = qq~<div class="bold green">$word</div><input type="hidden" name="output_web_answer_$i" value="$word">~;
$stat_correct++;
$is_correct++;
$vars{'correct_answer_list'} .= qq~:$word:~;
} 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++;
}

if ($MODE eq "scrambled" || $MODE eq "findwords") {

$display_word = &scram_display_word("",$MODE,$upper_answer,$is_correct,$vars{"output_web_cache_scram_pre_$i"},$vars{"output_web_cache_scram_post_$i"});

}

my $IMG;
if ($use_images) {
if (ONO::FW::Apps::Core::Lang->lang_image_validator($img)) {

my $IMG_URL = ONO::FW::Apps::Core::Lang->lang_image_url_generator($img,$vars{'username'},$community);

$IMG = qq~ <div class="bo radius5" onmouseover="onojs_block('img_preview_box');onojs_setsrc('img_preview_img','$BASE/$IMG_URL');"
onmouseout="onojs_hide('img_preview_box');">
<img class="block28 radius5" src="/$IMG_URL" alt="">
</div>
~;
}
$IMG = qq~ <td>$IMG</td>~;
}

if ($MODE eq "dictation") {
$display_word = ONO::Lib::Audio::Speech->speech_item($vars{'app_input_langs_lang_1'},$word,32);
$display_word = qq~<div class="fr">$display_word</div>~;
}

$WEB .= qq~<tr class="bt bb$BG">
<td class="w50 pad5_2 tar"><div class="lh125">$display_word</div></td>
$IMG
<td class="w50 pad5_2">$FIELD</td>
<td><div class="block32">$HINT</div></td>
</tr>
~;

my $splitter = 9;
if ($vars{'app_input_display_words'}) {
$splitter = 4;
}

if ($i == $splitter && $MODE ne "scrambled" && $MODE ne "findwords") {
$WEB .= ONO::FW::Apps::Core->multi_frame_split;
}

}

}

if ($vars{'app_input_display_words'}) {

my $LIST;

foreach my $hint (ONO::Lib::Basic->randomize_array(@WORD_HINTS)) {
my $color = "paper";
if ($vars{'correct_answer_list'} =~ /:$hint:/) {
$color = "green bold";
}

$LIST .= qq~<div class="box_$color p5 fl mr10 mb5"><div class="pad10_2">$hint</div></div>~;
}

$WEB =~ s~###_WORD_HINTS_###~$LIST~;

}

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

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

} else {

if ($vars{'app_input_allow_hints'}) {
$stats_switches .= "H";
}

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

my $use_question = $question_number-2;
if ($use_question < 1) {
$use_question = 0;
}

my ($img,$word) = split(/\^/,$WORDLIST[$use_question]);

if ($word) {

my ($CLASS,$TOP,$BOT,$IMG,$IMG_MB,$HINT,$hide1,$hide2,$switches,$alt_answer,$upper_answer,$is_wrong);

if ($MODE eq "scrambled" || $MODE eq "findwords") {

($alt_answer,$upper_answer) = &scram_init("",$word,$vars{'app_input_display_uppercase'},$vars{'app_input_article_required'});

if ($MODE eq "findwords") {
if (!$vars{"output_web_cache_scram"} || !$vars{"output_web_cache_scram_pre"} || !$vars{"output_web_cache_scram_post"} || $vars{'output_web_continue_key'}) {
my ($PRE,$POST);
($upper_answer,$PRE,$POST) = &scram_pre_post("",$upper_answer,$vars{'app_input_display_uppercase'},\@letters_lc,\@letters_uc);
$vars{"output_web_cache_scram"} = $upper_answer;
$vars{"output_web_cache_scram_pre"} = $PRE;
$vars{"output_web_cache_scram_post"} = $POST;
}
$WEB .= qq~<input type="hidden" name="output_web_cache_scram" value="$vars{"output_web_cache_scram"}">
<input type="hidden" name="output_web_cache_scram_pre" value="$vars{"output_web_cache_scram_pre"}">
<input type="hidden" name="output_web_cache_scram_post" value="$vars{"output_web_cache_scram_post"}">
~;
$upper_answer = $vars{"output_web_cache_scram"};
}

}

if ($MODE eq "dictation" && !$vars{'app_input_article_required'}) {
$alt_answer = ONO::Lib::Lang::ToolBox->remove_article($word);
}

if ($vars{'output_web_answer'}) {
$vars{'output_web_answer_status'} = 2;
if (&answer_is_correct("",$MODE,$word,$vars{'output_web_answer'},$alt_answer)) {
$vars{'output_web_answer_status'} = 1;
} else {
$vars{'output_web_mistakes'}++;
}

$WEB .= ONO::IO->devprint(qq~$word VS $vars{'output_web_answer'} = $vars{'output_web_answer_status'}~);

}

my $display_word = $word;
my $IMG_SIZE = 150;
my $HIGH_PAD = "p20";

if ($MODE eq "writewords") {
if ($vars{'app_input_display_words'}) {
$IMG_SIZE = 100;
$HIGH_PAD = "p10";

my @ARRAY = ONO::Lib::Basic->array_limit(9,ONO::Lib::Basic->randomize_array(@WORDLIST));

my ($LIST,%used);

foreach my $item (ONO::Lib::Basic->randomize_array("\^$word",@ARRAY)) {
my @wp = split(/\^/,$item);
if ($wp[1] && !$used{$wp[1]}) {
$used{$wp[1]}++;
my $color = "paper";
if ($vars{'output_web_answer_status'} == 1 && $wp[1] eq $vars{'output_web_answer'}) {
$color = "green bold";
}
$LIST .= qq~<div class="box_$color p5 fl mr10 mb5"><div class="pad10_2">$wp[1]</div></div>~;
}
}

$WEB .= qq~<div class="inline w80 auto">
<div class="box_fabric mt20" style="padding-bottom:5px">
<div class="inline w100">$LIST</div>
</div>
</div>
~;

}
} else {
$IMG_MB = " mb15";
}

if ($MODE eq "writewords") {
$display_word = "";
$CLASS = "";
}

if ($MODE eq "scrambled" || $MODE eq "findwords") {

my $is_correct;
if ($vars{'output_web_answer_status'} == 1) {
$is_correct = 1;
}

$IMG_SIZE = 100;
$display_word = qq~<div class="inline auto">~;
$display_word .= &scram_display_word("",$MODE,$upper_answer,$is_correct,$vars{"output_web_cache_scram_pre"},$vars{"output_web_cache_scram_post"});
$display_word .= qq~</div>~;

}

if ($MODE eq "remember") {

$TOP = qq~<div class="mb10">$txt[1]</div>~;
$BOT = qq~<div class="inline auto rel" style="top:5px">
<a href="javascript:void('0');" onclick="onojs_hide('langtrainer_single_question');onojs_block('langtrainer_single_answer_field');onojs_focus('output_web_answer_id');"
class="button_green button_big mt10">$BLK{'ok'}!</a>
</div>
~;
$CLASS = "box_paper bold large";
$hide2 = "hide";
$switches .= "F";

if ($vars{'output_web_answer_status'}) {
$TOP = qq~<div class="mb10">$txt[7]</div>~;
$CLASS = "box_green green bold large";
$BOT = qq~<div class="inline w100 auto rel" style="top:2px">
<div class="box_red lightred bold large">$vars{'output_web_answer'}</div>
</div>
$BOT
~;
$vars{'output_web_answer'} = "";
if ($vars{'output_web_answer_status'} == 1) {
$TOP = qq~<div class="mb10">$BLK{'Correct'}!</div>~;
$BOT = qq~<div class="inline auto rel" style="top:5px">
<input type="submit" name="output_web_continue_key" value="$BLK{'continue'}..." class="button_green button_big mt10">
</div>
~;
} else {
$IMG_SIZE = 100;
}
}

}

if ($MODE eq "rightwrong") {
if (int(rand(100)) > 49) {
my ($whilecounter,$new_word);
while ($whilecounter < 256 && (!$new_word || $new_word eq $word)) {
$whilecounter++;
my @wp = split(/\^/,$WORDLIST_RESCRAM[int(rand($words_found))]);
$new_word = $wp[1];
}
if ($new_word && $word ne $new_word) {
$is_wrong = 1;
$display_word = $new_word;
}
}
}

if ($MODE eq "dictation") {
$display_word = ONO::Lib::Audio::Speech->speech_item($vars{'app_input_langs_lang_1'},$word,64);
$display_word = qq~<div class="abs" style="top:260px;left:426px">
<div class="inline auto"><div class="bg_paper bo block64 radius32"><div class="rel" style="top:-3px;left:6px">$display_word</div></div></div>
</div>
~;
}

if ($use_images && ONO::FW::Apps::Core::Lang->lang_image_validator($img)) {
my $IMG_URL = ONO::FW::Apps::Core::Lang->lang_image_url_generator($img,$vars{'username'},$community);
$IMG = qq~<div class="inline auto"><div class="bo radius10$IMG_MB"><img class="block$IMG_SIZE radius10" src="/$IMG_URL" alt=""></div></div>~;
}

if ($vars{'app_input_select_timer'}) {

my $timer = $vars{'app_input_select_timer'}*1000;

$display_word = qq~<div id="display_word_div">$display_word</div>
<script>setTimeout(function(){onojs_gui_fx_fadeout('display_word_div',1,100,0);},$timer);</script>
~;

}

$WEB .= qq~<div id="langtrainer_single_question" class="$hide1">
<div class="inline auto"><div class="box_highlight $HIGH_PAD xlarge center mt20 mb20" style="min-width:320px;max-width:640px">$TOP$IMG<div class="$CLASS">$display_word</div>$BOT</div></div>
</div>
<div id="langtrainer_single_answer_field" class="$hide2">
~;

if ($MODE eq "remember") {
my $IMG;
if (ONO::FW::Apps::Core::Lang->lang_image_validator($img)) {
my $IMG_URL = ONO::FW::Apps::Core::Lang->lang_image_url_generator($img,$vars{'username'},$community);
$IMG = qq~<div class="inline auto"><div class="bo radius10 mt10"><img class="block150 radius10" src="/$IMG_URL" alt=""></div></div>~;
}
$WEB .= qq~<div class="inline auto"><div class="box_highlight p20 xlarge center mt20 mb20" style="min-width:320px;max-width:640px">$txt[2]$IMG</div></div>~;
}

if ($MODE eq "rightwrong") {

$WEB .= ONO::FW::Apps::Core->check_rightwrong($is_wrong,$BLK_ref);

} else {

$WEB .= ONO::FW::Apps::Core->check_single(
"",
$HINT,
320,
int((length $word)*1.5),
$BLK_ref,
\%vars,
"CfM$switches",
);

}

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

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

}


}

}

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

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

}

if ($vars{'output_paper'}) {

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

my ($def_x,$def_y) = (0,0);
if ($use_images) {
($def_x,$def_y) = (1,5);
}
if ($MODE24) {
$def_x = $def_x + 5;
$def_y = $def_y + 5;
}
my ($pdf_x,$pdf_y) = ($def_x,$def_y);

my $text_pos_x = $pdf_x;

my $img_pos_x = $pdf_x-1;
my $img_size = 15;

my $line_start = 0;
my $line_end = 170;

my $offset = 9.5;

if ($MODE24) {
$offset = 12;
}

my $line = $vars{'app_input_writelines_status'};
my $size = $vars{'app_input_writelines_size'};

if ($line eq "") {
$line = "std";
}

my @custom_cache;

if (!$size) {
if ($line eq "std") {
$size = 9.5;
}
if ($line eq "box") {
$size = 7;
}
if ($line eq "grid") {
$size = 5;
}
if ($line eq "kid") {
$size = 10;
}
}

if ($line eq "kid") {
$offset = $size + 5;
$pdf_y = $def_y+int($size/4);
}

if ($MODE eq "copywords") {
$line_start = 50;
}

if ($MODE eq "scrambled") {
$line_start = 70;
if (!$use_images && $offset < 12) {
$offset = $offset + 2;
}
}

if ($MODE eq "writewords") {
if ($vars{'app_input_display_words'}) {
$pdf_y = 40;
ONO::Lib::PDF::Draw->rect($canvas,0,0,170,30,1,"","0:250:230:175",5);
@custom_cache = ONO::Lib::Basic->randomize_array(("42.5:8","85:8","127.5:8","56.6:16","113.3:16","42.5:24","85:24","127.5:24"));
}
}

if ($MODE eq "findwords") {
$line_start = 70;
if (!$use_images && $offset < 12) {
$offset = $offset + 2;
}
}

if ($use_images && $vars{'app_input_select_words'} < 2) {
$line_start = $line_start + 20;
$text_pos_x = $text_pos_x + 20;
if ($offset < $img_size+4) {
$offset = $img_size+4;
}
if ($MODE24) {
$offset = 21;
}
}

$def_y = $pdf_y;

$vars{'corr_cache_offset'} = $offset;

$vars{'corr_cache_line'} = $line;
$vars{'corr_cache_size'} = $size;

$vars{'corr_cache_line_start'} = $line_start;
$vars{'corr_cache_line_end'} = $line_end;

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

my ($img,$word) = split(/\^/,$WORDLIST[$i]);

$corr_cache[$i] = "$word\^$img\^";

$vars{"corr_cache_pos_y_$i"} = $pdf_y;
$vars{"corr_cache_answer_line_$i"} = "$line:$line_start:$line_end:$pdf_y:$size";

if ($use_images && ONO::FW::Apps::Core::Lang->lang_image_validator($img)) {

if ($MODE eq "sentences" && $pdf_y > 185-$img_size) {
$pdf_y = $def_y;
&new_pdf_page("",$BASE,$canvas,$format,$PDF_OPTS,$vars{'app_input_print_options_title'},$vars{'app_input_print_options_code'},$vars_ref,$MODE24);
}

if (($MODE eq "imgwords" || $MODE eq "cutpaste") && $vars{'app_input_number_of_questions_status'} > 10 && $i > ($vars{'app_input_number_of_questions_status'}/2)-1) {
if ($i == $vars{'app_input_number_of_questions_status'}/2) {
$pdf_y = $def_y;
}
$img_pos_x = 155;
if ($MODE eq "cutpaste") {
$img_pos_x = 85;
}
}

my ($mv_x,$mv_y,$mv_size);
if ($MODE eq "imgwords" || $MODE eq "cutpaste") {
$mv_size = 3;
$mv_y = -1;
if ($vars{'app_input_number_of_questions_status'} == 8 || $vars{'app_input_number_of_questions_status'} == 16) {
$mv_size = 7;
$mv_y = ($i*5)-1;
}
if ($vars{'app_input_number_of_questions_status'} > 10 && $i > ($vars{'app_input_number_of_questions_status'}/2)-1) {
$mv_x = $mv_x-3;
if ($vars{'app_input_number_of_questions_status'} == 8 || $vars{'app_input_number_of_questions_status'} == 16) {
$mv_x = $mv_x-4;
$mv_y = $mv_y-40;
}
}

if ($MODE eq "cutpaste") {
my $start_x = $img_pos_x+$mv_x+$mv_size+18;
my $end_x = 170;
if ($vars{'app_input_number_of_questions_status'} > 10 && $i < ($vars{'app_input_number_of_questions_status'}/2)) {
$end_x = 80;
} else {
$mv_x = $mv_x + 10;
$start_x = $start_x + 10;
}

my @coords = ($start_x,$pdf_y-$def_y+$mv_y+3,$end_x,$pdf_y+$img_size+$mv_size-4+$mv_y);
$vars{"cache_rect_$i"} = "$coords[0]:$coords[1]:$coords[2]:$coords[3]";

ONO::Lib::PDF::Draw->rect($canvas,$coords[0],$coords[1],$coords[2],$coords[3],1,"","0:240:240:220",2);
}
}

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

my ($use_img_x,$use_img_y,$use_img_s) = ($img_pos_x+$mv_x,$pdf_y-4+$mv_y,$img_size+$mv_size);


my $IMG_URL = ONO::FW::Apps::Core::Lang->lang_image_url_generator($img,$vars{'username'},$community);

ONO::Lib::PDF::Draw->image($canvas,$use_img_x,$use_img_y,$use_img_s,$use_img_s,$IMG_URL,1,2);

$vars{"corr_cache_image_$i"} = "$img:$use_img_x:$use_img_y:$use_img_s";

if ($vars{'app_input_select_words'} > 1) {

for (my $r = 0; $r < $vars{'app_input_select_words'}; $r++) {
my ($rand,$whilecounter);
while ($whilecounter < 256 && (!$rand || $rand == $i)){
$whilecounter++;
$rand = int(rand($words_found));
}
my ($rimg,$rword) = split(/\^/,$WORDLIST[$rand]);
my $IMG_URL = ONO::FW::Apps::Core::Lang->lang_image_url_generator($rimg,$vars{'username'},$community);
ONO::Lib::PDF::Draw->image($canvas,$img_pos_x+$r*20,$pdf_y-4,$img_size,$img_size,$IMG_URL,1,2);
}

$pdf_y = $pdf_y + $size * 1.75;

}

}

# the default text line

if ($MODE ne "scrambled" && $MODE ne "writewords" && $MODE ne "findwords" && $MODE ne "sentences" && $MODE ne "imgwords" && $MODE ne "cutpaste") {

my $text_fix_x;

if ($MODE eq "rightwrong") {

$text_fix_x = 5;
if ($i > 9) {
$text_fix_x = 6;
}

my $check_x = $pdf_x+$text_fix_x+11;

ONO::Lib::PDF::Draw->square($canvas,$check_x,$pdf_y,7,1,"0:0:0:0","0:240:240:220",2);

$vars{"cache_check_$i"} = "$check_x:$pdf_y";

if (int(rand(100)) > 49) {
my $whilecounter;
while ($whilecounter < 256 && (!$vars{"cache_wrong_$i"} || $vars{"cache_wrong_$i"} eq $word)) {
$whilecounter++;
my @wp = split(/\^/,$WORDLIST_RESCRAM[int(rand($words_found))]);
$vars{"cache_wrong_$i"} = $wp[1];
}
$vars{"cache_right_$i"} = $word;
$word = $vars{"cache_wrong_$i"};
}

}

$vars{"cache_text_pos_x_$i"} = $text_pos_x+$text_fix_x;
$vars{"cache_text_pos_y_$i"} = $pdf_y+5;

ONO::Lib::PDF::Draw->text($canvas,$text_pos_x+$text_fix_x,$pdf_y+5,$word);

}

if ($MODE eq "imgwords") {
my ($img2,$word2) = split(/\^/,$WORDLIST_RESCRAM[$i]);
my $use_y = $pdf_y;
if ($i > ($vars{'app_input_number_of_questions_status'}/2)-1) {
$use_y = $pdf_y+$size;
}
if ($vars{'app_input_number_of_questions_status'} > 10 && ($vars{'app_input_number_of_questions_status'} == 8 || $vars{'app_input_number_of_questions_status'} == 16)) {
$use_y = ($use_y * 1.25) + 1;
}

my $length = ONO::Lib::PDF::Draw->string_width($word2);

my $rand_off = int(rand(20))-10;
if ($i == 0 || $i == $vars{'app_input_number_of_questions_status'}-1) {
$rand_off = 0;
}

if ($word2 =~ /[A-Za-z]/) {
if ($vars{'app_input_number_of_questions_status'} < 11) {
$use_y = ($use_y/1.8)+50;
ONO::Lib::PDF::Draw->rect($canvas,160-$length,$use_y-$def_y,170,$use_y-$def_y+$size/1.3,1,"","0:240:240:220",2);
ONO::Lib::PDF::Draw->text($canvas,165,$use_y,$word2,"r");
} else {
ONO::Lib::PDF::Draw->rect($canvas,170/2-$length/2-5+$rand_off,$use_y-$def_y,170/2+$length/2+5+$rand_off,$use_y-$def_y+$size/1.3,1,"","0:240:240:220",2);
ONO::Lib::PDF::Draw->text($canvas,170/2+$rand_off,$use_y,$word2,"c");
}
}
}

# the default answer line

if ($MODE ne "remember" && $MODE ne "imgwords" && $MODE ne "cutpaste" && $MODE ne "rightwrong") {

&pdf_answer_line("",$canvas,$line,$line_start,$line_end,$pdf_y,$size);

if ($vars{'app_input_select_lines'} > 1) {
for (my $l = 0; $l < $vars{'app_input_select_lines'}-1; $l++) {
$pdf_y = $pdf_y + $size*1.5;

if ($pdf_y > 185) {
$pdf_y = $def_y;
&new_pdf_page("",$BASE,$canvas,$format,$PDF_OPTS,$vars{'app_input_print_options_title'},$vars{'app_input_print_options_code'},$vars_ref,$MODE24);
}

&pdf_answer_line("",$canvas,$line,$line_start,$line_end,$pdf_y,$size);

}
}

if ($vars{'app_input_select_words'} > 1) {
$pdf_y = $pdf_y + $size/2;
}

}

# special cases...

if ($MODE eq "scrambled" || $MODE eq "findwords") {

my ($alt_answer,$upper_answer) = &scram_init("",$word,$vars{'app_input_display_uppercase'},$vars{'app_input_article_required'});

if ($MODE eq "findwords") {

my ($PRE,$POST);
($upper_answer,$PRE,$POST) = &scram_pre_post("",$upper_answer,$vars{'app_input_display_uppercase'},\@letters_lc,\@letters_uc);

$vars{"umlaut_string_length_pre_$i"} = length $PRE;
$vars{"umlaut_string_length_post_$i"} = length $POST;

}

my $alt_length = ONO::Lib::Basic->umlaut_string_length($upper_answer);
$vars{"umlaut_string_length_$i"} = $alt_length;
my $alt_num;
my $move_pos = 8;
if ($alt_length > 8) {
$move_pos = 8/$alt_length*8;
$move_pos = substr($move_pos,0,5)
}
if ($move_pos < 3) {
$move_pos = 3;
}

foreach my $letter (&scram_array("",$upper_answer,$MODE)) {

my $main_pos = $text_pos_x+$alt_num*$move_pos+2;

$alt_num++;

ONO::Lib::PDF::Draw->rect($canvas,$main_pos-2.5,$pdf_y,$main_pos-2.5+$move_pos,$pdf_y+5+2.5);
ONO::Lib::PDF::Draw->text($canvas,$main_pos+($move_pos/2)-2.5,$pdf_y+5,$letter,"c");

$vars{"cache_scrambled_letter_${i}_$alt_num"} = "$main_pos:$move_pos:$pdf_y:$letter:";

}
}

if ($MODE eq "writewords") {
if ($vars{'app_input_display_words'}) {
my @pp = split(/:/,$custom_cache[$i]);
ONO::Lib::PDF::Draw->text($canvas,$pp[0],$pp[1],$word,"c");
}
}

#

$pdf_y = $pdf_y + $offset;

if ($MODE24) {
if ($i%2 != 0) {
$pdf_y = $pdf_y + 5.5;
}
}

if (ONO::IO->devstation) {
$WEB .= qq~pdf_y ($offset)<br>~;
}

if ($MODE eq "remember" || $MODE eq "rightwrong") {
if ($pdf_y > 185 && $i < 20) {
$pdf_y = $def_y;
$pdf_x = 85;
$img_pos_x = $pdf_x;
$text_pos_x = $pdf_x+20;
}
}

if ($pdf_y > 185 && $i < $questions_per_page-1 && $MODE ne "imgwords" && $MODE ne "cutpaste") {
$pdf_y = $def_y;
&new_pdf_page("",$BASE,$canvas,$format,$PDF_OPTS,$vars{'app_input_print_options_title'},$vars{'app_input_print_options_code'},$vars_ref,$MODE24);
}

}

if ($MODE eq "remember") {

&new_pdf_page("",$BASE,$canvas,$format,$PDF_OPTS,$vars{'app_input_print_options_title'},$vars{'app_input_print_options_code'},$vars_ref,$MODE24);

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

my $line_start_2 = 0;
my $line_end_2 = 80;
if ($i > 9) {
$line_start_2 = 85;
$line_end_2 = 165;
}

my @ip = split(/:/,$vars{"corr_cache_image_$i"});

if ($ip[0]) {

my $IMG_URL = ONO::FW::Apps::Core::Lang->lang_image_url_generator($ip[0],$vars{'username'},$community);
ONO::Lib::PDF::Draw->image($canvas,$ip[1],$ip[2]-4,$ip[3],$ip[3],$IMG_URL,1,2);

&pdf_answer_line("",$canvas,$line,$line_start_2+20,$line_end_2,$ip[2],$size);

} else {

&pdf_answer_line("",$canvas,$line,$line_start,$line_end_2,$ip[2],$size);

}

}

}

if ($MODE eq "cutpaste") {

&new_pdf_page("",$BASE,$canvas,$format,$PDF_OPTS,$vars{'app_input_print_options_title'},$vars{'app_input_print_options_code'},$vars_ref,$MODE24);

my $mz_offset;
my $line_size = $vars{'app_input_writelines_size'};

if ($line eq "kid") {

if (($vars{'app_input_number_of_questions_status'} == 16 || $vars{'app_input_number_of_questions_status'} == 20) && $longest_word > $line_size*0.75) {
$line_size = 140/$longest_word;
}

$mz_offset = $line_size*1.55-0.5;
ONO::Lib::PDF::Draw->font("MZ",$line_size*$mz_font_multiplier);
}

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

my @cp = split(/:/,$vars{"cache_rect_$i"});
my ($img2,$word2) = split(/\^/,$WORDLIST_RESCRAM[$i]);

my $line_y = $cp[1]+($cp[3]-$cp[1])/2-$line_size/3;

ONO::Lib::PDF::Draw->rect($canvas,$cp[0],$cp[1],$cp[2],$cp[3],1,"","0:240:240:220",2);

if ($line ne "kid") {
$line_y = $line_y - 2;
}

if ($vars{'app_input_writelines_status'} ne "box") {
&pdf_answer_line("",$canvas,$line,$cp[0]+5,$cp[2]-5,$line_y,$line_size);
}

if ($line ne "kid") {
$line_y = $line_y + 4;
}

ONO::Lib::PDF::Draw->text($canvas,$cp[0]+6,$line_y+$line_size*2-$mz_offset,"$word2");

}

}

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

ONO::FW::Apps::Core->headers($vars_ref,$format,"c");
ONO::FW::Apps::PDF->title($BLK{'Corrections'},$PDF_OPTS,$vars{'app_input_print_options_code'},$format);

if ($MODE24) {
ONO::FW::Apps::Core::Graphics->pdf_draw_item_numbers($canvas,-2,0,1,4,"CHV",$vars_ref);
}

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

if ($MODE eq "writewords") {
if ($vars{'app_input_display_words'}) {
ONO::Lib::PDF::Draw->rect($canvas,0,0,170,30,1,"","0:250:230:175",5);
}
}

my ($pdf_x,$pdf_y) = ($def_x,$def_y);

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

my ($word,$img) = split(/\^/,$corr_cache[$c]);

if ($use_images && ONO::FW::Apps::Core::Lang->lang_image_validator($img)) {

my @ip = split(/:/,$vars{"corr_cache_image_$c"});

my $IMG_URL = ONO::FW::Apps::Core::Lang->lang_image_url_generator($img,$vars{'username'},$community);

ONO::Lib::PDF::Draw->image($canvas,$ip[1],$ip[2],$ip[3],$ip[3],$IMG_URL,1,2);

}

my @al = split(/:/,$vars{"corr_cache_answer_line_$c"});

if (($MODE eq "scrambled" || $MODE eq "findwords") && $al[0] eq "std") {
$al[3]++;
}
if ($MODE ne "rightwrong") {
&pdf_answer_line("",$canvas,$al[0],$al[1],$al[2],$al[3],$al[4],"0:200:200:200");
}
if ($al[0] eq "kid") {
ONO::Lib::PDF::Draw->font("MZ",$al[4]*$mz_font_multiplier);
}

if ($MODE eq "scrambled" || $MODE eq "findwords") {
$text_pos_x = 92;
}

if ($MODE eq "rightwrong") {

my $color = "0:50:240:50";
if ($vars{"cache_wrong_$c"}) {
$color = "0:240:50:50";
$word = $vars{"cache_wrong_$c"};
ONO::Lib::PDF::Draw->text($canvas,$vars{"cache_text_pos_x_$c"},$vars{"cache_text_pos_y_$c"}+5,qq~-> $vars{"cache_right_$c"}~);
}

my @cp = split(/:/,$vars{"cache_check_$c"});
ONO::Lib::PDF::Draw->square($canvas,$cp[0],$cp[1],7,1,"0:0:0:0",$color,2);

}

if (!$vars{"cache_text_pos_x_$c"} && $al[1]) {
$vars{"cache_text_pos_x_$c"} = $al[1]+1;
}
if (!$vars{"cache_text_pos_y_$c"} && $al[3]) {
$vars{"cache_text_pos_y_$c"} = $al[3]+3;
if ($al[0] eq "kid") {
$vars{"cache_text_pos_y_$c"} = $al[3]+5;
}
}

ONO::Lib::PDF::Draw->text($canvas,$vars{"cache_text_pos_x_$c"},$vars{"cache_text_pos_y_$c"},$word);

if ($MODE eq "copywords") {
ONO::Lib::PDF::Draw->text($canvas,$vars{'corr_cache_line_start'}+5,$vars{"corr_cache_pos_y_$c"}+5,$word);
}

if ($MODE eq "writewords") {
if ($vars{'app_input_display_words'}) {
my @pp = split(/:/,$custom_cache[$c]);
ONO::Lib::PDF::Draw->text($canvas,$pp[0],$pp[1],$word,"c");
}
}

if ($al[0] eq "kid") {
ONO::Lib::PDF::Draw->font("H",12);
}

if ($MODE eq "scrambled" || $MODE eq "findwords") {

my $alt_answer = ONO::Lib::Lang::ToolBox->remove_article($word);

foreach (my $l = 0; $l < $vars{"umlaut_string_length_$c"}+1; $l++) {

my @cp = split(/:/,$vars{"cache_scrambled_letter_${c}_$l"});

if ($cp[0]) {

if ($MODE eq "scrambled") {
ONO::Lib::PDF::Draw->rect($canvas,$cp[0]-2.5,$cp[2],$cp[0]-2.5+$cp[1],$cp[2]+5+2.5);
}
if ($MODE eq "findwords") {
if ($l > $vars{"umlaut_string_length_pre_$c"} && $l < $vars{"umlaut_string_length_$c"}-$vars{"umlaut_string_length_post_$c"}+1) {
ONO::Lib::PDF::Draw->rect($canvas,$cp[0]-2.5,$cp[2],$cp[0]-2.5+$cp[1],$cp[2]+5+2.5,1,"","0:125:200:125");
} else {
ONO::Lib::PDF::Draw->rect($canvas,$cp[0]-2.5,$cp[2],$cp[0]-2.5+$cp[1],$cp[2]+5+2.5);
}
}

ONO::Lib::PDF::Draw->text($canvas,$cp[0]+($cp[1]/2)-2.5,$cp[2]+5,$cp[3],"c");

}

}
}

$pdf_y = $pdf_y + $vars{'corr_cache_offset'};

if ($pdf_y > 185 && $c < $questions_per_page-1 && $MODE ne "imgwords" && $MODE ne "rightwrong") {
$pdf_y = $def_y;
&new_pdf_page("",$BASE,$canvas,$format,$PDF_OPTS,$vars{'app_input_print_options_title'},$vars{'app_input_print_options_code'},$vars_ref,$MODE24);
}

}
}

}

}

if ($vars{'output_web'} && !$vars{'output_web_finish'}) {

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

$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'},
$vars{'output_web_hints'},
);

}

if ($vars{'output_paper'}) {

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

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


}

}

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

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

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;
if (ONO::IO->device eq "phone") {
$vars{'app_input_number_of_questions'} = 10;
}
# if ($MODE eq "scrambled" && $vars{'output_paper'}) {
# $vars{'app_input_number_of_questions'} = 10;
# }
}

if (!$vars{'output_web'} && !$vars{'output_print'}) {
$vars{'app_input_display_images'}++;
}

my (
$default_ref,$default_lessons,$all_lessons,$custom_lessons,$LU,
) = ONO::FW::Apps::Core::Lang->lang_default_setup_config(\%vars);
my @default = @$default_ref;
if ($MODE eq "dictation") {
$LU = "";
}

$vars{'software_base'} = $BASE;

my $CONF .= ONO::FW::Apps::ToolBox->conf_input("lang", $BLK_ref,\%vars,"ips","$default[0];en:de:fr$LU");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("selections", $BLK_ref,\%vars,"Nl",$BLK{'lists'},$default_lessons,$all_lessons,"$BLK{'Add_a_list'}::$custom_lessons");

if ($MODE eq "sentences") {
if ($vars{'output_paper'}) {
if (!$vars{'app_input_select_sentences'}) {
$vars{'app_input_select_sentences'} = 10;
}
$CONF .= ONO::FW::Apps::ToolBox->conf_input("select", $BLK_ref,\%vars,"","4;5;6;8;10;12;15;20",$BLK{'sentences'},$vars{'app_input_select_sentences'},"","sentences");
}
$CONF .= ONO::FW::Apps::ToolBox->conf_input("select", $BLK_ref,\%vars,"","1;2;3;4;5",$txt[5],$vars{'app_input_select_words'},"","words");
}

my $if_possible = $BLK{'if_possible'};
my $img_switches;
if ($MODE eq "writewords" || $MODE eq "imgwords" || $MODE eq "cutpaste" || $MODE eq "rightwrong") {
$img_switches .= "d";
$if_possible = $BLK{'required'};
$vars{'app_input_display_images'} = 1;
}

$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"S$img_switches","","display_images",$vars{'app_input_display_images'},"$txt[0] ($if_possible)");

if ($MODE eq "writewords") {
if (!$vars{'output_web'} && !$vars{'output_paper'}) {
$vars{'app_input_display_words'} = 1;
}
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"S","","display_words",$vars{'app_input_display_words'},$txt[3]);
}

if ($MODE eq "scrambled" || $MODE eq "findwords" || $MODE eq "dictation") {
if ($MODE eq "scrambled" || $MODE eq "findwords") {
if (!$vars{'output_web'} && !$vars{'output_paper'}) {
$vars{'app_input_display_uppercase'} = 1;
}
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"S","","display_uppercase",$vars{'app_input_display_uppercase'},$txt[4]);
}

my $art = "the";
if ($vars{'app_input_langs_lang_1'} eq "de" || (!$vars{'app_input_langs_lang_1'} && $vars{'app_lang'} eq "de")) {
$art = "der, die, das";
}
if ($vars{'app_input_langs_lang_1'} eq "fr" || (!$vars{'app_input_langs_lang_1'} && $vars{'app_lang'} eq "fr")) {
$art = "le, la, les";
}
if ($vars{'app_input_langs_lang_1'} eq "lu" || (!$vars{'app_input_langs_lang_1'} && $vars{'app_lang'} eq "lu")) {
$art = "den";
}
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"S","","article_required",$vars{'app_input_article_required'},"$txt[8] ($art, ...)");
}

$CONF .= ONO::FW::Apps::ToolBox->conf_input("difficulty", $BLK_ref,\%vars,"i",5,3);

if ($MODE ne "imgwords" && $MODE ne "rightwrong") {
if ($vars{'output_paper'}) {
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("writelines", $BLK_ref,\%vars,"");
if ($MODE eq "sentences") {
if (!$vars{'app_input_select_lines'}) {
$vars{'app_input_select_lines'} = 2;
}
$CONF .= ONO::FW::Apps::ToolBox->conf_input("select", $BLK_ref,\%vars,"","1;2;3;4;5",$txt[6],$vars{'app_input_select_lines'},"","lines");
}
}
}

if ($MODE eq "copywords") {

if ($vars{'output_web'}) {

my $TIMER;
for (my $i = 2; $i < 121; $i++) {
if ($i < 11 || ($i < 61 && $i%5 == 0) || ($i%10 == 0)) {
$TIMER .= qq~;$i=$txt[9] $i $BLK{'seconds'}~;
}
}

$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("select", $BLK_ref,\%vars,"","0=$BLK{'timer'}: $BLK{'off'}$TIMER","",$vars{'app_input_select_timer'},"","timer");

} else {

$CONF .= qq~<input type="hidden" name="app_input_select_timer" value="$vars{'app_input_select_timer'}">~;

}

}

if ($MODE eq "imgwords" || $MODE eq "cutpaste") {

if (!$vars{'app_input_number_of_questions_status'}) {
$vars{'app_input_number_of_questions_status'} = 16;
}

$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars);
$CONF .= ONO::FW::Apps::ToolBox->conf_input("tabs", $BLK_ref,\%vars,"",$BLK{'words'},"number_of_questions","8:green:1 x 8;16:green:2 x 8;10:green:1 x 10;20:green:2 x 10");

}

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

my $BUTTONS = "op"; # online + print
my $PRINT = "ncd-CD"; # all printing options (n = number of copies, c = corrections, d = date)
my $MULTI = "NO"; # number of questions, one-by-one
my $LOADSTORE = "lsu"; # load, save, pdf
my $switches;

if ($MODE eq "copywords") {
$PRINT = "nd-D";
}

if ($MODE eq "remember") {
$PRINT = "nd-D";
$MULTI = "N";
}

if ($MODE eq "sentences" || $MODE eq "imgwords" || $MODE eq "cutpaste") {
$BUTTONS = "p";
$PRINT = "nd-D";
$LOADSTORE = "u";
}

if ($MODE eq "rightwrong") {
$MULTI = "N";
$switches .= "X";
}

if ($MODE eq "dictation") {
$BUTTONS = "o";
$PRINT = "";
$MULTI = "NO";
$LOADSTORE = "ls";
}

if ($MODE24) {
$PRINT .= "iI";
}

$WEB .= ONO::FW::Apps::Core->conf_box(
$db,
$community,
$app,
$form,
"",
$action_url,
$CONF,
$lang,
$BLK_ref,
\%vars,
"$BUTTONS-$PRINT-$LOADSTORE-$MULTI-$switches",
);

if (!$vars{'exercise'}) {

if ($MODE eq "dictation") {

$WEB .= ONO::FW::Apps::Core->infopics(
"screen:320:40:00::${MODE}_screenshot_1.jpg",
"screen:320:60:140::${MODE}_screenshot_2.jpg",
);

} else {

if ($BUTTONS eq "p") {

$WEB .= ONO::FW::Apps::Core->infopics(
"sheet:200:160:70:15:${MODE}_sheet_1.jpg",
"sheet:200:20:100:-10:${MODE}_sheet_2.jpg",
);
$WEB .= ONO::FW::Apps::Core->info_display(
ONO::FW::Apps::Core->info("info_indiv_diff", $vars{'app_lang'}),
);

} else {

$WEB .= ONO::FW::Apps::Core->infopics(
"screen:320:50:40::${MODE}_screenshot_1.jpg",
"sheet:168:180:120:15:${MODE}_sheet_1.jpg",
"sheet:168:40:150:-10:${MODE}_sheet_2.jpg",
);
$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 .= ONO::FW::Apps::Core->vardump($vars_ref);

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

}



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

my $VARIATION = ONO::FW::Edu::Apps::Variation->variation();
if ($community eq "school") {
$WEB = ONO::Lib::Encoding::HTML->encode($WEB);
}

return $WEB;

}

###################################################################
# subs
###################################################################

sub answer_is_correct {

my (
$self,
$MODE,
$word,
$answer,
$answer_alt,
) = @_;

my $answer_is_correct;

if ($MODE eq "copywords" || $MODE eq "writewords" || $MODE eq "remember") {
if ($word eq $answer) {
$answer_is_correct++;
}
}
if ($MODE eq "scrambled" || $MODE eq "findwords" || $MODE eq "dictation") {
if ($word eq $answer || ($answer_alt =~ /[A-Za-z]/ && $answer eq $answer_alt)) {
$answer_is_correct++;
}
}

return $answer_is_correct;

}

sub pdf_answer_line {

my (
$self,
$canvas,
$line,
$line_start,
$line_end,
$pdf_y,
$size,
$color,
) = @_;

if ($line eq "std") {
ONO::Lib::PDF::Draw->line($canvas, $line_start,$pdf_y+5, $line_end,$pdf_y+5);
}
if ($line eq "box") {
ONO::Lib::PDF::Draw->rect($canvas, $line_start,$pdf_y, $line_end,$pdf_y+$size);
}
if ($line eq "grid") {
ONO::Lib::PDF::Draw->grid($canvas, $line_start,$pdf_y, $line_end,$pdf_y+$size,$size,"","",1);
}
if ($line eq "kid") {
ONO::Lib::PDF::Draw->eduline($canvas, $line_start,$pdf_y+1-$size/4,$line_end,$size,"",$color);
}

}

sub scram_init {

my $alt_answer = ONO::Lib::Lang::ToolBox->remove_article($_[1]);
my $upper_answer = $alt_answer;
if ($_[2]) {
$upper_answer = ONO::Lib::Basic->umlaut_make_uppercase($alt_answer);
}
$alt_answer =~ s~ ~_~g;
$upper_answer =~ s~ ~_~g;

if ($_[3]) {
$alt_answer = "";
}

return ($alt_answer,$upper_answer);

}

sub scram_array {

my @array = ONO::Lib::Basic->umlaut_string_to_array($_[1]);
if ($_[2] eq "scrambled") {
@array = ONO::Lib::Basic->randomize_array(@array);
}

return @array;

}

sub scram_pre_post {

my (
$self,
$alt_answer,
$make_uc,
$letters_lc_ref,
$letters_uc_ref,
) = @_;

if ($make_uc) {
$letters_lc_ref = $letters_uc_ref;
}

my @letters_lc = @$letters_lc_ref;
my @letters_uc = @$letters_uc_ref;

$alt_answer =~ s~_~~g;
my $length_ini = length $alt_answer;
my $length_add = 1+int(rand($length_ini));
my $length_off = 1+int(rand($length_add));
my ($PRE,$POST);

for (my $p = 0; $p < $length_off+1; $p++) {
if (length $PRE < 4) {
if ($alt_answer =~ /[A-Z]/ && int(rand(10)) > 5) {
$PRE .= $letters_uc[int(rand(25))];
} else {
$PRE .= $letters_lc[int(rand(25))];
}
}
}
for (my $p = 0; $p < ($length_ini-$length_off)+1; $p++) {
if (length $POST < 4 && length "$PRE$alt_answer$POST" < 16) {
$POST .= $letters_lc[int(rand(25))];
}
}
if (!$PRE) {
$PRE = $letters_lc[int(rand(25))];
}
if (!$POST) {
$POST = $letters_lc[int(rand(25))];
}

return ("$PRE$alt_answer$POST",$PRE,$POST)

}

sub scram_display_word {

my (
$self,
$MODE,
$alt_answer,
$is_correct,
$pre,
$post,
) = @_;

my @array = &scram_array("",$alt_answer,$MODE);
my $array_len = @array;

my ($SCRAM,$scram_count,$make_green);

if ($is_correct) {
$make_green = length $pre;
}

foreach my $letter (@array) {

$scram_count++;
my $BG = "bg_paper";
if ($make_green && $scram_count > $make_green && $scram_count < ($array_len - length $post)+1) {
$BG = "bg_green bold green";
}
$SCRAM .= qq~<div class="bo pad5_2 fl $BG">$letter</div>~;

}

return qq~<div class="inline fr">$SCRAM</div>~;

}

sub new_pdf_page {

my (
$self,
$BASE,
$canvas,
$format,
$PDF_OPTS,
$title,
$code,
$vars_ref,
$MODE24,
) = @_;

ONO::FW::Apps::PDF->page("",$format);
ONO::FW::Apps::Core->headers($vars_ref,$format);
ONO::FW::Apps::PDF->title($title,$PDF_OPTS,$code,$format);
if ($MODE24) {
ONO::FW::Apps::Core::Graphics->pdf_draw_item_numbers($canvas,-2,0,1,4,"HV",$vars_ref);
}
# ONO::Lib::PDF::ToolBox->canvas_test($canvas);

}

sub app_opts {

return (
"copywords",
"remember",
"writewords",
"findwords",
"sentences",
"imgwords",
"scrambled",
"cutpaste",
"rightwrong",
);

}

sub app_opts_names {

my @NAMES = (
"Copy words",
"Memorize words",
"Write words",
"Find words",
"Write sentences",
"Link words and images",

"Scrambled words",
"Cut and paste",
"Right or wrong?",
"Dictation",
);

if ($_[1] eq "de") {
@NAMES = (
"Wörter abschreiben",
"Wörter verhalten",
"Wörter schreiben",
"Wörter finden",
"Schreibe Sätze",
"Verbinde Wort und Bild",

"Buchstaben-Salat",
"Ausschneiden und kleben",
"Richtig oder falsch?",
"Diktat",
);
}
if ($_[1] eq "lu") {
@NAMES = (
"Wierder ofschreiwen",
"Wierder verhalen",
"Wierder schreiwen",
"Wierder fannen",
"Sätz schreiwen",
"Wuert mat Bild verbannen",

"Buschstawen-Zalot",
"Ausschneiden a pechen",
"Richteg oder falsch?",
"Diktat",
);
}
if ($_[1] eq "fr") {
@NAMES = (
"Copier les mots",
"Se souvenir des mots",
"Ecrire les mots",
"Trouver les mots",
"Écrire des phrases",
"Relier",

"Mots en désordre",
"Couper et coller",
"Vrai ou faux?",
"Dictée",
);
}

return @NAMES;

}

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

1;

__END__