#ifndef XPKMASTER_QUERY_C
#define XPKMASTER_QUERY_C

/* Routinesheader

	Name:		query.c
	Main:		xpkmaster
	Versionstring:	$VER: query.c 1.10 (26.03.1998)
	Author:		SDI
	Distribution:	Freeware
	Description:	Implementation of XpkQuery

 1.0   06.10.96 : first real version
 1.1   27.12.96 : removed 1.3 specific functions
 1.2   09.03.97 : added USER mode
 1.3   31.03.97 : made tag processing better, nearly rewritten all, removed
 	goto's this way
 1.4   09.06.97 : fixed Enforcer hit, when library opening failed
 1.5   19.12.97 : code cleanup
 1.6   24.12.97 : no packmode brings default mode now
 1.7   01.01.98 : USER information is a bit better now
 1.8   21.02.98 : uses new style register definition
 1.9   03.03.98 : fixed enforcer hits
 1.10  26.03.98 : some optimizations
*/

#include <exec/memory.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/xpksub.h>
#include <proto/utility.h>
#include "xpkmaster.h"
#include "texts.h"

/************************************************************************
 *
 *  Information query
 *
 */

static const struct XpkMode USERMode = { 0,100,0,0,0,50,500,500,0,"user"};

static const struct XpkInfo USERInfo = { 1,0,0,1,"USER","User",
0, 0x55534552, XPKIF_PK_CHUNK|XPKIF_UP_CHUNK, DEFAULTCHUNKSIZE, 10,
DEFAULTCHUNKSIZE,0,0,0,0,100,0,&USERMode,0,0,0,0,0,0};

ASM(LONG) LIBXpkQuery(REG(a0, struct TagItem *tags))
{
  struct TagItem	*ti, *ti2 = tags;
  ULONG			packmode = 101,
			packmethod = 0,
  			prefs = 1; /* use prefs, default is true */
  LONG			error = 0;
  struct XpkPackerInfo *pinfo = 0;
  struct XpkPackerList *plist = 0;
  struct XpkMode *	pmode = 0;
  struct Library *	XpkSubBase = 0;
  struct XpkInfo *	sinfo = 0;
  UBYTE			libname[SUBLIBNAME_SIZE];

#ifdef DEBUG
  DebugTagList("XpkQuery", tags);
#endif

  while((ti = NextTagItem(&ti2)))
  {
    switch(ti->ti_Tag)
    {
    case XPK_PackersQuery: plist = (struct XpkPackerList *) ti->ti_Data;
      break;
    case XPK_ModeQuery: pmode = (struct XpkMode *) ti->ti_Data; break;
    case XPK_PackerQuery: pinfo = (struct XpkPackerInfo *) ti->ti_Data;
      break;
    case XPK_PackMethod: packmethod = idfromname((STRPTR) ti->ti_Data);
      break;
    case XPK_PackMode: packmode = ti->ti_Data; break;
    case XPK_Preferences: prefs = ti->ti_Data; break;
    }
  }

  if(plist)
  {
    struct FileInfoBlock *fib;

    if(!(fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
      error = XPKERR_NOMEM;
    else
    {
      ULONG lock;

      memset(plist, 0, sizeof(struct XpkPackerList));
      if(!(lock = Lock("LIBS:compressors", ACCESS_READ)))
        error = XPKERR_NOINFO;
      else
      {
        if(!Examine(lock, fib) || fib->fib_DirEntryType < 0)
          error = XPKERR_NOINFO;
        else
        {
	  while(ExNext(lock, fib))
	  {
	    if(!strncmp("xpk", fib->fib_FileName, 3) &&
            !strcmp(".library", fib->fib_FileName+7))
	    {
	      ULONG ID = idfromname(fib->fib_FileName+3), i;

              for(i = plist->xpl_NumPackers; i > 0 &&
	      *(ULONG *) plist->xpl_Packer[i - 1] > ID; i--)
	      *(ULONG *) plist->xpl_Packer[i] =
	      *(ULONG *) plist->xpl_Packer[i-1];
	      *(ULONG *) plist->xpl_Packer[i] = ID;

	      if(++plist->xpl_NumPackers == MAXPACKERS)
	        break;
	    }
	  }
          if(prefs) /* add USER mode */
          {
	    if(plist->xpl_NumPackers == MAXPACKERS)
	      --plist->xpl_NumPackers;
            *(ULONG *) plist->xpl_Packer[plist->xpl_NumPackers++] = 0x55534552;
          }
        }
        UnLock(lock);
      }
      FreeDosObject(DOS_FIB, fib);
    }
  }
  else if(packmethod)
  {
    if(packmethod == USER_COOKIE)
    {
      sinfo = (struct XpkInfo *) &USERInfo;
      sinfo->xi_Description = strings[TXT_USER_DESCRIPTION];
    }
    else
    {
      sprintf(libname, SUBLIBNAME_STRING, &packmethod);

      if(!(XpkSubBase = OpenLibrary(libname, 0)) ||
      !(sinfo = XpksPackerInfo()))
        error = XPKERR_MISSINGLIB;
    }
    
    if(!error)
    {
      if(pinfo)
      {
        sprintf(pinfo->xpi_Name, sinfo->xi_Name);
        sprintf(pinfo->xpi_LongName, sinfo->xi_LongName);
        sprintf(pinfo->xpi_Description, sinfo->xi_Description);
        pinfo->xpi_Flags = sinfo->xi_Flags;
        pinfo->xpi_MaxChunk = sinfo->xi_MaxPkInChunk;
        pinfo->xpi_DefChunk = sinfo->xi_DefPkInChunk;
        pinfo->xpi_DefMode = sinfo->xi_DefMode;
      }
      else if(pmode)
      {
        struct XpkMode* m = sinfo->xi_ModeDesc;

        if(packmode == 101)
          packmode = sinfo->xi_DefMode;

        while(m && m->xm_Upto < packmode)
          m = m->xm_Next;

        if(m)
        {
          CopyMem(m, pmode, sizeof(struct XpkMode));
          pmode->xm_Next = 0;
        }
        else
          error = XPKERR_NOINFO;
      }
      else
        error = XPKERR_BADPARAMS;
    }
    if(XpkSubBase)
      CloseLibrary(XpkSubBase);
  }
  else
    error = XPKERR_BADPARAMS;

  return parseerrortags(tags, error);
}

#endif /* XPKMASTER_QUERY_C */

