package keyboard;

use diagnostics;
use strict;

#-######################################################################################
#- misc imports
#-######################################################################################
use common qw(:common :system :file);
use run_program;
use install_any;
use log;
use c;


#-######################################################################################
#- Globals
#-######################################################################################
my $KMAP_MAGIC = 0x8B39C07F;

my %lang2keyboard =
(
  "en" => "us",
);

#- key = extension for Xmodmap file, [0] = description of the keyboard,
#- [1] = name for loadkeys, [2] = name for XKB
my %keyboards = (
#- armenian xmodmap have to be checked...
#- "am" => [ __("Armenian"),       "am-armscii8",  "am" ],
 "be" => [ __("Belgian"),        "be-latin1",   "be" ],
 "bg" => [ __("Bulgarian"),      "bg",          "bg" ],
#- TO CHECK CHANGED AS NEXT ONE "cz" => [ __("Czech"),          "cz-latin2",   "czsk" ],
 "cz" => [ __("Czech"),          "cz-lat2",     "czsk" ],
 "de" => [ __("German"),         "de-latin1",   "de" ],
 "dk" => [ __("Danish"),         "dk-latin1",   "dk" ],
 "dvorak" => [ __("Dvorak"),     "dvorak",      "dvorak" ],
#- TO CHECK "ee" => [ __("Estonian"),       "ee-latin9",   "ee" ],
#- TO CHECK CHANGED AS NEXT ONE "es" => [ __("Spanish"),        "es-latin1",   "es" ],
 "es" => [ __("Spanish"),        "es",          "es" ],
 "fi" => [ __("Finnish"),        "fi-latin1",   "fi" ],
 "fr" => [ __("French"),         "fr-latin1",   "fr" ],
#- georgian keyboards have to be written...
#-"ge_ru"=>[__("Georgian (\"Russian\" layout)","ge_ru-georgian_academy","ge_ru"],
#-"ge_la"=>[__("Georgian ("\Latin\" layout)","ge_la-georgian_academy","ge_la"],
#- TO CHECK CHANGED AS NEXT ONE "gr" => [ __("Greek"),          "gr-8859_7",   "gr" ],
 "gr" => [ __("Greek"),          "gr",          "gr" ],
#- TO CHECK CHANGED AS NEXT ONE "hu" => [ __("Hungarian"),      "hu-latin2",   "hu" ],
 "hu" => [ __("Hungarian"),      "hu",          "hu" ],
#- TO CHECK CHANGED AS NEXT ONE "il" => [ __("Israeli"),        "il-8859_8",   "il" ],
 "il" => [ __("Israeli"),        "hebrew",      "il" ],
 "is" => [ __("Icelandic"),      "is-latin1",   "is" ],
#- TO CHECK CHANGED AS NEXT ONE "it" => [ __("Italian"),        "it-latin1",   "it" ],
 "it" => [ __("Italian"),        "it",   "it" ],
 "la" => [ __("Latin American"), "la-latin1",   "la" ],
#- TO CHECK CHANGED AS NEXT ONE "nl" => [ __("Dutch"),          "nl-latin1",   "nl" ],
 "nl" => [ __("Dutch"),          "nl",          "nl" ],
#- TO CHECK "lt" => [ __("Lithuanian AZERTY"), "lta-latin7", "lt" ],
#- TO CHECK "lt_b" => [ __("Lithuanian \"number row\" QWERTY"), "ltb-latin7", "lt_b" ],
#- TO CHECK "lt_p" => [ __("Lithuanian \"phonetic\" QWERTY"), "ltp-latin7", "lt_p" ],
 "no" => [ __("Norwegian"),      "no-latin1",   "no" ],
#- TO CHECK CHANGED AS NEXT ONE "pl" => [ __("Polish"),         "pl-latin2",   "pl" ],
 "pl" => [ __("Polish"),         "pl",   "pl" ],
 "pt" => [ __("Portuguese"),     "pt-latin1",   "pt" ],
#- TO CHECK "qc" => [ __("Canadian (Quebec)"), "qc-latin1","ca_enhanced" ],
#- TO CHECK CHANGED AS NEXT ONE "ru" => [ __("Russian"),        "ru-koi8",     "ru" ],
 "ru" => [ __("Russian"),        "ru",          "ru" ],
 "se" => [ __("Swedish"),        "se-latin1",   "se_SE" ],
#- TO CHECK CHANGED AS NEXT ONE "sf" => [ __("Swiss (French layout)"), "sf-latin1", "fr_CH" ],
 "sf" => [ __("Swiss (French layout)"), "fr_CH-latin1", "fr_CH" ],
 "sg" => [ __("Swiss (German layout)"), "sg-latin1", "de_CH" ],
#- TO CHECK "si" => [ __("Slovenian"),      "si-latin1",   "si" ],
#- TO CHECK "sk" => [ __("Slovakian"),      "sk-latin2",   "czsk" ],
#- the xmodmap.th has to be fixed to use tis620 keymaps
#- "th" => [ __("Thai keyboard"),  "th",          "th" ],
 "tr_f"  => [ __("Turkish (traditional \"F\" model)"), "tr_f-latin5", "tr_f" ],
 "tr_q" => [ __("Turkish (modern \"Q\" model)"), "tr_q-latin5", "tr_q" ],
#- TO CHECK CHANGED AS NEXT ONE "uk" => [ __("UK keyboard"),    "uk-latin1",           "gb" ],
 "uk" => [ __("UK keyboard"),    "uk",           "gb" ],
#- TO CHECK CHANGED AS NEXT ONE "us" => [ __("US keyboard"),    "us-latin",           "us_intl" ],
 "us" => [ __("US keyboard"),    "us",           "us_intl" ],
#- TO CHECK "yu" => [ __("Yugoslavian (latin layout)"), "yu-latin2", "yu" ],
);

#-######################################################################################
#- Functions
#-######################################################################################
sub list { map { $_->[0] } values %keyboards }
sub xmodmaps { keys %keyboards }
sub keyboard2text { $keyboards{$_[0]} && $keyboards{$_[0]}[0] }
sub keyboard2xkb { $keyboards{$_[0]} && $keyboards{$_[0]}[2] }
sub text2keyboard {
    my ($t) = @_;
    while (my ($k, $v) = each %keyboards) {
        lc($v->[0]) eq lc($t) and return $k;
    }
    die "unknown keyboard $t";
}

sub kmap($) {
    my ($keyboard) = @_;
    ($keyboards{$keyboard} || [])->[1];
}

sub lang2keyboard($) {
    local ($_) = @_;
    $keyboards{$_} && $_ || $lang2keyboard{$_} || substr($_, 0, 2);
}

sub load($) {
    my ($keymap) = @_;

    my ($magic, @keymaps) = unpack "I i" . c::MAX_NR_KEYMAPS() . "a*", $keymap;
    $keymap = pop @keymaps;

    $magic != $KMAP_MAGIC and die "failed to read kmap magic";

    local *F;
    sysopen F, "/dev/console", 2 or die "failed to open /dev/console: $!";

    my $count = 0;
    foreach (0 .. c::MAX_NR_KEYMAPS() - 1) {
	$keymaps[$_] or next;

	my @keymap = unpack "s" . c::NR_KEYS() . "a*", $keymap;
	$keymap = pop @keymap;

	my $key = -1;
	foreach my $value (@keymap) {
	    $key++;
	    c::KTYP($value) != c::KT_SPEC() or next;
	    ioctl(F, c::KDSKBENT(), pack("CCS", $_, $key, $value)) or die "keymap ioctl failed ($_ $key $value): $!";
	 }
	$count++;
    }
    log::l("loaded $count keymap tables");
}

sub setup($) {
    my ($keyboard) = @_;
    my $o = $keyboards{$keyboard} or return;

    if (my $file = install_any::install_cpio("/usr/share/keymaps", "$o->[1].kmap")) {
	log::l("loading keymap $o->[1]");
	load(cat_($file)) if -e $file;
    }
    if (my $file = install_any::install_cpio("/usr/share/xmodmap", "xmodmap.$keyboard")) {
	eval { run_program::run('xmodmap', $file) } unless $::testing;
    }
}

sub write($$) {
    my ($prefix, $keyboard) = @_;

    setVarsInSh("$prefix/etc/sysconfig/keyboard", { KEYTABLE => kmap($keyboard) });

    run_program::rooted($prefix, "dumpkeys > /etc/sysconfig/console/default.kmap") or die "dumpkeys failed";
}

sub read($) {
    my ($prefix) = @_;

    my %keyf = getVarsFromSh("$prefix/etc/sysconfig/keyboard");
    map { kmap($_) eq $keyf{KEYTABLE} ? $_ : (); } keys %keyboards;
}

#-######################################################################################
#- Wonderful perl :(
#-######################################################################################
1;