# The ADS package, initiated September 23, 2007

package.checkclib('ads');  # has C dynamic link library been found ?

ads.initstring :=
   'ads v3.0.5 as of June 18, 2012\n';

# ads.createdict:
# Create an ADB file from a text dictionary. In the text file keys and values must be
# separated by pipes.

ads.createdict := proc(name, language) is
   if name :- string then
      error('Error in `ads.createdict`: pass the prefix of the filename as 1st argument.')
   fi;
   if language :- string then
      error('Error in `ads.createdict`: pass the name of the language as 2nd argument.')
   fi;
   local fn := os.getenv('AGENAPATH') & '/books/' & name & '.dict';
   local fout := os.getenv('AGENAPATH') & '/books/' & name & '.adb';
   local L := io.readlines(fn, '#');
   local it, max;
   max := 0;
   # determine largest key
   for j in L do
      it := j split '|';
      if size(it[1]) > max then
         max := size(it[1])
      fi
   od;
   ads.createbase(fout, size(L), 'database', 3, max);
   local fh := ads.openbase(fout);
   for j in L do
      it := j split '|';
      if it[1] <> '' then
         ads.writebase(fh, it[1], it[2], language)
      fi
   od;
   ads.closebase(fh)
end;

# ads.opendict written July 11, 2007

ads.opendict := proc(name) is
   local fout := os.getenv('AGENAPATH') & '/books/' & name & '.adb';
   return ads.openbase(fout)
end;

# ads.fastopen written July 12, 2007
# opens a database in readonly mode for later access by ads.fastread. The return is the number
# of the file handle plus an entry to global ads.baseinfo with various information needed by fastread.

ads.fastopen := proc(fn) is
   local fh := ads.openbase(fn, 'readonly');
   local inds := ads.indices(fh);
   local high := ads.sizeof(fh);
   local keylen := ads.attrib(fh)['keylength'];
   local listflag := ads.attrib(fh)['type'];
   if listflag > 1 then
      error('Error in `ads.fastopen`: function not applicable to sequences.')
   fi;
   if ads.baseinfo = null then
      create table ads.baseinfo
   fi;
   ads.baseinfo[fh] := [inds, high, keylen, listflag];
   return fh
end;

# ads.fastread written July 12, 2007:
# reads the value to the given key by high speed access to fh. fastread is 33 % faster than ads.read.
# Example:
# > fh := ads.fastopen('d:/t.agb');
# > ads.fastread(fh, 'aleks'):

ads.fastread := proc(fh, key) is
   local infos := ads.baseinfo[fh];
   return ads.fastseek(fh, key, infos[1], infos[2], infos[3], infos[4])
end;

# ads.fastclose written July 12, 2007

ads.fastclose := proc(fh) is
   local result := ads.closebase(fh);
   if result then
      clear ads.baseinfo[fh]
   fi;
   return result
end;

# ads.lookup written July 09, 2007
# search for a key in a database with internal diacritics and runes extension;
# If the function does not find the exact key, it searches anew by prepending `*` to the key.
# If it still cannot find anything it iterates over all keys and values in the database.
#
# Examples:
# > ads.lookup(fh, '<th>iudinassus') -> ads.seek(fh, 'şiudinassus') -> kingdom
#
# > ads.lookup(fh, '[.]*<th>iud'):
# Gutşiuda = Gotenfolk
# şiudinassus = Königreich

ads.lookup := proc(fh, word) is
   if fh = null or float(fh) then
      error('Error in `ads.lookup`: base not opened.')
   fi;
   if word :- string then
      error('Error in `ads.lookup`: expected a string.')
   fi;
   local key := ads.auxconvert(word);
   local found := ads.readbase(fh, key);
   if assigned(found) then
      return found
   else # search for reconstructed words marked by a preceeding asterisk
      found := ads.readbase(fh, '*' & key);
      if assigned(found) then
         return '[*] ' & found
      fi
   fi;
   # inprecise search, allowing regexs
   local s, t := ads.iterate(fh, '');
   create local table result;
   while s <> null do
      if key in s then
         result[s] := t
      fi;
      s, t := ads.iterate(fh, s)
   od;
   return result
end;

# ads.search, written July 21, 2007
# search all values in a dictionary for a given substring (with internal diacritics and runes extension);
# Return is a table.
#
# Examples:
# > ads.search(fh, '<th>iudinassus') -> ads.seek(fh, 'şiudinassus') -> kingdom
#
# > ads.seek(fh, '[.]*<th>iud'):
# Gutşiuda = Gotenvolk
# şiudinassus = Königreich

ads.search := proc(fh, word, column) is
   local col;
   if fh = null or float(fh) then
      error('Error in `ads.search`: base not opened.')
   fi;
   if word :- string then
      error('Error in `ads.search`: expected a string.')
   fi;
   col := is column = null then 2 else column si;
   local key := ads.auxconvert(word);
   return ads.rawsearch(fh, key, col)
end;

# close all open files in one stroke; July 09, 2007

ads.closeall := proc() is
   for keys i in ads.openfiles do
      ads.closebase(i)
   od
   return null
end;


# creates a sequence; April 22, 2008

ads.createseq := proc(fn) is
   if fn :- string then
      error('Error in `ads.createseq`: must get a filename (a string)')
   fi;
   ads.createbase(fn, 10, 'seq')
end;


