/****f* SERVER/XMLRPC_ServerAddIntrospectionData
 * NAME
 *   XMLRPC_ServerAddIntrospectionData
 * SYNOPSIS
 *   int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc)
 * FUNCTION
 *   updates server with additional introspection data
 * INPUTS
 *   server - target server
 *   desc - introspection data, should be a struct generated by 
 *          XMLRPC_IntrospectionCreateDescription ()
 * RESULT
 *   int - 1 if success, else 0
 * NOTES
 *  - function will fail if neither typeList nor methodList key is present in struct.
 *  - if method or type already exists, it will be replaced.
 *  - desc is never freed by the server.  caller is responsible for cleanup.
 * BUGS
 *   - horribly slow lookups. prime candidate for hash improvements.
 *   - uglier and more complex than I like to see for API functions.
 * SEE ALSO
 *   XMLRPC_ServerAddIntrospectionData ()
 *   XMLRPC_ServerRegisterIntrospectionCallback ()
 *   XMLRPC_CleanupValue ()
 * SOURCE
 */
int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) {
   int bSuccess = 0;
   if(server && desc) {
      XMLRPC_VALUE xNewTypes = XMLRPC_VectorGetValueWithID(desc, "typeList");
      XMLRPC_VALUE xNewMethods = XMLRPC_VectorGetValueWithID(desc, "methodList");
      XMLRPC_VALUE xServerTypes = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList");

      if(xNewMethods) {
         XMLRPC_VALUE xMethod = XMLRPC_VectorRewind(xNewMethods);

         while(xMethod) {
            const char* name = XMLRPC_VectorGetStringWithID(xMethod, xi_token_name);
            server_method* sm = find_method(server, name);

            if(sm) {
               if(sm->desc) {
                  XMLRPC_CleanupValue(sm->desc);
               }
               sm->desc = XMLRPC_CopyValue(xMethod);
               bSuccess = 1;
            }

            xMethod = XMLRPC_VectorNext(xNewMethods);
         }
      }
      if(xNewTypes) {
         if(!xServerTypes) {
            if(!server->xIntrospection) {
               server->xIntrospection = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
            }

            XMLRPC_AddValueToVector(server->xIntrospection, xNewTypes);
            bSuccess = 1;
         }
         else {
            XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xNewTypes);
            while(xIter) {
               /* get rid of old values */
               XMLRPC_VALUE xPrev = find_named_value(xServerTypes, XMLRPC_VectorGetStringWithID(xIter, xi_token_name));
               if(xPrev) {
                  XMLRPC_VectorRemoveValue(xServerTypes, xPrev);
               }
               XMLRPC_AddValueToVector(xServerTypes, xIter);
               bSuccess = 1;
               xIter = XMLRPC_VectorNext(xNewTypes);
            }
         }
      }
   }
   return bSuccess;
}
/*
 * This handler takes six parameters, and returns an array containing all the 
 * parameters.  
 */
XMLRPC_VALUE validator1_manyTypesTest (XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* userData) {
   XMLRPC_VALUE xArray = XMLRPC_CreateVector(0, xmlrpc_vector_array);

   if(xRequest && xArray) {
      XMLRPC_VALUE xParams = XMLRPC_RequestGetData(xRequest);
      XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xParams);

      while(xIter) {
         XMLRPC_AddValueToVector(xArray, XMLRPC_CopyValue(xIter));
         xIter = XMLRPC_VectorNext(xParams);
      }
   }

   return xArray;
}
/*
 * This handler takes a single parameter, a struct.  Your handler must return 
 * the struct.  
 */
XMLRPC_VALUE validator1_echoStructTest (XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* userData) {
   XMLRPC_VALUE xReturn = XMLRPC_CopyValue(XMLRPC_VectorRewind(XMLRPC_RequestGetData(xRequest)));
   return xReturn;
}