/*
 * Icesave Reiknir
 * Copyright (c) 2009 DataMarket ehf.
 * All rights reserved.
 */
jQuery(function($){

  function formatNumber ( val, decimal, group ) {
    val += '';
    var m = val.split('.');
    var _int = m[0];
    var _frc = m.length > 1 ? (decimal||',') + m[1] : '';
    var rex = /(\d+)(\d{3})/;
    var grp = '$1' + (group||'.') + '$2';
    while ( rex.test(_int) ) {
      _int = _int.replace( rex, grp );
    }
    return _int + _frc;
  }

  function parseNumber ( num, decimal ) {
    var R = (decimal == ',') ? /[^\,\d\-]/g : /[^\.\d\-]/g ;
    var m = ( num ).toString( 10 ).replace( R, '' ).split( /[.,]/ );
    return parseFloat( m[0] + '.' + m[1], 10 );
  }
    
  // notify CSS of browser type
  $.each( $.browser, function(a,b){$('body')[(b === true)?'addClass':'removeClass'](a);});

  var context = $( 'form#icesave-calc' );
  var defaults = context.serialize();
  var fields = context.find( '.formfield' );
  var glossary = $('#icesave-glossary').children();
  var focusOutTimer = null;

  glossary.css({
    height : context.height()
  });
  
  var focusBox = $('<div class="focusbox"></div>').hide().appendTo( context );
  var colL = $('#icesave-calculator .twocol-left');
  var colR = $('#icesave-calculator .twocol-right');
  focusBox.css('top',colL.offset().top );
  var activeField = null;
  
  function activateField ( target ) {
    target = $( target );
    
    if ( activeField === target[0] ) {
      return false;
    }
    activeField = target[0];
    
    fields.removeClass( 'focus' );
    var help = target.find( 'a.help' ).attr( 'href' );
    if ( target.is( 'fieldset:has(ul)' ) ) {
      target = target.find('ul');
    }
    target.addClass( 'focus' );
    glossary.hide();
    $( help ).show();
    focusBox
      .fadeIn()
      .css({
        position: 'absolute',
        left: (colL.offset().left + 1) + 'px',
        width: ( colL.width() + parseFloat(colL.css('marginRight'),10) ) + 'px'
      })
      .animate({
        height: (target.outerHeight() + 8) + 'px',
        top: (target.offset().top - 4) + 'px'
      }, 'fast');
    
  }
  
  function blurAllFields( ) {
    window.clearTimeout( focusOutTimer );
    focusOutTimer = window.setTimeout(function () {
      fields.removeClass( 'focus' );
      focusBox.fadeOut();
      glossary.hide();
      $( '#intro' ).show();
    },1);
  }

  // safari does not trigger focus event on radio/checkboxes 
  var sfix = $.browser.safari ? ' click change' : '';
  fields.find('input, a')
    .bind('focus'+sfix, function (e) {
      var f = $( this ),
          c = f.data( 'formfield' );
      // cache
      if ( !c ) {
        c = $( this ).parents( '.formfield:first' );
        f.data( 'formfield', c );
      }
      activateField( c );
    })
    .bind('keyup', function(){ update(); });
  
  $( document ).bind('amchartinited', function () {
    update();
  });
    
  var focusElms = /^(input|a|label)$/i;
  fields.bind('click', function (e) {
    if ( e.target && !focusElms.test( e.target.nodeName ) ) {
      var f = $( this );
      setTimeout(function () {
        window.clearTimeout( focusOutTimer );
        f.find('input, a').eq(0).focus();
      },8);
    }
  });

  $('#icesave-glossary').bind('click', function () {
    window.clearTimeout( focusOutTimer );
  });

  $('#resetlink').click(function () {
    context[0].reset();
    update();
    return false;
  });
  
  
  //----

  var ctxRex = /(^|\s)icesave(-|\s)/;   // /(^|\s)icesave(-|\s|$)/ cages clicks within entire block;
  $( 'html' ).click(function ( e ) {
    var c = e.target, contextual = false;
    while ( c && (c = c.parentNode) ) {
      if ( ctxRex.test(c.id) || ctxRex.test(c.className) ) {  
        contextual = true;
        break;
      }
    }
    if ( !contextual ) {
      blurAllFields();
    }
    update();
  });
  
  //----

  glossary.find( 'button' ).click(function () {

    var obj = {};
    var key = $( this ).parents( '[id]:first' ).attr( 'id' ).replace( /-help$/, '' );
    var val = this.getAttribute('value');//$( this ).val();
    if ( $.browser.msie && parseFloat( $.browser.version, 10 ) < 8) {
      val = this.getAttributeNode('value').value;
    }

    obj[key] = ( /^[\d\.,+-]*\d[\d\.,+-]*$/.test( val ) ? formatNumber( val ) : val );
    context.values( obj );
    
    focusBox
      .css('backgroundColor','orange')
      .animate({ 'backgroundColor':'#F0F0DD' }, 'slow');

    update();
    
    return false;
  });

  //----
  
  var tableWrap = $('<div id="table" style="display:none"></div>').appendTo('#icesave');
  var tableButton = $('<button id="tabletoggle">S&yacute;na &uacute;treikninga</button>').appendTo('#buttons');
  tableButton.click(function () {
    var table = $('#table');
    if ( table.is(':visible') ) {
      table.slideUp();
      $( this ).html( 'S&yacute;na &uacute;treikninga' );
    }
    else {
      update( true );
      table.slideDown();
      $( this ).html( 'Fela &uacute;treikninga' );
    }
   return false;
  });
  

  var lastXML = null;
  function update ( force_table ) {

    var values = context.values();
    var changes = ( context.serialize() != defaults );
    if ( changes ) {
      $.hashvar( values );
      $('li:has(#total_diff)').slideDown();
    }
    else {
      $.hashvar( '' );
      $('li:has(#total_diff)').slideUp();
    }
    
    var comma = ',';
    var fors = {
        'upphaflegt_lan' : {
          'gbp_ma' : 2.35,
          'eur_ma' : 1.329242850,
          'vextir_pr' : parseNumber( values.loan_interest[0], comma )
        },
        'eignasafn_li' : {
          'verdmat_isk_ma' : parseNumber( values.lsb_worth[0], comma ),
          'endurheimtuhlutfall_pr' : parseNumber( values.lsb_reclaim[0], comma )
        },
        'krofur_uk_gbp_ma' : 4.526988847,
        'krofur_nl_eur_ma' : 1.674285671,
        'tryggingarsjodur_faer_forgang' : values.demand_priority[0] == 'iceland_first', 
        'nuvirdingarvextir_pr' : parseNumber( values.npv_discounting_rate[0], comma ),
        'prop_of_assets_accum' : 0,
        'uk_assets_to_others_mid_accum' : 0,
        'uk_assets_to_others_hi_accum' : 0,
        'nl_assets_to_others_mid_accum' : 0,
        'nl_assets_to_others_hi_accum' : 0,
        'assets_to_us_accum' : 0,
        'gengi_gbpisk' : parseNumber( values.exchange_gbp[0], comma ) || $('#exchange_gbp')[0].defaultValue || 0,
        'gengi_eurisk' : parseNumber( values.exchange_eur[0], comma ) || $('#exchange_eur')[0].defaultValue || 0
        /*
        , 'compute_endurheimt' : function(year, quarter, fors, prev_row ) {
            if(year == 2009 && quarter >= 3 || year > 2009 && year < 2016) {
                prop = 1.0 / 26; // can make this time-dependent, but then average must be the same
                return this.eignasafn_li.verdmat_isk_ma * this.eignasafn_li.endurheimtuhlutfall_pr * 0.01 * prop * this.hlutfall_tryggingarsjods_pr * 0.01;
            } else {
                return 0;
            }
        }
        */
    };
    
    var result = icesave_compute( fors );
    var table = $( '#table' );
    if ( table.is(':visible') || force_table ) {
      table.html( icesave_render_table( result ) );
    }
    
    var mill = function (val, auk) {
      if (typeof(auk) == 'undefined') auk = 1;
      return (Math.abs(val) < 0.005 ? '0.0' : (Math.abs(val) < 1 ? val.toPrecision(2) : val.toFixed(auk)));
    }
    
    var gbp_lan_isk_ma = fors.upphaflegt_lan.gbp_ma * fors.gengi_gbpisk;
    var eur_lan_isk_ma = fors.upphaflegt_lan.eur_ma * fors.gengi_eurisk;
    var heild_lan_isk_ma = gbp_lan_isk_ma + eur_lan_isk_ma;
    var nuvirt = result.nuvirt;
    var crunched = {
      greidsla_rikissjods_isk: mill(result.samtals),
      total_diff: mill( -(355.90717 - result.nuvirt.toPrecision(8)) ),   // change from total original
      total_isk: mill(nuvirt),
      total_gbp: mill(nuvirt * gbp_lan_isk_ma / heild_lan_isk_ma / fors.gengi_gbpisk * 1000),
      total_eur: mill(nuvirt * eur_lan_isk_ma / heild_lan_isk_ma / fors.gengi_eurisk * 1000),
      per_capita: mill(nuvirt / 319326 * 1000000000, 0),   // population amt.
      per_export: mill(nuvirt / 466.860 * 100),            // export 2008
      per_gdp: mill(nuvirt / 1465.065 * 100)               // gdp 2008
    };
    
    // display numbers
    for ( var key in crunched ) {
      var val = crunched[key];
      if ( typeof val === 'string' || typeof val === 'number' ) {
        $( '#' + key ).text( formatNumber( val ) );
      }
    }

    // correct chart
    var chart = window.charts && window.charts['icesave_chart'];
    if ( chart ) {
      var xml = icesave_render_XML( result );
      if ( xml != lastXML ) {
        lastXML = xml;
        chart.setData( xml );
      }
    }

  }
  
  function icesave_compute ( fors ) {
    
    if ( !fors.compute_endurheimt) {
      //fors.compute_endurheimt = _old_default_endurheimt;
      fors.compute_endurheimt = _default_endurheimt;
    }
    var hofudstoll = fors.upphaflegt_lan.gbp_ma * fors.gengi_gbpisk + fors.upphaflegt_lan.eur_ma * fors.gengi_eurisk;
    var row = {
      'year' : 2008,
      'quarter' : 4,
      'hofudstoll_isk' : hofudstoll,
      'vextir_nu_isk' : 0,
      'vextir_intrayearaccum_isk' : 0,
      'vextir_upps_isk' : 0,
      'endurheimt_isk' : 0,
      'endurheimt_upps_isk' : 0,
      'greidsla_rikissjods_isk' : 0,
      'eftirstodvar_isk' : hofudstoll,
      'eftirstodvar_isk_vid_virkjun_lans' : NaN
    };
    var rows = [];
    rows.push(row);
    do {
      row = _icesave_iterate(row, fors)
      rows.push(row);
    } while (row.year < 2023 || row.quarter < 4);
    //;;console.log('assets_to_us_accum ' + (fors.assets_to_us_accum*1e-9));
    //;;console.log('uk_assets_to_others_mid_accum ' + (fors.uk_assets_to_others_mid_accum*1e-9));
    //;;console.log('uk_assets_to_others_hi_accum ' + (fors.uk_assets_to_others_hi_accum*1e-9));
    //;;console.log('nl_assets_to_others_mid_accum ' + (fors.nl_assets_to_others_mid_accum*1e-9));
    //;;console.log('nl_assets_to_others_hi_accum ' + (fors.nl_assets_to_others_hi_accum*1e-9));
    //;;console.log('sum_assets_to_others ' + ((fors.uk_assets_to_others_mid_accum + fors.uk_assets_to_others_hi_accum + fors.nl_assets_to_others_mid_accum + fors.nl_assets_to_others_hi_accum)*1e-9));
    
    var samtals = 0;
    var npv = 0;
    var discount_factor_per_quarter = 1.0 / Math.pow(1 + fors.nuvirdingarvextir_pr * 0.01, 0.25);
    for (var i=0; i < rows.length; i++) {
      var greidsla = rows[i].greidsla_rikissjods_isk;
      samtals += greidsla;
      npv += greidsla * Math.pow(discount_factor_per_quarter, i-2); // -2 because closest "present" in "net present value" is end of Q2 2009
    }
    return {
      'greidslurod' : rows,
      'samtals' : samtals,
      'nuvirt' : npv
    };
  }

  
  function node ( name ) {
    return {
      nodeName: name,
      childNodes: [],
      append: function ( n ) {
        for (var i=0; i<arguments.length; i++) {
          this.childNodes.push( arguments[i] );
        }
        return n;
      },
      toString: function () {
        var tag = (this.nodeName||'UNKNOWN');
        var r = '\n<' + tag;
        for ( var prop in this ) {
          if ( !/^(nodeName|childNodes|append|toString)$/.test( prop ) && this.hasOwnProperty( prop ) ) {
            r += ' ' + prop + '="' + (this[prop] ? this[prop].toString() : '') + '"';
          }
        }
        r += '>';
        r += $.map(this.childNodes, function (a) {
                return a.toString();
              }).join('');
        r += '</' + tag + '>';
        return r;
      }
    }
  }

  
  function icesave_render_XML ( result ) {
    
    var chart = node( 'chart' );
    var series = chart.append( node( 'series' ) );
    
    for (var i=0; i<=15; i++) {
      var n = node( 'value' );
      n.xid = i + 99;
      n.append( "'" + String( i + 1008 ).substr( 2 ) );
      series.append( n );
    }

    var graphs = chart.append( node( 'graphs' ) );
    var graph = [];
    graph[1] = graphs.append( node( 'graph' ) );
    graph[1].gid = 1;
    graph[2] = graphs.append( node( 'graph' ) );
    graph[2].gid = 2;
    graph[3] = graphs.append( node( 'graph' ) );
    graph[3].gid = 3;
    graph[4] = graphs.append( node( 'graph' ) );
    graph[4].gid = 4;
    
    // group quarters into years
    var rows = result.greidslurod;
    var map = {};
    for (var i=0; i<rows.length; i++) {
      var row = rows[i];
      var m = map[ row.year ] = map[ row.year ] || { payout:0, reclaim:0 };
      m.payout  += row.greidsla_rikissjods_isk;
      m.reclaim += row.endurheimt_isk;
      var xid = (row.year - 2009) + 100;

      if ( row.quarter == 4 ) {

        // add payments
        var vx = node( 'value' );
        vx.xid = xid;
        vx.append( ~~(m.reclaim || m.payout || 0) );
        vx.description = "Endurheimtar eignir " + row.year;
        if ( m.payout ) { 
          vx.color = "CC3333"; 
          vx.description = "Afborganir ríkisins " + row.year;
        }
        graph[4].append( vx );

      }
      
      if ( row.quarter == 4 ) {

        if ( row.year < 2016 ) {

          // add interest
          var vx = node( 'value' );
          vx.xid = xid;
          vx.description = "Uppsafnaðir vextir í árslok " + row.year;
          vx.append( ~~(row.vextir_upps_isk) );
          graph[3].append( vx );

          // add capital
          var vx = node( 'value' );
          vx.xid = xid;
          vx.description = "Höfuðstóll og uppsafnaðir vextir í árslok " + row.year;
          vx.append( ~~( row.hofudstoll_isk + row.vextir_upps_isk ) );
          graph[1].append( vx );
          
        }
        if ( row.year >= 2015 ) {
          
          // add remainder
          var vx = node( 'value' );
          vx.xid = xid;
          vx.description = ( row.year == 2015 )
                  ? "Afborganir hefjast. Eftirstöðvar í árslok 2015"
                  : "Eftirstöðvar í árslok " + row.year;
          vx.append( ~~( row.eftirstodvar_isk ) );
          graph[2].append( vx );
          
        }

      }

    }
    var xml = chart.toString();
    return '<?xml version="1.0" encoding="UTF-8"?>' + xml ;

  }


  function icesave_render_table ( result ) {
      var greidslurod = result.greidslurod
      var tableHTML =
            '<table class="icesave_greidslurod" cellpadding="0" cellspacing="0">'
          + '<thead><tr><th>Ársfjórðungur</th>'
          + '<th>Endurheimt</th>'
          + '<th>Vextir falla á</th>'
          + '<th>Greiðsla ríkissjóðs</th>'
          + '<th>Höfuðstóll</th>'
          + '<th>Uppsafnaðir vextir</th>'
          + '<th>Eftirstöðvar</th></tr></thead><tbody>';
      for (var i=0; i < greidslurod.length; i++) {
          var row = greidslurod[i];
          var klasses = i % 2 == 0 ? ['even'] : ['odd'];
          if ( row.year == 2015 && row.quarter == 4 ) {
              klasses.push('preloan_period_ends');
          }
          var preloan = row.year < 2016;
          tableHTML += '<tr class="' + klasses.join(' ') + '">'
                       + '<td>' + row.year + ' Q' + row.quarter
                       + '</td><td class="num">' + (preloan ? _format_jardur_mills(row.endurheimt_isk) : '&nbsp;')
                       + '</td><td class="num">' + _format_jardur_mills(row.vextir_nu_isk)
                       + '</td><td class="num">' + (preloan ? '&nbsp;' : _format_jardur_mills(row.greidsla_rikissjods_isk))
                       + '</td><td class="num">' + (preloan ? _format_jardur_mills(row.hofudstoll_isk) : '&nbsp;')
                       + '</td><td class="num">' + (preloan ? _format_jardur_mills(row.vextir_upps_isk) : '&nbsp;')
                       + '</td><td class="num">' + _format_jardur_mills(row.eftirstodvar_isk)
                       + '</td></tr>';
      }
      tableHTML += '</tbody></table>';
      return tableHTML;
  }
  
    var uk_corr = 6698; // a guess at correcting the Landsbanki Excel document (move claims to higher buckets such that Iceland totals fit)
    var num_uk_low = 140075 - uk_corr;
    var num_uk_mid = 59865 + uk_corr / 2;
    var num_uk_hi = 29230 + uk_corr / 2;
    var claims_uk_low = 769411213.0;
    var claims_uk_mid = 1611196295.0;
    var claims_uk_hi = 2146381339.0;
    var total_claims_gbp = claims_uk_low + claims_uk_mid + claims_uk_hi;
    var nl_corr = 7116; // best guess at correcting the Landsbanki Excel document (move claims to higher buckets such that Iceland totals fit)
    var num_nl_low = 89882 - nl_corr;
    var num_nl_mid = 13968 + nl_corr / 2;
    var num_nl_hi = 10286 + nl_corr / 2;
    var claims_nl_low = 674018598.0;
    var claims_nl_mid = 407288929.0;
    var claims_nl_hi = 592978145.0;
    var total_claims_eur = claims_nl_low + claims_nl_mid + claims_nl_hi;
    
    function parab_stem(a, b, c, x) {
        return a * x*x*x / 3 + b * x*x / 2 + c * x;
    }
    function parab(a, b, c) {
        this.a = a;
        this.b = b;
        this.c = c;
        //console.log('a = ' + a + ', b = ' + b + ', c = ' + c);
        this.scale = function(p) {
            pa = p*a;
            pb = p*b;
            pc = p*c;
            return {
                'area' : function(from, to) {
                    if ( isNaN(from) || from >= to ) {
                        return 0;
                    } else {
                        area = parab_stem(pa, pb, pc, to) - parab_stem(pa, pb, pc, from);
                        //;;console.log('area from ' + from + ' to ' + to + ': ' + area);
                        return area;
                    }
                },
                'intersect' : function(d) {
                    return (-b + Math.sqrt(b*b - 4 * a * (c - d/p))) / ( 2 * a);
                }
            }
        };
    }
    
    function range_parab(totalclaims, numaccounts, maxamount, minamount) {
        N = numaccounts * 0.001;
        maxmin = maxamount - minamount;
        avgmin = totalclaims/numaccounts - minamount;
        //console.log('maxmin ' + maxmin + ', avgmin ' + avgmin);
        b = 3*avgmin - maxmin;
        a = maxmin - 2 * avgmin;
        if(a < 0 || b > 0) {
            b = b * 2 / N;
            a = a * 3 / (N*N);
        } else {
            b = 0;
            a = 3 * avgmin / (N*N);
        }
        return new parab(a, b, minamount);
    }
    
    var uk_parab_mid = range_parab(claims_uk_mid, num_uk_mid, 35000, 16500);
    var nl_parab_mid = range_parab(claims_nl_mid, num_nl_mid, 40000, 20887);
    var uk_parab_hi  = range_parab(claims_uk_hi, num_uk_hi, 1e9, 35000);
    var nl_parab_hi  = range_parab(claims_nl_hi, num_nl_hi, 1e9, 40000);
    //aukm = uk_parab_mid.scale(1.0).area(0, num_uk_mid*0.001);
    //anlm = nl_parab_mid.scale(1.0).area(0, num_nl_mid*0.001);
    //aukh = uk_parab_hi.scale(1.0).area(0, num_uk_hi*0.001);
    //anlh = nl_parab_hi.scale(1.0).area(0, num_nl_hi*0.001);
    //console.log('area: ' + aukm + ', ' + anlm + ', ' + aukh + ', ' + anlh + ', total ' + (((aukm+aukh) * 213 +(anlm+anlh) * 181)*1000 + claims_uk_low * 213 + claims_nl_low * 181));
    function _default_endurheimt ( year, quarter, fors, prev_row) {
        if ( !fors ) {
            fors = this;
        }
        if ( ! fors.tryggingarsjodur_faer_forgang ) {
            return _old_default_endurheimt ( year, quarter, fors );
        } else if ( year < 2009 || year == 2009 && quarter < 3 || year >= 2016 ) {
            return 0;
        } else {
            var krofur_uk_isk_ma = fors.krofur_uk_gbp_ma * fors.gengi_gbpisk;
            var krofur_nl_isk_ma = fors.krofur_nl_eur_ma * fors.gengi_eurisk;
            var heildarkrofur_isk_ma = krofur_uk_isk_ma + krofur_nl_isk_ma;
            var total_claims_isk = total_claims_gbp * fors.gengi_gbpisk + total_claims_eur * fors.gengi_eurisk;
            var grand_total_assets_reclaimed_isk = fors.eignasafn_li.verdmat_isk_ma * 1e9 * fors.eignasafn_li.endurheimtuhlutfall_pr * 0.01;
            var assets_claims_proportion = grand_total_assets_reclaimed_isk / total_claims_isk;
            var assets_to_uk_accounts_isk = (total_claims_gbp * assets_claims_proportion * fors.gengi_gbpisk);
            var assets_to_nl_accounts_isk = (total_claims_eur * assets_claims_proportion * fors.gengi_eurisk);
            fors.prop_of_assets_accum = (year * 4 + quarter - (2009 * 4 + 2)) / 26;
            var p = fors.prop_of_assets_accum * assets_claims_proportion; // assets thus far reclaimed, as proportion of claims
            var uk_parab_mid_p = uk_parab_mid.scale(p);
            uk_mid_intersect = uk_parab_mid_p.intersect(16500);
            uk_mid_end = num_uk_mid * 0.001;
            uk_mid_start = isNaN(uk_mid_intersect) ? (uk_parab_mid.a < 0 ? uk_mid_end : 0) : Math.max(0, uk_mid_intersect);
            var uk_assets_to_others_mid_accum = (uk_parab_mid_p.area(uk_mid_start, uk_mid_end) - Math.max(0, uk_mid_end - uk_mid_start) * 16500) * 1000 * fors.gengi_gbpisk;
            var uk_assets_to_others_mid_now = uk_assets_to_others_mid_accum - fors.uk_assets_to_others_mid_accum;
            fors.uk_assets_to_others_mid_accum = uk_assets_to_others_mid_accum;
            var nl_parab_mid_p = nl_parab_mid.scale(p);
            nl_mid_intersect = nl_parab_mid_p.intersect(20887);
            nl_mid_end = num_nl_mid * 0.001;
            nl_mid_start = isNaN(nl_mid_intersect) ? (nl_parab_mid.a < 0 ? nl_mid_end : 0) : Math.max(0, nl_mid_intersect);
            var nl_assets_to_others_mid_accum = (nl_parab_mid_p.area(nl_mid_start, nl_mid_end) - Math.max(0, nl_mid_end - nl_mid_start) * 20887) * 1000 * fors.gengi_eurisk;
            var nl_assets_to_others_mid_now = nl_assets_to_others_mid_accum - fors.nl_assets_to_others_mid_accum;
            //console.log('area from ' + nl_mid_start + ' to ' + nl_mid_end + ' is ' + nl_assets_to_others_mid_now);
            fors.nl_assets_to_others_mid_accum = nl_assets_to_others_mid_accum;
            var uk_parab_hi_p = uk_parab_hi.scale(p);
            uk_hi_intersect = uk_parab_hi_p.intersect(16500);
            uk_hi_end = num_uk_hi * 0.001;
            uk_hi_start = isNaN(uk_hi_intersect) ? (uk_parab_hi.a < 0 ? uk_hi_end : 0) : Math.max(0, uk_hi_intersect);
            var uk_assets_to_others_hi_accum = (uk_parab_hi_p.area(uk_hi_start, uk_hi_end) - Math.max(0, uk_hi_end - uk_hi_start) * 16500) * 1000 * fors.gengi_gbpisk;
            var uk_assets_to_others_hi_now = uk_assets_to_others_hi_accum - fors.uk_assets_to_others_hi_accum;
            fors.uk_assets_to_others_hi_accum = uk_assets_to_others_hi_accum;
            var nl_parab_hi_p = nl_parab_hi.scale(p);
            nl_hi_intersect = nl_parab_hi_p.intersect(20887);
            nl_hi_end = num_nl_hi * 0.001;
            nl_hi_start = isNaN(nl_hi_intersect) ? (nl_parab_hi.a < 0 ? nl_hi_end : 0) : Math.max(0, nl_hi_intersect);
            var nl_assets_to_others_hi_accum = (nl_parab_hi_p.area(nl_hi_start, nl_hi_end) - Math.max(0, nl_hi_end - nl_hi_start) * 20887) * 1000 * fors.gengi_eurisk;
            var nl_assets_to_others_hi_now = nl_assets_to_others_hi_accum - fors.nl_assets_to_others_hi_accum;
            fors.nl_assets_to_others_hi_accum = nl_assets_to_others_hi_accum;
            endurheimt_now_isk = grand_total_assets_reclaimed_isk / 26 - uk_assets_to_others_mid_now - uk_assets_to_others_hi_now - nl_assets_to_others_mid_now - nl_assets_to_others_hi_now;
            //;;console.log('year ' + year + ' quarter ' + quarter + ' p ' + (Math.round(p*1e3)*1e-3) + ' nl ' + (Math.round(nl_assets_to_others_mid_now*1e-6)*1e-3) + ' ' + (Math.round(nl_assets_to_others_hi_now*1e-6)*1e-3) + ' uk ' + (Math.round(uk_assets_to_others_mid_now*1e-6)*1e-3) + ' ' + (Math.round(uk_assets_to_others_hi_now*1e-6)*1e-3) + ' we ' + (Math.round(endurheimt_now_isk*1e-6)*1e-3));
            fors.assets_to_us_accum = fors.assets_to_us_accum + endurheimt_now_isk;
            return endurheimt_now_isk * 1e-9;
        }
    }
  
  function _old_default_endurheimt ( year, quarter, fors, prev_row ) {
      if ( !fors ) {
          fors = this;
      }
      var krofur_uk_isk_ma = fors.krofur_uk_gbp_ma * fors.gengi_gbpisk;
      var krofur_nl_isk_ma = fors.krofur_nl_eur_ma * fors.gengi_eurisk;
      var heildarkrofur_isk_ma = krofur_uk_isk_ma + krofur_nl_isk_ma;
      var total_claims_isk = total_claims_gbp * fors.gengi_gbpisk + total_claims_eur * fors.gengi_eurisk;
      var assets_claims_proportion = fors.eignasafn_li.verdmat_isk_ma * 1e9 * fors.eignasafn_li.endurheimtuhlutfall_pr * 0.01 / total_claims_isk;
      var assets_to_uk_accounts_isk = (total_claims_gbp * assets_claims_proportion * fors.gengi_gbpisk);
      var assets_to_nl_accounts_isk = (total_claims_eur * assets_claims_proportion * fors.gengi_eurisk);
      if(fors.assets_ice_prop_uk && fors.assets_ice_prop_nl) {
          // Constant and already computed in a previous call to this function, just reuse.
          var assets_ice_prop_uk = fors.assets_ice_prop_uk;
          var assets_ice_prop_nl = fors.assets_ice_prop_nl;
      } else if(fors.tryggingarsjodur_faer_forgang) {
          var assets_per_account_uk_low = claims_uk_low * assets_claims_proportion / num_uk_low;
          var assets_per_account_uk_mid = claims_uk_mid * assets_claims_proportion / num_uk_mid;
          var assets_per_account_uk_hi = claims_uk_hi * assets_claims_proportion / num_uk_hi;
          var assets_total_uk = assets_per_account_uk_low * num_uk_low + assets_per_account_uk_mid * num_uk_mid + assets_per_account_uk_hi * num_uk_hi;
          var assets_per_account_uk_low_to_trygg = Math.min(16500, assets_per_account_uk_low);
          var assets_per_account_uk_mid_to_trygg = Math.min(16500, assets_per_account_uk_mid);
          var assets_per_account_uk_hi_to_trygg = Math.min(16500, assets_per_account_uk_hi);
          var assets_total_uk_to_trygg = assets_per_account_uk_low_to_trygg * num_uk_low + assets_per_account_uk_mid_to_trygg * num_uk_mid + assets_per_account_uk_hi_to_trygg * num_uk_hi;
          var assets_ice_prop_uk = assets_total_uk_to_trygg / assets_total_uk;
          var assets_per_account_nl_low = claims_nl_low * assets_claims_proportion / num_nl_low;
          var assets_per_account_nl_mid = claims_nl_mid * assets_claims_proportion / num_nl_mid;
          var assets_per_account_nl_hi = claims_nl_hi * assets_claims_proportion / num_nl_hi;
          var assets_total_nl = assets_per_account_nl_low * num_nl_low + assets_per_account_nl_mid * num_nl_mid + assets_per_account_nl_hi * num_nl_hi;
          var assets_per_account_nl_low_to_trygg = Math.min(20887, assets_per_account_nl_low);
          var assets_per_account_nl_mid_to_trygg = Math.min(20887, assets_per_account_nl_mid);
          var assets_per_account_nl_hi_to_trygg = Math.min(20887, assets_per_account_nl_hi);
          var assets_total_nl_to_trygg = assets_per_account_nl_low_to_trygg * num_nl_low + assets_per_account_nl_mid_to_trygg * num_nl_mid + assets_per_account_nl_hi_to_trygg * num_nl_hi;
          var assets_ice_prop_nl = assets_total_nl_to_trygg / assets_total_nl;
          // correct for bogus claims data
          assets_ice_prop_uk = assets_ice_prop_uk * fors.upphaflegt_lan.gbp_ma / 2.239478713;
          assets_ice_prop_nl = assets_ice_prop_nl * fors.upphaflegt_lan.eur_ma / 1.180611896;
          // Signal to later runs of this function that the values are constant and already computed
          fors.assets_ice_prop_uk = assets_ice_prop_uk;
          fors.assets_ice_prop_nl = assets_ice_prop_nl;
      } else {
          var assets_ice_prop_uk = 0.519;
          var assets_ice_prop_nl = 0.794;
      }
      var assets_to_tryggingarsjodur_isk = assets_to_uk_accounts_isk * assets_ice_prop_uk + assets_to_nl_accounts_isk * assets_ice_prop_nl;
      var ret = 0;
      if ( year == 2009 && quarter >= 3 || year > 2009 && year < 2016 ) {
          var prop = 1.0 / 26; // can make this time-dependent, but then average must be the same
          ret = prop * assets_to_tryggingarsjodur_isk / 1e9;
      }
      return ret;
  }
  
  function _format_jardur_mills ( val ) {
      return (Math.abs(val) < 0.005 ? '0.0' : (val < 1 ? val.toPrecision(2) : val.toFixed(1))).replace('.', ',');
  }

  function _icesave_iterate ( prev_row, fors ) {
      var year = prev_row.year + (prev_row.quarter == 4 ? 1 : 0);
      var quarter = (prev_row.quarter == 4) ? 1 : (prev_row.quarter + 1);
      var endurheimt_isk = Math.min(prev_row.hofudstoll_isk, fors.compute_endurheimt(year, quarter, fors, prev_row));
      var medaleftirstodvar = prev_row.eftirstodvar_isk - endurheimt_isk / 2;
      var vextir_nu_isk = medaleftirstodvar * fors.upphaflegt_lan.vextir_pr * 0.01 * 0.25;
      var preloan = year < 2016;
      var vextir_intrayearaccum_isk = preloan
            ? ((quarter == 1) ? vextir_nu_isk : (prev_row.vextir_intrayearaccum_isk + vextir_nu_isk))
            : 0;
      var vextir_upps_isk = (quarter == 4) ? prev_row.vextir_upps_isk + vextir_intrayearaccum_isk : prev_row.vextir_upps_isk;
      var greidsla_rikissjods_isk = preloan ? 0 : (prev_row.eftirstodvar_isk_vid_virkjun_lans / 32 + vextir_nu_isk);
      var hofudstoll_isk = prev_row.hofudstoll_isk - endurheimt_isk;
      if ( preloan ) {
          var eftirstodvar_isk = prev_row.eftirstodvar_isk + vextir_upps_isk - prev_row.vextir_upps_isk - endurheimt_isk;
      }
      else {
          var eftirstodvar_isk = prev_row.eftirstodvar_isk - greidsla_rikissjods_isk + vextir_nu_isk; 
      }
      return {
          'preloan' : preloan,
          'year' : year,
          'quarter' : quarter,
          'hofudstoll_isk' : hofudstoll_isk,
          'vextir_nu_isk' : vextir_nu_isk,
          'vextir_intrayearaccum_isk' : vextir_intrayearaccum_isk,
          'vextir_upps_isk' : vextir_upps_isk,
          'endurheimt_isk' : endurheimt_isk,
          'endurheimt_upps_isk' : prev_row.endurheimt_upps_isk + endurheimt_isk,
          'greidsla_rikissjods_isk' : greidsla_rikissjods_isk,
          'eftirstodvar_isk' : eftirstodvar_isk,
          'eftirstodvar_isk_vid_virkjun_lans' : (year != 2015 || quarter != 4) ? prev_row.eftirstodvar_isk_vid_virkjun_lans : eftirstodvar_isk
      };
  }

  
  //----

  context.values( $.hashvar() );

  update();
  
});
