#/*TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX*
#
#USERDEF   
#
#FXN       ColorString
#
#SHORTDOC  Defines a string for use in {\tt Print} to get colorful output.
#
#LONGDOC   This function generates a {\em VT100/ANSI} compatibel escape
#          sequence to change the output color. Regardless of the names
#          used here, the actual outcome is influenced by the terminal
#          itself: the terminal may have a visible bell, different
#          colors. The terminal can ignore certain combinations, refuse to
#          blink, \ldots.
#
#          The {\tt l} argument contains strings of the following form:
#          \begin{itemize}
#          \item {\tt "f_{\em color}"} with {\tt\em color} one of
#          {\tt black, red, green, brown, blue, magenta, cyan, white}.
#          This defines the {\em foreground} color.
#          \item {\tt "b_{\em color}"} for the background color.
#          \item {\tt "bright", "blink", "underscore", "reverse", "blank"}
#          to set additional attributes.
#          \item {\tt "bell"} to include a terminal-bell.
#          \end{itemize}
#
#          For example to produce red letters on a blue background, one should
#          use {\tt ColorString("f_red", "b_blue")}. Depending on the 
#          {\em termcap} entries and (eventually) the {\tt .Xresources}.
#
#          To get yellow, one should use {\tt "brown"} together with 
#          {\tt "bright"}.
#
#CALLING   s := ColorString(l);
# 
#ARGUS     s @ string
#          l @ list of strings
#
#CSRC      
#
#DEBUG    
#
#XREF      
#
#PACKAGE   
#
#EXAMPLE   @Print(ColorString("f_red", "b_black", "bright"), 
#                      "Hallo", ColorString("normal"), "\n");
#
#
#**HISTORY*|*HISTORY***HISTORY***HISTORY***HISTORY***HISTORY***HISTORY**HISTORY
#
#**KASH***KASH***KASH***KASH***KASH***KASH***KASH***KASH***KASH***KASH***KASH*/
#
#InstallDocumentation(
Ignore(
rec(
name := "ColorString",
kind := "FUNCTION",
sin  := [[list,"l"]],
sou  := [[string]],
short := 
"This function generates a VT100/ANSI compatibel escape"+
" sequence to change the output color. Regardless of the names"+
" used here, the actual outcome is influenced by the terminal"+
" itself: the terminal may have a visible bell, different"+
" colors. The terminal can ignore certain combinations, refuse to"+
" blink ..."+
"\n\n"+
"The 'l' argument contains strings of the following form:\n\n"+
"'f_color' with 'color' one of black, red, green, brown, blue, magenta, cyan, white."+
" This defines the foreground color.\n\n"+
"'b_color' for the background color.\n\n"+
"'bright', 'blink', 'underscore', 'reverse', 'blank'"+
" to set additional attributes.\n\n"+
"'bell' to include a terminal-bell.",
ex :=[
"# to produce red letters on a blue background, use\n"+
"ColorString(\"f_red\", \"b_blue\");",
"Print(ColorString(\"f_red\", \"b_black\", \"bright\"),\"Hallo\", ColorString(\"normal\"), \"\\n\");"]
)
);


ColorString := function(arg)
  local s,i,j, T, bell;
  # return empty string if colors are switched off, i.e. COLOR = false  
  if not COLOR then
    return "";
  fi;
  if Type(arg[1])=list then
    arg := arg[1];
  fi;
  if _Size_list(arg)=0 or Type(arg[1])<>elt-alg^boo then
    s := "[0";
  else
    s := "[0";
  fi;
  bell := "";

  T := [ "black", "red", "green", "brown", 
          "blue", "magenta", "cyan", "white" ];
  if _Size_list(arg)=1 and arg[1]=false then
    return T;
  fi;

  for i in [1.._Size_list(arg)] do
    if IsString(arg[i]) then
      if arg[i]{[1..2]}="f_" then
        j := Position(T, arg[i]{[3.._Size_list(arg[i])]});
        if j=false then
          Error("wrong color");
        fi;
        Append_(s, SPrint(";", 30+j-1));
      elif arg[i]{[1..2]}="b_" then
        j := Position(T, arg[i]{[3.._Size_list(arg[i])]});
        if j=false then
          Error("wrong color");
        fi;
        Append_(s, SPrint(";", 40+j-1));
      elif arg[i]="bright" then
        Append_(s, ";1");
      elif arg[i]="blink" then
        Append_(s, ";5");
      elif arg[i]="underscore" then
        Append_(s, ";4");
      elif arg[i]="reverse" then
        Append_(s, ";7");
      elif arg[i]="blank" then
        Append_(s, ";8");
      elif arg[i]="bell" then
        bell := "";
      fi;
    fi;
  od;
  Append_(s, "m");
  Append_(s, bell);
  return s;
end;

#/*TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX***TEX*
#
#USERDEF   
#
#FXN       Bell
#
#SHORTDOC  Sounds the terminal bell.
#
#LONGDOC   
#
#CALLING   Bell();
#
#ARGUS     
#
#CSRC      
#
#DEBUG    
#
#XREF      
#
#PACKAGE   
#
#EXAMPLE   @Bell();
#
#**HISTORY*|*HISTORY***HISTORY***HISTORY***HISTORY***HISTORY***HISTORY**HISTORY
#
#**KASH***KASH***KASH***KASH***KASH***KASH***KASH***KASH***KASH***KASH***KASH*/
##
Bell := function()
  Print("");
end;


#/*TEX**TEX|***TEX***TEX***TEX***TEX**TEX***TEX***TEX***TEX***TEX***TEX***TEX**
#FXN       Colors
#CALLING   Colors(flag);\\
#          Colors(s1, ..., sn);\\
#          Colors(L);
#SHORTDOC  Activate or deactivate color mode and customize colors.  
#LONGDOC   This function can be used to switch on or off a color
#          mode in \KASH \mbox{} compatible with {\tt ANSI/ISO 6429} standards. 
#          The resource
#          strings consist first of one of the strings {\tt "normal"}, {\tt "prompt"},
#          {\tt "command"}, {\tt "result"} or {\tt "error"} to indicate 
#          for which
#          type of output a color should be defined. The other strings
#          can be {\tt "black"}, {\tt "red"}, {\tt "green"}, {\tt "yellow"},
#          {\tt "blue"}, {\tt "magenta"}, 
#          {\tt "cyan"} or {\tt "white"} and additionally {\tt "bold"} or 
#          {\tt "light"}. The color mode works only for terminals
#          which can display colored letters like "{\tt color\_xterm}" or
#          "{\tt rxvt}". See the instructions for your terminal.
#
#          The default colors can be customized via the {\tt \_ColorTable}
#          array.
#
#          {\bf\tt \_ColorTable} is a list with exacly 5 entries defining 
#          (in this order)
#          the  "normal", "prompt", "command", "result", "error" colors.
#          Each entry is a list as described in {\tt ColorString}.
#          
#
#ARGUS     flag @ boolean @ switch color mode on or off
#          s1, ..., sn @ string @ resource strings
#          L  @ list @ list of lists of resource strings
#CSRC      kash\_colors.c
#KASH      @
#          Colors(true);
#          Colors("error", "red", "bold");
#          Colors([ [ "error", "red" ], [ "result", "green", "bold" ] ]);
#          Colors(false);
#
#**HISTORY*|*HISTORY***HISTORY***HISTORY**HISTORY***HISTORY***HISTORY***HISTORY
#
#  970217  FH  installed.
#
#**C***C***|***C***C***C***C***C***C**C***C***C***C***C***C***C***C***C***C***/

_ColorTable := [["bright"],    #### DEFAULT ####
                ["f_black"],
                [],
                ["f_blue"],
                ["f_red", "bell"]
               ];

__ColorTable := [[ "f_white", "b_black", "bright"],   
                ["f_white", "b_black"],
                ["f_white", "b_black", "bright"],
                ["f_green", "b_black", "bright"],
                ["f_red", "b_black", "bell" ]
               ];

Colors := function(arg)
   local a, aa, L, S, T, E, kc, i, b;
   S := [ "normal", "prompt", "command", "result", "error" ];
   T := [ "bold", "light", "black", "red", "green", "yellow", 
          "blue", "magenta", "cyan", "white" ];
   E := [ ";1", ";2", ";30", ";31", ";32", ";33", ";34", ";35", ";36",
          ";37" ];
   if _Size_list(arg) = 1 then
      if IsBool(arg[1]) then
         _Colors(arg[1]);
         if arg[1] then
           for i in [1..5] do
             _Colors(i-1, ColorString(Concatenation([true], _ColorTable[i])));
           od;
         fi;
         return;
      elif IsList(arg[1]) then
         L := arg[1];
      else
         return Error("usage: Colors( <bool> | <string>, ... , <string> | <list> )");
      fi;
   elif _Size_list(arg) >= 2 then
      L := [ arg ];
   else
      return Error("usage: Colors( <bool> | <string>, ... , <string> | <list> )");
   fi;
   
   for a in L do 
      
      if not IsList(a) then
         return Error("usage: Colors( <bool> | <string>, ... , <string> | <list> )");
      fi;
      
      kc := Position(S, a[1]);
      if kc = false then
         return Error("the mode must be one of \"normal\", \"prompt\", \"command\", \"result\" or \"error\" ");
      fi;
      kc := kc - 1;
      
      aa := _Apply_list_func(Butfirst(a), x->Position(T, x));
      if false in aa then
         return Error("the colors must consist of \"bold\", \"light\", \"black\", \"red\", \"green\", \"yellow\", \"blue\", \"magenta\", \"cyan\" or \"white\" "); 
      fi;                
      b := "[0";
      for i in aa do
         Append_(b, E[i]);
      od;  
      Append_(b, "m");
      
      _Colors(kc, b);
      _ColorTable[Position(S, a[1])] := a{[2.._Size_list(a)]};
      
   od;
end;


#############################################################################
##
#F  PrintString(<nof(string)> [, optarg])
##
## documentation see lib/init-methods.g
PrintString:=
  function(arg)
    local str,size,cols,optarg, i, len,
      threshold, offset, firstnl,
      nextwrap, words, wrap;

    size:= Winsize();
    SizeScreen(size);
    cols:= size[1];

    optarg:=ExtractOptarg_(arg);

    ## cat all args together
    str:="";
    for i in arg do
      str:=str+i;
    od;

    len:=_Size_list(str);

    ## now frobnicate an offset (which is the current indentation)
    offset:=_GetEntry_rec_string(optarg,"Start",rec(Fail:=GetCurrentColumn()));
    threshold := cols-offset-2;

    ## search for a newline
    firstnl := _Position_list_any(str,'\n',rec(Fail:=len));
    if firstnl<=threshold then
      ## the entire string fits in the window
      Print(str{[1..firstnl]});
      nextwrap := firstnl+1;
    else
      ## wouldnt fit whatsoever, so split the string
      words:=Positions(str,' ',rec(Fail:=[]));
      wrap := _Last_func_list(i->i<=threshold, words, rec(Fail:=threshold));
      Print(str{[1..wrap-1]},"\n");
      nextwrap:=wrap+1;
    fi;

    if nextwrap>0 then
      str:=str{[nextwrap..len]};
      if _Size_list(str)>0 then
        PrintString(str);
      fi;
    fi;

  end;
