{
    This file is part of Chentrah,
    Copyright (C) 2004-2008 Anton Rzheshevski (chebmaster@mail.ru).

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    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.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses/

 **********************************************************************}


 procedure InitUnicode;
 var
   j: integer;
   a: AnsiChar;
 begin
   For j:=0 to 127 do _UniToAnsiTable[j]:=chr(j);
   For j:=128 to  $FFFF do _UniToAnsiTable[j]:='?'; //everything else is undefined at first.
   For a:=#0 to #127 do _AnsiToUnitable[a]:={$ifdef fpc}a;{$else}WideChar(ord(a));{$endif}//Dumb Delphi! :(
   
   //Russian alphabet:
   // "a" to "ya", capitals then smalls, 32 + 32 characters
   For j:=$0410 to $044F do _UniToAnsiTable[j]:=chr($C0 + j - $0410);
   //33st character, "yo":
   _UniToAnsiTable[$0401]:=chr($A8); //capital
   _UniToAnsiTable[$0451]:=chr($B8); //small
   _UniToAnsiTable[ord('№')]:=chr($B9);
   _UniToAnsiTable[ord('«')]:=chr($AB);
   _UniToAnsiTable[ord('»')]:=chr($BB);

   For a:=#128 to #$DF do _AnsiToUnitable[a]:='?';
   //Russian alphabet again...
   For a:=#$C0 to #$FF do _AnsiToUnitable[a]:= WideChar($0410 + ord(a) - $C0);
   //"yo":
   _AnsiToUnitable[#$A8]:=WideChar($0401);
   _AnsiToUnitable[#$B8]:=WideChar($0451);
 end;

 function WideToCp1251(u: WideString): AnsiString;
 var
   j: integer;
 begin
   SetLength(Result, Length(u));
   For j:=1 to Length(u) do Result[j]:= _UniToAnsiTable[ord(u[j])];
 end;
 
 function Cp1251ToWide(a: AnsiString): WideString;
 var
   j: integer;
 begin
   SetLength(Result, Length(a));
   For j:=1 to Length(a) do Result[j]:= _AnsiToUniTable[a[j]];
 end;

 function Cp1251CharToWideChar(a: AnsiChar): WideChar;
 begin
   Result:= _AnsiToUniTable[a];
 end;

(*
const Trnslt: array[0..66, 0..1] of WideString = (
      ('А', 'A'),
      ('Б', 'B'),
      ('В', 'V'),
      ('Г', 'G'),
      ('Д', 'D'),
      ('Е', 'E'),
      ('Ё', 'YO'),
      ('Ж', 'ZH'),
      ('З', 'Z'),
      ('И', 'I'),
      ('Й', 'I'),
      ('К', 'K'),
      ('Л', 'L'),
      ('М', 'M'),
      ('Н', 'N'),
      ('О', 'O'),
      ('П', 'P'),
      ('Р', 'R'),
      ('С', 'S'),
      ('Т', 'T'),
      ('У', 'U'),
      ('Ф', 'F'),
      ('Х', 'H'),
      ('Ц', 'C'),
      ('Ч', 'CH'),
      ('Ш', 'SH'),
      ('Щ', 'SHCH'),
      ('Ь', ''''),
      ('Ы', 'Y'),
      ('Ъ', ''''),
      ('Э', 'E'),
      ('Ю', 'YU'),
      ('Я', 'YA'),
      ('а', 'a'),
      ('б', 'b'),
      ('в', 'v'),
      ('г', 'g'),
      ('д', 'd'),
      ('е', 'e'),
      ('ё', 'yo'),
      ('ж', 'zh'),
      ('з', 'z'),
      ('и', 'i'),
      ('й', 'i'),
      ('к', 'k'),
      ('л', 'l'),
      ('м', 'm'),
      ('н', 'n'),
      ('о', 'o'),
      ('п', 'p'),
      ('р', 'r'),
      ('с', 's'),
      ('т', 't'),
      ('у', 'u'),
      ('ф', 'f'),
      ('х', 'h'),
      ('ц', 'c'),
      ('ч', 'ch'),
      ('ш', 'sh'),
      ('щ', 'shch'),
      ('ь', ''''),
      ('ы', 'y'),
      ('ъ', ''''),
      ('э', 'e'),
      ('ю', 'yu'),
      ('я', 'ya'),
      (#13, '')
    );

Function Translit(source: WideString): WideString;
var i, j: integer;
begin
  Result:='';
    For i:=1 to Length(source) do
      for j:=high (Trnslt) downto - 1 do
        if j < 0
          then Result:=Result + source[i]
          else
            if source[i] = Trnslt[j, 0][1]
              then Result:=Result + Trnslt[j, 1];
  end;
   *)

 function WideToAnsi(u: WideString): AnsiString;
 {$ifndef unix}
 var
   i: integer;
   b: longbool;
   c: ansichar;
 {$endif}
 begin
   {$ifdef unix} //utf-8 assumed
    Result:=Utf8Encode(u);
   {$else}
    if u='' then Result:=''
    else begin
      i:=WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK or WC_DISCARDNS, @u[1], length(u), nil, 0, nil, nil);
      SetLength(Result, i);
      b:=True;
      c:='?';
      WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK or WC_DISCARDNS, @u[1], length(u), @Result[1], i, @c, @b);
    end;
   {$endif}
 end;

 function AnsiToWide(a: AnsiString): WideString;
 {$ifndef unix}
 var
   i: integer;
 {$endif}
 begin
   {$ifdef unix} //utf-8 assumed
    Result:=Utf8Decode(a);
   {$else}
    if a='' then Exit('')
    else begin
      i:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, @a[1], length(a), nil, 0);
      if i > 0 then begin
      SetLength(Result, i);
      MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, @a[1], length(a), @Result[1], i);
      end
      else
        if MotherState{$ifndef cgekernel}^{$endif}.OS = ostWin9x then begin
          //No Unicode support installed, assuming Russian/Cyrillic (CP 1251)
          Result:= CP1251ToWide(a);
        end;
    end;
   {$endif}
 end;

 function TrimWideString (u: WideString): WideString;
 var j, a, b: integer;
 begin
   a:=1;
   While (a < length(u)) and (ord(u[a]) <= 32) do inc(a);
   b:=length(u);
   While (b > 1) and (ord(u[a]) <= 32) do dec(b);
   if a > b then exit('');
   Result:= Copy(u, a, b - a + 1);
 end;

 function WideReplace(u: WideString; a, b: AnsiString): WideString; OVERLOAD;
 begin
   Result:=WideReplace(u, AnsiToWide(a), AnsiToWide(b));
 end;
 
 function WideReplace(u: WideString; a: AnsiString; b: WideString): WideString; OVERLOAD;
 begin
   Result:=WideReplace(u, AnsiToWide(a), b);
 end;


function WideCOPY(s: WideString; pos, len: integer): WideString;
var i: integer;
begin
  Result:='';
  For i:=pos to pos + len - 1 do begin
    if i > Length(s) then Exit;
    Result:=Result + s[i];
  end;
end;

function WideReplace(u, a, b: WideString): WideString; OVERLOAD;
var p: integer;
    s: WideString;
begin
  s:=u;
  p:= WidePos(a, b);
  if p > 0 then b:= WideReplace(b, a, '<!>'); //or else... >:(
  p:=WidePos(a, s);
  While p > 0 do begin
    s:=WideCOPY(s, 1, p - 1) + b + WideCOPY(s, p + Length(a), Length(s));
    p:=WidePos(a, s);
  end;
  Result:=s;
end;

 function WidePos(a, u: WideString): integer;
 var
   j, i: integer;
 begin
   Result:=-1;
   For j:=1 to length(u) do begin
     i:=1;
     While (i < Length(a) + 1) and (a[i] = u[i + j - 1]) do inc(i);
     if i = (Length(a) + 1) then begin
       Result:=j;
       Exit;
     end;
   end;
 end;

  function Explode(separator, s: WideString; TrimIt: system.boolean): WideStringArray; overload;
  var i, a: integer;
  begin
    Result:= nil;
    if s = '' then exit;
    if separator = '' then begin
      SetLength(Result, length(s));
      for i:= 0 to High(Result) do Result[i]:= COPY(s, i+1, 1);
      exit;
    end;
    i:= 1;
    a:= 1;
    repeat
      if (s[i] = separator[1]) and (COPY(s, i, length(separator)) = separator) then begin
        SetLength(Result, Length(Result) + 1);
        Result[High(Result)]:= COPY(s, a, i - a);
        if TrimIt then Result[High(Result)]:= TrimWideString(Result[High(Result)]);
        i+= length(separator);
        a:= i;
      end
      else i+= 1;
    until i > length(s);
    if (a < length(s)) then begin
      SetLength(Result, Length(Result) + 1);
      Result[High(Result)]:= COPY(s, a, length(s) - a + 1);
    end;
  end;

  function Explode(separator, s: AnsiString; TrimIt: system.boolean): AnsiStringArray; overload;
  var i, a: integer;
  begin
    Result:= nil;
    if s = '' then exit;
    if separator = '' then begin
      SetLength(Result, length(s));
      for i:= 0 to High(Result) do Result[i]:= COPY(s, i+1, 1);
      exit;
    end;
    i:= 1;
    a:= 1;
    repeat
      if (s[i] = separator[1]) and (COPY(s, i, length(separator)) = separator) then begin
        SetLength(Result, Length(Result) + 1);
        Result[High(Result)]:= COPY(s, a, i - a);
        if TrimIt then Result[High(Result)]:= Trim(Result[High(Result)]);
        i+= length(separator);
        a:= i;
      end
      else i+= 1;
    until i > length(s);
    if (a < length(s)) then begin
      SetLength(Result, Length(Result) + 1);
      Result[High(Result)]:= COPY(s, a, length(s) - a + 1);
    end;
  end;


  function Implode(separator: AnsiString; a: AnsiStringArray): AnsiString; overload;
  var i: integer;
  begin
    Result:= '';
    for i:=0 to High(a) do begin
      if i > 0 then Result+= separator;
      Result+= a[i];
    end;
  end;

  function Implode(separator: WideString; a: WideStringArray): WideString; overload;
  var i: integer;
  begin
    Result:= '';
    for i:=0 to High(a) do begin
      if i > 0 then Result+= separator;
      Result+= a[i];
    end;
  end;



