#ifndef XPKMASTER_QUERY_C
#define XPKMASTER_QUERY_C

/* Routinesheader

	Name:		query.c
	Main:		xpkmaster
	Versionstring:	$VER: query.c 1.4 (09.06.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
 1.4   09.06.97 : fixed Enforcer hit, when library opening failed
*/

#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(!error)
  {
    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 */

