#!/usr/local/bin/oraperl 
#
# Copyright (C) 1992 by Gustaf Neumann, Stefan Nusser
#
#      Wirtschaftsuniversitaet Wien,
#      Abteilung fuer Wirtschaftsinformatik
#      Augasse 2-6,
#      A-1090 Vienna, Austria
#      neumann@wu-wien.ac.at, nusser@wu-wien.ac.at
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted, provided
# that the above copyright notice appears in all copies and that both that
# copyright notice and this permission notice appear in all supporting
# documentation.  This software is provided "as is" without expressed or
# implied warranty.
#
# Date: Mon, Apr 13 1992
# Author: Gustaf Neumann
# Version: 0.92
#

%privOptions = (
	"b", "database: form 'userid/passwd\@T:host:oracleId",
	"a", "Applikation: Ablage oder Paper",
	"o", "ordner: z.B. Ein91",
	"O", "ordnerTable: eg. papordner",
	"v", ": verbs",
	);

$WafeLib = $ENV{'WAFELIB'} || "/usr/lib/X11/wafe";
require "$WafeLib/perl/wafe.pl";

$app= $opt_a || 'Paper';
$database = $opt_b || $wafeoraDB{$app};

if ($app eq 'Ablage') {

    $theTitle = 'Ablageverwaltung';
    $sqlTable =  'DOKUMENT';
    $standardOrdner = $opt_o || 'Ein91';
    $FOLDERNAME = 'ORDNER';
    $currentField = 1;

    $totalWidth = 530;
    $tWidth = 430;
    $lWidth = 95;
    $vTextWidth = 95;
    $gap = 70;
    $buttonStretch = 2;

    $lLongField = "width $lWidth left chainLeft right chainLeft";
    $tLongField  = "width $tWidth left chainLeft right chainRight";
    @longField = ('layout=hText', "latt=$lLongField", "tatt=$tLongField");

    @field = (
	  'D_NUMMER', 
	        join($;,'label=Dokumentnummer','type=autoid'),
	  'O_KURZ', 
	        join($;,'label=Ordner','type=folder'),
	  'NAME_ABSENDER', 
	        join($;,'label=Absender','maxLength=50','required=yes', @longField,
		     'vert=vertDistance 15'),
	  'NAME_EMPFAENGER', 
	        join($;,'label=Empfnger','maxLength=50','required=yes', @longField),
	  'ORGANISATION', 
	        join($;,'maxLength=50', @longField),
	  'ORT', 
	        join($;,'maxLength=50', @longField),
	  'BETREFF', 
	        join($;,'maxLength=255','lines=3','required=yes', @longField),
	  'DOK_DATUM', 
	        join($;,'label=Erstellt',"batt=width $vTextWidth", 'type=date',
		     'layout=vText', 'hor=fromHoriz lab-BETREFF'),
	  'EIN_DATUM', 
	        join($;,'label=Eingelangt',"batt=width $vTextWidth", 'type=date',
		     'layout=vText', "hor=horizDistance $gap"),
	  'ERF_DATUM', 
	        join($;,'label=Erfat',"batt=width $vTextWidth",'type=moddate',
		     'layout=vText', "hor=horizDistance $gap"),
	  'BEN_NUMMER', 
	        join($;,'type=owner'),
	      );	       
    $vertDistance = -20;
}
if ($app eq 'Paper') {

    $theTitle = 'Paper Base';
    $sqlTable =  'PAPER';
    $standardOrdner = $opt_o || 'DDB';
    $FOLDERNAME = 'PAPORDNER';
    $currentField = 1;

    $totalWidth = 555;
    $tWidth = 453;
    $lWidth = 95;
    $buttonStretch = 5;
    $vTextWidth = 118;
    $gap = 40;

    $lLongField = "width $lWidth left chainLeft right chainLeft";
    $tLongField  = "width $tWidth left chainLeft right chainRight ";
    @longField = ('layout=hText', "latt=$lLongField", "tatt=$tLongField");

    @field = (
	  'D_NUMMER', 
	        join($;,'label=Dokumentnummer','type=autoid'),
	  'O_KURZ', 
	        join($;,'label=Ordner','type=folder'),
	  'AUTOR', 
	        join($;,'label=Autoren','maxLength=70','required=yes', 'mv=,;',
		     @longField,
		     'normalize=name',   # currently only for mv-fields
		     'vert=vertDistance 15'),
	  'TITEL', 
	        join($;,'maxLength=255','lines=2','required=yes', @longField),
	  'KEYWORD', 
	        join($;,'label=Keywords','maxLength=70', 'mv=,;', @longField),
	  'BEMERKUNG', 
	        join($;,'maxLength=255','lines=2', @longField),
	  'EDITOR', 
	        join($;,'label=Herausgeber','maxLength=70', 'mv=,;', @longField,
                      'normalize=name', 'vert=vertDistance 15'),
	  'PUBLIN', 
	        join($;,'label=Erschienen in','maxLength=100', @longField),
	  'VERLAG', 
	        join($;,'maxLength=50',
		     'layout=hText', "latt=width $lWidth", "tatt=width $vTextWidth"),
	  'ORT', 
	        join($;,'maxLength=50',
		    'layout=hText', "tatt=width $vTextWidth", "latt=width $gap", 
	           "hor=fromHoriz VERLAG", "vert=fromVert PUBLIN"),
	  'JAHR', 
	        join($;,'label=Zeitp','maxLength=50',
		     'layout=hText', "tatt=width $vTextWidth", "latt=width $gap", 
		     'hor=fromHoriz ORT','vert=fromVert PUBLIN'),
	  'VOL', 
	        join($;,'maxLength=20',
		     'layout=vText', "batt=width $vTextWidth",
		     'vert=fromVert VERLAG', 'hor=fromHoriz lab-VERLAG'),
	  'SEITE', 
	        join($;,'maxLength=20',
		     'layout=vText', "batt=width $vTextWidth",
		     "hor=horizDistance ".($gap+8),'vert=fromVert VERLAG'),
	  'ERF_DATUM', 
	        join($;,'label=Erfat','type=moddate', 
		     'layout=vText', "batt=width $vTextWidth",
		     "hor=horizDistance ".($gap+8),'vert=fromVert VERLAG'),
	  'BEN_NUMMER', 
	        join($;,'type=owner'),
	      );	      
    $vertDistance = -7;

sub name {
    local($_) = @_;
    s/\\//g;
    s/([A-Z])\.\s+([A-Z])\./$1.$2./g;
    return "$3 $1" if /^((.\.\s*)+)\s+(.*)$/;
    return $_;
}
# print "<", &name("P. Chen"),">\n";
# print "<", &name("Bry F."),">\n";
# print "<", &name("W.C. Cheng"),">\n";
# print "<", &name('S.B.\ Navathe'),">\n";
# print "<", &name('R.\ Elmasri'),">\n";
# print "<", &name('S. B.\ Navathe'),">\n";
# print "<", &name('A Min Tjoa'),">\n";

$prettyPrint = 1;
sub pp {
    local($_,$string,$title,$abbrev,$ref,@aut);
    @aut = split(/[$_mv{'AUTOR'}]\s*/,$value{'AUTOR'});
    if (@aut > 1) {
	foreach (split(/[$_mv{'AUTOR'}]\s*/,$value{'AUTOR'})) {
	    $abbrev .= substr($_,0,1);
	}
    } else {$abbrev = substr($aut[$[],0,3);}
    $abbrev .= $2 if $value{'JAHR'} =~ /\D*(19)?(\d+)\D*/;
    ($ref = $abbrev) =~ tr/A-Z/a-z/;
    ($title = $value{'TITEL'}) =~ s/\\n/ /g;
    $string = "\\bibitem\[{$abbrev}\]\{$ref\}\n\t$value{'AUTOR'}:\n\t\\T{$title},\n\t";
    $string .= "in: " if $value{'EDITOR'} || $value{'PUBLIN'};
    $string .= "$value{'EDITOR'}: " if $value{'EDITOR'};
    $string .= "{\\em $value{'PUBLIN'}},\n\t" if $value{'PUBLIN'};
    $string .= "$value{'VERLAG'}, " if $value{'VERLAG'};
    $string .= "$value{'ORT'}, " if $value{'ORT'};
    $string .= "$value{'VOL'}, " if $value{'VOL'};
    $string .= "pp. $value{'SEITE'}, " if $value{'SEITE'};
    $string .= "$value{'JAHR'}" if $value{'JAHR'};
    return $string.".";
}
}

if ($app eq 'Ordner') {

    $theTitle = 'Ordnerverwaltung';
    $sqlTable =  $opt_O || 'PAPORDNER';
    $currentField = 0;
    $ordnerMode = 1;

    $totalWidth = 555;
    $tWidth = 443;
    $lWidth = 105;
    $buttonStretch = 5;
    $vTextWidth = 118;
    $gap = 40;

    $lLongField = "width $lWidth left chainLeft right chainLeft";
    $tLongField  = "width $tWidth left chainLeft right chainRight";
    @longField = ('layout=hText', "latt=$lLongField", "tatt=$tLongField");

    @field = (
	  'O_KURZ', 
	        join($;,'label=Kurzbezeichung', 'type=id','maxLength=10','required=yes',
	         "latt=width $lWidth"),
	  'O_LANG', 
	        join($;,'label=Inhalt','maxLength=30','required=yes', 
		     @longField),
	  'O_TYP', 
	        join($;,'label=Typ','maxLength=10', @longField),
	  'ABT_NUMMER', 
	        join($;,'label=Gruppe','maxLength=5','required=yes', @longField),
	  'BEN_NUMMER', 
	        join($;,'type=owner'),
	      );	       
    $vertDistance = -7;
}




for ($i=$[; $i<$#field; $i+=2) {
    local($f) = $field[$i];
    $index{$f} = @sqlField;
    push(@sqlField,$f);
    foreach(split($;, $field[$i+1])) {
	($attribute,$value) = ($1,$2) if m/([^=]+)=(.*)/; 
	$value="'$value'" if $value !~/^\d+\.?\d*$/;
#	print "\$_$attribute{'$f'} = $value\n";
	eval "\$_$attribute{'$f'} = $value\n";
    }
    if (!$_label{$f}) {
	($_label{$f} = $f) =~ tr/A-Z/a-z/;
	substr($_label{$f},0,1) = substr($f,0,1);
#	print "$f: <$_label{$f}>\n";
    }
    push(@mvOrder,$f) if $_mv{$f};
}

$dateFmt =  'DD.MM.YY';

($ID) = grep($_type{$_} =~ /id/,@sqlField);
($AUTOID) = grep($_type{$_} eq 'autoid',@sqlField);
($FOLDERFIELD) = grep($_type{$_} eq 'folder',@sqlField);

# $oraChar = '';
# $isoChar = '';


%ordnerTypLabel = (
		   "ein", "Eingang",
		   "aus", "Ausgang",
#		   "", "Umlauf",
		   "lok", "Umlauf",
		   );

#
# Benutzer, die entweder nicht im /etc/passwd z<u finden sind, und die
# generelle Vernderungsbefugnis besitzen
#

%ExtraBenutzer = (
           1205, join($;,"Gustaf Neumann","neumann",1),
           1233, join($;,"Robert Schischka","schisch",1), 
           1206, join($;,"Susanne Kremser","kremser",1),
           1219, join($;,"Lore Alkier","alkier",0),
           1348 ,join($;,"Yasmin Koenig","yasmin",1),
           1236, join($;,"Christopher Sima","sima",1), 
           1237, join($;,"Claudia Pohl","pohl",1), 
          20338,join($;,"Stefan Nusser","nusser",0),
             24,join($;,"Datenbernahme","root",0),
              2,join($;,"Mr Kernel","cray_machine",0),
	     );

$faceDir = $faceDir || "$WafeLib/faces";


$normalFont = 'font "-b&h-lucida-medium-r-*-*-12-*-*-*-*-*-*-*"';
$boldFont = 'font "-b&h-*-medium-i-*-*-12-*-*-*-*-*-*-*"';

$roColors .= " $normalFont";
$highLight .= " font -b&h-lucida-bold-r-*-*-12-*-*-*-*-*-*-*";

%extraResources = (
	'*Text', "$roColors displayCaret false $normalFont editType edit borderWidth 1",
	'*Label', "$boldFont $backGround borderWidth 0",
	'*List', $normalFont,
	'*Command', $backGround,
	'*MenuButton', $backGround,
);

sub benutzerNameBild {
    local($userId) = @_;
    return $ExtraBenutzer{$userId} ? 
	split($;,$ExtraBenutzer{$userId}) : ((getpwuid($userId))[6,0],0);
}

sub Info {
    &Xui("set lastInfo {$_[0]}");
    return &info($_[0]);
}

&wafe'setResources("",%textResources);
&wafe'setResources("",%extraResources);

($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
$today=sprintf("%02d.%02d.%02d",$mday,$mon+1,$year);

($aBenutzerName,$aBenutzerBild,$aBenutzerGuru) = &benutzerNameBild($<);
grep($userInGroup{$_}=1,split(/ /,$());


sub xSetup {
    local($left) = "left chainLeft right chainLeft";
    local($right) = "right chainRight left chainRight";
    local($growHoriz) = "left chainLeft right chainRight";
    local($tcl,$lastHor,$lastVert,$firstVert,$vert,$hor,%lastVert);

    $lastVert = 'vertDistance 10 fromVert line';

    if ($ID) {
	$lastHor = "fromHoriz $ID";
	$firstVert = $lastVert;
    }

    if ($FOLDERNAME) {
        $vertCorr = $threeD ?
	    ($lastVert =~ /vertDistance (\d+)/) && "$threeD vertDistance 7 $` $'" :
	    $lastVert;
	$tcl .= <<"FolderSetup";
MenuButton  OrdnerB top label "Ordner:" $boldFont menuName Ordner \\
           horizDistance 15 $vertCorr $lastHor menuName OrdnerShell
	       action OrdnerB override {<Btn1Up>: exec(popdown OrdnerShell)}
	       action OrdnerB override {<Btn1Up>: exec(popdown OrdnerShell)}
TransientShell OrdnerShell OrdnerB 
List Ordner OrdnerShell $menueAtts borderWidth 1 

Text $FOLDERFIELD top width 92 string {$standardOrdner} \\
           fromHoriz OrdnerB $lastVert

Label EinAus top label {}   width 100  justify right \\
           horizDistance 409 $lastVert $right
FolderSetup
}


    foreach (@sqlField) {
        $lastVert{$_} = $lastVert; 
#	print "$_: lastHor <$lastHor> lastVert <$lastVert>\n";

	if (!$_layout{$_}) {
	    $lastHor = "fromHoriz $_";
	    $lastVert = "fromVert $_"; 
	}
	if ($_layout{$_} eq 'hText') {
	    $vert = ($_vert{$_} =~ /fromVert/ || !lastVert) ? "" : $lastVert;
	    $multiLine = $_lines{$_}>1 ? 
		"scrollVertical whenNeeded autoFill true height ".($_lines{$_}*15) : "";
	    $tcl .= "hTextField $_ {$vert $_vert{$_}} {$_hor{$_}} "
		."{label {$_label{$_}:} $_latt{$_} justify right} "
		    ."{$multiLine $_tatt{$_}}\n";
	    $tcl .= "action $_ override \"<Key>Return: newline()\"\n" if $_lines{$_}>1;
	    $lastVert = "fromVert $_"; $lastHor = ''; 
	}
	if ($_layout{$_} eq 'vText') {
	    $hor = ($_hor{$_} =~ /fromHoriz/ || !$lastHor)  ? "" : "fromHoriz $lastHor";
	    ($vert,$lastVert) = ($_vert{$_} =~ /fromVert\s+(\S+)/ || !$lastVert) 
		   ? ("","fromVert $1") : ($lastVert,$lastVert);
	    $tcl .= "vTextField $_ {$_batt{$_}} {$vert $_vert{$_}} {$hor $_hor{$_}} "
	    ."{label {$_label{$_}:} $_latt{$_}} {$_tatt{$_}}\n";
	    $lastHor = $_; 
	}
    }


    $tcl = "hTextField $ID {$firstVert} {} "
	." {label {$_label{$ID}:} $_latt{$ID} justify right} {}\n" . $tcl
	    if $ID;


#    print "TCL= <$tcl>\n";

    undef %_layout;
    undef %_hor;
    undef %_vert;
    undef %_latt;
    undef %_tatt;


    &UI(<<"End of Wafe");

set titleFont "-b&h-lucida-bold-r-*-*-18-*-*-*-p-*-iso8859-*"
set lastInfo ""

proc help {widget} {global helpText lastInfo; set lastInfo [gV info label]; \\
		sV info label \$helpText(\$widget)}

proc leaveHelp {} {global lastInfo; sV info label "\$lastInfo"} 

proc readHack {s w} {echo \$s \$w [multiLineContent \$w]}
proc eV {w l} {echo value \$l [multiLineContent \$w]}
proc backSpace {w} { \\
    XawTextGetSelectionPos \$w from to; \\
    if \$from!=\$to \\
        {callActionProc \$w {} kill-selection; XawTextSetSelection \$w \$from \$from } \\
        {callActionProc \$w {} delete-previous-character}; \\
}

proc multiLineContent {widget} {return [join [split [gV \$widget string] \\n] "\\\\n"] }

proc hTextField {name vert horiz largs targs} { \\ 
    eval Label lab-\$name top \$vert \$horiz \$largs; \\
    eval Text \$name top \$vert fromHoriz lab-\$name \$targs}

proc vTextField {name batt vert horiz largs targs} { \\ 
    eval Text \$name top \$batt \$vert \$horiz \$targs; \\
    eval Label lab-\$name top \$batt fromVert \$name \$horiz \$largs}

proc stdKnopf {name father a} {\\
      eval Command \$name \$father fromVert line2 vertDistance 10 \$a}

proc stdKnopfCB {name father args} {\\
      stdKnopf \$name \$father "\$args callback {echo %w}"}

set helptrans "#override \\n \\
                         <Enter>:  exec(help %w) highlight() \\n \\
                         <Leave>:  exec(leaveHelp) reset()"

set texttrans "#override \\n \\
     <Key>Delete:  exec(backSpace %w) \\n \\
     <Key>Return:  no-op() \\n \\
     Ctrl<Key>s:  exec(readHack read %w) \\n \\
     Ctrl<Key>p:  exec(echo print) \\n \\
     Ctrl<Key>Tab:  exec(readHack complete %w) \\n \\
   ~Shift Meta<Key>a: insert-string() \\n \\
     Shift Meta<Key>A: insert-string() \\n \\
   ~Shift Meta<Key>o: insert-string() \\n \\
     Shift Meta<Key>O: insert-string() \\n \\
   ~Shift Meta<Key>u: insert-string() \\n \\
     Shift Meta<Key>U: insert-string() \\n \\
     Meta<Key>s: insert-string() \\n \\
     None<Key>Prior : exec(echo Prev)  \\n \\
     None<Key>Next : exec(echo Next)  \\n \\
     Meta<Key>Prior : exec(echo field && 1) \\n \\
     Meta<Key>Next : exec(echo field && $#inputField) \\n \\
     Meta<Key>Next : end-of-file() \\n \\
     Meta<Key>Right : forward-word() \\n \\
     Meta<Key>Left : backward-word() \\n \\
         <Key>apLineDel : delete-next-character() \\n \\
         <Key>Home : beginning-of-file() \\n \\
         <Key>End : end-of-line() \\n \\
         <Key>Select : kill-to-end-of-paragraph() \\n \\
     <Btn1Up> :  extend-end(PRIMARY, CUT_BUFFER0) exec(echo goto %w) \\n \\
     Ctrl<Key>Delete : beginning-of-line() kill-to-end-of-line() \\n \\
     Ctrl<Key>Down :  exec(echo Next) \\n \\
     Ctrl<Key>Up :  exec(echo Prev) \\n \\
     Shift<Key>Tab :  exec(echo field -1) \\n \\
     None<Key>Tab :  exec(echo field +1)"

set helpText(Ende) "Beenden das Programmes"
set helpText(Prev) "Vorhergehender Eintrag"
set helpText(Next) "Nchster Eintrag"
set helpText(Suche) "Abfrage der Datenbank"
#set helpText(Neu) "Erfassen eines neuen Dokuments"
set helpText(Neu) "Ordnerverwaltung"
set helpText(Speichern) "Neuabspeichern des aktuellen Eintrags in der Datenbank"
set helpText(Veraendern) "Verndern  des aktuellen Eintrags in der Datenbank"
set helpText(Loeschen) "Lsche aktuellen Eintrag in der Datenbank"
set helpText(Vollst) "Vervollstndige Eingabefeld"
set helpText(cancel) "Beseitige Ausdruckfenster"
set helpText(OrdnerB) "verfgbare Ordner"

mergeResources topLevel \\
    *borderWidth              0  \\
    *Label.internalWidth      0 \\
    *Command*translations     \$helptrans \\
    *Text.translations        \$texttrans \\
    *SimpleMenu*translations  "#override \\n <Motion> : highlight()" \\
    *List*translations        "#override \\n <Motion> : Set()\\n " \\
    *cursorName               left_ptr \\
    *Command*horizDistance    $buttonStretch

Form top topLevel $backGround



Label info top justify center width $totalWidth borderWidth 1 \\
      resize false $infoColors

Clock uhr top width 60 height 60 highlight red $backGround $threeD \\
      fromVert info  $left 

Label Ablageverwaltung top justify center width 200 label {$theTitle} \\
      font \$titleFont vertDistance 24 fromVert info fromHoriz uhr

Label Bearbeiter top label "An der Arbeit:" \\
      horizDistance [expr $totalWidth-200] fromVert info vertDistance 30 $right

Label BearbeiterBild top label "" bitmap root.xbm  \\
     fromVert info vertDistance 8 $right
sV BearbeiterBild horizDistance [expr $totalWidth-[gV BearbeiterBild width]+6]

Label Name top label {$aBenutzerName} width 140 justify left resize false \\
     fromVert Bearbeiter  horizDistance [expr $totalWidth-200] $right

Label line top width $totalWidth height 1 background black label {} \\
     fromVert Name  $growHoriz

$tcl

Label BEN_NUMMER top label {} width 55 height 55 \\
     $lastVert{BEN_NUMMER} vertDistance $vertDistance

Label ErfasserName top width 300 label "" \\
     fromVert BEN_NUMMER justify left

Label line2 top width $totalWidth height 1 background black label "" \\
     fromVert ErfasserName vertDistance 5 

stdKnopfCB Ende top bitmap exit.xbm $threeD
stdKnopfCB Suche top  $buttonAtts fromHoriz Ende
stdKnopfCB Vollst top $buttonAtts label {Vervollstndigen} fromHoriz Suche
stdKnopfCB Neu top  label {Ordner} $buttonAtts sensitive false fromHoriz Vollst
stdKnopfCB Speichern top  label {NeuAnlegen} $buttonAtts sensitive false fromHoriz Neu
stdKnopfCB Veraendern top  $buttonAtts label {Verndern} sensitive false fromHoriz Speichern
stdKnopf Loeschen top  {$buttonAtts label {Lschen} sensitive false \\
	fromHoriz Veraendern callback {echo Loesche \[gV $ID string\]}}
stdKnopfCB Next top  bitmap arrdown.xbm fromHoriz Loeschen $threeD
stdKnopfCB Prev top  bitmap arrup.xbm fromHoriz Next $threeD

realize; deleteWindowProtocol quit
sV topLevel maxHeight [gV topLevel height]


TransientShell POPUPshell top
    callback POPUPshell popupCallback position top:50/130

       Form POPUPform POPUPshell $backGround
          Text POPUP POPUPform width 590 height 150 type string \\
               scrollVertical always wrap word $textFont $roColors
#          sV POPUP.vertical $sbColors 
          Command  cancel POPUPform label {Beseitige}  \\
	      fromVert POPUP $buttonAtts \\
              callback {popdown POPUPshell}

SimpleMenu completions top $menueAtts borderWidth 1


End of Wafe
}

&xSetup();

sub beep {
    &Xui("callActionProc $ID {} no-op RingBell");
}

sub setPicture {
    local($w,$pic) = @_;
    if (-r "$faceDir/$pic.xpm") {
	&Xui("changePixmap $w bitmap $faceDir/$pic.xpm");
    } else {
	local($bitmap);
	$bitmap = -r "$faceDir/$pic.xbm" && "$faceDir/$pic.xbm" 
	    || -r "$pic.xbm" && "$pic.xbm";
	&Xui("sV $w bitmap ". ($bitmap || "None width 55 height 55"));
    }
}

&setPicture('BearbeiterBild',$aBenutzerBild);

sub reverseLookup {
    local($entry,@array) = @_;
    for ($[ .. $#array) {
	return $_ if $entry eq $array[$_];
    }
    return -1;
}

sub setField {
    local($exp) = @_;
    local($f); eval '$f = '.$exp; 
    &beep(), return if $f < 0;
    return if $f == $currentField;
    &Xui("sV $inputField[$currentField] $roColors displayCaret false");
#    &Xui("XawTextUnsetSelection $inputField[$currentField]");
    &Xui("XawTextSetSelection $inputField[$currentField] 0 0");
    $currentField = $f;
    &Xui("sV $inputField[$currentField] $highLight displayCaret true");
    &Xui("setKeyboardFocus top $inputField[$currentField]");
}

sub setButtons {
    ($erfMode) = @_;
    &wafe'sensitive(!$erfMode,("Next","Prev","Suche"));
    &wafe'sensitive(!$erfMode && $current ne "" &&
		    ($aBenutzerGuru || $< == $owner),("Veraendern","Loeschen"));
#    &wafe'sensitive($erfMode,("Speichern"));
#    &wafe'sensitive($mayInsert && !$erfMode,("Neu"));
    &wafe'sensitive(!$ordnerMode,("Neu"));
    &wafe'sensitive($mayInsert && !$erfMode,("Speichern"));
}

sub mayInsert {
    local($folder) = @_;
    return 1 if !$FOLDERNAME;
    return $userInGroup{$ordnerGruppe{$folder}} || $aBenutzerGuru;
}

sub inOrdner {
    return "" if !$FOLDERNAME;
    return "im Ordner $_[$[] ";
}

sub simpleMenueL {
    local($f,$target,$type,@entries) = @_;
    &Xui("sV $f defaultColumns ". int(@entries/15+1)
	 ." callback {sV $target $type {%s};echo $target %s};"
         ."XawListChange $f 0 0 1 Arg ".(join(" ",@entries)).";" 
         ."action $f override {<Btn1Up>: Set() Notify() exec(popdown ${f}Shell)};"
         ."action $f override {<Leave>: exec(popdown ${f}Shell)}");
}

#
# fetch $i'th solution either from 
# the caching array or from oracle
# maintaining global variables $current and $max

sub fetchValue {
    local($i) = @_;
    return () if $i == 0;

    # fetching from cache
    if ($i <= $max) {
	$current = $i;
	return split(/$;/,$solution[$i]);
    }

    local(@result) = &ora_fetch($cursor) if $cursor;
    $cursor ="", return @result if !@result;
#    foreach ($[..$#result) { 
#	eval '$result[$_] =~ '. "tr/$oraChar/$isoChar/";
#    }

    foreach(@mvOrder) {
	local($value,@values);
	print "SQL: select $_ from $_ where $ID=$result[$[]\n"  if $opt_v;;
	local($mvCursor) = 
	    &ora_open($connection, "select $_ from $_ where $ID=$result[$[] order by pos");
	    while (($value) = &ora_fetch($mvCursor)) {
		push(@values,$value);
	    }
	&ora_close($mvCursor); 
	splice(@result,$index{$_},0,join(substr($_mv{$_},0,1).' ' ,@values));
    }

    $solution[$i] = join($;,@result);
    $current = $i; 
    $max = $i;
    return @result;
}

sub displayValue {
    local($index) = @_;
    local(@result,$tcl);
    if ($index>=0) {
	@result = &fetchValue($index);
	if (!@result) {
	    &beep();
	    &Info("Kein passender Eintrag "
		  .($suchOrdner eq "*"?"in keinem Ordner ":&inOrdner($suchOrdner)) 
		  ."gefunden!") if $max == 0;
	    return -1;
	}
	$momentanerKey = $result[$index{$AUTOID || $ID}];
	$momentanerOrdner = $result[$index{$FOLDERFIELD}];
	local($ordnerTyp) = $ordnerTyp{$momentanerOrdner};
	$mayInsert = &mayInsert($momentanerOrdner);;
	if ($FOLDERNAME && $letzterOrdnerTyp ne $ordnerTyp) {
	    &Xui("sV EinAus label {$ordnerTyp}");
	    $letzterOrdnerTyp = $ordnerTyp;
	}
	&Info(
	      "Eintrag $current von $answers        ("
	      ."Suche in ".($suchOrdner eq "*" ? "allen Ordnern)":"Ordner $suchOrdner)"));
    }
    foreach ($[..$#sqlField) {
	if ($_type{$sqlField[$_]} eq "owner") {
	    $owner = $result[$_];
            local($name,$bild,$guru) = &benutzerNameBild($owner);
	    &setPicture($sqlField[$_],$bild);	    
	    &Xui("sV ErfasserName label {$name}"); 
	    next;
	}
        $result[$_] =~ s/\"/\\"/g;  # take care of "s in the string 
	&Xui("sV $sqlField[$_] string \"$result[$_]\""); 
    }
    &setButtons(0);
    return 1;
}


sub sqlCondition {
    local($_,$key,$folder) = @_;
    local($cond,$test);
    $folder = '' if $folder eq '*';
    $key = "=$key" if /DATUM/ && $key != /^=/;
  TEST: {
      ($key,$test) = ($2,$1), last TEST if $key =~ /^([=><])\s*(.*)$/; 
      ($key,$test) = ("$1%",'like') if $key =~ /^(.*)(\\n)*$/;      # strip trailing "\\n" s
  }
  COND:  {		      
      $cond = "$_ $test $key", last COND if /NUMMER/ && $test ne 'like';
      $cond = "$_ $test to_date('$key','$dateFmt')", last COND if /DATUM/;
      $cond = "upper($_) $test upper('$key')";
  }
    return $cond . ($folder ? " and $FOLDERFIELD = '$folder'" : "");
}

sub getOrdner {
    local($cursor) = 
	&ora_open($connection, 
             "select $FOLDERFIELD,o_typ,ABT_NUMMER from $FOLDERNAME order by $FOLDERFIELD");
    local($ordnerzahl,$typ,$gruppe); 
    %ordnerTyp = ();
    while (($ordner[$ordnerzahl],$typ,$gruppe) = &ora_fetch($cursor)) {
	$ordnerTyp{$ordner[$ordnerzahl]} = $typ;
	$ordnerGruppe{$ordner[$ordnerzahl]} = $gruppe;
	$ordnerzahl ++;
    }
    pop(@ordner);
    push(@ordner,"*");

#    &Xui("destroyWidget Ordner");
##    &Xui("SimpleMenu Ordner OrdnerB $menueAtts borderWidth 1");
#    &Xui("List Ordner OrdnerShell $menueAtts borderWidth 1");
    &simpleMenueL("Ordner",$FOLDERFIELD,"string",@ordner); 
    &ora_close($cursor);       
}

$connection = &ora_login("", $database, "") || die $ora_errstr;
&Info("Sie sind jetzt mit der Datenbank ".((split(/:/,$database))[1])." verbunden.");
# &Info("Sie sind jetzt mit der Datenbank $database verbunden.");

&getOrdner() if $FOLDERFIELD;

# inputField = @sqlField - special fields
#
(@inputField) = grep($_type{$_} ne 'owner' && $_type{$_} ne 'folder' ,@sqlField);

# ssqlField = @sqlField - mv fields
#
(@ssqlField)=grep(!$_mv{$_},@sqlField);

# sqlQueryfield = @ssqlField + format information
#
(@sqlQueryFields)=@ssqlField;
grep(/DATUM/ && ($_="to_char($_,'$dateFmt')") || 
     $_type{$_} =~ /id/ && ($_="$sqlTable.$_") || $_,@sqlQueryFields);


#
# initialize global variables

if ($FOLDERNAME) {
    $suchOrdner = $standardOrdner;
    $letzterOrdnerTyp = $ordnerTyp{$standardOrdner};
    &Xui("sV EinAus label {$letzterOrdnerTyp}");
}
$mayInsert = &mayInsert($standardOrdner);;
&setButtons(0);


&Xui("sV $inputField[$currentField] $highLight displayCaret true");
&Xui("setKeyboardFocus top $inputField[$currentField]");

while ($_=&wafe'read) {
    chop;

    if (/^read\s+(\S+)\s+(.*)/ ) {
	$key = $2;
        $att = $inputField[$currentField];
#	eval '$key =~ '. "tr/$isoChar/$oraChar/";
	&ora_close($cursor) if $cursor;
	$max = 0; 
        local($queryTables) = $_mv{$att} ? "$sqlTable,$att" : $sqlTable; 
        local($mvCond) = $_mv{$att} ? "and $sqlTable.$ID = $att.$ID" : ""; 
	local($sqlCondition) = &sqlCondition($att,$key,$suchOrdner);
        local($dPerFolder) = "||$FOLDERFIELD" if $FOLDERFIELD;
        $sqlQueryC = "select count(distinct $sqlTable.$ID$dPerFolder) from $queryTables "
	    ."where $sqlCondition $mvCond";
	print "SQL: $sqlQueryC\n" if $opt_v;
	$cursor = &ora_open($connection, $sqlQueryC );
	($answers) = &ora_fetch($cursor);
	&ora_close($cursor);

	if ($answers > 300) {
	    &beep();
	    &Info("Mehr als 300 passende Eintrge ($answers) gefunden! Seien Sie spezifischer!");
	} elsif ($answers == 0) {
	    &beep();
	    &Info("Kein passender Eintrag "
		  .($suchOrdner eq "*"?"in keinem Ordner ":&inOrdner($suchOrdner)) 
		  ."gefunden!") if $max == 0;
	} else {
	    $sqlQuery = 
  	    "select distinct ".join(',',@sqlQueryFields)." from $queryTables "
		    ."where $sqlCondition $mvCond order by $sqlTable.$ID ";
	    print "SQL: $sqlQuery\n"  if $opt_v;;
	    $cursor = &ora_open($connection, $sqlQuery ) || die $ora_errstr;
    &displayValue(1);
	}
    }

    if (/^complete\s+(\S+)\s+(.*)/ ) {
	($att,$key) = ($1,$2);
	&Info("Geben Sie bitte ein Suchkriterium an!"),&beep(),next if $key eq "";
	&Info("Vervollstndigung ist in mehrzeiligen Felder nicht mglich!"),&beep(),next 
	    if $_lines{$att}>1;
#	eval '$key =~ '. "tr/$isoChar/$oraChar/";
	&ora_close($cursor) if $cursor;
        $sqlQuery = "select unique $att from "
	    .($_mv{$att} ? $att : $sqlTable)
	    ." where $att like '$key%' ";

        print "SQL: $sqlQuery\n"  if $opt_v;;
	local($cursor) = &ora_open($connection, "$sqlQuery");
	for($sol=0,@sol=(); $sol < 20; $sol++) {
	    (($answer) = &ora_fetch($cursor)) =~  s/\"/\\"/g;  # take care of "s in the string 
	    last if !$answer;
	    push(@sol,$answer);
	}
	&ora_close($cursor);
#	print "possible completions are $#sol <",join(",",@sol),"> $#sol\n";
	
	if ($#sol == $[) {
#	    print "only one completion: <$sol[$[]>\n";
	    &Xui("sV $att string \"$sol[$[]\"");
	} elsif ($#sol > $[) {
#	    print "several completions: $#sol\n";
	    &Xui("destroyWidget completions");
	    &Xui("SimpleMenu completions top $menueAtts borderWidth 1");
            &Xui("callback completions popupCallback positionCursor 45");
	    &simpleMenue("completions",$att,"string",@sol); 
	    &Xui("popup completions none");
	} else {
	    &beep();
	    &Info("Keine Vervollstndigung mglich!");
#	    print "No completion: \n";
	}
    }

    if (/^Neu/) {
	$ordnerMode = 1; 
	&setButtons(0);
	system "xwafeora -a Ordner -b $database -O $FOLDERNAME &";
    }
    if (/^leaveOrdner/) {
	$ordnerMode = 0; 
	&setButtons(0);
	&getOrdner() if $FOLDERFIELD;
#	&setButtons(1);
#	&Xui("sV $AUTOID string **auto**") if $AUTOID;
#	grep(/DATUM/ &&  &Xui("sV $_ string $today"),@sqlField);
    }

    if (/^Loesche\s+(.*)/) {
	next if !($doknr = $1);
        $doknr = "'$doknr'" if $doknr !~ /^\d+$/;
	if (&ora_do($connection,"DELETE FROM $sqlTable WHERE $ID = $doknr "
		    .($FOLDERFIELD? "and $FOLDERFIELD = '$momentanerOrdner'" : ""))) {
	    foreach(@mvOrder) {
		&ora_do($connection,"DELETE FROM $_ WHERE $ID = $doknr");
	    }
	    &Info("Eintrag $doknr wurde ".&inOrdner($momentanerOrdner)."gelscht");
	    $solution[$current] = "gelscht$;";
	    &displayValue(-1);
	} else {
	    &Info("Eintrag $doknr konnte nicht ".&inOrdner($momentanerOrdner)
          ."gelscht werden: <$oraerr>");
	}
    }

    if (/^(Speichern|Veraendern)/) {
	foreach (@inputField,($FOLDERFIELD||())) { &Xui("eV $_ $_"); };
	&Xui("echo checkInput ".($1 eq "Speichern"));
    }

    if (/^$FOLDERFIELD\s+(.*)/o) {
	$suchOrdner = $1;
	$momentanerOrdner = $suchOrdner if $suchOrdner ne "*";
	$mayInsert = &mayInsert($momentanerOrdner);
	&setButtons(0);
   };    

    if (/^value\s+(\S+)\s+(.*)/ ) {
	$value{$1} =$2;
#	print "value of <$1> = $2\n";
    }

    if (/^checkInput\s+(.*)/) {
	local($doInsert) = $1;
	local(@invalid) = grep(!$value{$_},keys %_required);
        local($sequence);
        local($insertOrdner) = $momentanerOrdner || 
	    ($value{$FOLDERFIELD} ne "*" && $value{$FOLDERFIELD});

	if (@invalid) {
	    &Info("unvollstndig: ".(join(", ",grep($_=$_label{$_},@invalid))));
	    &beep();
	} elsif (@invalid = grep($_maxLength{$_} && length($value{$_})>$_maxLength{$_},
				 @inputField)) {
	    &Info("zu lang: ".(join(", ",grep($_=$_label{$_},@invalid))));
	    &beep();
	} elsif (@invalid = grep(!$_lines{$_}>1 && $value{$_} =~ /\\n/,@inputField)) {
	    &Info("mehrzeiliger Feldinhalt: ".(join(", ",grep($_=$_label{$_},@invalid))));
	    &beep();
	} elsif ($FOLDERFIELD && !$insertOrdner) {
	    &Info("ungltiger Ordner");
	    &beep();
	} elsif (!$doInsert && ($ID||$AUTOID) && $value{$ID||$AUTOID} ne $momentanerKey) {
	    &Info("Verwenden Sie Lschen und Einfgen um den Schlssel zu verndern");
	    &beep();
	} else {
	    local(@sqlContent,@sqlUpdate,$i);
	    $sequence = $sqlTable."nr";
	    foreach (@ssqlField) {
		$value{$_} =~ s/'/''/g;
                local($content) = 
		    ($_type{$_} eq "owner" && ($value{$_} = $<)) ||
		    ($_type{$_} eq "folder" && ($value{$_}=$insertOrdner) && "'$insertOrdner'") ||
		    ($_type{$_} eq "autoid" && $doInsert && 
                           ($value{$_} = "$sequence.currval") && "$sequence.nextval") ||
		    ($_type{$_} eq "moddate" && "to_date('$today','$dateFmt')") ||
		    ($_type{$_} eq "date" && $value{$_} ne ""&&"to_date('$value{$_}','$dateFmt')")||
		    ($_type{$_} eq "date" && "NULL") ||
  		    "'$value{$_}'";

		push(@sqlContent,$content);
		push(@sqlUpdate,"$_ = $content") if $_type{$_} ne 'autoid';
	    }
            
	    if ($doInsert) {
		$sqlCmd =  "insert into $sqlTable (".join(",",@ssqlField).") values ("
		    . join(",",@sqlContent) .")";
	    } else {
                $fromFolder = (split($;,$solution[$current]))[$index{$FOLDERFIELD}];
		$sqlCmd =  "update $sqlTable set ".join(",",@sqlUpdate) 
		    . " where $ID = ".($_type{$ID} eq 'autoid'? $value{$ID} : "'$value{$ID}'")
                    . ($FOLDERFIELD? "and $FOLDERFIELD = '$fromFolder'" : "");
	    }
	    
            print "SQL: $sqlCmd\n" if $opt_v;
	    &ora_do($connection,$sqlCmd);
            &beep(), &Info("SQL Fehler: $ora_errstr"), next if $ora_errno;

            foreach (@mvOrder) {
                print "delete from $_ where $ID = $value{$ID}\n";
                &ora_do($connection,"delete from $_ where $ID = $value{$ID}");
                local($pos) = 0;
                foreach $v (split(/[$_mv{$_}]\s*/,$value{$_})) {
                    eval "\$v = &$_normalize{$_}('$v')" if $_normalize{$_};
                    print "insert into $_ values ('$v',$value{$ID},$pos)\n";
                    &ora_do($connection,"insert into $_ values ('$v',$value{$ID},$pos)");
                    $pos++;
                }
            }

	    &ora_commit($connection);
	    if ($doInsert) {
		local($scursor) = &ora_open($connection, "select $sequence.currval from dual");
		local($nr) = &ora_fetch($scursor);
		&ora_close($scursor); 
                if ($AUTOID) {
		    &Info("Vergebene $_label{$ID}: $nr");
 		    &Xui("sV $ID string {$nr}");
                } else {
		    &Info("Eintrag gespeichert");
                }
                $owner = $<; $current = $current || 0;
	    } else {
		&Info("Eintrag $value{$ID} ".&inOrdner($momentanerOrdner)."verndert");
                local(@tmp);
                grep(push(@tmp,$value{$_}),@sqlField);
                $solution[$current] = join($;,@tmp);
	    }
	    &setButtons(0);
	}
    }

    if (/^print/) {
	foreach (@inputField,($FOLDERFIELD||())) { &Xui("eV $_ $_"); };
	&Xui("echo doPrint");
    }

    if (/^doPrint/) {
         local($printString);
         if ($prettyPrint ) { $printString = &pp(); }
         else {grep($printString .= "$_ = $value{$_}\n",@sqlField);}
#print "printString = <$printString>\n";
         $printString =~  s/(["[{\\])/\\$1/g;
         $printString =~  s/\n/\\n/g;
#print "printString = <$printString>\n";
         &Xui("sV POPUP string \"$printString\"; popup POPUPshell none");
   }

    &setField("($currentField $1)%($#inputField+1)") if /^field\s+(.*)/;
    &setField(&reverseLookup($1,@inputField)) if /^goto\s+(.*)/;
    &Xui("readHack read $inputField[$currentField]") if /^Suche/;
    &Xui("readHack complete $inputField[$currentField]") if /^Vollst/;
    &displayValue($current+1) if /^Next/;
    &displayValue($current-1) if /^Prev/;
    if (/^Ende/) {
	last if !$erfMode;
	&setButtons(0);
    };
    last if /^quit/;

#   print "<$_>\n";
}

&ora_close($cursor) if $cursor;
&ora_logoff($connection) || die "can't log off Oracle";
&Xui("puts stdout {%echo leaveOrdner}") if $opt_O;
&Xui("quit");

