/*
 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 <IO/Manager/IOModel.hpp>
#include <IO/Manager/IOView.hpp>

#include <Cocoa/Cocoa.h>

#define USER_DEFAULTS [ NSUserDefaults standardUserDefaults ]

extern "C" void postNotification( NSString * key );
extern "C" void addObserver( NSObject * observer, NSString * key );
extern "C" void removeObserver( NSString * key );


static string ftoa( float val )
{
    char buf[128];
    
    sprintf( buf, "%f", val );
    
    return buf;
}

static string itoa( int val )
{
    char buf[128];
    
    sprintf( buf, "%d", val );
    
    return buf;
}

static string GetString( const char * name ) 
{
    NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ];

    NSString * key = 0;
    
    //printf( "GetString(%s)\n", name );
    //fflush( stdout );
    
    NSString * val = 0;
    id         obj;
    string     result;
   
    key = [ NSString stringWithCString:name ];
    
    obj = [  USER_DEFAULTS objectForKey: key ];
        
    if( obj != nil ) {

        val = (NSString*) obj; //[ USER_DEFAULTS stringForKey: [ NSString stringWithCString:name ]];

        //printf( "GetString(%s) = %p\n", name, val );
        //fflush( stdout );

    }

    if( val != 0 ) {    
        result = [ val cString ];
    }
    else {
        result = "";
    }
    
    //printf( "GetString(%s) = %s\n", name, result.c_str() );
    //fflush( stdout );
    
    [ pool release ];
    
    return result;
}

static void WriteString( const char * name, const char * value )
{
    NSAutoreleasePool * pool =[ [ NSAutoreleasePool alloc ] init ];

    NSLog( @"WriteString %s = %s \n",  name, value );

    NSString * key = [ NSString stringWithCString : name  ];
    NSString * val = [ NSString stringWithCString : value ];
    
    [ USER_DEFAULTS setObject:val forKey:key ];

    [ USER_DEFAULTS synchronize];

    NSString * app = [[NSBundle mainBundle ] bundleIdentifier];
    
    //printf("appName(%s)\n", [ app cString ] );
    
    //[[NSDistributedNotificationCenter defaultCenter] postNotificationName:app object:key ];

    postNotification( key );
    
    [ pool release ];

}

// ----------  cocoa specific ----------------

@interface MyModelDelegate : NSObject
{
    IOModel * myBuddy;
}

- (void) initWithBuddy: ( IOModel * ) buddy;
- (void) changed:(NSNotification *)notification;

@end


@implementation MyModelDelegate

- (void) initWithBuddy: ( IOModel * ) buddy;
{
    [ super init ];
    
    myBuddy = buddy;
    
}

- (void) changed
{
    [ USER_DEFAULTS synchronize];

    string value = GetString( myBuddy->getName().c_str() );

    printf("MyModelDelegate.changed %s = %s \n",  myBuddy->getName().c_str(), value.c_str() );
    
    myBuddy->setValue( value );
}

- (void) changed:(NSNotification *)notification
{
    //puts("prefs changed");

    [ self changed ];    
}

@end // MyModelDelegate

// ------------- IOModel _________________
 
IOModel::IOModel( const string & name )
 : IOObject( name, "IOModel" )
{
    init();
}

IOModel::~IOModel()
{
    finit();
}
    
void IOModel::init()
{
    NSAutoreleasePool * pool =[ [ NSAutoreleasePool alloc ] init ];

    //printf("register for %s\n", getName().c_str() );

    mMyDelegate = [ MyModelDelegate alloc ];

    [ mMyDelegate retain ];
    
    [ mMyDelegate initWithBuddy: this ];
    
    NSString * keyName = [ NSString stringWithCString: getName().c_str() ];
    NSString * appName = [[NSBundle mainBundle ] bundleIdentifier];

    //printf("appName(%s)\n", [ appName cString ] );
    
    /*
    [[NSDistributedNotificationCenter defaultCenter] addObserver:mMyDelegate selector:@selector( changed:) name:appName
        object:keyName suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; 
    */
    
    addObserver( mMyDelegate, keyName );
    
    mValue = GetString( getName().c_str() );

    [ pool release ];
}

void IOModel::finit()
{    
    //[[NSDistributedNotificationCenter defaultCenter] removeObserver:mMyDelegate ]; 

    NSAutoreleasePool * pool =[ [ NSAutoreleasePool alloc ] init ];

    NSString * keyName = [ NSString stringWithCString: getName().c_str() ];
    
    removeObserver( keyName );
    
    [ mMyDelegate release ];

    [ pool release ];
}

void IOModel::setValue( const string & newVal )
{
    if( mValue != newVal ) {

        mValue = newVal;

        WriteString( getName().c_str(), mValue.c_str() );

        changed();
    }
}

void IOModel::setValue( int newVal )
{
    if( atoi(mValue.c_str()) != newVal ) {

        mValue = itoa(newVal);

        WriteString( getName().c_str(), mValue.c_str() );

        changed();
    }
}
    
void IOModel::setValue( float newVal )
{
    if( atof(mValue.c_str()) != newVal ) {

        mValue = ftoa(newVal);

        WriteString( getName().c_str(), mValue.c_str() );

        changed();
    }
}

void IOModel::changed()
{    
    list<IOView*>::iterator iter( mObservers.begin() );
    
    while( iter != mObservers.end() ) {
    
        IOView * v = *iter;
        
        v->updateFrom( this );
        
        iter++;
    }
}
    
int IOModel::getInt()
{
    return atoi( mValue.c_str() );
}

float IOModel::getFloat()
{
    return atof( mValue.c_str() );
}

const string & IOModel::getString()
{
    return mValue;
}

IOView * IOModel::findView( IOView * aView )
{
    list<IOView*>::iterator iter( mObservers.begin() );
    
    while( iter != mObservers.end() ) {
    
        IOView * v = *iter;
        
        if( v == aView ) {
            return v;
        }
        iter++;
    }
    return 0;
}

void IOModel::addView( IOView * aView )
{
    if( ! findView( aView )) {
        mObservers.push_back( aView );
    }
}

void IOModel::remView( IOView * aView )
{
    if(  findView( aView )) {
        mObservers.remove( aView );
    }
}

