//
// N2y6B2-RenCalcD v1.6.4 (18-feb-08) 
//  written by Jean-Pol Tamenne 
//  inspired by scripts written by Alexander Babichev in 2006 
//
// v1.6 
//	new per-calendar-month rental in mid season
//	optimization in the selection of rental contract type 
//	(per-night vs per-calendar-month contract)
//
// v1.5.1
//      lower additional nights after per-calendar month rental
//
// v1.5
//	allow for spliting totals into revenue/cost
//
// v1.4
//	force an all time discount based on an added parameter
//
// v1.3
//	added GBP support
//
// v1.2
//	monthly rent down to 600 from 500
//	last minute: first 7 nights at 40% off
//
// notes -
//      new Date valueOf = number of milliseconds since midnight 01 January, 1970 UTC
//

function N2y6B2WriteOutVer(lg)
{
  // new function in v1.6

  var rtext = "<hr><p>"
  switch (lg) {
    case 1: // french
      rtext += "<i>v1.6.4 (18-fév-2008)</i><br>"
      break;
    default: // english
      rtext += "<i>v1.6.4 (18-feb-2008)</i><br>"
      break;
  }
  rtext += "</p><hr><br>"

  var ver = '<div style="color: rgb(0, 0, 0);" class="webheadnote">' + 
		                                         rtext + '</div>'
  document.write(ver)
}

function N2y6B2WriteOutWarn(lg)
{
  // new function in v1.6.3

  var rtext = "<hr><p>"
  switch (lg) {
    case 1: // french
      rtext += "<i>Information indicative/non-contractuelle.</i><br>"
      break;
    default: // english
      rtext += "<i>Non-contractual/indicative information.</i><br>"
      break;
  }
  rtext += "</p><hr><br>"
 
  rtext = '<div style="color: rgb(0, 0, 0);" class="webheadnote">' + 
	                                                rtext + '</div>'
  document.write(rtext)
}

function N2y6B2DayName(lang, dayn)
{
  var dname;
  dayn %= 7;
  switch (lang) {
    case 1:
      dname = (new Array("Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"))[dayn];
      break;
    default:
      dname = (new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"))[dayn];
      break;
  }
  return dname;
}

function N2y6B2MonthName(lang, monthn)
{
  var mname;
  monthn %= 12;
  switch (lang) {
    case 1:
      mname = (new Array("Janvier", "Février", "Mars", "Avril",
    			"Mai", "Juin", "Juillet", "Août",
			"Septembre", "Octobre", "Novembre", "Décembre")) [monthn];
      break;
    default:
      mname = (new Array("January", "February", "March", "April",
    			"May", "June", "July", "August",
			"September", "October", "November", "December")) [monthn];

      break;
  }
  return mname;
}

function N2y6B2ShortMonthName(lang, monthn)
{
  var mname;
  monthn %= 12;
  switch (lang) {
    case 1:
      mname = (new Array("Jan", "Fev", "Mar", "Avr",
    			"Mai", "Jun", "Jui", "Aou",
			"Sep", "Oct", "Nov", "Dec")) [monthn];
      break;
    default:
      mname = (new Array("Jan", "Feb", "Mar", "Apr",
    			"May", "Jun", "Jul", "Aug",
			"Sep", "Oct", "Nov", "Dec")) [monthn];

      break;
  }
  return mname;
}

function N2y6B2WriteOutCalendarD(lg, cal, pdisc)
{
  // lg: 1 = français otherwise english
  // cal: calendar number, 0=start date, 1=end date
  // from v1.4: pdisc: permanent discount in percentage (<0 for pre-v1.4 logic)

  var now = new Date
  var dd = now.getDate()
  var mm = now.getMonth()
  var dow = now.getDay()
  var yyyy = now.getFullYear()

  // array of years for the droplist
  var arrY = new Array()
  for (ii=0;ii<=6;ii++) {
    arrY[ii] = yyyy + ii -2
  }

  // piece of web page to write out
  var text = ""
  var parms = lg + "," + cal + "," + pdisc

// start of form NEy6B2CalForm0 or 1
  text = "<form name=N2y6B2CalForm" + cal + "> "

  if (lg == 1) {
    text += "<label class='labl' for='ResultDate'><i>"+
            ( (cal==0) ? "Du " : "Au " )+"</i></label>"
  }
  else {
    text += "<label class='labl' for='ResultDate'><i>"+
            ( (cal==0) ? "From " : "To " )+"</i></label>"
  }
  text += "<input type='text' size='10' style='text-align: left;'"+
          " id='ResultDate' readonly='readonly'>"
  if (lg == 1) {
    text += "<label class='labl' for='ResultDate'>"+
            ( (cal==0) ? " après 17h" : " avant midi" )+"</label>"
  }
  else {
    text += "<label class='labl' for='ResultDate'>"+
            ( (cal==0) ? " after 5pm" : " before noon" )+"</label>"
  }
  text += "<br><br>"

// start of table 1.
  text += "<table border=1>"
  text += "<tr>"
  text += "<td>"

// start of table 1.1.
  text += "<table width=100%>"

  text += "<tr>"
  text += "<td align=left>"

  text += "<a href=Month- onClick='N2y6B2ChangeMonthD(" + parms + 
          ",-1);this.blur();return false;'>" 
  text += "<img src=../picts/N2y6B2-RentCalc-LeftArrow.gif border=0></a>&nbsp;"

  text += "<select name=SelMonth onChange='N2y6B2RefreshCalD(" + parms + ",-1)'>"
  for (ii=0;ii<=11;ii++) {
    if (ii==mm) {
      // current month is selected
      text += "<option value= " + ii + " Selected>" + 
              N2y6B2MonthName(lg,ii) + "</option>"
    }
    else {
      text += "<option value= " + ii + ">" + 
              N2y6B2MonthName(lg,ii) + "</option>"
    }
  }
  text += "</select>&nbsp;"

  text += "<a href=Month+ onClick='N2y6B2ChangeMonthD(" + parms + 
          ",1);this.blur();return false;'>"
  text += "<img src=../picts/N2y6B2-RentCalc-RightArrow.gif border=0></a>"

  text += "</td>"

  text += "<td align=right>"

  text += "<select name=SelYear onChange='N2y6B2RefreshCalD(" + parms + ",-1)'>"
  for (ii=0;ii<=6;ii++) {
    if (arrY[ii]==yyyy) {
      // current year is selected
      text += "<option value= " + arrY[ii] + " Selected>" + arrY[ii] + "</option>"
    }
    else {		
      text += "<option value= " + arrY[ii] + ">" + arrY[ii] + "</option>"
    }
  }
  text += "</select>"

  text += "</td>"
  text += "</tr>"

  text += "</table>"
// end of table 1.1.

  text += "</td>"
  text += "</tr>"

  text += "<tr>"
  text += "<td>"

// start of table 1.2.
  text += "<table border=1>"
  text += "<tr>"
  for (ii=0;ii<=6;ii++) {
    text += "<td align=center width=35 Valign=middle class=label>" + 
            N2y6B2DayName(lg,ii) + "</td>"
  }
  text += "</tr>"

  aa = cal*100
  for (kk=0;kk<=5;kk++) {
    text += "<tr>"
    for (ii=0;ii<=6;ii++) {
      text += "<td align=center id=td" + aa + ">"
      text += "<a href=" + aa + " ID=" + aa + 
	      " class=cal onClick='N2y6B2RefreshCalD(" + parms + 
              ",this.id);this.blur();return false'>1</a>"
      text += "</td>"
      aa += 1
    }
    text += "</tr>"
  }
  text += "</table>"
// end of table 1.2.

  text += "</td>"
  text += "</tr>"

  text += "</table>"
// end of table 1.

  text += "</form>"
// end of form   

  document.write(text)

  N2y6B2RefreshCalD(lg, cal, pdisc, -1)
  N2y6B2DisplayCookedReport(lg, 0)
}

function N2y6B2ChangeMonthD(lg, cal, pdisc, offset) {

  var now = new Date
  var minY = now.getFullYear() - 2
  var maxY = now.getFullYear() + 4

  var mm
  var yyyy
  if (cal == 0) {
    mm = parseInt(document.N2y6B2CalForm0.SelMonth.value)
    yyyy = parseInt(document.N2y6B2CalForm0.SelYear.value)
  }
  else {
    mm = parseInt(document.N2y6B2CalForm1.SelMonth.value)
    yyyy = parseInt(document.N2y6B2CalForm1.SelYear.value)
  }

  // should never go lower than the first month/year or
  //    go higher than the last month/year 
  if (! (yyyy == minY && mm == 0 && parseInt(offset) == -1) &&
        ! (yyyy == maxY && mm == 11 && parseInt(offset) == 1) ) {

    // apply offset to month
    mm += parseInt(offset)

    // get one year sooner
    if (mm == -1) {
      mm = 11
      yyyy -= 1
    }

    // get one year later
    if (mm == 12) {
      mm = 0
      yyyy += 1
    }

    // update on-screen month / year
    if (cal == 0) {
      document.N2y6B2CalForm0.SelMonth.value = mm
      document.N2y6B2CalForm0.SelYear.value = yyyy
    }
    else {
      document.N2y6B2CalForm1.SelMonth.value = mm
      document.N2y6B2CalForm1.SelYear.value = yyyy
    }

    // refresh on-screen month calendar
    N2y6B2RefreshCalD(lg, cal, pdisc, -1)		
  }
}

function N2y6B2RefreshCalD(lg, cal, pdisc, selectedId) 
{
  var TDelem
  var elem	

  var now = new Date
  var dd = now.getDate()
  var mm = now.getMonth()
  var dow = now.getDay()
  var yyyy = now.getFullYear()

  var currM
  var currY
  if (cal == 0) {
    currM = parseInt(document.N2y6B2CalForm0.SelMonth.value)
    currY = parseInt(document.N2y6B2CalForm0.SelYear.value)
  } 
  else {
    currM = parseInt(document.N2y6B2CalForm1.SelMonth.value)
    currY = parseInt(document.N2y6B2CalForm1.SelYear.value)
  }

  var prevM
  if (currM != 0) {
    prevM = currM - 1
  }
  else {
    prevM = 11
  }
	
  var mmyyyy = new Date()
  mmyyyy.setFullYear(currY, currM, 1)

  var day1 = mmyyyy.getDay()
  if (day1 == 0) {
    day1 = 7
  }

  var arrN = new Array(41)

  for (ii=0;ii<day1;ii++) {
    arrN[ii] = N2y6B2MaxDays((prevM),currY) - day1 + ii + 1
  }

  var aa = 1
  for (ii=day1;ii<=day1+N2y6B2MaxDays(currM,currY)-1;ii++) {	
    arrN[ii] = aa
    aa += 1
  }
	
  aa = 1
  for (ii=day1+N2y6B2MaxDays(currM,currY);ii<=41;ii++) {
    arrN[ii] = aa
    aa += 1
  }

  // compute a selected id without calendar number in the 100s
  var sid
  if (selectedId >= 0) {
    sid = selectedId - (100 * parseInt(selectedId / 100))
  }
  else {
    sid = -1
  }

  // update on-screen calendar
  var dCount = 0
  for (ii=0;ii<=41;ii++) {

    TDelem = eval("document.getElementById('td"+(100*cal+ii)+"')") 		
    elem = eval("document.getElementById('"+(100*cal+ii)+"')") 		

    // set color and bold attribute
    if ( ((ii<7) && (arrN[ii]>20)) || ((ii>27) && (arrN[ii]<20)) ) {
      // day outside displayed month

      // default settings
      TDelem.style.backgroundColor = "white"
      elem.style.color = "#000000"
      elem.style.fontWeight = "normal"	

      // set text to display
      elem.innerHTML = "--"
    }
    else {
      // day inside displayed month

      // background is:
      //   yellow by priority if selected
      //   some green if current day
      //   white in all other cases
      TDelem.style.backgroundColor = (ii == sid) ? "yellow" : 
        (((arrN[ii]==dd)&&(mm==currM)&&(yyyy==currY)) ? "#90ee90" : "white")

      if ((dCount==0)||(dCount==6)) {
        // week-end
        elem.style.color = "#FF0000"				
	elem.style.fontWeight = "bold"				
      }
      else {
        // weekday
	elem.style.color = "#000000"
        elem.style.fontWeight = "bold"
      }

      // set text to display
      elem.innerHTML = arrN[ii]
    }

    dCount += 1
    if (dCount>6) {
      dCount=0
    }						
  }

  // evaluate the date
  var dateStr = ""
  if (sid >= 0) {
    monthStr = currM + 1
    yearStr = currY
    if (sid < day1) {
      if (currM == 0) {
        monthStr = 12
        yearStr = currY - 1
      }
      else {
        monthStr = currM
      }
    }
    else {
      if (sid > day1+N2y6B2MaxDays(currM,currY)-1) {
        if (currM == 11) {
	  monthStr = 1
          yearStr = currY + 1
        }
        else {
	  monthStr = currM + 2
        }
      }
    }    

    dayStr = N2y6B2Right("00" + arrN[sid], 2)
    monthStr = N2y6B2Right("00" + monthStr, 2)
    yearStr = N2y6B2Right("0000" + yearStr, 4)

    dateStr = dayStr + "-" + monthStr + "-" + yearStr
    dateStr = N2y6B2ValidateNewDateD(lg, cal, pdisc, dateStr)
  }	

  // update date field
  if (cal == 0) {
    document.N2y6B2CalForm0.ResultDate.value = dateStr
  }
  else {
    document.N2y6B2CalForm1.ResultDate.value = dateStr
  }
}

function N2y6B2ValidateNewDateD(lg, cal, pdisc, newdate)
{
  // retrieve both current dates
  var dateStr0
  var dateStr1

  // bring the update
  if (cal == 0) {
    dateStr0 = newdate
    dateStr1 = document.N2y6B2CalForm1.ResultDate.value
  }
  else {
    dateStr0 = document.N2y6B2CalForm0.ResultDate.value
    dateStr1 = newdate
  }

  var finaldate

  // check for non empry strings
  if (dateStr0 == "" || dateStr1 == "") {
    // can not check anyway so let it go
    finaldate = newdate
    N2y6B2DisplayCookedReport(lg, 1)
  }
  else {
    // split elements
    dateElems0 = dateStr0.split("-")
    dateElems1 = dateStr1.split("-")

    // init a date
    var dateObj0 = new Date(dateElems0[2],dateElems0[1] - 1,dateElems0[0])
    var dateObj1 = new Date(dateElems1[2],dateElems1[1] - 1,dateElems1[0])

    // check date #1 < date #2 (at least a day in-between
    if (dateObj0.valueOf() < dateObj1.valueOf()) {
      // date #1 effectively < date #2

      // accept the new date
      finaldate = newdate

      // compute the difference in number of days
      var msdiff = dateObj1.valueOf() - dateObj0.valueOf()
      var msdiffremainder = msdiff % 86400000
      msdiff -= msdiffremainder
      var days = msdiff / 86400000

      // compute and display the rent
      N2y6B2ComputeRentD(lg, pdisc, days,
       dateElems0[2], dateElems0[1] - 1, dateElems0[0], 
       dateElems1[2], dateElems1[1] - 1, dateElems1[0])
    }
    else {

      // accept the new date
      finaldate = newdate

      // the dates are not sequential & empty report
      N2y6B2DisplayCookedReport(lg, 2)
    }
  }

  return finaldate
}

function N2y6B2DisplayCookedReport(lg, msgCode)
{
    var rtext = "<hr><p>"

    switch (lg) {
      case 1: // french
        switch (msgCode) {
          case 1:
            rtext += "<i>Entrez une seconde date</i><br>"
            break;
          case 2:
            rtext += "<i>Vous quittez avant d'arriver!</i><br>"
            break;
          case 3:
            rtext += "<i>Notre proposition</i><br>"
            break;
          case 4:
            rtext += "<i>Nos deux propositions applicables</i><br>"
            break;
          default:  
            rtext += "<i>Sélectionnez vos dates d'entrée et de sortie</i><br>"
            break;
        }
        break;
      default: // english
        switch (msgCode) {
          case 1:
            rtext += "<i>Enter a second date</i><br>"
            break;
          case 2:
            rtext += "<i>You are leaving before arriving!</i><br>"
            break;
          case 3:
            rtext += "<i>Our proposal</i><br>"
            break;
          case 4:
            rtext += "<i>Our two applicable proposals</i><br>"
            break;
          default:  
            rtext += "<i>Select start/end dates</i><br>"
            break;
        }
        break;
    }
    rtext += "</p>"

    // display empty report
    document.getElementById("N2y6B2Message").innerHTML = rtext
}

function N2y6B2ComputeRentD(lg, pdisc, days, yfrom, mfrom, dfrom, yto, mto, dto)
{
  var displayedContracts = 0   
     // returned value is the displayed contracts: 0-none, 1-PN, 2-PCM, 3-PN+PCM
  var doDispPN= false   // true if we have to display the per-night rent
  var doDispPCM= false    // true if we have to display the per-cal-month rent

  // firstly evaluate every type of contract (without touching the display)
  var perNight_value = N2y6B2ComputePNRentD2(false, lg, pdisc, days, 
                                             yfrom, mfrom, dfrom, yto, mto, dto)
  var perCalMonth_value = N2y6B2ComputePCMRentD2(false, lg, pdisc, days, 
                                                 yfrom, mfrom, dfrom, yto, mto, dto)

  // look for which report should be displayed
  if (perNight_value > 0) {

    if (perCalMonth_value > 0) {

      // look for the best solution
      //    use 150 euros as max electricity charge
      if (perNight_value > perCalMonth_value && 
              perNight_value < (perCalMonth_value + 150)) {

        // both contracts are possible

        // compute the date one month later
        var nmd = dfrom
	var nmm = mfrom + 1
        var nmy = yfrom
        if (nmm > 11) { // also next year ?
          nmy ++    // go to next year
          nmm = 0   // get back to january
        }
        var maxnmd = N2y6B2MaxDays(nmm, nmy)
        // check that next month day is not too high in that month
        if (nmd > maxnmd) {   
          nmd = maxnmd
        }
        var nmStartDate = new Date(nmy, nmm, nmd)
	var endDate = new Date(yto, mto, dto)

	// check that we have at least a month 
        if (nmStartDate.valueOf() <= endDate.valueOf()) {

          // a month or more => go only for per-cal-month contract 
          //   (always cheaper for the tenant)
          doDispPCM = true
        } else {

          // less than a month => show both and let the user pick up the best one
          //   (we can not guess the electricity invoice to pay on top 
          //    with the per-calendar-month contract) 
          doDispPN = true 
          doDispPCM = true
        }
      } else {

        if (perNight_value <= perCalMonth_value) {
  
          // display only per-night contract 
          //   as the tenant will pay less (or equal) all-inclusive
          doDispPN = true 
        } else {

          // display only per-calendar-night contract from 200 euros in electricity
          doDispPCM = true 
        }
      }

    }  // else dont display anything - no contract type is applicable !!?
  } else {

    // per-night contract is not applicable

    // display per-calendar-month results ONLY
    if (perCalMonth_value > 0) {

      // display only per-cal-month contract
      doDispPCM = true
    }
  }

  var contract1Text
  var contract2Text
  if (doDispPN && doDispPCM) {
    // display both contract details
    contract1Text = N2y6B2ComputePNRentD2(true, lg, pdisc, days, 
                                          yfrom, mfrom, dfrom, yto, mto, dto)
    contract2Text = N2y6B2ComputePCMRentD2(true, lg, pdisc, days, 
                                           yfrom, mfrom, dfrom, yto, mto, dto)
    displayedContracts = 3 
    N2y6B2DisplayCookedReport(lg, 4)
  } else {
    // display just the best solution
    if (doDispPN) {
      contract1Text = N2y6B2ComputePNRentD2(true, lg, pdisc, days, 
                                            yfrom, mfrom, dfrom, yto, mto, dto)
      displayedContracts = 1 
    } else { 
      contract1Text = N2y6B2ComputePCMRentD2(true, lg, pdisc, days, 
                                             yfrom, mfrom, dfrom, yto, mto, dto)
      displayedContracts = 2 
    }
    contract2Text = ""
    N2y6B2DisplayCookedReport(lg, 3)
  }
  var c1Field = document.getElementById("N2y6B2Contract1")
  if (c1Field != null) {
    c1Field.innerHTML = contract1Text
  }
  var c2Field = document.getElementById("N2y6B2Contract2")
  if (c2Field != null) {
    c2Field.innerHTML = contract2Text
  }

  return displayedContracts
}

function N2y6B2ComputePNRentD2(doDisplay, lg, pdisc, days, 
                                    yfrom, mfrom, dfrom, yto, mto, dto)
{
  // v1.6
  //   specific version for per-night vacation rentals ("PN")
  //   <doDisplay> is false: returns the contract value 
  //   <doDisplay> is true: returns text to be displayed
  //
  // v1.5
  //   <lg> is the language for the report
  //   <pdisc> is the permanent discount value 
  //                       (<0:last minute, 0:none, >0:permanent for always)
  //   <days> is the number of days between <from> and <to> dates 
  //                       (y:year=2008.., m:month=0-11, d:day=1-31)

  var contractValue = 0  // v1.6 returned value if not to be displayed

  // v1.5 logic based on element presence in web page (= document)
  var splitEl = document.getElementById("N2y6B2Split")
  var displaySplit = (splitEl == null) ? false : true

  // rates (constants across this function)
  var RATE_GBP = 0.677892  // multiply euros by this to get GBP
  var EMAIL_ADDR = "info@suissehome.com"
  var EMAIL_CCADDR = "jptamenne@be.ibm.com"
  var RATE_CLEANUP = 50  // euros
  var RATE_GUARANTEE = 275  // euros

  var RATE_LOWDAYRENT = 30  // euros
  var RATE_LOWSTFEE = 5  // euros
  var RATE_MIDDAYRENT = 42  // euros
  var RATE_MIDSTFEE = 7  // euros
  var RATE_HIDAYRENT = 60  // euros
  var RATE_HISTFEE = 10  // euros

  var RATE_LASTMINDISCOUNT = (pdisc < 0) ? (- pdisc) : pdisc  
        // %   v1.4: new parameter <pdisc>
  var MULTLASTMIN = (100 - RATE_LASTMINDISCOUNT) / 100
  var RATE_LASTMINTERM = (pdisc < 0) ? 7 : ((pdisc == 0) ? 0 : -1)  
        // days (maximum)    v1.4: no maximum if pdisc >= 0
	// pdisc < 0 ==> old last minute with discount = <pdisc> (pre-v1.4 logic)
	// pdisc == 0 ==> no discount at all, old last minute logic not applied
 	// pdisc > 0 ==> permanent discount applied equal to <pdisc>
  var RATE_LASTMINDAYS = 7  // days in adv at earliest (only used in pre-v1.4 logic
  var isDiscounted = N2y6B2IsDiscounted(pdisc, RATE_LASTMINDAYS, yfrom, mfrom, dfrom)

  // report text
  var rtext = ""

  // global number of days/months
  var cost = 0
  var fee = 0    // v1.5
  var paidNights = days

  var costLastMin = 0

  var lowdayrent = 0
  var middayrent = 0
  var hidayrent = 0

  var lowdayrentLastMin = 0
  var middayrentLastMin = 0
  var hidayrentLastMin = 0

  // per month number of days/months
  var costPM 
  var feePM     // v1.5
  var costLastMinPM 
  var lowdayrentPM 
  var middayrentPM
  var hidayrentPM 
  var lowdayrentLastMinPM 
  var middayrentLastMinPM
  var hidayrentLastMinPM 

  // last minute countdown
  countdownLastMin = RATE_LASTMINTERM

  // one day less at the end (easier to compute)
  //     -> set dlast, mlast, ylast
  var dlast
  var mlast 
  var ylast 
  dlast = dto - 1
  if (dlast < 1) {
    mlast = mto - 1
    if (mlast < 0) {
      ylast = yto - 1
      mlast = 11
    } else {
      ylast = yto
    }
    dlast = N2y6B2MaxDays(mlast, ylast)
  } else {
    mlast = mto
    ylast = yto
  }

  // scan all months / loop on y(ear), m(onth)
  var y = yfrom
  var m = mfrom

  // loop on months
  while (y < ylast || (y == ylast && m <= mlast)) {  

    // reset stats for this month
    costPM = 0 
    feePM = 0  // v1.5
    costLastMinPM = 0 
    lowdayrentPM = 0
    middayrentPM = 0
    hidayrentPM = 0
    lowdayrentLastMinPM = 0
    middayrentLastMinPM = 0
    hidayrentLastMinPM = 0

    // compute the number of days over that month
    //      firstmday = first day in this month
    var firstmday    // 1..31
    //      lastmday = last day in this month
    var lastmday     // 1..31
    if (y == yfrom && m == mfrom) {

      // very first month of renting
      firstmday = dfrom
      if (y == ylast && m == mlast) {
        // first and last month
        lastmday = dlast
      }
      else {
        // first but not last month
        lastmday = N2y6B2MaxDays(m, y)
      }

    }
    else {

      // following months after 1st one
      firstmday = 1
      if (y == ylast && m == mlast) {
        // last month but not the first month
	lastmday = dlast
      }
      else {
        // middle full month
        lastmday = N2y6B2MaxDays(m, y)
      }
    }

    // compute how much days (or nights) in this month
    var daysToAdd = lastmday - firstmday + 1

    // exhaust first last minute discounted days
    if (countdownLastMin != 0)
    {
      var daysToAddLastMin 

      if (countdownLastMin < 0) {
        // no limit
        daysToAddLastMin = daysToAdd
      } else {
        // limited last minute period
        daysToAddLastMin = (daysToAdd < countdownLastMin) ? 
                                        daysToAdd : countdownLastMin
      }
      switch (N2y6B2MonthSeason(m)) {
        // low season
        default:
          lowdayrentLastMinPM += daysToAddLastMin
          break
        // medium season
        case 1:
          middayrentLastMinPM += daysToAddLastMin
          break
        // high
        case 2:
          hidayrentLastMinPM += daysToAddLastMin
          break
      }
      if (countdownLastMin > 0) {
        countdownLastMin -= daysToAddLastMin
      }
      daysToAdd -= daysToAddLastMin
    }

    // add the rest to counts
    switch (N2y6B2MonthSeason(m)) {
      // low season
      default:
        lowdayrentPM += daysToAdd
        break
      // medium season
      case 1:
        middayrentPM += daysToAdd
        break
      // high
      case 2:
        hidayrentPM += daysToAdd
        break
    }
    daysToAdd = 0   // all added (just cleanup)

    // update report over this month
    var rtextPM = "<hr><p>"
    switch (lg) {
      case 1: // french
        rtextPM += "<i>Mois " + N2y6B2ShortMonthName(lg,m) + "-" + y + "</i><br>"
        if ((lowdayrentLastMinPM + lowdayrentPM) > 0) {
          rtextPM += (lowdayrentLastMinPM + lowdayrentPM) + 
                     " nuit(s) en basse saison<br>"
          costPM += (lowdayrentLastMinPM + lowdayrentPM) * RATE_LOWDAYRENT
          feePM += (lowdayrentLastMinPM + lowdayrentPM) * RATE_LOWSTFEE
          costLastMinPM += lowdayrentLastMinPM * RATE_LOWDAYRENT * MULTLASTMIN  + 
     			   lowdayrentPM * RATE_LOWDAYRENT
        }
        if ((middayrentLastMinPM + middayrentPM) > 0) {
          rtextPM += (middayrentLastMinPM + middayrentPM) + 
                     " nuit(s) en moyenne saison<br>"
          costPM += (middayrentLastMinPM + middayrentPM) * RATE_MIDDAYRENT
          feePM += (middayrentLastMinPM + middayrentPM) * RATE_MIDSTFEE
          costLastMinPM += middayrentLastMinPM * RATE_MIDDAYRENT * MULTLASTMIN  + 
     			   middayrentPM * RATE_MIDDAYRENT
        }
        if ((hidayrentLastMinPM + hidayrentPM) > 0) {
          rtextPM += (hidayrentLastMinPM + hidayrentPM) + 
                     " nuit(s) en haute saison<br>"
          costPM += (hidayrentLastMinPM + hidayrentPM) * RATE_HIDAYRENT
          feePM += (hidayrentLastMinPM + hidayrentPM) * RATE_HISTFEE
          costLastMinPM += hidayrentLastMinPM * RATE_HIDAYRENT * MULTLASTMIN + 
     		           hidayrentPM * RATE_HIDAYRENT
        }
        if (costPM > 0) {
          if (! isDiscounted || Math.round(costLastMinPM) == Math.round(costPM)) {
            rtextPM += "<i>Total:</i> " + Math.round(costPM) + " EUR ou " + 
                                          Math.round(costPM * RATE_GBP) + 
                                          " GBP<br>"
          } else {
            rtextPM += "<i>Total:</i> " + Math.round(costLastMinPM) + " EUR ou " +
                                          Math.round(costLastMinPM * RATE_GBP) +
                                          " GBP<br>" +
                       "<i>Prix normal:</i> " + Math.round(costPM) + " EUR ou " +
                                          Math.round(costPM * RATE_GBP) +
                                          " GBP<br>"
          }
        }
        break;

      default: // english
        rtextPM += "<i>Month " + N2y6B2ShortMonthName(lg,m) + "-" + y + "</i><br>"
        if ((lowdayrentLastMinPM + lowdayrentPM) > 0) {
          rtextPM += (lowdayrentLastMinPM + lowdayrentPM) + 
                     " night(s) in low season<br>"
          costPM += (lowdayrentLastMinPM + lowdayrentPM) * RATE_LOWDAYRENT
          feePM += (lowdayrentLastMinPM + lowdayrentPM) * RATE_LOWSTFEE
          costLastMinPM += lowdayrentLastMinPM * RATE_LOWDAYRENT * MULTLASTMIN  + 
     		  	   lowdayrentPM * RATE_LOWDAYRENT
        }
        if ((middayrentLastMinPM + middayrentPM) > 0) {
          rtextPM += (middayrentLastMinPM + middayrentPM) + 
                     " night(s) in mid season<br>"
          costPM += (middayrentLastMinPM + middayrentPM) * RATE_MIDDAYRENT
          feePM += (middayrentLastMinPM + middayrentPM) * RATE_MIDSTFEE
          costLastMinPM += middayrentLastMinPM * RATE_MIDDAYRENT * MULTLASTMIN  + 
     			   middayrentPM * RATE_MIDDAYRENT
        }
        if ((hidayrentLastMinPM + hidayrentPM) > 0) {
          rtextPM += (hidayrentLastMinPM + hidayrentPM) + 
                     " night(s) in high season<br>"
          costPM += (hidayrentLastMinPM + hidayrentPM) * RATE_HIDAYRENT
          feePM += (hidayrentLastMinPM + hidayrentPM) * RATE_HISTFEE
          costLastMinPM += hidayrentLastMinPM * RATE_HIDAYRENT * MULTLASTMIN  + 
     			   hidayrentPM * RATE_HIDAYRENT
        }
        if (costPM > 0) {
          if (! isDiscounted || Math.round(costLastMinPM) == Math.round(costPM)) {
            rtextPM += "<i>Total:</i> " + Math.round(costPM) + " EUR or " + 
                                          Math.round(costPM * RATE_GBP) + 
                                          " GBP<br>"
          } else {
            rtextPM += "<i>Total:</i> " + Math.round(costLastMinPM) + " EUR or " +
                                          Math.round(costLastMinPM * RATE_GBP) +
                                          " GBP<br>" + 
                       "<i>Regular price:</i> " + Math.round(costPM) + " EUR or " +
                                                  Math.round(costPM * RATE_GBP) +
                                                  " GBP<br>"
          }
        }
        break;
    }
    rtextPM += "</p>"
    if (costPM > 0) {
      rtext += rtextPM   // save it for later report
    }

    // update global stats
    cost += Math.round(costPM)
    fee += Math.round(feePM)  // v1.5
    costLastMin += Math.round(costLastMinPM)
    lowdayrent += lowdayrentPM
    middayrent += middayrentPM
    hidayrent += hidayrentPM
    lowdayrentLastMin += lowdayrentLastMinPM
    middayrentLastMin += middayrentLastMinPM
    hidayrentLastMin += hidayrentLastMinPM

    // next month
    m ++
    if (m >= 12) {
      y ++	
      m = 0
    }
  }

  // special fee for short stay
  var stfee = 0;
  if (days < 7) {
    var stfeedays = 7 - days;
    if ((hidayrentLastMin + hidayrent) > 0) {
      stfee = stfeedays * RATE_HISTFEE 
    } else {
      if ((middayrentLastMin + middayrent) > 0) {
        stfee = stfeedays * RATE_MIDSTFEE
      } else {
        stfee = stfeedays * RATE_LOWSTFEE
      }
    }
    cost += stfee; 
    fee += stfee;    // v1.5 
    costLastMin += stfee;
  }

  // integrate cleanup
  if (cost > 0) {
    cost += RATE_CLEANUP;  
    costLastMin += RATE_CLEANUP; 
    fee += RATE_CLEANUP;
  }

  // put together the summary report for e-mail
  var fromdate = dfrom + "-" + N2y6B2ShortMonthName(lg, mfrom) + "-" + yfrom
  var todate = dto + "-" + N2y6B2ShortMonthName(lg, mto) + "-" + yto
  var emailsubject
  var emailbody

  switch (lg) {
    case 1: // french
      emailsubject = "NeptunoII 6B2"
      emailbody = "%0A"
      emailbody += "Du " + fromdate + " au " + todate + " (" + days + " nuits)%0A"
      if (! isDiscounted) {
        emailbody += "Réservation avec nettoyage: " + 
                     cost + " EUR ou " + Math.round(cost*RATE_GBP) + " GBP"
      } else {
        emailbody += "Réservation avec réduction de " + 
                     RATE_LASTMINDISCOUNT + "% et nettoyage: " + costLastMin + 
                     " EUR ou " + Math.round(costLastMin*RATE_GBP) + " GBP"
      }
      if (stfee > 0) {
        emailbody += " (incl. frais séjour court " + stfee + " EUR ou " +
                             Math.round(stfee*RATE_GBP) + " GBP)"
      }
      emailbody += "%0A%0A"
      break;

    default: // english
      emailsubject = "NeptunoII 6B2"
      emailbody = "%0A"
      emailbody += "From " + fromdate + " to " + todate + " (" + days + " nights)%0A"
      if (! isDiscounted) {
        emailbody += "Booking with cleanup: " + cost + " EUR or " + 
                     Math.round(cost*RATE_GBP) + " GBP"
      } else  {
        emailbody += "Booking with " + RATE_LASTMINDISCOUNT + 
                     "% off and cleanup: " + costLastMin + " EUR or " + 
                     Math.round(costLastMin*RATE_GBP) + " GBP"
      }
      if (stfee > 0) {
        emailbody += " (incl. short stay fee " + stfee + " EUR or " + 
                     Math.round(stfee*RATE_GBP) + " GBP)"
      }
      emailbody += "%0A%0A"
      break;
  }

  // put together the summary report heading the per-month reports
  var rtextALL = ""
  var stextALL = "" // v1.5  split report
  rtextALL += "<hr>"
  rtextALL += "<p>"
  stextALL = rtextALL  // v1.5  same header
  switch (lg) {
    case 1: // french
      rtextALL += "Location vacances par nuit<br>" +
                  "Toutes charges comprises<br>"
      rtextALL += "Incluant " + paidNights + " nuits<br>"
      rtextALL += "<small style=\"color: rgb(153, 153, 153);\">" +
                  "Taux de change: 1 EUR = " + RATE_GBP + " GBP</small><br>"
      if (! isDiscounted) {
        rtextALL += "<i>Total:</i> " + cost + " EUR ou " + 
                    Math.round(cost*RATE_GBP) + " GBP<br>"
        contractValue = cost  // v1.6
      } else {
        rtextALL += "<small style=\"color: rgb(153, 153, 153);\">" +
                    " Réduction de " + RATE_LASTMINDISCOUNT + "%" 
        if (pdisc < 0) {
	  rtextALL += " sur les " + RATE_LASTMINTERM + " premières nuits" 
        }
        rtextALL += "</small><br>"
        rtextALL += "<i>Total:</i> " + costLastMin + " EUR ou " + 
                    Math.round(costLastMin*RATE_GBP) + 
                    " GBP<br>" +
                    "<i>prix normal:</i> " + cost + " EUR ou " + 
                    Math.round(cost*RATE_GBP) + 
                    " GBP<br>"
        contractValue = costLastMin  // v1.6
      }
      rtextALL += "<small style=\"color: rgb(153, 153, 153);\">"
      if (stfee > 0) {
        rtextALL += "(incl. " + stfee + " EUR ou " + Math.round(stfee*RATE_GBP) + 
                    " GBP pour frais séjour court)<br>"
      }
      rtextALL += "(incl. " + RATE_CLEANUP + " EUR ou " + 
                   Math.round(RATE_CLEANUP*RATE_GBP) + " GBP pour nettoyage)<br>"
      rtextALL += RATE_GUARANTEE + " EUR ou " + Math.round(RATE_GUARANTEE*RATE_GBP) + 
                  " GBP de garantie en cash<br>"
      rtextALL += "</small>"
      rtextALL += "<a href='mailto:" + EMAIL_ADDR + 
                     "?CC=" + EMAIL_CCADDR +
                     "?SUBJECT=" + emailsubject + 
                     "?BODY=" + emailbody + "' ID=451 class=cal>"
      rtextALL += "<i>Demander la disponibilité</i></a><br>" 

      // v1.5
      if (! isDiscounted) {
        stextALL += "<i>Propriétaire:</i> " + (cost - fee) + " EUR<br>"
      } else {
        stextALL += "<i>Propriétaire:</i> " + (costLastMin - fee) + " EUR<br>"
        stextALL += "<i>Locataire:</i> " + (cost - costLastMin) + " EUR<br>"
      }
      stextALL += "<i>Support:</i> " + (fee - RATE_CLEANUP) + " EUR<br>"
      stextALL += "<i>Nettoyage:</i> " + RATE_CLEANUP + " EUR<br>"
      break;

    default: // english
      rtextALL += "Per-night vacation rental<br>" +
                  "All charges included<br>"
      rtextALL += "Including " + paidNights + " nights<br>"
      rtextALL += "<small style=\"color: rgb(153, 153, 153);\">" +
                  "Currency rate: 1 EUR = " + RATE_GBP + " GBP</small><br>"
      if (! isDiscounted) {
        rtextALL += "<i>Total:</i> " + cost + " EUR or " + 
                    Math.round(cost*RATE_GBP) + " GBP<br>"
        contractValue = cost  // v1.6
      } else {
        rtextALL += "<small style=\"color: rgb(153, 153, 153);\"> " + 
                        RATE_LASTMINDISCOUNT + "% off"
        if (pdisc < 0) {
          rtextALL += " on the first " + RATE_LASTMINTERM + " nights"
        }
	rtextALL += "</small><br>"
        rtextALL += "<i>Total:</i> " + costLastMin + " EUR or " + 
                    Math.round(costLastMin*RATE_GBP) +  
                    " GBP<br>" +
                    "<i>Regular price:</i> " + cost + " EUR or " + 
                    Math.round(cost*RATE_GBP) + 
                    " GBP<br>"
        contractValue = costLastMin  // v1.6
      }
      rtextALL += "<small style=\"color: rgb(153, 153, 153);\">"
      if (stfee > 0) {
        rtextALL += "(incl. " + stfee + " EUR or " + 
                    Math.round(stfee*RATE_GBP) + " GBP as short stay fee)<br>"
      }
      rtextALL += "(incl. " + RATE_CLEANUP + " EUR or " + 
                  Math.round(RATE_CLEANUP*RATE_GBP) + " GBP for cleanup)<br>"
      rtextALL += RATE_GUARANTEE + " EUR or " + 
                  Math.round(RATE_GUARANTEE*RATE_GBP) + 
                  " GBP guarantee cash deposit<br>"
      rtextALL += "</small>"
      rtextALL += "<a href='mailto:" + EMAIL_ADDR + 
                     "?CC=" + EMAIL_CCADDR +
                     "?SUBJECT=" + emailsubject +  
                     "?BODY=" + emailbody + "' ID=452 class=cal>"
      rtextALL += "<i>Inquiry for availability</i></a><br>"

      // v1.5
      if (! isDiscounted) {
        stextALL += "<i>Owner:</i> " + (cost - fee) + " EUR<br>"
      } else {
        stextALL += "<i>Owner:</i> " + (costLastMin - fee) + " EUR<br>"
        stextALL += "<i>Tenant:</i> " + (cost - costLastMin) + " EUR<br>"
      }
      stextALL += "<i>Support:</i> " + (fee - RATE_CLEANUP) + " EUR<br>"
      stextALL += "<i>Cleanup:</i> " + RATE_CLEANUP + " EUR<br>"
      break;
  }
  rtextALL += "</p>"
  stextALL += "</p>" // v1.5

  // v1.5 append profitability report
  if (displaySplit) {
    rtextALL += stextALL
  }

  // append per month detail only if beyond a month
  // if (yfrom != yto || mfrom != mto) {
    rtextALL += rtext
  // } 

  // display report based on <doDisplay> or just return the contract value
  if (doDisplay) {
    // returns the text
    return rtextALL
  } else {
    // just returns the contract value in euros without displaying anything
    return contractValue
  }
}

function N2y6B2ComputePCMRentD2(doDisplay, lg, pdisc, days, 
                                           yfrom, mfrom, dfrom, yto, mto, dto)
{
  // v1.6
  //   specific version for per-calendar-month vacation rentals ("PCM")
  //   <doDisplay> is false: returns the contract value 
  //   <doDisplay> is true: returns text to be displayed
  //
  // v1.5
  //   <lg> is the language for the report
  //   <pdisc> is the permanent discount value 
  //                   (<0:not applicable, 0:none, >0:permanent for always)
  //   <days> is the number of days between <from> and <to> dates 
  //                   (y:year=2008.., m:month=0..11, d:day=1..31)

  var contractValue = 0  // v1.6 returned value if not to be displayed

  // v1.5  logic based on element presence in web page (= document)
  var splitEl = document.getElementById("N2y6B2Split")
  var displaySplit = (splitEl == null) ? false : true

  // rates (constants across this function)
  var RATE_GBP = 0.677892  // multiply euros by this to get GBP
  var EMAIL_ADDR = "info@suissehome.com"
  var EMAIL_CCADDR = "jptamenne@be.ibm.com"
  var RATE_CLEANUP = 50  // euros
  var RATE_GUARANTEE = 275  // euros

  var RATE_LOWMONTHRENT = 500  // euros
  var RATE_LOWMONTHFEE = 84 // euros (v1.5)
  var RATE_MIDMONTHRENT = 700  // euros (v1.6)
  var RATE_MIDMONTHFEE = 117 // euros (v1.6)
  var RATE_HIMONTHRENT = 1500  // euros (v1.6)
  var RATE_HIMONTHFEE = 250 // euros (v1.6)

  var RATE_LOWMONTHDAYRENT = 18  // euros (updated in v1.5.1)
  var RATE_LOWMONTHDAYFEE = 3  // euros (v1.5)
  var RATE_MIDMONTHDAYRENT = 24  // euros (v1.6)
  var RATE_MIDMONTHDAYFEE = 4  // euros (v1.6)
  var RATE_HIMONTHDAYRENT = 48  // euros (v1.6)
  var RATE_HIMONTHDAYFEE = 8  // euros (v1.6)

  var RATE_LASTMINDISCOUNT = (pdisc <= 0) ? 0 : pdisc  
        // %   v1.4: new parameter <pdisc>
  var MULTLASTMIN = (100 - RATE_LASTMINDISCOUNT) / 100
  var RATE_LASTMINTERM = (pdisc <= 0) ? 0 : -1  
        // days (maximum)    v1.4: no maximum if pdisc >= 0
	// pdisc <= 0 ==> no discount at all, 
        //             old last minute logic never applied in per-month rentals
 	// pdisc > 0 ==> permanent discount applied equal to <pdisc>
  var isDiscounted = N2y6B2IsDiscounted(pdisc, 0, yfrom, mfrom, dfrom)

  // report text
  var rtext = ""

  // global number of days/months
  var cost = 0
  var fee = 0    // v1.5
  var costLastMin = 0
  var paidNights = 0   // v1.6

  // per month number of days/months
  var costPM 
  var feePM     // v1.5
  var costLastMinPM 
  var monthrentvaluePM
  var monthfeevaluePM
  var lowmonthdaysPM
  var midmonthdaysPM
  var himonthdaysPM

  // make sure we have at least a month
  //    add days to reach a full month if required
  var dlast
  var mlast
  var ylast
  mlast = mfrom + 1  // a month later
  ylast = yfrom
  if (mlast > 11) {  // a month later than december ?
    mlast = 0 // back to january
    ylast ++  // next year
  }
  dlast = N2y6B2MaxDays(mlast, ylast)
  if (dfrom < dlast) {
    dlast = dfrom
  } 
  var dateOneMonthLater = new Date(ylast, mlast, dlast)
  var endDate = new Date(yto, mto, dto)
  // check that we have at least a month to the end
  if (dateOneMonthLater.valueOf() <= endDate.valueOf()) {
    // use the end date as this is at least a month later
    ylast = yto
    mlast = mto
    dlast = dto
  }

  // scan all months
  var y = yfrom
  var m = mfrom

  // loop on months
  //   this month is (y, m)
  //   next month is (ynext, mnext)
  //   last month is (ylast, mlast)
  while (y < ylast || (y == ylast && m <= mlast)) {  

    // reset stats for this month
    costPM = 0 
    feePM = 0  // v1.5
    costLastMinPM = 0 
    monthrentvaluePM = 0
    monthfeevaluePM = 0
    lowmonthdaysPM = 0
    midmonthdaysPM = 0
    himonthdaysPM = 0

    // set next month index
    var ynext
    ynext = y 
    var mnext
    mnext = m + 1
    if (mnext > 11) {
      mnext = 0 // back to january
      ynext ++	// next year
    }

    // index of the last day in this month
    var thisMonthLastDay 
    thisMonthLastDay = N2y6B2MaxDays(m, y)

    // index of the first day in the month
    var firstmday     
    if (dfrom < thisMonthLastDay) {
      firstmday = dfrom
    } else {
      firstmday = thisMonthLastDay
    }

    var thisMonthNights  // how much days/nights this month
    var nextMonthNights  // how much days/nights next month   
    var isFullMonth      // true if the month is full

    // case #1: current month is the last one
    if (y == ylast && m == mlast) {
      if (firstmday < dlast) {
        thisMonthNights = dlast - firstmday
      } else {
        thisMonthNights = 0
      }
      nextMonthNights = 0
      isFullMonth = false
    } else {

      // case #2: next month is the last one    
      if (ynext == ylast && mnext == mlast) {
        thisMonthNights = thisMonthLastDay - firstmday + 1
        if (firstmday <= dlast) {
          nextMonthNights = firstmday - 1
          isFullMonth = true
        } else {
          nextMonthNights = dlast - 1
          isFullMonth = false
        }
      } else {

        // case #3: current/next month is not the last one
        thisMonthNights = thisMonthLastDay - firstmday + 1
        nextMonthNights = firstmday - 1
        isFullMonth = true
      }
    }

    // update nights to be paid
    paidNights += parseInt(thisMonthNights)
    paidNights += parseInt(nextMonthNights)

    // check that we have something to compute and report
    var totalNights
    totalNights = thisMonthNights + nextMonthNights
    if (totalNights > 0) {

      // compute the rent in low/mid/hi counters based on days
      if (isFullMonth) {
        if (firstmday == 0 || 
                 N2y6B2MonthSeason(m) == N2y6B2MonthSeason(mnext)) {
          // simple case: full month without crossing seasons
          switch (N2y6B2MonthSeason(m)) {
            // low season
            default:
              monthrentvaluePM = RATE_LOWMONTHRENT
              monthfeevaluePM = RATE_LOWMONTHFEE
              break
            // medium season
            case 1:
              monthrentvaluePM = RATE_MIDMONTHRENT
              monthfeevaluePM = RATE_MIDMONTHFEE
              break
            // high season
            case 2:
              monthrentvaluePM = RATE_HIMONTHRENT
              monthfeevaluePM = RATE_HIMONTHFEE
              break
          }
        } else {
          // month crossing seasons
          monthrentvaluePM = 0
          if (thisMonthNights > 0) {
            switch (N2y6B2MonthSeason(m)) {
              // low season
              default:
                monthrentvaluePM += 
                     (thisMonthNights / totalNights) * RATE_LOWMONTHRENT
                monthfeevaluePM += 
                     (thisMonthNights / totalNights) * RATE_LOWMONTHFEE
                break
              // medium season
              case 1:
                monthrentvaluePM += 
                     (thisMonthNights / totalNights) * RATE_MIDMONTHRENT
                monthfeevaluePM += 
                     (thisMonthNights / totalNights) * RATE_MIDMONTHFEE
                break
              // high
              case 2:
                monthrentvaluePM += 
                     (thisMonthNights / totalNights) * RATE_HIMONTHRENT
                monthfeevaluePM += 
                     (thisMonthNights / totalNights) * RATE_HIMONTHFEE
                break
            }
          }
          if (nextMonthNights > 0) {
            switch (N2y6B2MonthSeason(mnext)) {
              // low season
              default:
                monthrentvaluePM += 
                     (nextMonthNights / totalNights) * RATE_LOWMONTHRENT
                monthfeevaluePM += 
                     (nextMonthNights / totalNights) * RATE_LOWMONTHFEE
                break
              // medium season
              case 1:
                monthrentvaluePM += 
                     (nextMonthNights / totalNights) * RATE_MIDMONTHRENT
                monthfeevaluePM += 
                     (nextMonthNights / totalNights) * RATE_MIDMONTHFEE
                break
              // high
              case 2:
                monthrentvaluePM += 
                     (nextMonthNights / totalNights) * RATE_HIMONTHRENT
                monthfeevaluePM += 
                     (nextMonthNights / totalNights) * RATE_HIMONTHFEE
                break
            }
            monthrentvaluePM = Math.round(monthrentvaluePM)
            monthfeevaluePM = Math.round(monthfeevaluePM)
          }
        }
      } else {
        // have to split in nights according to season

        switch (N2y6B2MonthSeason(m)) {
          // low season
          default:
            lowmonthdaysPM += thisMonthNights
            break
          // medium season
          case 1:
            midmonthdaysPM += thisMonthNights
            break
          // high
          case 2:
            himonthdaysPM += thisMonthNights
            break
        }
        switch (N2y6B2MonthSeason(mnext)) {
          // low season
          default:
            lowmonthdaysPM += nextMonthNights
            break
          // medium season
          case 1:
            midmonthdaysPM += nextMonthNights
            break
          // high
          case 2:
            himonthdaysPM += nextMonthNights
            break
        }
      }

      // update report over this month
      var rtextPM = "<hr><p>"
      switch (lg) {
        case 1: // french
          rtextPM += "<i>Mois " + N2y6B2ShortMonthName(lg,m) + "-" + y + 
                            ", à partir du " + firstmday + "</i><br>"
          switch (N2y6B2MonthSeason(m)) {
            // low season
            default:
              rtextPM += "Basse"
              break
            // medium season
            case 1:
              rtextPM += "Moyenne"
              break
            // high
            case 2:
              rtextPM += "Haute"
              break
          }
          if (nextMonthNights > 0 && 
                     N2y6B2MonthSeason(m) != N2y6B2MonthSeason(mnext)) {
            switch (N2y6B2MonthSeason(mnext)) {
              // low season
              default:
                rtextPM += " et basse"
                break
              // medium season
              case 1:
                rtextPM += " et moyenne"
                break
              // high
              case 2:
                rtextPM += " et haute"
                break
            }
          }
          rtextPM += " saison<br>"
          if (monthrentvaluePM > 0) {
            costPM += monthrentvaluePM
            feePM += monthfeevaluePM
            if (pdisc > 0) {
              // permanent discount: applies to monthly rents
              costLastMinPM += monthrentvaluePM * MULTLASTMIN
            } else {
              // no discount
              costLastMinPM += monthrentvaluePM
            }
          }
          if (lowmonthdaysPM > 0) {
            rtextPM += lowmonthdaysPM + 
                       " nuit(s) en basse saison<br>" +
                       "(fin de location au mois calendrier)<br>"
            costPM += lowmonthdaysPM * RATE_LOWMONTHDAYRENT
            feePM += lowmonthdaysPM * RATE_LOWMONTHDAYFEE
            if (pdisc > 0) {
              // permanent discount
              costLastMinPM += lowmonthdaysPM * RATE_LOWMONTHDAYRENT * MULTLASTMIN
            } else {
              // no discount
              costLastMinPM += lowmonthdaysPM * RATE_LOWMONTHDAYRENT
            }
          }
          if (midmonthdaysPM > 0) {
            rtextPM += midmonthdaysPM + 
                       " nuit(s) en moyenne saison<br>" + 
                       "(fin de location au mois calendrier)<br>"
            costPM += midmonthdaysPM * RATE_MIDMONTHDAYRENT
            feePM += midmonthdaysPM * RATE_MIDMONTHDAYFEE
            if (pdisc > 0) {
              // permanent discount
              costLastMinPM += midmonthdaysPM * RATE_MIDMONTHDAYRENT * MULTLASTMIN
            } else {
              // no discount
              costLastMinPM += midmonthdaysPM * RATE_MIDMONTHDAYRENT
            }
          }
          if (himonthdaysPM > 0) {
            rtextPM += himonthdaysPM + 
                       " nuit(s) en haute saison<br>" + 
                       "(fin de location au mois calendrie)<br>"
            costPM += himonthdaysPM * RATE_HIMONTHDAYRENT
            feePM += himonthdaysPM * RATE_HIMONTHDAYFEE
            if (pdisc > 0) {
              // permanent discount
              costLastMinPM += himonthdaysPM * RATE_LOWMONTHDAYRENT * MULTLASTMIN
            } else {
              // no discount
              costLastMinPM += himonthdaysPM * RATE_LOWMONTHDAYRENT
            }
          }
          if (costPM > 0) {
            if (! isDiscounted || Math.round(costLastMinPM) == Math.round(costPM)) {
              rtextPM += "<i>Total:</i> " + Math.round(costPM) + " EUR ou " + 
                                            Math.round(costPM * RATE_GBP) + 
                                            " GBP<br>"
            } else {
              rtextPM += "<i>Total:</i> " + Math.round(costLastMinPM) + " EUR ou " +
                                            Math.round(costLastMinPM * RATE_GBP) +
                                            " GBP<br>" +
                         "<i>prix normal:</i> " + Math.round(costPM) + " EUR ou " +
                                                  Math.round(costPM * RATE_GBP) +
                                                  " GBP<br>"
            }
          }
          break;

        default: // english
          rtextPM += "<i>Month " + N2y6B2ShortMonthName(lg,m) + "-" + y + 
                            ", from " + firstmday + "</i><br>"
          switch (N2y6B2MonthSeason(m)) {
            // low season
            default:
              rtextPM += "Low"
              break
            // medium season
            case 1:
              rtextPM += "Mid"
              break
            // high
            case 2:
              rtextPM += "High"
              break
          }
          if (nextMonthNights > 0 && 
                       N2y6B2MonthSeason(m) != N2y6B2MonthSeason(mnext)) {
            switch (N2y6B2MonthSeason(mnext)) {
              // low season
              default:
                rtextPM += " and low"
                break
              // medium season
              case 1:
                rtextPM += " and mid"
                break
              // high
              case 2:
                rtextPM += " and high"
                break
            }
          }
          rtextPM += " season<br>"
          if (monthrentvaluePM > 0) {
            costPM += monthrentvaluePM
            feePM += monthfeevaluePM
            if (pdisc > 0) {
              // permanent discount: applies to monthly rents
              costLastMinPM += monthrentvaluePM * MULTLASTMIN
            } else {
              // no discount
              costLastMinPM += monthrentvaluePM
            }
          }
          if (lowmonthdaysPM > 0) {
            rtextPM += lowmonthdaysPM + 
                       " night(s) in low season<br>" +
                       "(end of per-calendar-month rental)<br>"
            costPM += lowmonthdaysPM * RATE_LOWMONTHDAYRENT
            feePM += lowmonthdaysPM * RATE_LOWMONTHDAYFEE
            if (pdisc > 0) {
              // permanent discount
              costLastMinPM += lowmonthdaysPM * RATE_LOWMONTHDAYRENT * MULTLASTMIN
            } else {
              // no discount
              costLastMinPM += lowmonthdaysPM * RATE_LOWMONTHDAYRENT
            }
          }
          if (midmonthdaysPM > 0) {
            rtextPM += midmonthdaysPM + 
                       " night(s) in mid season<br>" +
                       "(end of per-calendar-month rental)<br>"
            costPM += midmonthdaysPM * RATE_MIDMONTHDAYRENT
            feePM += midmonthdaysPM * RATE_MIDMONTHDAYFEE
            if (pdisc > 0) {
              // permanent discount
              costLastMinPM += midmonthdaysPM * RATE_MIDMONTHDAYRENT * MULTLASTMIN
            } else {
              // no discount
              costLastMinPM += midmonthdaysPM * RATE_MIDMONTHDAYRENT
            }
          }
          if (himonthdaysPM > 0) {
            rtextPM += himonthdaysPM + 
                       " night(s) in high season<br>" +
                       "(end of per-calendar-month rental)<br>"
            costPM += himonthdaysPM * RATE_HIMONTHDAYRENT
            feePM += himonthdaysPM * RATE_HIMONTHDAYFEE
            if (pdisc > 0) {
              // permanent discount
              costLastMinPM += himonthdaysPM * RATE_LOWMONTHDAYRENT * MULTLASTMIN
            } else {
              // no discount
              costLastMinPM += himonthdaysPM * RATE_LOWMONTHDAYRENT
            }
          }
          if (costPM > 0) {
            if (! isDiscounted || Math.round(costLastMinPM) == Math.round(costPM)) {
              rtextPM += "<i>Total:</i> " + Math.round(costPM) + " EUR or " + 
                                            Math.round(costPM * RATE_GBP) + 
                                            " GBP<br>"
            } else {
              rtextPM += "<i>Total:</i> " + Math.round(costLastMinPM) + " EUR or " +
                                            Math.round(costLastMinPM * RATE_GBP) +
                                            " GBP<br>" +
                         "<i>regular price:</i> " + Math.round(costPM) + " EUR or " +
                                                    Math.round(costPM * RATE_GBP) +
                                                    " GBP<br>"
            }
          }
          break;
      }
      rtextPM += "</p>"

      if (costPM > 0) {
        rtext += rtextPM   // save it for later report
      }
    }  // else we are done (no nights)

    // update global stats
    cost += Math.round(costPM)
    fee += Math.round(feePM)  // v1.5
    costLastMin += Math.round(costLastMinPM)

    // next month
    m = mnext
    y = ynext
  }

  // integrate cleanup
  if (cost > 0) {
    cost += RATE_CLEANUP;  
    costLastMin += RATE_CLEANUP; 
    fee += RATE_CLEANUP;
  }

  // put together the summary report for e-mail
  var fromdate
  var todate
  var emailsubject
  var emailbody

  fromdate =  dfrom + "-" + N2y6B2ShortMonthName(lg, mfrom) + "-" + yfrom
  todate = dto + "-" + N2y6B2ShortMonthName(lg, mto) + "-" + yto

  switch (lg) {
    case 1: // french
      emailsubject = "NeptunoII 6B2"
      emailbody = "%0A"
      emailbody += "Du " + fromdate + " au " + todate + " (" + days + " nuits)%0A"
      if (! isDiscounted) {
        emailbody += "Réservation avec nettoyage: " + 
                     cost + " EUR ou " + Math.round(cost*RATE_GBP) + " GBP"
      } else {
        emailbody += "Réservation avec réduction de " + RATE_LASTMINDISCOUNT + 
                     "% et nettoyage: " + costLastMin + " EUR ou " + 
                     Math.round(costLastMin*RATE_GBP) + " GBP"
      }
      emailbody += "%0A%0A"
      break;
    default: // english
      emailsubject = "NeptunoII 6B2"
      emailbody = "%0A"
      emailbody += "From " + fromdate + " to " + todate + " (" + days + " nights)%0A"
      if (! isDiscounted) {
        emailbody += "Booking with cleanup: " + 
                     cost + " EUR or " + Math.round(cost*RATE_GBP) + " GBP"
      } else  {
        emailbody += "Booking with " + RATE_LASTMINDISCOUNT + 
                     "% off and cleanup: " + costLastMin + " EUR or " + 
                     Math.round(costLastMin*RATE_GBP) + " GBP"
      }
      emailbody += "%0A%0A"
      break;
  }

  // put together the summary report heading the per-month reports
  var rtextALL = ""
  var stextALL = "" // v1.5  split report
  rtextALL += "<hr>"
  rtextALL += "<p>"
  stextALL = rtextALL  // v1.5  same header
  var finalEndDate = 
         dlast + "-" + N2y6B2ShortMonthName(lg, mlast) + "-" + ylast
  switch (lg) {
    case 1: // french
      rtextALL += "Location vacances au mois calendrier<br>" +
                  "Toutes charges comprises <i>sauf électricité</i><br>"
      rtextALL += "Incluant " + paidNights + 
                  " nuits (jusqu'à " + finalEndDate + ")<br>"

      rtextALL += "<small style=\"color: rgb(153, 153, 153);\">" +
                  "Taux de change: 1 EUR = " + RATE_GBP + " GBP</small><br>"
      if (! isDiscounted) {
        rtextALL += "<i>Total:</i> " + cost + " EUR ou " + 
                    Math.round(cost*RATE_GBP) + " GBP<br>"
        contractValue = cost  // v1.6
      } else {
        rtextALL += "<small style=\"color: rgb(153, 153, 153);\"> Réduction de " + 
                        RATE_LASTMINDISCOUNT + "%" 
        rtextALL += "</small><br>"
        rtextALL += "<i>Total:</i> " + costLastMin + " EUR ou " + 
                    Math.round(costLastMin*RATE_GBP) + 
                    " GBP<br>" +
                    "<i>prix normal:</i> " + cost + " EUR ou " + 
                    Math.round(cost*RATE_GBP) + 
                    " GBP<br>"
        contractValue = costLastMin  // v1.6
      }
      rtextALL += "<small style=\"color: rgb(153, 153, 153);\">"
      rtextALL += "(incl. " + RATE_CLEANUP + " EUR ou " + 
                  Math.round(RATE_CLEANUP*RATE_GBP) + " GBP pour nettoyage)<br>"
      rtextALL += RATE_GUARANTEE + " EUR ou " + Math.round(RATE_GUARANTEE*RATE_GBP) + 
                  " GBP de garantie en cash<br>"
      rtextALL += "</small>"
      rtextALL += "<a href='mailto:" + EMAIL_ADDR + 
                     "?CC=" + EMAIL_CCADDR +
                     "?SUBJECT=" + emailsubject + 
                     "?BODY=" + emailbody + "' ID=451 class=cal>"
      rtextALL += "<i>Demander la disponibilité</i></a><br>"

      // v1.5
      if (! isDiscounted) {
        stextALL += "<i>Propriétaire:</i> " + (cost - fee) + " EUR<br>"
      } else {
        stextALL += "<i>Propriétaire:</i> " + (costLastMin - fee) + " EUR<br>"
        stextALL += "<i>Locataire:</i> " + (cost - costLastMin) + " EUR<br>"
      }
      stextALL += "<i>Support:</i> " + (fee - RATE_CLEANUP) + " EUR<br>"
      stextALL += "<i>Nettoyage:</i> " + RATE_CLEANUP + " EUR<br>"
      break;

    default: // english
      rtextALL += "Per-calendar-month vacation rental<br>" +
                  "All charges included <i>except electricity</i><br>"
      rtextALL += "Including " + paidNights + 
                  " nights (until " + finalEndDate + ")<br>"
      rtextALL += "<small style=\"color: rgb(153, 153, 153);\">" +
                  "Currency rate: 1 EUR = " + RATE_GBP + " GBP</small><br>"
      if (! isDiscounted) {
        rtextALL += "<i>Total:</i> " + cost + " EUR or " + 
                    Math.round(cost*RATE_GBP) + " GBP<br>"
        contractValue = cost  // v1.6
      } else {
        rtextALL += "<small style=\"color: rgb(153, 153, 153);\"> " + 
                        RATE_LASTMINDISCOUNT + "% off"
	rtextALL += "</small><br>"
        rtextALL += "<i>Total:</i> " + costLastMin + " EUR or " + 
                    Math.round(costLastMin*RATE_GBP) + 
                    " GBP<br>" +
                    "<i>regular price:</i> " + cost + " EUR or " + 
                    Math.round(cost*RATE_GBP) + 
                    " GBP<br>"
        contractValue = costLastMin  // v1.6
      }
      rtextALL += "<small style=\"color: rgb(153, 153, 153);\">"
      rtextALL += "(incl. " + RATE_CLEANUP + " EUR or " + 
                  Math.round(RATE_CLEANUP*RATE_GBP) + " GBP for cleanup)<br>"
      rtextALL += RATE_GUARANTEE + " EUR or " + 
                  Math.round(RATE_GUARANTEE*RATE_GBP) + 
                  " GBP guarantee cash deposit<br>"
      rtextALL += "</small>"
      rtextALL += "<a href='mailto:" + EMAIL_ADDR + 
                     "?CC=" + EMAIL_CCADDR +
                     "?SUBJECT=" + emailsubject + 
                     "?BODY=" + emailbody + "' ID=452 class=cal>"
      rtextALL += "<i>Inquiry for availability</i></a><br>"

      // v1.5
      if (! isDiscounted) {
        stextALL += "<i>Owner:</i> " + (cost - fee) + " EUR<br>"
      } else {
        stextALL += "<i>Owner:</i> " + (costLastMin - fee) + " EUR<br>"
        stextALL += "<i>Tenant:</i> " + (cost - costLastMin) + " EUR<br>"
      }
      stextALL += "<i>Support:</i> " + (fee - RATE_CLEANUP) + " EUR<br>"
      stextALL += "<i>Cleanup:</i> " + RATE_CLEANUP + " EUR<br>"
      break;
  }
  rtextALL += "</p>"
  stextALL += "</p>" // v1.5

  // v1.5 append profitability report
  if (displaySplit) {
    rtextALL += stextALL
  }

  // append per month detail only if beyond a month
  // if (yfrom != yto || mfrom != mto) {
    rtextALL += rtext
  // }

  // display report based on <doDisplay> or just return the contract value
  if (doDisplay) {
    // returns the contract type
    return rtextALL
  } else {
    // just returns the contract value in euros without displaying anything
    return contractValue
  }
}

function N2y6B2MaxDays(mm, yyyy)
{
  // mm: month number from 0
  // yyyy: year

  var mDay;

  if ((mm == 3) || (mm == 5) || (mm == 8) || (mm == 10)) { 
    // apr, jun, sep, nov have all 30 days
    mDay = 30
  } else {
    // feb which has 29 days every 4 years and 28 otherwise
    if (mm == 1) {
      if ((yyyy % 4) == 0) {
        mDay = 29
      } else {
        mDay = 28
      }
    } else {
      // all other have 31 days
      mDay = 31
    }
  }
  return mDay; 
}

function N2y6B2Right(str, n)
{
  if (n <= 0)
    return "";
  else if (n > String(str).length)
    return str;
  else {
    var iLen = String(str).length;
    return String(str).substring(iLen, iLen - n);
  }
}

function N2y6B2IsDiscounted(pdisc, days, yfrom, mfrom, dfrom)
{
  // return true if we are in last minute time
  //    at most <days> before (yfrom, mfrom, dfrom)

  if (pdisc < 0 && days > 0) {
    // pre-v1.4 logic

    // get current date and time
    var now = new Date

    // get start date
    var startDate = new Date(yfrom, mfrom, dfrom, 17, 0, 0, 0)

    // compute the difference in number of days
    var msdiff = startDate.valueOf() - now.valueOf()
    var msdiffremainder = msdiff % 86400000
    msdiff -= msdiffremainder
    var daysdiff = msdiff / 86400000
    if (msdiffremainder > 0) daysdiff ++

    // check diff if no more than <days>
    return ( (daysdiff >= 0 && daysdiff <= days) ? true : false )
  } else {
    // v1.4 logic
    //   apply permanently a discount 

    // last minute logic if permanent discount greater than 0
    return ( (pdisc > 0) ? true : false )
  }
}

function N2y6B2MonthSeason(month)
{
  // v1.6 returns the season based on the month
  //   input: <month> 0-11 (jan to dec)
  //   output: 0 for low season, 1 for mid season, 2 for hi season
  var season = 0

  // normalize the month (0-11)
  month = month % 12

  // get the season
  switch (month) {
    // low season: nov to apr
    default:
      season = 0
      break
    // mid season: may, june, oct, sep
    case 4: case 5: case 8: case 9:
      season = 1
      break
    // high season: jul, aug
    case 6: case 7:
      season = 2
      break
  }

  return season
}

// end

