// =====================================================
//
//   miniLA_win - Misc. utilities
//
//   (c) miniLA Team
//
// =====================================================
//
// This 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, or (at your option)
// any later version.
//
// This software 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 package; see the file COPYING.  If not, write to
// the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.


unit uUtils;

interface

function IntToBin(Value:cardinal; NumOfBits:integer; SupZero:boolean):string;
function IntToOct(Value:cardinal; NumOfBits:integer):string;
function IntToHex(Value:cardinal; NumOfBits:integer):string;

function BinToInt(Value:string):cardinal;
function OctToInt(Value:string):cardinal;
function HexToInt(Value:string):cardinal;

function IntLog2(value: integer): integer;
function IntExp2(value: integer): integer;

function TmToStr(T:double;Decimals:integer):string;
function GetDecades(Number:Int64):Int64;

function IntToDecStr(val: int64):string;

implementation

uses SysUtils;

//==============================================================================
//  Conversion functions
//==============================================================================

//==========================================================
// IntToBin converter with selectable leading zeroes supression
//==========================================================
function IntToBin(Value:cardinal; NumOfBits:integer; SupZero:boolean):string;
begin
  Result:='';
  while (NumOfBits>0) do begin
    if (value and (1 shl (NumOfBits-1))) <> 0 then
     begin
       SupZero := false;
       Result:=Result+'1';
     end
    else if (SupZero=false) or (NumOfBits=1) then
       Result:=Result+'0';

    dec(NumOfBits);
  end;
end;

//==========================================================
function IntToOct(Value:cardinal; NumOfBits:integer):string;
//==========================================================
var digits: byte;
begin
  digits:=(NumOfBits+2) div 3;
  Result:='';
  while (digits>0) or (Value>0) do begin
    Result:=Chr(Ord('0')+(Value and 7))+Result;
    Value:=Value shr 3;
    dec(digits);
  end;
end;

//==========================================================
function IntToHex(Value:cardinal; NumOfBits:integer):string;
//==========================================================
const pole:array[0..15] of char='0123456789ABCDEF';
var digits: byte;
begin
  Result:='';
  digits:=(NumOfBits+3) div 4;
  while (digits>0) or (Value>0) do begin
    Result:=pole[Value and 15]+Result;
    Value:=Value shr 4;
    dec(digits);
  end;
end;


//==========================================================
function BinToInt(Value:string):cardinal;
//==========================================================
var
   i	: word;
begin
  Result:=0;
  for i:=1 to length(value) do
   begin
     result := result*2;
     if value[i] = '1' then
        result := result + 1;
   end;
end;

//==========================================================
function OctToInt(Value:string):cardinal;
//==========================================================
var
   i	: word;
begin
  Result:=0;
  for i:=1 to length(value) do
   begin
     result := result shl 3;
     case value[i] of
	'0'..'7': result := result + ord(value[i]) - ord('0');
     end;
   end;
end;

//==========================================================
function HexToInt(Value:string):cardinal;
//==========================================================
var
   i	: word;
begin
  Result:=0;
  for i:=1 to length(value) do
   begin
     result := result shl 4;
     case value[i] of
	'0'..'9': result := result + ord(value[i]) - ord('0');
	'A'..'F': result := result + ord(value[i]) - ord('A') + 10;
	'a'..'f': result := result + ord(value[i]) - ord('a') + 10;
     end;
   end;
end;

//==========================================================
function IntLog2(value: integer): integer;
//==========================================================
begin
   result := 0;
   value := abs(value);
   while (value > 1) do
    begin
      value := value div 2;
      inc(result);
    end;
end;

//==========================================================
function IntExp2(value: integer): integer;
//==========================================================
var
   i	: integer;
begin
   result := 1;
   for i:=1 to value do
      result := result * 2;
end;



//=================================================================
// Convert time in sec [double] to string
//=================================================================
function TmToStr(T:double;Decimals:integer):string;
const rady:array[-6..6] of char='afpnum KMGTPE';
var rad:integer;
    sign:integer;
begin
  // handle zero
  if T=0 then begin
    str(T:1:Decimals,Result);
    exit;
  end;

  rad:=0;
  sign:=Round(Abs(T)/T);
  T:=Abs(T);
  if T<1 then
    while T<1 do begin
      dec(rad);
      T:=T*1000;
    end
  else if T>1000 then
    while T>1000 do begin
      inc(rad);
      T:=T/1000;
    end;
  str(T*sign:1:Decimals,Result);
  if rad<>0 then Result:=Result+rady[rad];
end;

{
//=================================================================
// Calculate the step in form [1,2,4] * 10^n
//=================================================================
function GetDecades(Number:Int64):Int64;
begin
 Result:=1;
 while Number > 10 do		  		// 1*10^n ?
  begin
    Number := Number div 2;
    Result := Result * 2;
    if Number <= 10 then			// 2*10^n ?
       break;

    if (Number div 2) <= 10 then          	// 4*10^n ?
     begin
      Result := Result * 2;
      break;
     end;

    Number := Number div 5;
    Result := Result * 5;
  end;
}

//=================================================================
// Calculate the step in form [1,2,5] * 10^n
//=================================================================
function GetDecades(Number:Int64):Int64;
begin
 Result:=1;
 while Number > 10 do		  		// 1*10^n ?
  begin
    if (Number div 2) <= 10 then          	// 2*10^n ?
     begin
      Result := Result * 2;
      break;
     end;

    if (Number div 5) <= 10 then          	// 5*10^n ?
     begin
      Result := Result * 5;
      break;
     end;

    Number := Number div 10;
    Result := Result * 10;
  end;
end;

//=================================================================
// Convert integer to string with separated decimal places 
//=================================================================
function IntToDecStr(val: int64):string;
var
   i, m, n : byte;
   str: string;
   neg: boolean;
begin
   if val<0 then
    begin
       val:=-1*val;
       neg:= true;
    end;

   str := IntToStr(val);
   n := length(str) div 3;
   m := length(str) mod 3;
   Result := '';
   for i:=1 to n do
     Result := copy(str, length(str)-i*3+1, 3) + ' ' + Result;

   if m<>0 then
      Result := copy(str, 1, m) + ' ' + Result;

   if neg then
      Result := '-' + Result;
end;

end.
