/*
 *	$Source: /u1/Xr/src/Xrlib/Intrinsic/RCS/resource.c,v $
 *	$Header: resource.c,v 1.1 86/12/17 09:09:19 swick Exp $
 */

#ifndef lint
static char *rcsid_resource_c = "$Header: resource.c,v 1.1 86/12/17 09:09:19 swick Exp $";
#endif	lint

#include <Xr/xr-copyright.h>

/* $Header: resource.c,v 1.1 86/12/17 09:09:19 swick Exp $ */
/* Copyright 1986, Hewlett-Packard Company */
/* Copyright 1986, Massachussetts Institute of Technology */

static char rcsid[] = "$Header: resource.c,v 1.1 86/12/17 09:09:19 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        resource.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: This file contains the source for the X-ray resource
 **                manager.
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	resource.c,v $
 * Revision 1.1  86/12/17  09:09:19  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:21:40  08:21:40  rick ()
 * Final QA release
 * 
 * Revision 6.0  86/11/10  15:22:49  15:22:49  rick ()
 * QA #2 release
 * 
 * Revision 5.2  86/11/07  14:02:35  14:02:35  rick ()
 * Added the copyright message.
 * 
 * Revision 5.1  86/11/03  15:10:10  15:10:10  rick ()
 * Remove the MSG_UPDATE message.  Made the error number return conditions
 * more explicit.  Put in additional error checking.
 * 
 * Revision 5.0  86/10/28  08:23:31  08:23:31  rick ()
 * QA #1.1 release
 * 
 * Revision 4.0  86/10/20  12:09:30  12:09:30  rick ()
 * QA 1 release
 * 
 * Revision 3.3  86/10/17  12:23:56  12:23:56  rick ()
 * Linted
 * 
 * Revision 3.2  86/10/16  11:21:08  11:21:08  rick ()
 * Added register variables.
 * 
 * Revision 3.1  86/10/15  13:57:44  13:57:44  rick ()
 * Added the code for the NEWTYPE and FREETYPE messages.
 * 
 * Revision 3.0  86/10/02  15:59:19  15:59:19  rick ()
 *  Alpha release set to 3.0
 * 
 * Revision 2.0  86/09/16  08:03:39  08:03:39  rick ()
 * *** empty log message ***
 * 
 * Revision 1.1  86/09/03  13:35:18  13:35:18  rick ()
 * Initial revision
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/


#include <X/Xlib.h>
#include <Xr/defs.h>
#include <Xr/types.h>



extern xrResource * _XrTreeSearch();


/*
 *  Defines used internally by the resource manager.
 */

#define _XrINTERNSET 64000	/* reserved resource types and ids   */
#define _XrINTERNCOUNT 11 	/* number of internal resource types */



/*
 *  Definition and initialization of X-ray's internal resource types
 */

static xrResourceType internTypeSet[] =
   { { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, 
     { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL },
     { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL },
     { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL },
     { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL } };

static xrResourceType * internType = internTypeSet;


/*
 *  Definition and initialization of the variable to hold the
 *  application defined resource types.
 */

static xrResourceType * externType = NULL;
static INT32 externTypeCount = 0;



/*************************************<->*************************************
 *
 *  XrResource (message, data)
 *  INT32  message;
 *  INT8 * data;
 *
 *
 *   Description:
 *   -----------
 *     XrResource() is the main resource manager routine.  The resource 
 *     manager is used to make the control and acess of resource objects
 *     easy by allowing resources to be added, retrieved, and reoved from
 *     an internally managed list.  The resource manager allow resources
 *     to reside explicitly in memory or within a resource disc file.
 *     XrResource() provides the message handling code segments for each
 *     of the resource managers capabilities.  For a complete description
 *     of the resource manager, refer to XrResource(3XR) and the X-ray
 *     toolbox manual.
 *
 *
 *   Inputs:
 *   ------
 *     message = Contains the message which describes the capability
 *               to be executed.
 *
 *     data    = Contains a pointer to a structure necessary for the
 *               completion of the message.
 *
 *     For a complete description of the resource managers messages and
 *     data parameters, refer to XrResource(3XR) and the X-ray toolbox manual.
 * 
 *   Outputs:
 *   -------
 *     TRUE  = Returned as the value of the function if the message succeeds.
 *
 *     FALSE = Returned as the value of the function if the message fails.
 *
 *     data  = Several of the messages return information in the structure
 *             pointed at by data.
 *
 *     xrError = The error variable is set to one several values upon
 *               failure of this routine.
 *
 *     For a complete description of the values returned in data, 
 *     refer to XrResource(3XR) and the X-ray toolbox manual.
 *
 *
 *   Procedures Called
 *   -----------------
 *     _XrVerifyType
 *     _XrResourceGet
 *     _XrResourcePut
 *     _XrTreeSearch  - tree.c
 *     _XrTreeInsert  - tree.c
 *     _XrTreeDelete  - tree.c
 *
 *************************************<->***********************************/


XrResource (message, data)
UINT32 message;
INT8 * data;

{
   xrResource ** _XrVerifyType();


   /*
    *  Set up a switch statement to handle each of the possible
    *  messages as an independent case.
    */

   switch (message)
   {

      /*
       *  The following set of messages handle the file accessing
       *  for the resource manager.
       */

      case MSG_OPEN:		/*  Open a resource file  */
         xrErrno = XrINVALIDMSG;
         return (FALSE);
      break;


      case MSG_CLOSE:		/*  Close a resource file  */
         xrErrno = XrINVALIDMSG;
         return (FALSE);
      break;


      case MSG_NEW:		/*  Create a new disc based resource  */
         xrErrno = XrINVALIDMSG;
         return (FALSE);
      break;


      case MSG_FREE:		/*  Destroy a disc based resource  */
         xrErrno = XrINVALIDMSG;
         return (FALSE);
      break;


      case MSG_UPDATEFILE:	/*  Update an entire resource file  */
         xrErrno = XrINVALIDMSG;
         return (FALSE);
      break;


      case MSG_UPDATEALLFILES:	/*  Update all of the resource files  */
         xrErrno = XrINVALIDMSG;
         return (FALSE);
      break;


      /*
       *  The following set of messages provide for the main-line
       *  accessing of the resources contained in the resource lists.
       */

      case MSG_ADD:		/*  Add a resource to the tree  */
      {
         xrResourceInfo * resourceInfo;
         xrResource       resource;
         xrResource     * node;
         xrResource    ** parent;


         if ((resourceInfo = (xrResourceInfo *) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return (FALSE);
         }


         /*
          *  Verify that the id is valid.
          */

         if (resourceInfo -> resourceId == 0)
         {
            xrErrno = XrINVALIDID;
            return (FALSE);
         }


         /*
          *  Verify that the resource type specified is ok.
          */

         if ((parent = _XrVerifyType (resourceInfo -> resourceType)) == 
              (xrResource **) NULL)
            return (FALSE);


         /*
          *  Check to see if the node is in the tree.  If it is and
          *  it is locked, fail.
          */

         if ((node = _XrTreeSearch(resourceInfo->resourceId, &parent)) !=
              (xrResource *) NULL)
            if (node -> resourceState & XrLOCK)
            {
               xrErrno = XrINVALIDSTATE;
               return (FALSE);
            }


         /*
          *  See if the new resource is from disc or memory.
          *  If from disc, go and read it.
          */

         if (resourceInfo -> resourceObject == NULL)
         {
            if (_XrResourceGet (resourceInfo, &resource) == FALSE)
               return (FALSE);
         }
         else
         {
            resource.resourceId = resourceInfo -> resourceId;
            resource.resourceState = resourceInfo -> resourceState;
            resource.resourceObject = resourceInfo -> resourceObject;
            resource.resourceFile = XrMEMORY;
         }


         /*
          *  If the node is already in the tree, save the old
          *  resource object into the application info structure
          *  so that it has access to it.  If the node is not
          *  in the tree, allocate a node, set the neccessay
          *  node values and add the node into the tree.
          */

         if (node != NULL)
         {
           if (node -> resourceFile == XrMEMORY)
              resourceInfo -> resourceObject = node -> resourceObject;
         }
         else
         {
            if ((node = (xrResource *)
                        (*xrMalloc)(sizeof(xrResource))) == NULL)
            {
               xrErrno = XrOUTOFMEM;
               return (FALSE);
            }
            node -> resourceId = resource.resourceId;
            node -> left = node -> right = NULL;
            _XrTreeInsert (parent, node);
         }


         /*
          *  Set the remaining node values and return success.
          */

         node -> resourceState = resource.resourceState;
         node -> resourceObject = resource.resourceObject;
         node -> resourceFile = resource.resourceFile;

         return (TRUE);
      }
      break;


      case MSG_REMOVE:		/*  Remove a resource from the tree  */
      {
         xrResourceInfo * resourceInfo;
         xrResource     * node;
         xrResource    ** parent;


         if ((resourceInfo = (xrResourceInfo *) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return (FALSE);
         }


         /*
          *  Verify that the resource type specified is ok.
          */

         if ((parent = _XrVerifyType (resourceInfo -> resourceType)) == 
              (xrResource **) NULL)
            return (FALSE);


         /*
          *  Check to see if the node is in the tree.  If not, fail.
          */

         if ((node = _XrTreeSearch (resourceInfo -> resourceId, &parent)) ==
              (xrResource *) NULL)
         {
            xrErrno = XrINVALIDID;
            return (FALSE);
         }


         /*
          *  See if the resource is locked.  If so, fail.  
          */

         if (node -> resourceState & XrLOCK)
         {
            xrErrno = XrINVALIDSTATE;
            return (FALSE);
         }


         /*
          *  See if the resource is from disc or memory.  If from
          *  disc, and its update flag is set, and its protect flag
          *  is not set, write the resource.
          */

         if (node -> resourceFile != XrMEMORY)
         {
            if (node -> resourceState & XrUPDATE &&
                !(node -> resourceState & XrPROTECT))
            {
               if (_XrResourcePut (node) == FALSE)
                  return (FALSE);
            }
         }
         else
         {
            resourceInfo -> resourceState = node -> resourceState;
            resourceInfo -> resourceObject = node -> resourceObject;
         }


         /*
          *  Delete the node from the tree and free the node.
          */

         _XrTreeDelete (parent, node);
         (*xrFree) (node);

         return (TRUE);
      }
      break;


      case MSG_FIND:		/*  Search for a resource in the tree  */
      {
         xrResourceInfo * resourceInfo;
         xrResource     * node;
         xrResource    ** parent;


         if ((resourceInfo = (xrResourceInfo *) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return (FALSE);
         }


         /*
          *  Verify that the resource type specified is ok.
          */

         if ((parent = _XrVerifyType (resourceInfo -> resourceType)) == 
              (xrResource **) NULL)
            return (FALSE);


         /*
          *  Check to see if the node is in the tree.  If not, fail.
          */

         if ((node = _XrTreeSearch(resourceInfo->resourceId, &parent)) ==
              (xrResource *) NULL)
         {
            xrErrno = XrINVALIDID;
            return (FALSE);
         }


         /*
          *  Copy the members of the resource node that has been found
          *  into the resourceInfo structure provided by the application.
          */

         resourceInfo -> resourceState = node -> resourceState;
         resourceInfo -> resourceObject = node -> resourceObject;
         resourceInfo -> resourceFile = node -> resourceFile;

         return (TRUE);
      }
      break;


      case MSG_UPDATE:		/*  Update a resource to disc  */
         xrErrno = XrINVALIDMSG;
         return (FALSE);
      break;


      case MSG_SETSTATE:	/*  Set the state of a resource  */
      {
         xrResourceInfo * resourceInfo;
         xrResource     * node;
         xrResource    ** parent;


         if ((resourceInfo = (xrResourceInfo *) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return (FALSE);
         }


         /*
          *  Verify that the resource type specified is ok.
          */

         if ((parent = _XrVerifyType (resourceInfo -> resourceType)) == 
              (xrResource **) NULL)
            return (FALSE);


         /*
          *  Check to see if the node is in the tree.  If not, fail.
          */

         if ((node = _XrTreeSearch(resourceInfo->resourceId, &parent)) ==
              (xrResource *) NULL)
         {
            xrErrno = XrINVALIDID;
            return (FALSE);
         }


         /*
          *  Set the state and return success.
          */

         node -> resourceState = resourceInfo -> resourceState;

         return (TRUE);
      }
      break;


      /*
       *  The following two messages handle the addition and deletion
       *  of application defined resoruce types.
       */

      case MSG_NEWTYPE:		/*  Create a new resource type  */
      {
         xrResourceTypeInfo * newType;
         INT32 i;


         if ((newType = (xrResourceTypeInfo *) data) == NULL)
         {
            xrErrno = XrINVALIDPARM;
            return (FALSE);
         }

         if (newType -> resourceType < 1 || newType -> resourceType > 63999)
         {
            xrErrno = XrINVALIDTYPE;
            return (FALSE);
         }

         if (externTypeCount == 0)
         {
            if ((externType = (xrResourceType *) (*xrMalloc)
               ((newType -> resourceType + 1) * 
                 sizeof (xrResourceType))) == NULL)
            {
               xrErrno = XrOUTOFMEM;
               return (FALSE);
            }
         }

         else if (externTypeCount - 1 < newType -> resourceType)
         {
            if ((externType = (xrResourceType *) (*xrRealloc)
               (externType, (newType -> resourceType + 1)
                 * sizeof (xrResourceType))) == NULL)
            {
               xrErrno = XrOUTOFMEM;
               return (FALSE);
            }
         }

         else if (externType[newType -> resourceType].resourceHandler != 
                  (xrPFI) -1)
         {
            xrErrno = XrINVALIDTYPE;
            return (FALSE);
         }

         for (i = externTypeCount; i < newType -> resourceType + 1; i++)
         {
            externType[i].resourcePtr = NULL;
            externType[i].resourceHandler = (xrPFI) - 1;
         }

         if (externTypeCount < newType -> resourceType + 1)
            externTypeCount = newType -> resourceType + 1;

         externType[newType -> resourceType].resourceHandler = 0;
         return (TRUE);
      }
      break;


      case MSG_FREETYPE:	/*  Destroy a resource type  */
      {
         UINT16 freeType;
         INT32 i;

         freeType = (UINT16) data;

         if (freeType == 0 || freeType >= externTypeCount)
         {
            xrErrno = XrINVALIDTYPE;
            return (FALSE);
         }

         if (externType[freeType].resourcePtr != NULL ||
             externType[freeType].resourceHandler != NULL)
         {
            xrErrno = XrINVALIDTYPE;
            return (FALSE);
         }

         if (freeType == externTypeCount - 1)
         {
            for (i = externTypeCount - 2; i > 0; i--)
               if ((externType[i].resourceHandler) != (xrPFI) -1)
                  break;
            if (i == 0)
            {
               free (externType);
               externType = NULL;
               externTypeCount = 0;
            }
            else
            {
               if ((externType = (xrResourceType *) (*xrRealloc)
                   (externType, (i + 1) * sizeof (xrResourceType))) == NULL)
               {
                  xrErrno = XrOUTOFMEM;
                  return (FALSE);
               }
               externTypeCount = i + 1;
            }
        }
        else
           externType[freeType].resourceHandler = (xrPFI) -1;         

        return (TRUE);
      }
      break;


      default:
         xrErrno = XrINVALIDMSG;
         return (FALSE);
      break;
   }
}



/*************************************<->*************************************
 *
 *  _XrVerifyType (resourceType)
 *  UINT16 resourceType;
 *
 *
 *   Description:
 *   -----------
 *     _XrVerifyType is a static internal routine which verifys that
 *     the resource type specified is valid whether being an internal
 *     or external type.  When the type is verified, the pointer to
 *     the head of the tree which contains the resources for the type
 *     is extracted and returned.
 *
 *
 *   Inputs:
 *   ------
 *     resourceType = The 16 bit unsigned integer resource 
 *                    type to be verified.
 * 
 *   Outputs:
 *   -------
 *     treeHead = Returned as the value of the function when it succeeds.
 *
 *     NULL     = Returned as the value of the function when it fails.
 *
 *     xrErrno  = When this routine fails, xrErrno is set to XrINVALIDID.
 *
 *
 *   Procedures Called
 *   -----------------
 *     None
 *
 *************************************<->***********************************/


static xrResource **
_XrVerifyType (resourceType)
UINT16 resourceType;

{
   if (resourceType >= _XrINTERNSET &&
       resourceType <= _XrINTERNSET + _XrINTERNCOUNT - 1)
      return (&((internType + resourceType - _XrINTERNSET) -> resourcePtr));

   else if (resourceType < externTypeCount && 
            resourceType != 0              &&
            &(externType + resourceType) -> resourcePtr != NULL)
      return (&((externType + resourceType) -> resourcePtr));

   else
   {
      xrErrno = XrINVALIDTYPE;
      return (NULL);
   }
}



/*************************************<->*************************************
 *
 *  _XrResourceGet (resourceInfo, resource)
 *  xrResourceInfo * resourceInfo;
 *  xrResource     * resource;
 *
 *
 *   Description:
 *   -----------
 *     _XrResourceGet() finds and reads a disc based resource described
 *     by resourceInfo.  The resource is information read is placed
 *     into the resource structure pointed at by resource.
 *
 *
 *   Inputs:
 *   ------
 *     resourceInfo = This is a pointer to an xrResourceInfo structure
 *                    which contains the type, id, state, and file of
 *                    the resource to be read.
 *
 *     resource     = This is a pointer to an xrResource structure.
 *                    It is only used to return values.
 *
 * 
 *   Outputs:
 *   -------
 *     TRUE     = Returned as the value of the function if the resource
 *                is successfully read.
 *
 *     FALSE    = Returned as the value of the function if the resource
 *                cannot be found or the file identifier in resourceInfo
 *                is invalid.
 *
 *     resource = All of the fields of this structure will be set to
 *                the appropriate resource information when the routine
 *                succeeds.
 *
 *     xrErrno  = When this routine fails, xrErrno is set to XrFILEERROR.
 *
 *
 *   Procedures Called
 *   -----------------
 *     ???
 *     ???
 *
 *************************************<->***********************************/


static
_XrResourceGet (resourceInfo, resource)
xrResourceInfo * resourceInfo;
xrResource     * resource;

{
   xrErrno = XrINVALIDPARM;
   return (FALSE);
}



/*************************************<->*************************************
 *
 *  _XrResourcePut (resource)
 *  xrResource * resource;
 *
 *
 *   Description:
 *   -----------
 *     _XrResourceGet() finds and writes a disc based resource contained
 *     in resource.
 *
 *
 *   Inputs:
 *   ------
 *     resource = This is a pointer to an xrResource structure which
 *                contains the resource information to be written.
 *
 * 
 *   Outputs:
 *   -------
 *     TRUE    = Returned as the value of the function if the resource
 *               is successfully written.
 *
 *     FALSE   = Returned as the value of the function if the file
 *               file identifier is invalid.
 *
 *     xrErrno = When this routine fails, xrErrno is set to XrFILEERROR.
 *
 *
 *   Procedures Called
 *   -----------------
 *     ???
 *     ???
 *
 *************************************<->***********************************/


static
_XrResourcePut (resource)
xrResource * resource;

{
   xrErrno = XrINVALIDPARM;
   return (FALSE);
}

