/**
    .---------------------------.
    |   Money Exchange class    |
    *---------------------------*
    
    Class: Money Exchange
    	Represents a currency information center.
    	
    Requires:
        - <utility_functions_for_internationalization.js>
        
    Author: 
        Marko Ristin
    
    Changelog:
        - 2007/01/27, mristin, initial version
        - 2007/08/13, ahermann, reformatted comments for automatic documentation
**/
function Money_exchange( a_prefetched_currencies_package, a_prefetched_exchange_rates_package, language_code, a_currency_select_box )
{                       
    /*extern show_errors, show_errors_dump */
    /*extern Option, add_option_to_select_box, create_and_add_option_to_select_box */
    /*extern gettext */
    
       
    this.currencies     = null;
    this.exchange_rates = null;
    
    /*  Database for language code -> abbreviation */
    this.lang_currency = [];
    this.lang_currency['de'   ] = 'eur';
    this.lang_currency['de-ch'] = 'chf';
    this.lang_currency['de-at'] = 'eur';
    this.lang_currency['en'   ] = 'usd';
    this.lang_currency['en-us'] = 'usd';
    
    this.locale_currency               = null;
    this.currency_select_box           = a_currency_select_box;
    this.signed_up_objects_for_update  = [];
    
    /*
        Function: update_signed_up_objects
        	Goes through all signed up objects and applies the specified 
        	update function to the object.
    */
    this.update_signed_up_objects = function ()
    {
         for ( var i = 0; i < this.signed_up_objects_for_update.length; i ++ )
         {
            var a_signed_up_object = this.signed_up_objects_for_update [ i ];
            
            var a_self           = a_signed_up_object.self;            
            var update_function  = a_signed_up_object.update_function;
            
            /*
                Call the update function:
            */
           update_function ( a_self );
         }    
    };
    
    /*
        Function: set_locale_currency_with_abb
        	Searches for the currency with the given abbreviation and sets
        	it as current locale currency.
        
        Parameters:
            a_currency_abb - String, currency abbreviation
    */
    this.set_locale_currency_with_abb = function ( a_currency_abb )
    {
         var a_new_locale_currency = this.find_currency_with_abb(a_currency_abb);                                             
         
         if (a_new_locale_currency)
         {
            this.locale_currency = a_new_locale_currency;
         }
         else
         {
             this.locale_currency = null;
         }
         
        /*
            Update objects:
        */
        this.update_signed_up_objects();
    };
    
    /*
        Function: find_currency_with_id
        Traverses all currencies and returns the currency with the given identifier.
        
        Parameters:
            an_id - Currency identifier
        
        Returns:
            Currency object with the given identifier.
            If no such currency exists, it returns null.
    */
    this.find_currency_with_id = function ( an_id )
    {
        var result = null;
        
        for ( var i = 0; i < this.currencies.length; i ++ )
        {
            if ( this.currencies[i].id === an_id )
            {
                result = this.currencies[i];
                break;
            }
        }
        return result;
    };
   
    /**
     * Function: find_currency_with_abb 
     *   	Traverses all currencies and returns the currency with the given abbreviation
     * 
     * @param {Object} an_abbreviation Currency abbrevation
     * @return {Object} Currency with the given abbreviation or null if not found
     */
    this.find_currency_with_abb = function(an_abbreviation)
    {
        var result = null;
                    
        for (var i = 0; i < this.currencies.length; i++ )
        {                
            if (this.currencies[i].abbreviation.toLowerCase() === an_abbreviation.toLowerCase())
            {
                result = this.currencies[i];
                break;
            }
        }
        return result;
    };
    
    /*
        Function: find_exchange_rate_with_abb
        	Traverses all the exchange rates until it finds the one which represents the
            specified exchange rate.
            
        Parameters:
            from_currency_abb - String, the source currency
            to_currency_abb - String, the destination currency
        
        Returns:
            Matching exchange rate
            Null, if nothing can be found.
    */
    this.find_exchange_rate_with_abb = function(from_currency_abb, to_currency_abb)
    {
        var result = null;
        
        var from_currency = this.find_currency_with_abb(from_currency_abb);
        var to_currency = this.find_currency_with_abb(to_currency_abb);
        
        if (!from_currency)
        {
            show_errors(['Currency: '+from_currency_abb+' could not be found.']);
            return 0;
        }
        
        if (!to_currency)
        {
            show_errors(['Currency: '+to_currency_abb+' could not be found.']);
            return 0;
        }
        
        for (var i = 0; i < this.exchange_rates.length; i++)
        {
            if (this.exchange_rates[i].from_currency === from_currency.id &&
                this.exchange_rates[i].to_currency === to_currency.id)
            {
                result = this.exchange_rates[i];
                break;
            }
        }
        
        if (result === null)
        {
            show_errors(['Exchange rate: '+from_currency_abb+' -> '+to_currency_abb+' could not be found.']);
            show_errors_dump(this.exchange_rates, 'Exchange rates', 'exchange_rates');
        }
        
        return result;
    };

    /**
     * Calculates the amount of the from currency in the rate of to currency.
     * @param {String} from_currency_abb Source currency abbreviation
     * @param {String} to_currency_abb Destination currency abbreviation
     * @param {Number} amount Currency amount
     * @return {Number} Converted amount. Null, if it is not possible to exchange money
     */
    this.exchange = function (from_currency_abb, to_currency_abb, amount)
    {
        var result = null;
        
        if (from_currency_abb === to_currency_abb)
        {
            result = amount;
        }
        else
        {
            var an_exchange_rate = this.find_exchange_rate_with_abb(from_currency_abb, to_currency_abb);
            result = amount * an_exchange_rate.rate;
        }
        
        return result;                                                                                              
    };
    
    /*
        Function: amount_to_str
        Returns a string representation of the amount.
        
        Returns:
            Rounded amount string
    */
    this.amount_to_str = function (amount)
    {
        return amount.toFixed(0);
    };
    
    /*
        Function: to_locale_currency
        	Converts amount into the current locale currency
        
        Parameters:
            from_currency_abb - String, source currency abbreviation
            amount - Float, currency amount
        
        Returns:
            Float, converted amount
    */
    this.to_locale_currency = function ( from_currency_abb, amount )
    {
        return this.exchange(from_currency_abb, this.locale_currency.abbreviation, amount);
    };
    
    
    /*
        Function: repr_amount_in
            Returns a string representing the amount in the given currency.
        
        Parameters:
            currency_abb - String, currency abbreviation
            amount - Float, currency amount
            
        Returns:
            String, amount in the given currency
    */
    this.repr_amount_in = function ( currency_abb, amount )
    {                             
        var a_str = '';                
        
        var currency_abb_uppercase = currency_abb.toUpperCase();
        
        a_str += currency_abb_uppercase + ' ' + this.amount_to_str( amount );                                                                                       
        
        return a_str;
    };
    
    /*  
        Function: repr_amount
            Returns a string representing the given amount in the terms of locale currency.
        
        Parameters:
            currency_abb - String, currency abbreviation
            amount - Float, amount of currency
        
        Returns:
            String, representing the given amount in the terms of locale currency.
        
    */
    this.repr_amount = function ( currency_abb, amount )
    {         
        var a_str = '';                
        
        var amount_in_locale_curr = this.to_locale_currency( currency_abb, amount );
        a_str += this.repr_amount_in( this.locale_currency.abbreviation, amount_in_locale_curr );
            
        return a_str;
    };
    
    /*
        Function: repr_amount_in_both_currencies
            Represents the given amount first in original currency and then converts the amount 
            and adds it to the representation.
        
        Parameters:
            amount - Float, amount of source currency
            original_currency - Source currency
            currency_to_convert_in - Destination currency
        
        Returns:
            String, representing both values
    */
    this.repr_amount_in_both_currencies = function ( amount, original_currency, currency_to_convert_in )
    {       
        var a_str = '';
        var original_repr = this.repr_amount_in( original_currency, amount );
                                                     
        if ( original_currency === currency_to_convert_in )
        {
            a_str += original_repr;                                                     
        }
        else
        {                                                     
            var converted_amount = this.exchange( original_currency, currency_to_convert_in, amount );
            var converted_repr = this.repr_amount_in( currency_to_convert_in, converted_amount );                                             
                                                          
            a_str += original_repr + ' / ' + converted_repr;
        }
                      
        return a_str;                                                              
    };
                       
    /*
        Function: repr_amount_in_locale_and_foreign_currency
            This function returns a string representing
            the given amount first in locale and then in foreign currency.
            
        Parameters:
            foreign_currency - Foreign currency
            amount - Float, amount of foreign currency
        
        Returns:
            String, representing the given amount first in locale and then in foreign currency.
    */                    
    this.repr_amount_in_locale_and_foreign_currency = function(foreign_currency, amount)
    {   
        return this.repr_amount_in_both_currencies ( amount, this.locale_currency.abbreviation, foreign_currency );
    };
    
    /*
        Function: repr_amount_in_foreign_and_locale_currency
            This function returns a string representing
            the given amount first in foreign and then in locale currency.
            
        Parameters:
            foreign_currency - Foreign currency
            amount - Float, amount of foreign currency
        
        Returns:
            String, representing the given amount first in foreign and then in locale currency.
    */
    this.repr_amount_in_foreign_and_locale_currency = function(foreign_currency, amount)
    {    
        return this.repr_amount_in_both_currencies ( amount,
                                                     foreign_currency,
                                                     this.locale_currency.abbreviation);
    };
    
    /*
        Function: repr_amount_of_locale_currency
            Creates a formatted string of the given amount.
            
        Parameters:
            amount - Float, locale currency amount
        
        Returns:
            String, representing the given amount
    */
    this.repr_amount_of_locale_currency = function ( amount )
    {
        return this.repr_amount( this.locale_currency.abbreviation, amount );
    };
    
    /*
        Sign up functions:
    */
    
    /*
        Function: sign_up_object_for_update
            Signs up the given object and the update function.
            The update function should take the given object as the only argument. 
            
        Parameters:
            an_obj -
            an_update_function -
    */
    this.sign_up_object_for_update = function ( an_obj,
                                                an_update_function )
    {
        var a_new_signed_up_object = {};
        
        a_new_signed_up_object.self             = an_obj;
        a_new_signed_up_object.update_function  = an_update_function;
        this.signed_up_objects_for_update.push ( a_new_signed_up_object );        
    };
    
    /*
        Function: sign_off_object_for_update
            This function traverses all signed up objects 
            for update and removes the given object
            from the update list.
        
        Parameters:
            an_obj - 
            an_update_function -
    */
    this.sign_off_object_for_update = function ( an_obj,
                                                 an_update_function)
    {
        for ( var i = 0; i < this.signed_up_objects_for_update.length; i ++ )
        {
            if ( this.signed_up_objects_for_update [ i ].self             === an_obj &&
                 this.signed_up_objects_for_update [ i ].update_function  === an_update_function )
            {
                /*
                    Remove it from the array:
                */
                this.signed_up_objects_for_update .splice ( i, 1 );
            }
        }
    };
    
    /*  Currency select box functions:  */
    
    /*
        Function: fill_currency_select_box
        	Extracts 'please choose' option from html as the second option.
        	It fills the select box with the currencies.
    */
    this.fill_currency_select_box = function ()
    {
        /*
            Make the first currency default locale
            currency:
        */
        //this.locale_currency = this.currencies [ 0 ];
        //this.set_locale_currency_with_abb ( this.lang_currency [ language_code ] );            
        
        /*
            Clear all options:
        */
        this.currency_select_box.options.length = 0;
        
        var caption_option = new Option( gettext('Bitte wähle eine Währung:'), '' );
        add_option_to_select_box( this.currency_select_box, caption_option );
        
        var a_currency;
        for (var i = 0; i < this.currencies.length; i++ )
        {           
            a_currency = this.currencies[i];        
            
            // only insert selectable currencies
            if (a_currency.selectable == true)
            {
                create_and_add_option_to_select_box( 
                    this.currency_select_box, 
                    a_currency.name, /* Caption */
                    a_currency.abbreviation, /* Value */
                    '' /* Value to select */);
            }
        }
        
        /* display the caption */
        this.currency_select_box.options[0].selected = true;
        
        /*
            Connect it with the change event:
        */
        this.currency_select_box.money_exchange = this;                      
        
        this.currency_select_box.disabled = false;
    };
    
    /*
        Function: init
        Initializes the instance of the class.
    */
    this.init = function ()
    {                  
        this.currencies     = a_prefetched_currencies_package.currencies;
        this.exchange_rates = a_prefetched_exchange_rates_package.exchange_rates;                        
        
        /*
            Make the first currency default locale
            currency:
        */
        //this.locale_currency = this.currencies [ 0 ];
        
        //this.set_locale_currency_with_abb ( this.lang_currency [ language_code ] );        
        
        /*
            Initialize currency select box if 
            provided:
        */
        if ( this.currency_select_box )
        {
            // this.fill_currency_select_box ();    
            this.currency_select_box.innerHTML = '<option>N/A</option>';
        }
    };
    
    this.init();       
}
