/*
 Copyright (C) 2002 Andreas Thiede ( a.thiede@berlin.de )

 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
*/

#include <util/Loader.h>
#import <mach-o/dyld.h>
#import <AppKit/AppKit.h>
#import <string>
#import <Foundation/NSBundle.h>

static void undefined(const char *symbolName)
{
    printf("Undefined symbol: %s\n", symbolName );
}

static NSModule multiple( NSSymbol s, NSModule oldModule, NSModule newModule)
{
    printf("Multiple symbol:  %s\n", NSNameOfSymbol( s ) );

    return oldModule;
}

static void linkEdit( NSLinkEditErrors errorClass, int errorNumber, const char *fileName, const char *errorString )
{
    printf("Link error %s in file %s\n", errorString, fileName );
}

static NSLinkEditErrorHandlers handlers = { undefined, multiple, linkEdit };

bool loadLibrary( const char *  path  )
{
    if( strstr( path, "framework" )) {
        return NSAddLibrary( path );
    }
    else {
    
        NSBundle * bundle = [ NSBundle bundleWithPath: [NSString stringWithCString:path ]];
        
        if( bundle ) {
        
            BOOL result = [ bundle load ];
            
            if( result ) {
                return true;
            }
            printf( "failed to load %s\n", path );
        }
    }
    
    return false;
}

extern "C" void * lookupSymbol( const char * libraryName, const char * symbolName )
{
    void * handle = 0;

    bool loadSuccess;
    
    loadSuccess =  loadLibrary( [[NSString stringWithFormat:@"%@/%s.bundle", [[NSBundle mainBundle] builtInPlugInsPath], libraryName] cString] );

    if( loadSuccess ) {

        //printf("Found library %s\n", libraryName );
        NSSymbol symbol;

        int defined = NSIsSymbolNameDefined(  symbolName );
        
        if( defined ) {
            //printf("Found symbol %s.%s\n", libraryName, symbolName );
            symbol = NSLookupAndBindSymbol( symbolName );
            handle = NSAddressOfSymbol( symbol );
        }
    }
    return handle;
}

extern "C" int loadModule( const char * moduleName, int argc, const char ** argv )
{
    char buf[256];
    
    sprintf( buf, "_init%s", moduleName );
    
    char * p = strstr( buf, ".bundle" );
    
    if( p == 0 ) {
        p = strstr( buf, ".framework" );
    }
    
    if( p != 0 ) {
        * p = 0;
    }
    
    InitFunc initFunc = (InitFunc) lookupSymbol( moduleName, buf );

    if( initFunc ) {
        return initFunc( argc, argv );
    }
    return false;
}

extern "C" int loadPlugin( const char * moduleName, int argc, const char ** argv  )
{
    return loadModule( moduleName, argc, argv );
}