function getAbsLeft(obj){
	var	l=obj.offsetLeft;
	while(obj=obj.offsetParent)
		l+=obj.offsetLeft;
	return l;
}

function getAbsTop(obj){
	var	t=obj.offsetTop;
	while(obj=obj.offsetParent)
		t+=obj.offsetTop;
	return	t;
}

function changeBkgrnd(obj){
	addClassName(obj, "selected");
}

function changeBkgrnd_Blur(obj){
	removeClassName(obj, "selected");
}

function addClassName(element, className) {
 	if (!Element.hasClassName(element, className)) element.className = (element.className+' '+className);
 }

function removeClassName(element, className) {
 	if (Element.hasClassName(element, className)) element.className = element.className.replace(className, '');
}


/*
 * this is a cache to hold flight data items so that we don't have to create them everytime
 */
var FlightDataCache = Class.create();
Object.extend(FlightDataCache.prototype, {
  initialize : function () {
  	this.flightDataCacheArray = new Object();
  },
  getFlightDataItem : function (dataContainer, from, to) {
	var itemFrom = this.flightDataCacheArray[from];
	if (itemFrom == null) {
		itemFrom = new Object();
		this.flightDataCacheArray[from] = itemFrom;
	}
  	var item = itemFrom[to];
	if (item == null) {
		item = new FlightData(dataContainer, from, to);
		itemFrom[to] = item;
	}
	
	return item;
  }
}
);

// initialise as a singleton
var FlightDataCache = new FlightDataCache();

/*
 * this object holds data for a flight combination, eg SYD-MEL
 * it uses a data container which holds all the information relevant to 
 * this airport pair combination.
 * 
 * This object can be queried for valid flights, valid classes and can be 
 * extended to hold further information by adding convenience methods and 
 * adding to the data matrix within the data container
 */
var FlightData = Class.create();
FlightData.prototype = {
  initialize : function (dataContainer, from, to) {
  	this.dataContainer = dataContainer;
  	this.airports = dataContainer.getAirports();
  	this.fromAirports = dataContainer.getFromAirports();
  	this.toAirports = dataContainer.getToAirports();
  	this.classes = dataContainer.getClasses();
  	this.matrix = dataContainer.getMatrix();
    this.fromAirport = getObjectFromArrayByCode(from, this.airports);
    this.toAirport = getObjectFromArrayByCode(to, this.airports);
    this.fromAirportIndex = indexOfAirportByCode(from, this.fromAirports);
    this.toAirportIndex = indexOfAirportByCode(to, this.toAirports);
	this.matrixItem = getMatrixItem(this.fromAirportIndex,this.toAirportIndex,this.matrix, this.fromAirports.length, this.toAirports.length);
 },
  isValidFlight : function (evt) {
  	if (this.matrixItem != null) {		
		// make assumption here that can't fly from and to the same city (SYD to SYD)
		if (this.fromAirport != this.toAirport) {
			if (determineBooleanValueFromMatrixItem(this.matrixItem, this.dataContainer.getValidFlightIndex())) {
				return true;
			}
		}
  	}
	return false;
  },
  // could move this data into matrix and thereby moving business logic out of front end
  isDomestic : function () {
	if (this.fromAirport.country == this.toAirport.country) {
		return true;
	}
	return false;
  },
  // could move this data into matrix and thereby moving business logic out of front end
  isInternational : function () {
	if (this.fromAirport.country != this.toAirport.country
		&& !this.isTransTasman()) {
		return true;
	}
	return false;
  },
  // could move this data into matrix and thereby moving business logic out of front end
  isTransTasman : function () {
	if ((this.fromAirport.country.code == 'AU' 
		 && this.toAirport.country.code == 'NZ')
		 ||
		(this.fromAirport.country.code == 'NZ' 
		 && this.toAirport.country.code == 'AU')) {
		return true;
	} else {
		return false;
	}
  },
  getClasses : function (departCalendar) {
  	if (this.matrixItem != null) {
  		return getClassesForFlight(this.matrixItem, this.dataContainer, departCalendar, this.fromAirport, this.toAirport);
  	}
  	
  	return new Array();
  	
  }
}

/* 
 * this object holds the basic airport data for a airport
 */
var Airport = Class.create();
Airport.prototype = {
  initialize : function (code, airportName, countryCode, countries) {
    this.code = code;
    this.airportName = airportName;
	this.country = getObjectFromArrayByCode(countryCode, countries);
  },
  getCountry : function () {
  	return this.country;
  },
  toStringNameOnly : function () {
  	return this.airportName;
  },
  toString : function () {
  	return this.toStringNoCode() + " (" + this.code + ")";
  },
  toStringAirportCodeOnly : function () {
  	return this.toStringNoCode() + "<span class=\'aCode\'>" + " (" + this.code + ")" + "</span>";
  },
  toStringNoCode : function () {
  	return this.airportName + ", " + this.country.countryName;
  },
  // this assumes toString format of Airport, Country (AirportCode)
  toStringWithHighlightedAirport : function (highlightValue) {
  	var airportText = this.toString();
	var indexOfMatch = airportText.toLowerCase().indexOf(highlightValue.toLowerCase());
	var countryMatchflag = "flagno";


	// check if index match is in airport name, if not then look for match in code
	if (indexOfMatch > this.airportName.length) {
		var lengthOfStringNoCode = this.toStringNoCode().length;
		var indexAfterCountry = airportText.substring(lengthOfStringNoCode).toLowerCase().indexOf(highlightValue.toLowerCase());
		indexOfMatch = lengthOfStringNoCode + indexAfterCountry;
		countryMatchflag = "flagyes";
	}
	if(countryMatchflag == "flagno"){
	var beforeHighlight = airportText.substring(0, indexOfMatch);
	var highlighted = airportText.substring(indexOfMatch, indexOfMatch + highlightValue.length);
	var afterHighlight = airportText.substring(indexOfMatch + highlightValue.length,airportText.length);
		var airportCodeAlone = afterHighlight.substring(afterHighlight.lastIndexOf("("),afterHighlight.lastIndexOf(")")+1);
		var afterHightlightCode  = afterHighlight.substring(0,afterHighlight.lastIndexOf("("));
		return beforeHighlight + "<B>" + highlighted + "</B>" +  afterHightlightCode + "<span class=\'aCode\'>" + airportCodeAlone + "</span>";
	} else {
		var beforeCodeHighlight	 = airportText.substring(0, indexOfMatch); // Takes the code upto where it matches (Rome , Italy ( --> when you type 'f')
		var lastHighlightedValue = beforeCodeHighlight.substring(airportText.lastIndexOf("("));// It gives the last index value where it matches "("
		var beforeHighlightSpan  = airportText.substring(0, (indexOfMatch-highlightValue.length)); // it will give now as (Rome , Italy ")
		var codeHighlighted      = airportText.substring(0, ((indexOfMatch+1) - (highlightValue.length)));
		var highlighted1		 = airportText.substring(indexOfMatch, indexOfMatch + highlightValue.length);
		var afterHighlight1		 = airportText.substring(indexOfMatch + highlightValue.length,airportText.length)
		if( highlightValue.length == 2){
			return beforeHighlightSpan + "<span class=\'aCode\'>" + lastHighlightedValue + "<B>" + highlighted1 + "</B>" +  afterHighlight1 +"</span>";
		} else if(highlightValue.length == 1){
			return beforeHighlightSpan + "<span class=\'aCode\'>"+ "(" + "<B>" + highlighted1 + "</B>" +  afterHighlight1 +"</span>";				
		} else {
			return codeHighlighted + "<span class=\'aCode\'>"+"(" + "<B>" + highlighted1 + "</B>" +  afterHighlight1 +"</span>";
		}
	}

  }
}

/**
 * this function takes a airport object and represents it as a hyperlinked String and highlights
 * the text entered to find it.
 */
function getAirportAsHTMLString(currentAirport, highlightValue, highlightMatch) {
	
	var anchor = "";
	var highlight = "";
	if (currentAirport.airportName.toLowerCase().indexOf(highlightValue.toLowerCase())==0) {
		anchor = "<font id=\"anchor\"></font>"
		if (currentAirport.airportName.toLowerCase()==(highlightValue.toLowerCase())) {
			highlight=" class=\"toBoxHighlight\" ";
		}
	}
	var openingAnchorTag = anchor + "<a onFocus='changeBkgrnd(this)' onBlur='changeBkgrnd_Blur(this)' href='javascript:void(0)' id='to" + currentAirport.code + "'" + highlight + "/>";
	var airportText;
	if (highlightMatch) {
		airportText = currentAirport.toStringWithHighlightedAirport(highlightValue);
	} else {
		airportText = currentAirport.toStringAirportCodeOnly();
	}
	var closingAnchorTag = "</A>";
	return openingAnchorTag + airportText + closingAnchorTag;
}


/* 
 * this object holds the basic data for a booking class
 */
var BookingClass = Class.create();
BookingClass.prototype = {
  initialize : function (code, value, className) {
    this.code = code;
    this.value = value;
    this.className = className;
  }
}
  
/* 
 * this object holds the basic data for a country
 */
var Country = Class.create();
Country.prototype = {
  initialize : function (code, countryName) {
    this.code = code;
    this.countryName = countryName;
  }
}

/*
 * this object is the control object for the From Selection Box.
 * It sets up initial data and handles any expected events for the box.
 */
var FromBoxControl = Class.create();
FromBoxControl.prototype = {
  initialize : function (fromBoxId, dataContainer, defaultValue, showCountries, fromHeader) {

    this.fromBox = $(fromBoxId);
	this.popularFromAirports = dataContainer.getPopularFromAirports();
	this.fromAirports = dataContainer.getFromAirports();
	this.airports = dataContainer.getAirports();
	this.defaultValue = defaultValue;
	this.showCountries = showCountries;
	this.fromHeader = fromHeader;
	this.fromBox.onchange = this.fromBoxChange.bindAsEventListener(this);
	

	// Temp fix
	if(this.fromAirports!=null && this.fromAirports.length>1)
	{
		this.fromAirports=RemoveDuplicates(this.fromAirports);
	}

	if(this.popularFromAirports!=null && this.popularFromAirports.length>1)
	{
		this.popularFromAirports=RemoveDuplicates(this.popularFromAirports);
	}
	
	//End of temp fix
	this.populateFromBox();


  },
  fromBoxChange : function (evt) {
  	
  	
  },
  populateFromBox : function () {
    var selected=false;
	var selectedIndex=0;
	this.fromBox.options.length=0;
	// place select from city at top
	var index = 0;
	this.fromBox.options[index]=new Option(this.fromHeader,'');
	index++;
	// put in seperator
	this.fromBox.options[index]=new Option('-----------------','separator');
	index++;
	// now put popular airports
	if (this.popularFromAirports != null) {
		for (var i=0;i<this.popularFromAirports.length;++i, index++){
			var currentAirport = getObjectFromArrayByCode(this.popularFromAirports[i], this.airports);
			this.fromBox.options[index]=new Option(currentAirport.airportName,currentAirport.code);
			if (!selected && this.defaultValue == currentAirport.code) {
				selectedIndex = index;
				selected = true;
			}
		}
		// put in seperator
		this.fromBox.options[index]=new Option('-----------------','separator');
		index++;
	}
	var lastDropDownCountry = "";
	// now put all airports
 	for (var i=0;i<this.fromAirports.length;++i, index++){
 		var currentAirport = getObjectFromArrayByCode(this.fromAirports[i], this.airports);
 		if (this.showCountries && currentAirport.country.countryName != lastDropDownCountry) {
			this.fromBox.options[index]=new Option(currentAirport.country.countryName,"");
			this.fromBox.options[index].className = "cityDropDownCountry";
			index++;
			lastDropDownCountry = currentAirport.country.countryName;
 		}
		this.fromBox.options[index]=new Option(currentAirport.airportName,currentAirport.code);
		if (!selected && this.defaultValue == currentAirport.code) {
			selectedIndex = index;
			selected = true;
		}
 	}
	this.fromBox.selectedIndex = selectedIndex;
  }
}

/*
 * this object is the control object for the To Selection Box.
 * It sets up initial data and handles any expected events for the box.
 */
var ToDropControl = Class.create();
ToDropControl.prototype = {
  initialize : function (fromBoxId, toBoxId, dataContainer, departCalendar, showCountries, toHeader) {
    this.fromBox = $(fromBoxId);
    this.toBox = $(toBoxId);
    this.departCalendar = departCalendar;
    this.dataContainer = dataContainer;
	this.showCountries = showCountries;
	this.toHeader = toHeader;
	this.toAirports = this.dataContainer.getToAirports();
	this.popularToAirports = this.dataContainer.popularToAirports;
	this.airports = this.dataContainer.getAirports();
	this.toBox.onchange = this.toBoxChange.bindAsEventListener(this);
	this.inputType = 'selectBox';
	
	// Temp fix
	if(this.fromAirports!=null && this.fromAirports.length>1)
	{
		this.fromAirports=RemoveDuplicates(this.fromAirports);
	}

	if(this.popularFromAirports!=null && this.popularFromAirports.length>1)
	{
		this.popularFromAirports=RemoveDuplicates(this.popularFromAirports);
	}
	
	//End of temp fix

	this.populateToBox();

  },
  toBoxChange : function (evt) {
  	
  	
  },
  populateToBox : function (initialValue) {
	this.toBox.options.length=0;
	// place select from city at top
	var index = 0;
	var selectedIndex = 0;
	this.toBox.options[index]=new Option(this.toHeader,'');
	index++;
	// put in seperator
	this.toBox.options[index]=new Option('-----------------','separator');
	index++;
	
	// now put popular airports
	if (this.popularToAirports != null) {
		for (var i=0;i<this.popularToAirports.length;++i, index++){
			var currentAirport = getObjectFromArrayByCode(this.popularToAirports[i], this.airports);
			this.toBox.options[index]=new Option(currentAirport.airportName,currentAirport.code);
			if (this.defaultValue == currentAirport.code) {
				selectedIndex = index;
			}
		}
		// put in seperator
		this.toBox.options[index]=new Option('-----------------','separator');
		index++;
	}

	var lastDropDownCountry = "";
	// now put all airports
 	for (var i=0;i<this.toAirports.length;i++){
 		var currentAirport = getObjectFromArrayByCode(this.toAirports[i], this.airports);
 		if (this.showCountries && currentAirport.country.countryName != lastDropDownCountry) {
			this.toBox.options[index]=new Option(currentAirport.country.countryName,"");
			this.toBox.options[index].className = "cityDropDownCountry";
			index++;
			lastDropDownCountry = currentAirport.country.countryName;
 		}
 		if (this.fromBox.value != '') {
			var flightDataItem = FlightDataCache.getFlightDataItem(this.dataContainer, this.fromBox.value, currentAirport.code);
			// check that flight combo is valid, if yes add to select
			if (flightDataItem.isValidFlight()) {
				this.toBox.options[index]=new Option(currentAirport.airportName,currentAirport.code);
				if (currentAirport.code == initialValue) {
					selectedIndex = index;
				}
				index++;
			}
 		} else {
			this.toBox.options[index]=new Option(currentAirport.airportName,currentAirport.code);
			if (currentAirport.code == initialValue) {
				selectedIndex = index;
			}
			index++;
 		}
 	}
 	
 	this.toBox.selectedIndex = selectedIndex;
 	
  }
}

/*
 * this object is the control object for the To text Box.
 * It sets up initial data and handles any expected events for the box.
 * 
 * Most importantly it handles the keyup event which will populate the available
 * to airports.
 */
var ToBoxControl = Class.create();
ToBoxControl.prototype = {
  initialize : function (fromBoxId, toBoxId, toBoxListDivId, toBoxPlusSign, toSelectionFieldId, thisForm, fieldsToHide, dataContainer,hideOnlyCloseButton) {
    this.fromBox = $(fromBoxId);
    this.toBox = $(toBoxId);
    this.toBoxListDiv = $(toBoxListDivId);
    this.toSelectionField = $(toSelectionFieldId);
    this.toBoxPlusSign = $(toBoxPlusSign);
	this.thisForm = $(thisForm);
	this.currentSelection = "";
	this.fieldsToHide = fieldsToHide;
	this.dataContainer = dataContainer;
	this.hideOnlyCloseButton = hideOnlyCloseButton;
	this.toBox.onkeydown = this.toBoxKeyDown.bindAsEventListener(this);
	this.toBox.onkeyup = this.toBoxKeyUp.bindAsEventListener(this);
	this.toBox.onfocus = this.toBoxFocus.bindAsEventListener(this);
	this.toBoxPlusSign.onclick = this.toBoxPlusSignClick.bindAsEventListener(this);
	this.boxOpen = false;
	this.inputType = 'textBox';
  },
  toBoxKeyDown : function (evt) {

	if(evt != null && (evt.keyCode==40)){  	
		var predictiveTable = $("predictiveLookUp");
		if(predictiveTable != null) {
			var anchorTags = predictiveTable.getElementsByTagName("a");
			if (this.currentSelection == "") {
				var firstItem = anchorTags[0];
				this.currentSelection = firstItem;
				changeBkgrnd(firstItem);
			} else {
				for (var i=0; i < anchorTags.length; i++) {
					if (Element.hasClassName(anchorTags[i], "selected")) {
						changeBkgrnd_Blur(anchorTags[i]);
						// if not the last item
						if (i < (anchorTags.length - 1)) {
							nextItem = anchorTags[i+1];
						// ie we are on the last item, go to first
						} else {
							nextItem = anchorTags[0];
						}
						this.currentSelection = nextItem;
						changeBkgrnd(nextItem);
						i = anchorTags.length;
					}
				}
			}
		}
		fixScrollPosition(this.toBoxListDiv, this.currentSelection);
		return false;
	} else if(evt != null && evt.keyCode==38) {  
		var predictiveTable = $("predictiveLookUp");
		if(predictiveTable != null) {
			var anchorTags = predictiveTable.getElementsByTagName("a");
			if (this.currentSelection != "") {
				for (var i=0; i < anchorTags.length; i++) {
					if (Element.hasClassName(anchorTags[i], "selected")) {
						changeBkgrnd_Blur(anchorTags[i]);
						// if not the last item
						if (i > 0) {
							nextItem = anchorTags[i-1];
						// on the first item, go to the last
						} else {
							nextItem = anchorTags[anchorTags.length - 1];
						}
						this.currentSelection = nextItem;
						changeBkgrnd(nextItem);
						i = anchorTags.length;
					}
				}
		// select last item
		} else {
			var lastItem = anchorTags[anchorTags.length - 1];
			this.currentSelection = lastItem;
			changeBkgrnd(lastItem);
			}
		}
		fixScrollPosition(this.toBoxListDiv, this.currentSelection);
		return false;
	} else if(evt != null && evt.keyCode==13) {  
		if (this.currentSelection != "") {
			this.currentSelection.onclick();
		} else {
			if (this.toBoxListDiv.getElementsByTagName("a").length==1) {
				this.toBoxListDiv.getElementsByTagName("a")[0].onclick();
			}
		}
	}
  },
  toBoxKeyUp : function (evt) {
	if(evt == null || evt.keyCode==40 || evt.keyCode==38 || evt.keyCode==13 || evt.keyCode==9 || evt.keyCode==37 || evt.keyCode==39 ) {  
	} else {
		this.currentSelection = "";
  	this.populateToMatchingAirports(evt);
	}
  },
  toBoxFocus : function (evt) {
  	this.toBox.select();
  	
  },
  toBoxPlusSignClick : function (evt) {
  	this.populateToAllAirports(evt);
  	this.toBox.focus();
	var predictiveTable = $("predictiveLookUp");
	var anchorTags = predictiveTable.getElementsByTagName("a");
	for (var i=0; i < anchorTags.length; i++) {
		if (("to" + this.toSelectionField.value) == anchorTags[i].id) {
			this.currentSelection = anchorTags[i];
			changeBkgrnd(anchorTags[i]);
			fixScrollPosition(this.toBoxListDiv,this.currentSelection);
		}
	}
  },
  populateToAllAirports : function (evt) {
	var toAirports = getAirportsFromAirportCodes(this.dataContainer.getToAirports(), this.dataContainer.getAirports());
	var validAirports = getValidToAirports(this.fromBox.value, toAirports, this.dataContainer);
  	this.populateToOptions(evt, validAirports, false);
  	
  },
  populateToMatchingAirports : function (evt) {
	var matchingAirports = getValidToAirportsThatMatchString(this.fromBox.value, this.toBox.value, this.dataContainer);
	this.populateToOptions(evt, matchingAirports, true);
  },
  populateToOptions : function (evt, airportsToRender, highlightMatch) {
 	var divString = '';
	var homePageTabs=$("homePageTabs");
  	this.toBoxListDiv.style.display='block';
	this.setBoxOpen(true);
	if (airportsToRender.length == 0) {
		if (homePageTabs!=null) {
			this.toBoxListDiv.style.left=getAbsLeft(this.toBox)-getAbsLeft(this.thisForm)+"px";
			this.toBoxListDiv.style.top=getAbsTop(this.toBox)-getAbsTop(this.thisForm)+55+"px";
		} else {
			this.toBoxListDiv.style.left=getAbsLeft(this.toBox)+"px";
			this.toBoxListDiv.style.top=getAbsTop(this.toBox)+20+"px";
		}
		this.toBoxListDiv.innerHTML="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;There are no cities matching your request. Try again or click on the + to see valid destination cities.";
		this.toBoxListDiv.style.width="250px";
		$("toBoxCloseButton").onclick = this.closeToBoxListDiv.bindAsEventListener(this);
	} else {
		var toSelections = new Array();
		this.toBoxListDiv.style.width="480px";
		var optionListStrC1="";
		var optionListStrC2="";
		var singleColumnLength=5;
		var recordCount=0;
		singleColumnLength=(singleColumnLength<airportsToRender.length/2)?(airportsToRender.length/2):singleColumnLength;
		for (var x=0;x < airportsToRender.length; x++) {
			var currentAirport = airportsToRender[x];
			if (recordCount < singleColumnLength) {
				optionListStrC1=optionListStrC1+getAirportAsHTMLString(currentAirport, this.toBox.value, highlightMatch) + "<BR>";
			} else {
				optionListStrC2=optionListStrC2+getAirportAsHTMLString(currentAirport, this.toBox.value, highlightMatch) + "<BR>";
			}
			recordCount++;
		}
		optionList=
			"<table id=\"predictiveLookUp\">" + "<tr>" +  "<td width=\'10px' valign=\"top\">" +
					"</td>" +
			"<td valign=\"top\">" +
						optionListStrC1
					"</td>";
		if (optionListStrC2 != "") {
			optionList=optionList +	"<td valign=\"top\">" +	optionListStrC2 + "</td>";
		}

		optionList=optionList +	"</tr>" + "</table>";

		if(recordCount < "6"){
				this.toBoxListDiv.style.width="280px";
		} else if(recordCount > "5") {
				this.toBoxListDiv.style.width="480px";
		} else {
				this.toBoxListDiv.style.width="";
		}

		this.toBoxListDiv.innerHTML = optionList;
		$("toBoxCloseButton").onclick = this.closeToBoxListDiv.bindAsEventListener(this);
		
		// next line is dodgy, need to fiX!!
		if (homePageTabs!=null) {
			this.toBoxListDiv.style.left=getAbsLeft(this.toBox)-getAbsLeft(this.thisForm)+"px";
			this.toBoxListDiv.style.top=getAbsTop(this.toBox)-getAbsTop(this.thisForm)+55+"px";
		} else {
			this.toBoxListDiv.style.left=getAbsLeft(this.toBox)+"px";
			this.toBoxListDiv.style.top=getAbsTop(this.toBox)+20+"px";
		}

		
		for (var x=0;x < airportsToRender.length; x++) {
			var currentAirport = airportsToRender[x];
			new ToSelection(currentAirport, this.toBox, this.toSelectionField, this.toBoxListDiv, this);
		}
		if (airportsToRender.length > 0) {
			document.onclick = this.closeToBoxListDiv.bindAsEventListener(this);
		}
	}

  },
  closeToBoxListDiv : function (evt) {
	  if (evt.target) targ = evt.target
		else if (evt.srcElement) targ = evt.srcElement
		if(targ.id != "toBoxPlusSign"){
	if (this.boxOpen) {
	  	this.toBoxListDiv.style.display='none';
		this.hideShowFields(false);
	  	if (this.toSelectionField.value == '') {
	  		this.toBox.value = '';
	  	} else {
	  		var previousAirport = getObjectFromArrayByCode(this.toSelectionField.value, this.dataContainer.getAirports());
			this.toBox.value = previousAirport.toStringNameOnly();
	  	}
		this.setBoxOpen(false);
	}
	}
  },
  setBoxOpen : function (boxOpen) {
  	this.boxOpen = boxOpen;
	this.hideShowFields(boxOpen);
	this.hideShowCloseButton(boxOpen);
	if (!boxOpen) {
		this.currentSelection = "";
	}
  },
  hideShowFields : function (hide) {
    for (var i=0; i < this.fieldsToHide.length; i++) {
		if (hide) {
			$(fieldsToHide[i]).style.visibility="hidden";
		} else {
			$(fieldsToHide[i]).style.visibility="visible";
		}
	}
  },
  hideShowCloseButton : function (hide) {
    for (var i=0; i < this.hideOnlyCloseButton.length; i++) {
		if (hide) {
			$(hideOnlyCloseButton[i]).style.display="block";
		} else {
			$(hideOnlyCloseButton[i]).style.display="none";
		}
	}
  }
}

function fixScrollPosition(currentDiv, currentItem) {
	if(currentItem.offsetTop > (currentDiv.offsetHeight -20)){
		currentDiv.scrollTop = currentItem.offsetTop;
	
	}
	if(currentItem.offsetTop<currentDiv.scrollTop)
	{
		currentDiv.scrollTop = 0; 
	}
}

/*    

 * this object is the control object for when a 'from' or 'to' is selected and we are
 * required to do something.
 */
var FromToHandler = Class.create();
FromToHandler.prototype = {
  initialize : function (fromBoxControl, toBoxControl, classBoxId, intDomConvertFunction, dataContainer, departCalendar) {
	this.fromBoxControl = fromBoxControl;
	this.toBoxControl = toBoxControl;
	if (this.toBoxControl.inputType == 'textBox') {
		this.toSelectionField = this.toBoxControl.toSelectionField;
	} else {
		this.toSelectionField = this.toBoxControl.toBox;
	}
    this.toBox = this.toBoxControl.toBox;
	this.classBox = $(classBoxId);
	this.departCalendar = departCalendar;
	this.intDomConvertFunction = intDomConvertFunction;
	this.fromBoxControl.fromBox.onchange = this.fromToChange.bindAsEventListener(this);
	this.toSelectionField.onchange = this.fromToChange.bindAsEventListener(this);
	this.dataContainer = dataContainer;
  },
  fromToChange: function (evt) {
	// now if the box is open, reload the contents
	if (this.toBoxControl.inputType == 'textBox' && this.toBoxControl.boxOpen) {
		this.toBoxControl.populateToMatchingAirports(evt);
	} else {
		if (this.toBoxControl.inputType == 'selectBox') {
			this.toBoxControl.populateToBox(this.toSelectionField.value);
		}
		if (this.fromBoxControl.fromBox.value != '' && this.toSelectionField.value != '') {
			var flightDataItem = FlightDataCache.getFlightDataItem(this.dataContainer, this.fromBoxControl.fromBox.value, this.toSelectionField.value);
			// check that flight combo is still valid, if not clear the to box
			if (!flightDataItem.isValidFlight()) {
				if (this.toBoxControl.inputType == 'textBox') {
					this.toSelectionField.value = '';
					this.toBox.value = '';
				} else {
					this.toSelectionField.selectedIndex = 0;
				}
				this.intDomConvertFunction();
			} else {
				if (flightDataItem.isInternational()) {
					this.populateClasses(flightDataItem);
				}
				this.intDomConvertFunction(flightDataItem);
			}
		} else { // To get rid of 'Premium Economy' from the drop down, if its already present
			this.populateClassesForRoute();
			// call this method to setup default look (ie when we dont have the citypair)
			this.intDomConvertFunction();
		}
	}
  },
  populateClasses : function (flightDataItem) {
	if (this.classBox != null) {
	  	if (flightDataItem != null){
			var classes = flightDataItem.getClasses(this.departCalendar);
		}else{
			var classes = getClassesForFlight(null, this.dataContainer, this.departCalendar, this.fromAirport, this.toAirport);
		}
		var indexSelected = this.classBox.selectedIndex;
		this.classBox.options.length=0;
		for (var i=0;i<classes.length;i++){
			var currentClass = classes[i];
			this.classBox.options[i]=new Option(currentClass.className,currentClass.value);
		}
		if(indexSelected != -1){
			this.classBox.selectedIndex = indexSelected;
		}
  	}
  },
  populateClassesForRoute : function () {
	if (this.fromBoxControl.fromBox.value != "" && this.toSelectionField.value != ""){
		var flightDataItem = FlightDataCache.getFlightDataItem(this.dataContainer, this.fromBoxControl.fromBox.value, this.toSelectionField.value, this.toBoxControl.departCalendar);
		this.populateClasses(flightDataItem)
	}else{
		this.populateClasses();
	}
  },
  setInitialValues : function (from, to) {
	// setup frombox
	var valueMatched = false;
	for(var i=0;i<this.fromBoxControl.fromBox.options.length;++i){
		if(this.fromBoxControl.fromBox.options[i].value==from){
			this.fromBoxControl.fromBox.selectedIndex=i;
			valueMatched = true;
			break;
		}
	}
	if(valueMatched == false && from==''){
		// presumes element 0 is always the default eg "Select a City..."
		this.fromBoxControl.fromBox.selectedIndex=0;
	}

	if (this.toBoxControl.inputType == 'textBox' && to != null && to != '') {
		var toAirport = getObjectFromArrayByCode(to, this.dataContainer.getAirports());
		if (toAirport != null) {
			this.toBox.value = toAirport.airportName;
			this.toSelectionField.value = toAirport.code;
		}
	}
	
	// run the onchange method to ensure all is setup ok
	this.fromToChange();

	// setup tobox
	if (this.toBoxControl.inputType == 'textBox') {
//		var toAirport = getObjectFromArrayByCode(to, this.dataContainer.getAirports());
//		this.toBox.value = toAirport.airportName;
//		this.toSelectionField.value = toAirport.code;
	} else {
		var valueMatched = false;
		for(var i=0;i<this.toBoxControl.toBox.options.length;++i){
			if(this.toBoxControl.toBox.options[i].value==to){
				this.toBoxControl.toBox.selectedIndex=i;
				valueMatched = true;
				break;
			}
		}
		if(valueMatched == false && from==''){
			// presumes element 0 is always the default eg "Select a City..."
			this.toBoxControl.toBox.selectedIndex=0;
		}
		
	}
  }
}

/**
 * this is the control object for each anchor link in the 'to' selection list.
 */
var ToSelection = Class.create();
ToSelection.prototype = {
  initialize : function (airport, toBox, toSelectionField, toBoxListDiv, toBoxControl) {
    this.airport = airport;
    this.toBox = toBox;
    this.toSelectionField = toSelectionField;
    this.toBoxListDiv = toBoxListDiv;
    this.toBoxControl = toBoxControl;
    this.airportHref = $("to" + airport.code);
	this.airportHref.onclick = this.airportHrefClick.bindAsEventListener(this);
  },
  airportHrefClick : function (evt) {
	this.toBoxControl.setBoxOpen(false);
  	this.toSelectionField.value = this.airport.code;
  	this.toBox.value = this.airport.toStringNameOnly();
  	this.toSelectionField.onchange();
  	this.toBoxListDiv.innerHTML = '';
	this.toBoxListDiv.style.display='none';
  }
}

/**
 * gets the matching airports and validates that the airport is valid for the 
 * from/to combination it will form.
 */
function getValidToAirportsThatMatchString(fromAirport, stringToMatch, dataContainer) {
	
	var airportCodeList = dataContainer.getToAirports();
	var airports = dataContainer.getAirports();
	var matchingAirports = getAirportsThatMatchString(stringToMatch, airportCodeList, airports);
	// ensure all matching airports are valid for this from/to combination
	var validAirports = getValidToAirports(fromAirport, matchingAirports, dataContainer)
	return validAirports;
	
}

/**
 * takes a list of airports and returms only those that are valid for the from/to combination
 */
function getValidToAirports(fromAirport, airports, dataContainer) {

	// ensure all matching airports are valid for this from/to combination
	var validAirports = new Array();
    for (var i=0; i<airports.length;i++) {
    	var currentAirport = airports[i];
		// check if airport pair valid
			var flightItem = FlightDataCache.getFlightDataItem(dataContainer, fromAirport, currentAirport.code);
			if (flightItem.isValidFlight() || fromAirport.length == "0") {
				validAirports.push(currentAirport);
			}
    }
	return validAirports;
}

/**
 * takes a list of airport codes and gets the airport objects for them out of the provided airport list
 *
 */
function getAirportsFromAirportCodes(airportCodes, allAirports) {
	var airports = new Array();
	for (var i=0; i<airportCodes.length;i++) {
		var currentAirport = getObjectFromArrayByCode(airportCodes[i], allAirports);
		airports.push(currentAirport);
	}
	return airports;
}

/**
 * search the airport list to find airports that match the provided string either by
 * full name or airport code.
*/
function getAirportsThatMatchString(stringToMatch, airportCodeList, airports) {
	
	var matchingAirports = new Array();

	if (stringToMatch != '' && stringToMatch != null) {

		if(stringToMatch.length == 1){
			var pattern = new RegExp("^" +stringToMatch , "i");
		} else {
				pattern = new RegExp("" +stringToMatch, "i");
		}
	
		for (var i=0; i<airportCodeList.length;i++) {
			var currentAirport = getObjectFromArrayByCode(airportCodeList[i], airports);
			// check if code matches
			if (pattern.test(currentAirport.code)) {
				matchingAirports.push(currentAirport);
			} else if (pattern.test(currentAirport.airportName)) {
				matchingAirports.push(currentAirport);
			}
		}
	}
		
	return matchingAirports;
	
}

/**
 * returns the index of the airport code within an array
 */
function indexOfAirportByCode(code,airportArray) {
    for (var i=0;i<airportArray.length;i++) {
       if (code == airportArray[i]) {
           return i;
       }
    }

    return -1;
}

/**
 * returns the full object from an array when searching by code.
 * Assumes that the object will have a 'code' property.
 */
function getObjectFromArrayByCode(code, ourArray) {
	for (var i=0;i<ourArray.length;i++) {
	   if (code == ourArray[i].code) {
		   return ourArray[i];
	   }
	}

    return null;
}

function getMatrixItem(fromIndex, toIndex, matrix, numberOfFroms, numberOfTos) {
	var itemIndex = (fromIndex * numberOfTos) + toIndex;
	var item32 = matrix.charAt(itemIndex);
	var matrixItemDecimal = parseInt(item32, 32);
	var matrixItemBoolean = matrixItemDecimal.toString(2);
	
	return matrixItemBoolean.padLeft(5,'0');
}

/*
 * checks if a matrix item is representing true or false
 */
function determineBooleanValueFromMatrixItem(matrixItem, index) {
	if (matrixItem.charAt(index) == '1') {
		return true;
	} 
	return false;	
}

/*
 * checks the matrix item to see what classes are valid for a particular from/to
 * combination
 */
function getClassesForFlight(matrixItem, dataContainer, departCalendar, fromAirport, toAirport) {
	
	var classesForFlight = new Array();

	/* 
		Hard coded solution for departure date to be set for travel class 
	*/

	var departDate = departCalendar.getDate().format('YYYYmmDD');
	var travelDate = dataContainer.getTravelDate();
	
	var cityPair = new Array(['SYD','BOM'],['SYD','LHR'],['SYD','MEL']);
	
	for(var i=0;i<cityPair.length;i++) {
		if(fromAirport==cityPair[i][0] &&  toAirport==cityPair[i][1]){
		//travelDate = "20080501";
		}

	}


	if(dataContainer.getIsSaleDate() == 'true' 
		&& departDate >= travelDate
		&& matrixItem != null) {

		var travelClassObjectY = getObjectFromArrayByCode("Y", dataContainer.getClasses());
		var travelClassObjectP = getObjectFromArrayByCode("P", dataContainer.getClasses());
		var travelClassObjectJ = getObjectFromArrayByCode("J", dataContainer.getClasses());
		var travelClassObjectF = getObjectFromArrayByCode("F", dataContainer.getClasses());

		if (determineBooleanValueFromMatrixItem(matrixItem, dataContainer.getEconomyClassIndex())) {
			if (travelClassObjectY != null){
				classesForFlight.push(travelClassObjectY);	
			}
		}
		if (determineBooleanValueFromMatrixItem(matrixItem, dataContainer.getPremiumClassIndex())) {
			if (travelClassObjectP != null){
				classesForFlight.push(travelClassObjectP);	
			}
		}
		if (determineBooleanValueFromMatrixItem(matrixItem, dataContainer.getBusinessClassIndex())) {
			if (travelClassObjectJ != null){
				classesForFlight.push(travelClassObjectJ);	
			}
		}
		if (determineBooleanValueFromMatrixItem(matrixItem, dataContainer.getFirstClassIndex())) {
			if (travelClassObjectF != null){
				classesForFlight.push(travelClassObjectF);	
			}
		}
	} else {
		var travelClassObjectY = getObjectFromArrayByCode("Y", dataContainer.getClasses());
		var travelClassObjectJ = getObjectFromArrayByCode("J", dataContainer.getClasses());
		var travelClassObjectF = getObjectFromArrayByCode("F", dataContainer.getClasses());
		if (matrixItem == null){
			if (travelClassObjectY != null){
				classesForFlight.push(travelClassObjectY);
			}
			if (travelClassObjectJ != null){
				classesForFlight.push(travelClassObjectJ);
			}
			if (travelClassObjectF != null){
				classesForFlight.push(travelClassObjectF);
			}
		}else{
			if (determineBooleanValueFromMatrixItem(matrixItem, dataContainer.getEconomyClassIndex())) {
				if (travelClassObjectY != null){
					classesForFlight.push(travelClassObjectY);	
				}
			}
			if (determineBooleanValueFromMatrixItem(matrixItem, dataContainer.getBusinessClassIndex())) {
				if (travelClassObjectJ != null){
					classesForFlight.push(travelClassObjectJ);	
				}
			}
			if (determineBooleanValueFromMatrixItem(matrixItem, dataContainer.getFirstClassIndex())) {
				if (travelClassObjectF != null){
					classesForFlight.push(travelClassObjectF);	
				}
			}
		}
	}
	
	return classesForFlight;
}


// Create the internal pad prototype
String.prototype._pad = function(width,padChar,side) {
	var str = [side ? "" : this, side ? this : ""];
	while (str[side].length < (width ? width : 0)
		&& (str[side] = str[1] +(padChar ? padChar : " ")+str[0] ));
	return str[side];
}

// Create pad functions for general use
// "width" is the total width to pad to,
// "padChar" is the optional pad character -- default " "
String.prototype.padLeft = function(width,padChar) {
	return this._pad(width,padChar,0) };
String.prototype.padRight = function(width,padChar) {
	return this._pad(width,padChar,1) };
Number.prototype.padLeft = function(width,padChar) {
	return (""+this).padLeft(width,padChar) };
Number.prototype.padRight = function(width,padChar) {
	return (""+this).padRight(width,padChar) };


  
  function RemoveDuplicates(arr)
   {
	  

if( arr!=null && arr.length>1)
	   {
		//get sorted array as input and returns the same array without duplicates.
		var result=new Array();
		var lastValue="";
		for (var i=0; i<arr.length; i++)
		{
	  var curValue=arr[i];
	  if (curValue != lastValue)
	  {
	result[result.length] = curValue;
	  }
	  lastValue=curValue;
		}
	   }
    return result;
   }

