// Программа кодирует строки, используя алгоритмв класса ROT
// !!! Не работает для 4-байтных символов UNICODE и многосимвольной диакритики
// Alexey Kuzminov (с) 2016

program MultiROT;

var
  strFrom: WideString;
  strTo: WideString;

procedure ClearTable;
begin
  strFrom := '';
  strTo := '';
end;

// Процедура добавляет к имеющейся таблице кодирования символы алфавита, для
// замены импользуется циклический сдвиг на shift символов.
procedure InitTable(const alphabet: String; shift: Integer);
var
  i, nPos, nLength: Integer;
  strAlphabet: WideString;
begin
  strAlphabet := UTF8Decode(alphabet);
  nLength := Length(strAlphabet);
  if nLength <= 0 then Exit;
  
  if shift = 0 then
    shift := nLength div 2
  else
    shift := ((shift mod nLength) + nLength) mod nLength;
  
  for i := 1 to nLength do begin
    nPos := Pos(strAlphabet[i], strFrom);
    if nPos > 0 then
      strTo[nPos] := strAlphabet[(i - 1 + shift) mod nLength + 1]
    else begin
      strFrom := strFrom + strAlphabet[i];
      strTo := strTo + strAlphabet[(i - 1 + shift) mod nLength + 1];
    end;
  end;
end;

// Если при передаче опущен параметр, то он будет равен половине длины строки
procedure InitTable(const alphabet: String);
begin
  InitTable(alphabet, 0);
end;

function Encode(const str: String): String;
var
  i, nPos: Integer;
  strInput, strOutput: WideString;
begin
  strInput := UTF8Decode(str);
  strOutput := '';
  
  for i := 1 to Length(strInput) do begin
    nPos := Pos(strInput[i], strFrom);
    if nPos > 0 then
      strOutput := strOutput + strTo[nPos]
    else
      strOutput := strOutput + strInput[i];
  end;
  
  Encode := UTF8Encode(strOutput);
end;
 

begin
  // Шифр Цезаря (3 символа - классика)
  ClearTable;
  InitTable('ABCDEFGHIJKLMNOPQRSTUVWXYZ', -3);
  InitTable('abcdefghijklmnopqrstuvwxyz', -3);
  WriteLn(Encode('Alphabet 13'), ' - Caesar' );

  // ROT5
  ClearTable;
  InitTable('0123456789');
  WriteLn(Encode('Alphabet 13'), ' - ROT5');
  
  // ROT13
  ClearTable;
  InitTable('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
  InitTable('abcdefghijklmnopqrstuvwxyz');
  WriteLn(Encode('Alphabet 13'), ' - ROT13');

  // ROT18
  ClearTable;
  InitTable('0123456789');
  InitTable('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
  InitTable('abcdefghijklmnopqrstuvwxyz');
  WriteLn(Encode('Alphabet 13'), ' - ROT18');

  // ROT47
  ClearTable;
  InitTable('!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
    '[\]^_`abcdefghijklmnopqrstuvwxyz{|}~');
  WriteLn(Encode('Alphabet 13'), ' - ROT47');

end.