unit menu_prog;

{$MODE OBJFPC}
{$H+}
{$RANGECHECKS ON}
{$SMARTLINK ON}

interface
uses sysutils,classes,msestrings,unix,msetypes;

type
taos = array of msestring;
taoi64 = array of Int64;
TProgItem = object
name : utf8string; // en name
dirno : byte;
icon : utf8string;
cat : Int64;
exec : utf8string;
public
procedure run;
end;
taopi = array of TProgItem;
TMenuProg = class(TObject)
a: taopi;
dirno : byte;
public
constructor Create;
procedure ParseFile(n: utf8string);
end;

var
 ucat: taos;
 ulist: array of taoi64;
 user_dir: utf8string = '';

function AddUnique(s: utf8string): Int64;

implementation

const
dir0 = '/usr/share/applications/';
dir1 = '/usr/local/share/applications/';

constructor TMenuProg.Create;
  procedure Search(const APath2: string);
  var
    LRec: TSearchRec;
  begin
    if FindFirst(APath2, faAnyFile, LRec) = 0 then begin
      repeat
       ParseFile(LRec.Name);
      until FindNext(LRec) <> 0;
      FindClose(LRec);
    end;
  end;
begin
inherited;
Search(dir0+'*.desktop');
Inc(dirno);
Search(dir1+'*.desktop');
Inc(dirno);
if user_dir <> '' then begin Search(user_dir+'*.desktop'); Inc(dirno); end;
end;

procedure TMenuProg.ParseFile(n: utf8string);
var
 fp: Text;
 i: TProgItem;
 desktop_entry: bytebool = false;
 s: utf8string = '';
 cat: utf8string = '';
 l,p: Int64;
 fn: utf8string;
function SupressPercent(s: utf8string) : utf8string;
var
 f,l,p: Int64;
begin
result := s;
l := Length(s);
for f := 1 to l do if s[f] = '%' then begin
 result[f] := ' ';
 if f < l then result[f+1] := ' ';
end;
end;
begin
//WriteLn(n);
case dirno of
0:fn := dir0 + n;
1:fn := dir1 + n;
2:fn := user_dir + n;
end;
//WriteLn(fn);
Assign(fp, fn);
FileMode := 0;
ReSet(fp);
i.cat := -1;
while not eof(fp) do begin
ReadLn(fp, s);
l := Length(s);
if s = '[Desktop Entry]' then begin desktop_entry := true; continue; end;
if not desktop_entry then continue;
if Pos('[',s) = 1 then break;
if Pos('Exec=',s) = 1 then begin
i.exec := SupressPercent(Copy(s,6,l-5));
//WriteLn('i.exec = ', i.exec);
continue;
end;
if Pos('Name=',s) = 1 then begin
i.name := Copy(s,6,l-5);
//WriteLn('i.name = ', i.name);
continue;
end;
if Pos('Categories=',s) = 1 then begin
p := Pos(';',s);
cat := Copy(s,12,p-12);
if cat <> '' then i.cat := AddUnique(cat);
//WriteLn('Category = ', cat);
continue;
end;
end;
Close(fp);
if desktop_entry and (i.name <> '') and (i.exec <> '') then begin
SetLength(a, Length(a)+1);
a[High(a)] := i;
 if i.cat >= 0 then begin
  SetLength(ulist[i.cat],Length(ulist[i.cat])+1);
  ulist[i.cat][High(ulist[i.cat])] := High(a);
 end;
end else WriteLn('Bad program menu entry. File: ', n);
end;

procedure TProgItem.run;
begin
fpSystem('gorg64_runner ' + exec + ' >/dev/null 2>/dev/null');
end;

function AddUnique(s: utf8string): Int64;
var
 f: Int64;
begin
for f := 0 to High(ucat) do if s = ucat[f] then Exit(f);
SetLength(ucat,Length(ucat)+1);
SetLength(ulist,Length(ucat)+1);
ucat[High(ucat)] := s;
Exit(High(ucat));
end;

end.