#ifndef XPKMASTER_QUERY_C
#define XPKMASTER_QUERY_C

/* Routinesheader

	Name:		query.c
	Main:		xpkmaster
	Versionstring:	$VER: query.c 1.3 (31.03.97)
	Author:		SDI
	Distribution:	PD
	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
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <dos/dos.h>
#include "xpkmaster.h"
#include "xpk_strings.h"

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

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

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

#ifdef __cplusplus
  extern "C"
#endif

LONG __asm LIBXpkQuery(register __a0 struct TagItem *ti)
{
  struct TagItem	*tags = ti;
  STRPTR		packmethod = 0,
  			errtext = 0;
  ULONG			packmode = 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[] = "compressors/xpk____.library";

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

  while((ti = NextTagItem(&tags)))
  {
    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 = (STRPTR) ti->ti_Data; break;
    case XPK_PackMode: packmode = ti->ti_Data; break;
    case XPK_GetError: errtext = (STRPTR) ti->ti_Data; break;
    case XPK_Preferences: prefs = ti->ti_Data; break;
    };
  }

  if(packmethod)
  {
    libname[15] = toupper(packmethod[0]);
    libname[16] = toupper(packmethod[1]);
    libname[17] = toupper(packmethod[2]);
    libname[18] = toupper(packmethod[3]);

    if(strnicmp("USER", libname+15, 4))
    {
      if(!(XpkSubBase = OpenLibrary(libname, 0)) ||
      !(sinfo = XpksPackerInfo()))
        error = XPKERR_MISSINGLIB;
    }
    else
    {
      sinfo = &USERInfo;
      sinfo->xi_Description = strings[TXT_USER_DESCRIPTION];
    }
  }

  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(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;
    while(m && m->xm_Upto < packmode)
      m = m->xm_Next;

    if(!m)
      error = XPKERR_NOINFO;
    else
      CopyMem(m, pmode, sizeof(struct XpkMode));
  }
  else
    error = XPKERR_BADPARAMS;

  if(errtext)
    sprintf(errtext, XpkErrs[-error]);

  if(XpkSubBase)
    CloseLibrary(XpkSubBase);

  return error;
}

#endif /* XPKMASTER_QUERY_C */

