/* XRACER (C) 1999-2000 Richard W.M. Jones <rich@annexia.org> and other AUTHORS
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Id: track.c,v 1.4 2000/01/15 16:14:35 rich Exp $
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#if HAVE_DLFCN_H
#include <dlfcn.h>
#endif

#include <GL/glut.h>

#include "xracer.h"
#include "xracer-track.h"
#include "xracer-log.h"
#include "xracer-PATH_MAX.h"

/* Only one track can be loaded at a time. The details of that track
 * are stored here.
 */
struct xrTrackControl *xrTrack = 0; /* Currently loaded track. */

/* Make a track the current track. */
void
xrTrackMakeCurrent (void *vtrack)
{
  struct xrTrackControl *track = (struct xrTrackControl *) vtrack;

  /* Is there a current track already? If so, unload it. */
  if (xrTrack)
    xrTrackUnload (xrTrack);

  /* Make the new track into the current track. */
  xrTrack = track;
}

/* Unload a track. */
void
xrTrackUnload (void *vtrack)
{
  struct xrTrackControl *track = (struct xrTrackControl *) vtrack;

  /* Call the track clean-up function, if there is one. */
  if (track->unload) track->unload ();

  /* Close the library. */
#if HAVE_DL_API
  dlclose (track->_lib);
#else
#error "require working dlopen(2)/dlsym(2)/dlclose(2) API"
#endif
}

/* Load a track from the tracks/ subdirectory. */
void *
xrTrackLoadByName (const char *name)
{
  char filename[PATH_MAX];

  /* Try to construct the name of the shared library containing this track. */
  snprintf (filename, sizeof filename, "tracks/libtrack%s.so", name);

  return xrTrackLoadByFilename (filename);
}

/* Load a track by filename. */
void *
xrTrackLoadByFilename (const char *filename)
{
#if HAVE_DL_API

  void *lib;
  void *track_struct;
  struct xrTrackControl *track;

  /* See if we can open this track. Make sure we resolve all link-time
   * errors now, and make sure that symbols from the track don't pollute
   * the namespace.
   */
  lib = dlopen (filename, RTLD_NOW);

  if (lib == NULL)
    {
      xrLog (LOG_ERROR, "dlopen: %s: %s", filename, dlerror ());
      return 0;
    }

  /* The shared library contains one symbol of interest: ``track'' */
  track_struct = dlsym (lib, "track");

  /* This is OK. This symbol should never actually be NULL. */
  if (track_struct == NULL)
    {
      xrLog (LOG_ERROR, "dlsym: track: %s", dlerror ());
      dlclose (lib);
      return 0;
    }

  /* Store the track's library address. */
  track = (struct xrTrackControl *) track_struct;
  track->_lib = lib;

  /* Call track on-load function. */
  if (track->load) track->load ();

  if (track->name) xrLog (LOG_DEBUG, "loaded track: %s", track->name);

  return track_struct;

#else
#error "working dlopen(3)/dlsym(3)/dlclose(3) API required"
#endif
}
