#define MICO_CONF_IMR
#include <CORBA-SMALL.h>
#include <iostream.h>
#include <fstream.h>
#include <unistd.h>
#include <map.h>
#include "cache.h"
#include "wordpair.h"

// create objects on demand when requested by a bind()
#define OBJECT_CREATION_ON_DEMAND

/*
 * DictionaryFilter implementation
 */


class DictionaryFilter_impl : virtual public DictionaryFilter_skel {
private:
	string dict_cache[5][2];
	int priority[5];
	int _count;
	char * search(char * word);
	void refreshCache(int lru);
public:
    DictionaryFilter_impl (const CORBA::BOA::ReferenceData &refdata)
	: DictionaryFilter_skel (refdata)
    {
	    _count = -1;
	    for(int i=0; i<5; i++)
		    priority[i] = i;
	    
    }

    DictionaryFilter_impl (CORBA::Object_ptr obj)
        : DictionaryFilter_skel (obj)
    {
	CORBA::BOA_var boa = _boa();
	CORBA::BOA::ReferenceData_var id = boa->get_id (this);
	CORBA::String_var str = CORBA::ORB::tag_to_string (id);
	_count = -1;
	for(int i=0; i<5; i++)
		    priority[i] = i;
    }

    wpair * lookupUp(char *& word)
    {
	    char *m = search(word);
		wpair *w = new wpair();
	    w->word = CORBA::string_dup(word);

	    if(strlen(m))
	    {
		    w->meaning = CORBA::string_dup(m);
		    setBounce();
			cout << "Bouncing\n" << flush;
	    }
		else
		    w->meaning = CORBA::string_dup("");

	    cout << "Returning from lookupUp. Word = " << w->word << " AND Meaning = " << w->meaning << ".\n" << flush;
		
	    return w;
    }

    wpair * lookupDown(const wpair & w)
    {
	    if(_count < 4)
			++_count;
			
		int lru = priority[_count];

	    dict_cache[lru][0] = string(w.word);
	    dict_cache[lru][1] = string(w.meaning);
	    refreshCache(lru);

	    wpair *ret = new wpair(w);

	    cout << "Returning from lookupDown. Word = " << ret->word << " AND Meaning = " << ret->meaning << ".\n" << flush;
	    
	    return ret;
    }

};

char * DictionaryFilter_impl::search(char * word)
{
	char *c = "";

	for(int i=0; i<=_count; i++)
	{
		if( dict_cache[i][0] == word ) {
			refreshCache(i);
			c = CORBA::string_dup(dict_cache[i][1].c_str());
			break;
		}
	}

	return c;
}

void DictionaryFilter_impl::refreshCache(int lru) 
{
	int i;
	
	for(i=0; i<=_count; i++)
	{
		if(priority[i]==lru)
			break;
	}
	
	for(int j=i; j > 0; j--)
		priority[j] = priority[j-1];
	
	priority[0] = lru;
}

/*
 * DictionaryFilter object restorer
 */

class DictionaryFilterLoader : public CORBA::BOAObjectRestorer {
public:
    CORBA::Boolean restore (CORBA::Object_ptr obj)
    {
        if (!strcmp (obj->_repoid(), "IDL:DictionaryFilter:1.0")) {
            (void)new DictionaryFilter_impl (obj);
            return TRUE;
        }
        cout << "Cannot restore " << obj->_repoid() << " objects" << endl;
        return FALSE;
    }
#ifdef OBJECT_CREATION_ON_DEMAND
    CORBA::Boolean bind (const char *repoid, const CORBA::ORB::ObjectTag &tag)
    {
        if (!strcmp (repoid, "IDL:DictionaryFilter:1.0")) {
	    cout << "Creating filter in bind... " << endl;
	    (void)new DictionaryFilter_impl (tag);
	    return TRUE;
	}
	return FALSE;
    }
#endif
};


int main( int argc, char *argv[] )
{
    cout << "Filter init." << endl;

    DictionaryFilterLoader loader;
    CORBA::ORB_var orb = CORBA::ORB_init( argc, argv, "mico-local-orb" );
    CORBA::BOA_var boa = orb->BOA_init (argc, argv, "mico-local-boa");

    if (!boa->restoring()) {
#ifndef OBJECT_CREATION_ON_DEMAND
	cout << "Creating filter in main... " << endl;
	CORBA::ORB::ObjectTag_var tag = CORBA::ORB::string_to_tag ("foobar");
	/*
	 * create an cache object whose ReferenceData equals "foobar".
	 */
        DictionaryFilter_ptr acc = new DictionaryFilter_impl (tag);
#endif
    }
    boa->impl_is_ready (CORBA::ImplementationDef::_nil());
    orb->run ();

    return 0;
}
