unit UnitTWideChar;
interface
uses SysUtils, Classes;

{$REGION 'PURPOSE:'}
{
PURPOSE:
	This code was originally written in an older version of Delphi and serves no
    purpose, other than making legacy code work.

    It's now just a wrapper for real a Unicode string.
}
{$ENDREGION}

type TWideChar = class(TObject)
    private
        ms : TMemoryStream;
        str : string;
    protected
        procedure PositionForAppend;
    public
        constructor Create;
        destructor Destroy; override;
        procedure Append(s : ansistring); overload;
        procedure AppendUnicode(s : string);
        procedure Append(wc : TWideChar); overload;
        procedure Append(c : WideChar); overload;
        procedure TrimLeft(chars : cardinal);
        procedure TrimRight(chars : cardinal);
        procedure LeftStr(len : cardinal);
        procedure RightStr(len : cardinal);
        procedure Replace(find : widechar; replace : widechar; removenulls : boolean = true); overload;
        procedure Replace(find : widestring; replace : widestring; replacestream : boolean = false); overload;


        function Memory : Pointer;
        function size : int64;
        function StrLength : int64;
        function GetChar(pos : int64) : widechar;

        function GetString : string;

        procedure Clear;
end;

{////////////////////}
implementation
{////////////////////}

uses UnitMisc, Windows, Math, Dialogs, StrUtils;

{ TWideChar }

function TWideChar.GetString : string;
begin
    result := str;
end;


procedure TWideChar.AppendUnicode(s : string);
begin
	str := str + s;
    {
	self.positionforappend;
    ms.write(s[1], StrSize(s));
    c := #0;
    ms.Write(c, sizeof(c));}
end;

procedure TWideChar.Append(s: ansistring);
begin
	str := str + string(s);
{
    Windows.SetLastError(ERROR_SUCCESS);
    if s = '' then EXIT;

    c := (length(s) + 1) * 2; // include null space
    GetMem(pwc2, c);

    FillChar(pwc2^, c, #0);
    StringToWideChar(s, pwc2, c);

    self.PositionForAppend;
    ms.Write(pwc2^, c);

    FreeMem(pwc2);
}
end;

// NOT TESTED
procedure TWideChar.Append(wc: TWideChar);
begin
	str := str + wc.str;
    {
    if wc.Size = 0 then EXIT;

    self.PositionForAppend;
    self.ms.Write(wc.Memory^, wc.size);}
end;

//procedure TWideChar.Append(GlobalH: THandle; size : cardinal);
//begin
//	str := str + UnitMisc.ClipToString(globalh, size);
//end;

constructor TWideChar.Create;
begin
    ms := TMemoryStream.Create;
end;

destructor TWideChar.Destroy;
begin
    self.Clear;
    MyFree(ms);
    inherited;
end;




function TWideChar.StrLength: int64;
begin
	result := length(str);
{
    result := trunc(ms.Size / 2) + (ms.Size mod 2);
}
end;

function TWideChar.Memory: Pointer;
begin
	result := PWideChar(@str[1]);
	//ms.Clear;
    //ms.Write(str[1], strsize(str));
    //result := ms.Memory;
end;

procedure TWideChar.PositionForAppend;
begin
{
    if ms.Size > 0 then begin
        ms.Seek(ms.Size - 2, soFromBeginning); // get rid of null terminator
    end else begin
        ms.Seek(0, soFromBeginning);
    end;
}
end;

function TWideChar.size: int64;
begin
	result := Strsize(str);
{
    result := ms.Size;
}
end;

// NOT TESTED
procedure TWideChar.TrimLeft(chars: cardinal);
begin
	str := strutils.rightstr(str, length(str)-chars);
{
    if (chars > ms.Size) then begin
        ms.Clear;
    end else begin
        ms2 := TMemoryStream.Create;
        c := ms.size - (chars * 2);
        GetMem(pwc, c);
        ms.Seek(chars * 2, soFromBeginning);
        ms.Read(pwc^, c);
        ms2.Write(pwc^, c);

        MyFree(ms);
        ms := ms2;
    end;
}
end;

// NOT TESTED
procedure TWideChar.TrimRight(chars: cardinal);




begin
	str := strutils.leftstr(str, length(str)-chars);
{
    chars := chars * 2;
    if (chars = ms.Size) then begin
        ms.Clear;
    end else if (chars < ms.Size) then begin
        ms2 := TMemoryStream.Create;
        c := ms.size - chars;
        GetMem(pwc, c);
        ms.Seek(0, soFromBeginning);
        ms.Read(pwc^, c);
        ms2.Write(pwc^, c);
        w := 0; // write null terminator
        ms2.Write(w,2);

        MyFree(ms);
        ms := ms2;
    end;
}
end;


procedure TWideChar.LeftStr(len: cardinal);
begin
	str := strutils.LeftStr(str, len);
{
    len := len * 2;
    len := min(len, ms.size-2);

    //if (ms.Size - 2) > len then begin
        ms2 := TMemoryStream.Create;
        ms2.Write(ms.Memory^, len);
        w := 0;
        ms2.write(w, 2);
        MyFree(ms);
        ms := ms2;
    //end;
}
end;

// NOT TESTED
procedure TWideChar.Replace(find, replace: widestring; replacestream: boolean);




begin
	str := StringReplace(str,find,replace,[rfReplaceAll]);

{
	p := ms.memory;
    ms2 := TMemoryStream.Create;
    ms2.Seek(0, soFromBeginning);

    FirstCase := true;
    i := pos(WideString(find), WideString(p));
    first := i;
    while i <> 0 do begin
        //ms2.Write(p, i);
        for j := 1 to i - 1 do begin
            ms2.write(p^, 2);
            inc(p, 1);
        end;
        inc(p, length(find));
        p2 := @replace[1];
        if (replacestream)  then begin
            if (i > 1) or FirstCase then begin
                r := @replace;
                ms2.write(p2^, length(replace)*2);
            end;
        end else begin
            r := @replace;
            ms2.write(p2^, length(replace)*2);
        end;
        FirstCase := false;
        i := pos(find, WideString(p));
    end;

    if first=0 then EXIT;
    

    if p <> '' then begin
        ms2.Write(p^, length(p)*2);
    end;
    if ms2.size > 0 then begin
    	w := #0;
        ms2.Write(w, sizeof(w));
        ms.clear;
        ms.Seek(0, soFromBeginning);
        ms.Write(ms2.memory^, ms2.size)
    end;

    ms2.clear;
    myfree(ms2);
}
end;

procedure TWideChar.RightStr(len: cardinal);

begin
	str := strutils.RightStr(str, len);
{
    len := len * 2;
    if ms.Size > len then begin
        ms2 := TMemoryStream.Create;
        GetMem(pwc, len);
        ms.Seek((ms.size - len) - 2, soFromBeginning); // don't include null

        ms2.Write(ms.Memory^, len);
        w := 0;
        ms2.write(w, 2); // write null

        MyFree(ms);
        FreeMem(pwc);
        ms := ms2;
    end;
}
end;

procedure TWideChar.Replace(find: widechar; replace: widechar; removenulls : boolean = true);



begin
	if replace = #0 then begin
		str := StringReplace(str,find,'',[rfReplaceAll] );
    end else begin
		str := StringReplace(str,find,replace,[rfReplaceAll] );
    end;

{
    ms.Seek(0, soFromBeginning);
    ms2 := TMemoryStream.Create;
    for i := 0 to trunc((ms.Size-1) / 2)  do begin
        ms.read(w, 2);
        if WideChar(w) <> find  then begin
            ms2.Write(w, 2);
        end else begin
            // Fails only when #0 and removenulls is disabled
            if (replace <> #0) or (not removenulls) then begin
                ms2.Write(replace, 2)
            end;
        end;
    end;
    ms.Clear;
    MyFree(ms);
    ms := ms2;

    ms.Seek(0, soFromEnd);
}
end;


function TWideChar.GetChar(pos: int64): widechar;
begin
	result := str[pos];
{
    ms.Seek(pos, soFromBeginning);
    ms.read(result, sizeof(result));
}
end;

procedure TWideChar.Append(c: WideChar);

begin
	str := str + c;
{
	self.PositionForAppend;
    w[0] := c;
    w[1] := #0;
    ms.Write(w, sizeof(w));
}
end;

procedure TWideChar.Clear;
begin
	str := '';
{
    self.Append(' ');
    if ms.Size <> 0 then ms.Clear;
}
end;

end.
