var search_queue = {};
var searching_obj = null;
var photo_obj = null;
var photo_cache = new Array();
var photo_list = new Array();
var current_index = 0;
var rs_id = "";
var now = '';
var property_cache = {};

$(function()
{
  
	$('nav ul').hover(  
	   function() {  
		  $(this).addClass('hovered');     /* On hover add the class 'hovered' and apply the hovered styles */ 
	   }, function() {  
		  $(this).removeClass('hovered');  /* On mouseout remove the class 'hovered' and reset the styles   */ 
	   }  
	);  
  
	if (lang_code == 'fr')
		$.datepicker.setDefaults($.datepicker.regional['fr']);
  
	

	setTimeout(setupArrivalCalendar, 1000);
	
	
	
  // quick search
  $("#quick_search .browse_for").click(browseRentals);   
	
  // change search
  if ($('.change_search').length > 0)
  {
	  $(".change_search").click(showAvailabilitySearchForProperty);
  }
		
	
  // availability search	
  $('#avs_submit').click(function() {
      setupSearchResults();
  });	
	
  // create the searching overlow
  $("#searching").overlay({
	  // some mask tweaks suitable for facebox-looking dialogs
	  mask: {
		  color: '#000000',
		  loadSpeed: 200,
		  opacity: 0.75
	  },
	  closeOnClick: false
  });
  
  searching_obj = $("#searching").data("overlay");
  $('#searching').bgiframe();

	if ($('#gallery_thumbs img').length > 0)
	{
		loadThumbnail($("#gallery_thumbs img:first"));
		$("#gallery_thumbs img").click(loadThumbnail);
	}
	
  if ($('#photo_gallery_overlay').length > 0)
  {
	// create the photo gallery overlay
	$("#photo_gallery_overlay").overlay({
		mask: {
			color: '#000000',
			loadSpeed: 200,
			opacity: 0.75
		},
		left: 'center',
		top: 15,
        onBeforeLoad: function() {
          this.getOverlay().appendTo('body');
		}
	});
	
	photo_obj = $("#photo_gallery_overlay").data("overlay");
	$('#photo_gallery_overlay').bgiframe();
	
	
	$('#photos .thumbnail').click(setPhoto);
	$('.property_image').click(setPhoto);
	
	$('#photo_gallery_overlay .prev').click(prevPhoto);
	$('#photo_gallery_overlay .next').click(nextPhoto);
	//cachePhotos();
  }

  if ($('#inquire_date').length > 0)
  {
		$("#inquire_date").datepicker({
				showOn: 'button',
				buttonImage: '/cms-themes/Default/images/calendar.png',
				buttonImageOnly: true,
				dateFormat: 'dd/mm/yy'
			});  
  }  
  
  if ($('#RfpForm_calStartDate').length > 0)
  {
		$("#RfpForm_calStartDate").datepicker({
				showOn: 'button',
				buttonImage: '/cms-themes/Default/images/calendar.png',
				buttonImageOnly: true,
				dateFormat: 'dd/mm/yy'
			});
		
		$("#RfpForm_calDepartDate").datepicker({
				showOn: 'button',
				buttonImage: '/cms-themes/Default/images/calendar.png',
				buttonImageOnly: true,
				dateFormat: 'dd/mm/yy'
			});
		
		$("#RfpForm_calRespondByDate").datepicker({
				showOn: 'button',
				buttonImage: '/cms-themes/Default/images/calendar.png',
				buttonImageOnly: true,
				dateFormat: 'dd/mm/yy'
			});
		
		$("#RfpForm_calAlternateDate").datepicker({
				showOn: 'button',
				buttonImage: '/cms-themes/Default/images/calendar.png',
				buttonImageOnly: true,
				dateFormat: 'dd/mm/yy'
			});
		
		
  }
  
  if ($('#weddingRfpForm_calStartDate').length > 0)
  {  
  		$("#weddingRfpForm_calStartDate").datepicker({
				showOn: 'button',
				buttonImage: '/cms-themes/Default/images/calendar.png',
				buttonImageOnly: true,
				dateFormat: 'dd/mm/yy'
			});
		
		$("#weddingRfpForm_calAlternateDate").datepicker({
				showOn: 'button',
				buttonImage: '/cms-themes/Default/images/calendar.png',
				buttonImageOnly: true,
				dateFormat: 'dd/mm/yy'
			});  
  }
  
  if ($('#inquire_form').length > 0)
  {
	  $("#inquire_form").validationEngine()
  }  
  
  if ($('#wizard_form').length > 0)
  {
	  $("#wizard_form").validationEngine()
  }   
  
  $( "#auto_properties" ).autocomplete({
	  minLength: 3,
	  source: function(request, response) {
		  if ( request.term in property_cache ) {
			  response( property_cache[ request.term ] );
			  return;
		  }
		  
		  $.ajax({
			  url: "/property-search",
			  dataType: "json",
			  data: request,
			  success: function( data ) {
				  property_cache[ request.term ] = data;
				  response( data );
			  }
		  });
	  },
	  select: function(event, ui) {
		var url = ui.item.id;
		if (url !='' && url != undefined && url != null)
		{
		  window.location.href = url;
		}
	  }
  });
  
  if ($('#service_cancel').length > 0)
  {
	  $("#service_cancel").click(function() {
			var ret = confirm((lang_code == 'fr' ? html_entity_decode('&Ecirc;tes-vous s&ucirc;rs de vouloir annuler vos services additionnels?', 'ENT_QUOTES') : 'Are you sure you want to cancel your additional services?'));
			if (ret)
				$('#wizard_cancel_form').submit();
	  });
  }    
  
  if ($('#service_back').length > 0)
  {
	  $("#service_back").click(function() {
			$('#wizard_back_form').submit();
	  });
  }
  
  if ($('#service_no_thanks').length > 0)
  {
	  $("#service_no_thanks").click(function() {
			$('#additional_services').slideUp();
	  });
  }     
  
  if ($('.service_addon').length > 0)
  {
		loadWizardTotals(0,0,0);
	  $(".service_addon").change(function() {
			var temp = $(this).attr('id').split('_');
			var option_id = temp[1];
			var quantity = $(this).val();
			var cat = html_entity_decode($('#category').val(), 'ENT_QUOTES');
			loadWizardTotals(option_id, quantity, cat);
	  });
  }    
  
  loadBookingEngine();
  
	if ($('#accordion').length > 0)
	{
		$('#accordion').accordion({
				autoHeight: false,
				navigation: true,
				active: false, 
			    collapsible: true				
			});
	}  
  
});

function loadWizardTotals(option_id, quantity, cat)
{
	cat = encodeURI(cat);
	$('#wizard_totals').load("/"+lang_code+"/additional-services?category="+cat+"&option_id="+option_id+"&quantity="+quantity, function(response, status, xhr){
		$('#wizard_totals').html(response);
		setupTaxes();		
    });
}

// for some reason IE6 would only work if I
// put the calendar setup in a timer
function setupArrivalCalendar()
{
	$("#avs_arrival").datepicker({
		showOn: 'button',
		buttonImage: '/cms-themes/Default/images/calendar.png',
		buttonImageOnly: true,
		dateFormat: 'dd/mm/yy',
		minDate: new Date()
	});
}

function loadThumbnail(obj)
{
	if (obj.length == undefined)
	{
		if (obj.currentTarget != undefined)
		{
			obj = $(this);
		}
	}
	
	if (obj != undefined)
	{
		$('#gallery_thumbs img').removeClass('on');
		$('#gallery_thumbs img').addClass('off');
		
		var url = obj.attr('src').replace("../..", "").replace(".jpg", "_large.jpg");
		var img = new Image();
	 
	 
		// call this function after it's loaded
		img.onload = function() {
			// change the image
			$('#large_image').attr("src", url);
			obj.removeClass('off');
			obj.addClass('on');
		};
	 
		// begin loading the image from www.flickr.com
		img.src = url;
	}
}

function loadBookingEngine(params)
{
  // only do this if the booking engine element exists!
  if ($('#booking_engine').length > 0)
  {
	  setupBookingEngine();
  }
}

function setupBookingEngine()
{
	$("#ls_date").datepicker({
			showOn: 'button',
			buttonImage: '/cms-themes/Default/images/calendar.png',
			buttonImageOnly: true,
			dateFormat: 'dd/mm/yy',
			beforeShowDay : function (date)
			{
				if (date < now)
					return [0];
					
				var day = date.getDate()
				var month = parseInt(date.getMonth()) + 1;
				if (month == arrival_month)
				{
					if (in_array(day, disabled_dates))
					{
						return [0];
					}
					else
					{
						return [1];
					}
				}
				else
				{
					return [0];
				}
			},
			onChangeMonthYear : function (year,month,inst)
			{
				var ran=Math.floor(Math.random()*1000000);
				$.ajax({
					  url: "/get_availability_calendar.php",
					  global: false,
					  type: "GET",
					  async: false,
					  data: ({arrival_month: month, arrival_year: year, rs_id: rs_id, r: ran}),
					  dataType: "text",
					  success: function(data){
						disabled_dates = data.split(',');
						arrival_month = month;
					  }
				   }
				);					
			}				
		});
	
  if ($('#book_now').length > 0)
  {
	  $("#book_now").validationEngine()
  }
  
	setupTaxes();
  
  if ($('#card_type').length > 0)
  {
	  $("#card_type").click(function(){
		  $.validationEngine.loadValidation("#card_number");
	  });
  }
  
	if ($('#booking_policy').length > 0)
	{
		$("#booking_policy[rel]").overlay();
		$("#booking_overlay").bgiframe();
	}
	
	if ($('#use_travel_insurance').length > 0)
	{
		$("#use_travel_insurance").click(function(){
			$('#travel_insurance_check').val(($(this).attr('checked') ? 1 : 0));
			$('#travel_insurance').submit();
		});
	}	
	
	if ($('#additional_persons').length > 0)
	{
		$("#adults").change(function(){
			updateTravelers();
		});
		$("#child_0").change(function(){
			updateTravelers();
		});
		$("#child_11").change(function(){
			updateTravelers();
		});
	}		
}

function setupTaxes()
{
	if ($('#show_taxes').length > 0)
	{
		$("#show_taxes").unbind('click');
		$("#show_taxes").click(function(){
			$("#tax_details").slideToggle();
			return false;
		});
	}
	
	if ($('.show_taxes').length > 0)
	{
		$(".show_taxes").unbind('click');
		$(".show_taxes").click(function(){
			$(this).parent().next().next().slideToggle();
			return false;
		});
	}		
}

function updateTravelers()
{
	$('#add_adults').val($('#adults').val());
	$('#add_child_0').val($('#child_0').val());
	$('#add_child_11').val($('#child_11').val());
	$('#additional_persons').submit();	
}

function showAvailabilitySearchForProperty()
{
  if ($('#search_area').length > 0)
  {  
	$('#search_area').slideDown();
  }
}

// cache the large photos for quicker loading
function cachePhotos()
{
 	var args_len = photo_list.length;
	for (i = 0;i<args_len; i++)
	{
	  var cacheImage = document.createElement('img');
	  cacheImage.src = photo_list[i].photo;
	  photo_cache[i] = cacheImage;
	} 
}

function nextPhoto()
{
	current_index++;
	if (current_index >= photo_list.length)
	{
		current_index = 0;
	}
	setPhoto(current_index);
}

function prevPhoto()
{
	current_index--;
	if (current_index < 0)
	{
		current_index = photo_list.length - 1;
	}
	setPhoto(current_index);	
}

function setPhoto(index)
{
	if (!photo_obj.isOpened())
	  photo_obj.load();
	  
	$('#large_image_src').fadeOut(200, function()
	{
		// figure out our index
		if (typeof index != 'number')
		{
			var temp = index.target.id.split('_');
			index = parseInt(temp[1]);
		}
		$("#large_image_src").attr("src", photo_cache[index].src);
		$('#photo_gallery_overlay .caption').html(photo_list[index].caption);
		
		var current_page = current_index + 1;
		
		$('#photo_gallery_overlay .gallery_status').html(current_page + '/' + photo_list.length);
		current_index = index;						
		$("#large_image_src").fadeIn(200);
	});
}


function setupSort()
{
   $('#avs_sort').change(function() {
   	  search_queue['getSearchResults()'] = 'sort';
	  setTimeout(processQueue, 1000);
   });    
}
 
function setupFilters()
{
  $("#search_filters .filter").unbind('click');
	$("#search_filters .filter").click(function(){
	  var key = $(this).attr('name') + $(this).val();
	  search_queue['getSearchResults()'] = key;
	  setTimeout(processQueue, 1000);
  });
}
function setupSearchResults()
{
  $('#browse_rentals').val(0)
  setupFilters();
  getSearchResults();
}

function processQueue()
{
  for (n in search_queue)
  {
	if (n != 'remove')
	{
	  eval(n);
	  delete search_queue[n];
	}
  }
}

function browseRentals(obj)
{
  setupFilters();
  $('#browse_rentals').val(1);
  
  // if we want exact parameters. More than likely through the /search-results page
  if (obj.resort != undefined)
  {
	  $('#quick_bedrooms').val(obj.rooms);
	  $('#keyword').val(obj.keyword);
	  $('p.group_property_type .filter').each(function() {
		  if ($(this).val() == obj.type)
		  {
			$(this).attr('checked', true);
		  }
	  });
	  $('p.group_resort .filter').each(function() {
		  if ($(this).attr('title') == obj.resort)
		  {
			$(this).attr('checked', true);
		  }
	  });
	getSearchResults();
	return false;
  }
 
  $('#quick_bedrooms').val($(this).attr('title'));
  
  $('.filter').attr('checked', false);
  
  if ($('#quick_bedrooms').val() == 'private')
  {
	$('#quick_bedrooms').val('')
	$('p.group_property_type .filter').each(function() {
	    if ($(this).val() == '1')
		{
		  $(this).attr('checked', true);
		}
	});
  }
  getSearchResults();
  return false;
} 

function getSearchResults()
{
	//$("#property_temp").val('');
	  
	var arrival = '';	  
	if ($('#browse_rentals').val() == '0')
	{
	  var arrival = $('#avs_arrival').val();
	  if (arrival == 'mm/dd/yyyy')
	  {
		//TODO make this look nicer, maybe handle it a different way
		alert("Please choose an arrival date");
		return false;
	  }
	}	
	$('#below_search').hide();
	//$('#search_filters').slideDown('fast');
	
  
	  
	searching_obj.load();
	  
	var bedrooms = '';
	if ($('#browse_rentals').val() == '0')
	{
	  bedrooms = $('#avs_bedrooms').val();
	}
	else
	{
	  bedrooms = $('#quick_bedrooms').val();
	}	  
	  
	if (bedrooms == 'private')
	{
	  bedrooms = '';
	  $('p.group_property_type .filter').each(function() {
		  if ($(this).val() == '1')
		  {
			$(this).attr('checked', true);
		  }
	  });
	}
   	var property_type = [];
     $('.group_property_type :checked').each(function() {
       property_type.push($(this).val());
     });


	var nights = '';     
	if ($('#browse_rentals').val() == '0')
	  nights = $('#avs_nights').val();

	var occupancy = 0;
	var adults = '';
	if ($('#avs_adults').val() > 0)
	{
	  occupancy = parseInt($('#avs_adults').val());
	  adults = parseInt($('#avs_adults').val());
	}
	  
	var children = '';
	if ($('#ls_child').val() > 0)
	{
	  occupancy += parseInt($('#ls_child').val());
	  children = parseInt($('#ls_child').val());
	}
	  
	var sort = '0';
	if  ($('#avs_sort').length > 0)
	  sort = $('#avs_sort').val();
	 
    var ran=Math.floor(Math.random()*1000000);
	
	var browse = '';
	if ($('#browse_rentals').val() == '1')
	  browse = '&browse=1';	
	
	var keyword = '';
	if ($('#keyword').val() != '')
	  keyword = $('#keyword').val();
	  
	var container = $("#full_right_column");
	if ($('#property_right_column').length > 0)
		container = $('#property_right_column');
		
    container.load("/"+lang_code+"/ajax-search-results?arrival="+arrival+browse+"&nights="+nights+"&adults="+adults+"&children="+children+"&occupancy="+occupancy+"&rooms="+bedrooms+"&property_type="+property_type+"&keyword="+keyword+"&sort="+sort+"&r="+ran, function(response, status, xhr){
	   container.html(decodeURI(response));
	   setTimeout("closeMe()",200);
    });
	
	return true;
}

 function closeMe()
 {
	searching_obj.close();
 }
 
 function doCheckCreditCard()
 {
	var card_num = $('#card_number').val();
	var card_type = $('#card_type').val();
	var val = checkCreditCard(card_num, card_type);
	return (val ? false : true);
 }
 
function checkCreditCard (cardnumber, cardname) {
     
  // Array to hold the permitted card characteristics
  var cards = new Array();

  // Define the cards we support. You may add addtional card types.
  
  //  Name:      As in the selection box of the form - must be same as user's
  //  Length:    List of possible valid lengths of the card number for the card
  //  prefixes:  List of possible prefixes for the card
  //  checkdigit Boolean to say whether there is a check digit
  
  cards [0] = {name: "Visa", 
               length: "13,16", 
               prefixes: "4",
               checkdigit: true};
  cards [1] = {name: "MasterCard", 
               length: "16", 
               prefixes: "51,52,53,54,55",
               checkdigit: true};
  cards [2] = {name: "DinersClub", 
               length: "14,16", 
               prefixes: "305, 36, 38, 54,55",
               checkdigit: true};
  cards [3] = {name: "CarteBlanche", 
               length: "14", 
               prefixes: "300,301,302,303,304,305",
               checkdigit: true};
  cards [4] = {name: "AmEx", 
               length: "15", 
               prefixes: "34,37",
               checkdigit: true};
  cards [5] = {name: "Discover", 
               length: "16", 
               prefixes: "6011,622,64,65",
               checkdigit: true};
  cards [6] = {name: "JCB", 
               length: "16", 
               prefixes: "35",
               checkdigit: true};
  cards [7] = {name: "enRoute", 
               length: "15", 
               prefixes: "2014,2149",
               checkdigit: true};
  cards [8] = {name: "Solo", 
               length: "16,18,19", 
               prefixes: "6334, 6767",
               checkdigit: true};
  cards [9] = {name: "Switch", 
               length: "16,18,19", 
               prefixes: "4903,4905,4911,4936,564182,633110,6333,6759",
               checkdigit: true};
  cards [10] = {name: "Maestro", 
               length: "12,13,14,15,16,18,19", 
               prefixes: "5018,5020,5038,6304,6759,6761",
               checkdigit: true};
  cards [11] = {name: "VisaElectron", 
               length: "16", 
               prefixes: "417500,4917,4913,4508,4844",
               checkdigit: true};
  cards [12] = {name: "LaserCard", 
               length: "16,17,18,19", 
               prefixes: "6304,6706,6771,6709",
               checkdigit: true};
               
  // Establish card type
  var cardType = -1;
  for (var i=0; i<cards.length; i++) {

    // See if it is this card (ignoring the case of the string)
    if (cardname.toLowerCase () == cards[i].name.toLowerCase()) {
      cardType = i;
      break;
    }
  }
  
  // If card type not found, report an error
  if (cardType == -1) {
     ccErrorNo = 0;
     return false; 
  }
   
  // Ensure that the user has provided a credit card number
  if (cardnumber.length == 0)  {
     ccErrorNo = 1;
     return false; 
  }
    
  // Now remove any spaces from the credit card number
  cardnumber = cardnumber.replace (/\s/g, "");
  
  // Check that the number is numeric
  var cardNo = cardnumber
  var cardexp = /^[0-9]{13,19}$/;
  if (!cardexp.exec(cardNo))  {
     ccErrorNo = 2;
     return false; 
  }
       
  // Now check the modulus 10 check digit - if required
  if (cards[cardType].checkdigit) {
    var checksum = 0;                                  // running checksum total
    var mychar = "";                                   // next char to process
    var j = 1;                                         // takes value of 1 or 2
  
    // Process each digit one by one starting at the right
    var calc;
    for (i = cardNo.length - 1; i >= 0; i--) {
    
      // Extract the next digit and multiply by 1 or 2 on alternative digits.
      calc = Number(cardNo.charAt(i)) * j;
    
      // If the result is in two digits add 1 to the checksum total
      if (calc > 9) {
        checksum = checksum + 1;
        calc = calc - 10;
      }
    
      // Add the units element to the checksum total
      checksum = checksum + calc;
    
      // Switch the value of j
      if (j ==1) {j = 2} else {j = 1};
    } 
  
    // All done - if checksum is divisible by 10, it is a valid modulus 10.
    // If not, report an error.
    if (checksum % 10 != 0)  {
     ccErrorNo = 3;
     return false; 
    }
  }  

  // The following are the card-specific checks we undertake.
  var LengthValid = false;
  var PrefixValid = false; 
  var undefined; 

  // We use these for holding the valid lengths and prefixes of a card type
  var prefix = new Array ();
  var lengths = new Array ();
    
  // Load an array with the valid prefixes for this card
  prefix = cards[cardType].prefixes.split(",");
      
  // Now see if any of them match what we have in the card number
  for (i=0; i<prefix.length; i++) {
    var exp = new RegExp ("^" + prefix[i]);
    if (exp.test (cardNo)) PrefixValid = true;
  }
      
  // If it isn't a valid prefix there's no point at looking at the length
  if (!PrefixValid) {
     ccErrorNo = 3;
     return false; 
  }
    
  // See if the length is valid for this card
  lengths = cards[cardType].length.split(",");
  for (j=0; j<lengths.length; j++) {
    if (cardNo.length == lengths[j]) LengthValid = true;
  }
  
  // See if all is OK by seeing if the length was valid. We only check the 
  // length if all else was hunky dory.
  if (!LengthValid) {
     ccErrorNo = 4;
     return false; 
  };   
  
  // The credit card is in the required format.
  return true;
}
 
 /*** utility functions ***/
 
function in_array (needle, haystack, argStrict) {
	var key = '', strict = !!argStrict;

	if (strict) {
		for (key in haystack) {
			if (haystack[key] === needle) {
				return true;
			}
		}
	} else {
		for (key in haystack) {
			if (haystack[key] == needle) {
				return true;
			}
		}
	}

	return false;
}
 
var popup;
function openWindow(url,myWidth,myHeight)
{
  if (popup != null && !popup.closed) { 
  	popup.close();
  }
  popup = window.open(url,"","toolbar=0,location=0,directories=0,status=no,scrollbars=yes,menubar=0,resizable=yes,screenX=10,screenY=10,left=10,top=10,width=" + myWidth + ",height=" + myHeight);
}

function openNewWindow(URLtoOpen,windowName,height,width)
{
	windowFeatures="menubar=no,scrollbars=no,location=no,favorites=no,resizable=no,status=no,toolbar=no,directories=no";
	var test = "'";
	winLeft = (screen.width-width)/2;
	winTop = (screen.height-(height+110))/2;
	myWin= open(URLtoOpen,windowName,"width=" + width +",height=" + height + ",left=" + winLeft + ",top=" + winTop + test + windowFeatures + test);
}

function html_entity_decode (string, quote_style) {
    var hash_map = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();
    
    if (false === (hash_map = this.get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }

    // fix &amp; problem
    // http://phpjs.org/functions/get_html_translation_table:416#comment_97660
    delete(hash_map['&']);
    hash_map['&'] = '&amp;';

    for (symbol in hash_map) {
        entity = hash_map[symbol];
        tmp_str = tmp_str.split(entity).join(symbol);
    }
    tmp_str = tmp_str.split('&#039;').join("'");
    
    return tmp_str;
}

function get_html_translation_table (table, quote_style) {
   
    var entities = {}, hash_map = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};
    
    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';

    useTable       = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS';
    useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT';

    if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') {
        throw new Error("Table: "+useTable+' not supported');
        // return false;
    }

    entities['38'] = '&amp;';
    if (useTable === 'HTML_ENTITIES') {
        entities['160'] = '&nbsp;';
        entities['161'] = '&iexcl;';
        entities['162'] = '&cent;';
        entities['163'] = '&pound;';
        entities['164'] = '&curren;';
        entities['165'] = '&yen;';
        entities['166'] = '&brvbar;';
        entities['167'] = '&sect;';
        entities['168'] = '&uml;';
        entities['169'] = '&copy;';
        entities['170'] = '&ordf;';
        entities['171'] = '&laquo;';
        entities['172'] = '&not;';
        entities['173'] = '&shy;';
        entities['174'] = '&reg;';
        entities['175'] = '&macr;';
        entities['176'] = '&deg;';
        entities['177'] = '&plusmn;';
        entities['178'] = '&sup2;';
        entities['179'] = '&sup3;';
        entities['180'] = '&acute;';
        entities['181'] = '&micro;';
        entities['182'] = '&para;';
        entities['183'] = '&middot;';
        entities['184'] = '&cedil;';
        entities['185'] = '&sup1;';
        entities['186'] = '&ordm;';
        entities['187'] = '&raquo;';
        entities['188'] = '&frac14;';
        entities['189'] = '&frac12;';
        entities['190'] = '&frac34;';
        entities['191'] = '&iquest;';
        entities['192'] = '&Agrave;';
        entities['193'] = '&Aacute;';
        entities['194'] = '&Acirc;';
        entities['195'] = '&Atilde;';
        entities['196'] = '&Auml;';
        entities['197'] = '&Aring;';
        entities['198'] = '&AElig;';
        entities['199'] = '&Ccedil;';
        entities['200'] = '&Egrave;';
        entities['201'] = '&Eacute;';
        entities['202'] = '&Ecirc;';
        entities['203'] = '&Euml;';
        entities['204'] = '&Igrave;';
        entities['205'] = '&Iacute;';
        entities['206'] = '&Icirc;';
        entities['207'] = '&Iuml;';
        entities['208'] = '&ETH;';
        entities['209'] = '&Ntilde;';
        entities['210'] = '&Ograve;';
        entities['211'] = '&Oacute;';
        entities['212'] = '&Ocirc;';
        entities['213'] = '&Otilde;';
        entities['214'] = '&Ouml;';
        entities['215'] = '&times;';
        entities['216'] = '&Oslash;';
        entities['217'] = '&Ugrave;';
        entities['218'] = '&Uacute;';
        entities['219'] = '&Ucirc;';
        entities['220'] = '&Uuml;';
        entities['221'] = '&Yacute;';
        entities['222'] = '&THORN;';
        entities['223'] = '&szlig;';
        entities['224'] = '&agrave;';
        entities['225'] = '&aacute;';
        entities['226'] = '&acirc;';
        entities['227'] = '&atilde;';
        entities['228'] = '&auml;';
        entities['229'] = '&aring;';
        entities['230'] = '&aelig;';
        entities['231'] = '&ccedil;';
        entities['232'] = '&egrave;';
        entities['233'] = '&eacute;';
        entities['234'] = '&ecirc;';
        entities['235'] = '&euml;';
        entities['236'] = '&igrave;';
        entities['237'] = '&iacute;';
        entities['238'] = '&icirc;';
        entities['239'] = '&iuml;';
        entities['240'] = '&eth;';
        entities['241'] = '&ntilde;';
        entities['242'] = '&ograve;';
        entities['243'] = '&oacute;';
        entities['244'] = '&ocirc;';
        entities['245'] = '&otilde;';
        entities['246'] = '&ouml;';
        entities['247'] = '&divide;';
        entities['248'] = '&oslash;';
        entities['249'] = '&ugrave;';
        entities['250'] = '&uacute;';
        entities['251'] = '&ucirc;';
        entities['252'] = '&uuml;';
        entities['253'] = '&yacute;';
        entities['254'] = '&thorn;';
        entities['255'] = '&yuml;';
    }

    if (useQuoteStyle !== 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }
    if (useQuoteStyle === 'ENT_QUOTES') {
        entities['39'] = '&#39;';
    }
    entities['60'] = '&lt;';
    entities['62'] = '&gt;';


    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal);
        hash_map[symbol] = entities[decimal];
    }
    
    return hash_map;
}

