function validateFields(form_id) {
    
    var form = $(form_id);
	var errorBox = $('form_errors');
    var errors = new Array();
    $A(form.getElementsByClassName('required')).each(
       function(node) {
           if (node.value.length == 0) {
               node.style.border = "1px solid red";
               errors.push(node.name);
           } else {
               node.style.border = "1px solid #7f9db7";
           }
       }
    );
    
    // special djuizz sauce for pienrakentaja
    if (form_id == 'pienrakentajantarjouspyyntoFormi' || form_id == 'valmisbetonirakennusliikkeentarjouspyyntoFormi' || form_id == 'kiviainesrakennusliikkeentarjouspyyntoFormi') {
        var emailField = $('email');
        var faxField = $('fax');
        if ($('byEmail').checked && emailField.value.length == 0) {
            errors.push(emailField.name);
        } else if ($('byFax').checked && faxField.value.length == 0) {
            errors.push(faxField.name);
        }
    }
		

    
    if (errors.length > 0) {
		errorBox.innerHTML = 'Seuraavat kentät ovat pakolliset:<br/>- ' + errors.join("<br/>- ");
		errorBox.style.margin = '20px 0';
		errorBox.show();
		window.scrollTo(0,0);
        alert('Seuraavat kentät ovat pakolliset:\n- ' + errors.join("\n- "));
		return false;
    } else {
        //form.submit();
		return true;
    }
	
}

/* https päälle */
function forceHttps() {
	if (window.location.protocol != "https:") {
		redirUrlStr = "https://" + window.location.host + window.location.pathname + window.location.search;
		window.location.href = redirUrlStr;
	}
}

/* https pois päältä */
function forceHttp() {
	if (window.location.protocol != "http:") {
		redirUrlStr = "http://" + window.location.host + window.location.pathname +window.location.search;
		window.location.href = redirUrlStr;
	}
}

/* Google Maps -funktioita */

/* Mapponator
	-- Google Maps Apu
	-- Sisältää kartat ja niiden markkerit
	-- Mm. markkereiden infowindow-lomakkeiden html-hallinta	
*/

function Mapponator() {
	//Olio joka helpottaa karttojen luontia ja hallintaa
	
	//Note: Wrapper - not a Gmap2-prototype!! 
	
	//requires: Google Maps Scripts+Key && ExtInfoWindow.js
	//requires: <div class="map_canvas" /> && <div class="directions" />
	//requires: Toimipaikka js obj
	//requires: olettaa tällä hetkellä karttaolion nimeksi mapX
	
	//usage: munKartta = new Mapponator(); //kartta sivulle
	//usage: munKartta = new Mapponator(myDiv); //kartta sivulle containeriin jonka id="myDiv"
	
	//usage with gmarkers:
	//1. in js create a gmarkerobject (toimipaikka etc) argument array.
	//2. in js: munKartta.createMarkerObject(argArray, markerType);
	
	//TODO
	//Zoomikerroin - kannasta?
	
	//Future features
	//- Toimii Warmasti vain yhdellä kartalla, yksi per sivu - gmaps pitäisi sisältää omat gmarkerobsit ymsit shit

	this.canvasDivRef; //html div -> map
	
	this.gmapobj = 0;
	this.gmaps = []; //Google-Maps karttaoliot (GMap2) //tulevaa käyttöä varten

    this.gmarkerobjs = []; //sisältää gmarkereita sisältäviä olkkuja, esim. toimipaikka
	this.bbox; //bounding-box karttakoordinaattipisteille
	
	this.gdirections; //reittihakuolkku
	this.direlem; //rudus_saddr || rudus_daddr
	
	//New map ********************************************************************
	this.createNewMap = function(canvasRefStr) {
		if (!canvasRefStr) { this.canvasDivRef = "map_canvas"; } else { this.canvasDivRef = canvasRefStr; }

		//GMap options (delimiter: ',')
		mapOptions = { size:new GSize(600,480) }; //not in use, use by adding to GMap2 constructor call as an arg (, mapOptions)
				
		//GMap olio
		this.gmapobj = new GMap2(document.getElementById(this.canvasDivRef));
		
		tmpgp = new GLatLng(64, 25);
		this.gmapobj.setCenter(tmpgp, 5);
		
		//TODO dynaamiset keskitykset
		
		//Kontrollit
		this.gmapobj.addControl(new GLargeMapControl());
		this.gmapobj.addControl(new GMapTypeControl());
		
		//viite talteen
		this.gmaps.push(this.gmapobj);
		
		return this.gmapobj;
	}
	
	
	//Markerit *********************************************************************
	this.createMarkerObject = function(markArgArr, markType) {
		//Katso markArgArr ja markTypen muoto Toimipaikka-oliosta.
		
		//toimipaikan numero
		tmpn = this.gmarkerobjs.length; 
		
		//New Marker
		tmpm = new Toimipaikka(markArgArr, this.gmapobj, markType, tmpn);

		this.gmarkerobjs.push(tmpm);
		
		//Laske bounding box ja keskitä kartta
		//this.getBoundingBoxPoints();
		
		return tmpm;
	}
	
	this.addMarkerObj = function(markerObjRef) {
		this.gmarkerobjs.push(markerObjRef);
		//todo set markerobj map ref? muuten toimii vain yhdellä kartalla
		//todo set markerobj number? muuten toimii ilman iw
		
		//Laske bounding box ja keskitä kartta
		//this.getBoundingBoxPoints();
	}
	
	
	////Infowindow helpers ********************************************************
	// functions that open the directions forms
	// modeStr a: basic html, b: to-html, c:from-html
	this.showiwtohere = function(intI) { this.gmarkerobjs[intI].openInfoWindowExpHtml('b'); }
	this.showiwfromhere = function(intI) { this.gmarkerobjs[intI].openInfoWindowExpHtml('c');  }

	//Errorit
	
	//Eventit
	
	//Rajaus / Zoom / Bounding Box  *********************************************
	/* Yksittäisen toimipaikan keskitys kartalle - toimii vain jos vain yksi marker objekti */
	this.centerAndZoomOnSinglePoint = function() {
			this.gmapobj.setCenter(new GLatLng(this.gmarkerobjs[0].coordx, this.gmarkerobjs[0].coordy)); //keskitetään siihen
			this.gmapobj.setZoom(13);
	}
	
	/* Lasketaan toimipisteille bounding box josta kartan keskipiste, zoomitaso */
	this.getBoundingBoxPoints = function() {

		xarr = new Array();	
		yarr = new Array();
		
		//Koordinaatit jonoihin
		var j = this.gmarkerobjs.length;
		
		if (j<1) { //Ei toimipaikkoja
			this.gmapobj.setCenter(new GLatLng(64,24), 5); //suomen kartta
			
		} else { //toimipaikkoja monta
			//Lasketaan toimipaikoista kaakkoisin ja lounaisin ja asetetaan keskipiste ja mittakaava sen mukaan
			for (var i=0; i<j; i=i+1) {
				xarr.push(this.gmarkerobjs[i].coordx);  
				yarr.push(this.gmarkerobjs[i].coordy);
			}
			
			xarr.sort(sortNumber); //suurin=pohjoisin
			yarr.sort(sortNumber); //suurin=itäisin
			
			//Luodaan bounding box joka suurempi kuin pisteiden rajaama alue jotta kontrollit tai reunat eivät peitä pisteitä
			var bb_north_east = new GLatLng((xarr[(xarr.length-1)]*1.003), (yarr[(yarr.length-1)]*1.001));
			var bb_south_west = new GLatLng((xarr[0]*0.999), (yarr[0]*0.997));
			
			this.bbox = new GLatLngBounds(bb_south_west, bb_north_east);
			this.gmapobj.setCenter(this.bbox.getCenter(), this.gmapobj.getBoundsZoomLevel(this.bbox));
		} //end if
	}
	
	//APUFUNKTIOITA/HELPERS **********************************************
	//numeroiden sorttausapu (bboxi)
	function sortNumber(a, b) { return a - b;  }
	
	//Errors on page (to eliminate alert boxes)
	this.printMsg = function(errorTextStr) {
		var errDiv = document.createElement('div');
		errDiv.setAttribute('class', 'errorDiv');
		errDiv.id = "errorDiv"; //IE haxx

		var txtNode = document.createTextNode(errorTextStr);
		errDiv.appendChild(txtNode);
		
		var tgDiv = document.getElementById("directions");
		tgDiv.appendChild(errDiv);
		
	}

	// ALUSTUS/INIT *********************************************************
	
	if (GBrowserIsCompatible()) { //Selain yhteensopiva?

		//kartan alustus
		this.createNewMap();
		
		// === create a GDirections Object ===
		this.gdirections = new GDirections(this.gmapobj, document.getElementById("directions"));
		
		//Directions
		//Get directions
		this.getDirections = function(fromStr) {
			//jos selain on firefox, lisätään kommentti reittihaun tulostumattomuudesta
			if (navigator.appName == "Netscape") { 
				msgText = "Käyttämäsi selain ei tue täysin reittigrafiikan tulostamista. Kartalla näkyvä reitti ei välttämättä näy tulosteissa.";
				alert(msgText);
				this.printMsg(msgText); //tulosta viesti
			}

			//asetetaan potentiaalista error-viestiä varten haku-input-boxin elementti
			if (fromStr == 'a') { this.direlem = "rudus_daddr"; } 
			if (fromStr == 'b') { this.direlem = "rudus_saddr"; }
			var ru_saddr = document.getElementById("rudus_saddr").value;
			var ru_daddr = document.getElementById("rudus_daddr").value;

			this.gdirections.load("from: "+ ru_saddr+" to: "+ ru_daddr);
			
			//TODO gdirections debug
		}
		
		// === Array for decoding the failure codes ===
		this.reasons=[];
		this.reasons[G_GEO_SUCCESS]            = "Koordinaattihaku onnistui"; //TODO käännetään loput mikäli tarwitaan.
		this.reasons[G_GEO_MISSING_ADDRESS]    = "Puuttuva osoite: Osoite puuttui tai oli tyhjä. Missing Address: The address was either missing or had no value.";
		this.reasons[G_GEO_UNKNOWN_ADDRESS]    = "Tuntematon osoite: Osoitteelle ei löytynyt maantieteellistä sijaintia. Unknown Address:  No corresponding geographic location could be found for the specified address.";
		this.reasons[G_GEO_UNAVAILABLE_ADDRESS]= "Osoite ei saatavilla: Osoitteen sijaintia ei voitu palauttaa laillisista tai sopimusteknisistä syistä. Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
		this.reasons[G_GEO_BAD_KEY]            = "Virheellinen google-avain: API-avain on virheellinen tai ei sovi verkkotunnukseen jolle se on myönnetty. Bad Key: The API key is either invalid or does not match the domain for which it was given";
		this.reasons[G_GEO_TOO_MANY_QUERIES]   = "Liian monta hakua: Päivittäinen hakumäärä tälle verkkopalvelulle on ylitetty. Too Many Queries: The daily geocoding quota for this site has been exceeded.";
		this.reasons[G_GEO_SERVER_ERROR]       = "Palvelinvirhe: geokoodauspyyntöä ei voitu käsitellä. Server error: The geocoding request could not be successfully processed.";
		this.reasons[G_GEO_BAD_REQUEST]        = "Reirrihakupyyntöä ei voitu onnistuneesti käsitellä. A directions request could not be successfully parsed.";
		this.reasons[G_GEO_MISSING_QUERY]      = "Syötteelle ei määritelty hakua. No query was specified in the input.";
		this.reasons[G_GEO_UNKNOWN_DIRECTIONS] = "Reittihaku-objekti ei voinut laskea ajo-ohjeita pisteiden välille. The GDirections object could not compute directions between the points.";
		
		var tmpMap = this;
		
		// === catch Directions errors ===
		this.gDirectionsStatus = function() {
			var code = tmpMap.gdirections.getStatus().code;
			var reason="Code "+code;
			if (tmpMap.reasons[code]) {
				reason = tmpMap.reasons[code]
			}
			
			//Lisätään epäonnistuneen haun pisteet
			var searchAddr = document.getElementById(tmpMap.direlem).value;
			
			msgText = "Reittihaku '" + searchAddr + "' epäonnistui, ";
			
			alert(msgText+reason);
			tmpMap.printMsg((msgText+reason)); //errorize
		}
		
		GEvent.addListener(this.gdirections, "error", this.gDirectionsStatus);
		
		return this; //*palautetaan viite mapponaattoriin*
		
	} else { <!-- Ei yhteensopiva selain -teksti esille -->
				this.printMsg("Selaimesi ei valitettavasti ole yhteensopiva karttapalvelun kanssa. Your Browser is not compatible with maps.");
				return false;
	}
}

//TEMPORARY MARKER VARS

/* Toimipaikkaolio */

function Toimipaikka(argArray, mapRefe, behaviourType, markerNum) {
	
	//Requires: reittihaku olettaa että sivulla oleva kartta on 'mapX'
	
	//Toimipaikka-muuttujat *************************
	this.tpnimi = argArray[0];
	this.paikkakunta = argArray[1];
	this.raine = argArray[2];
	this.aukiolo = argArray[3];
	this.puhelin = argArray[4];
	this.ltietoja = argArray[5];
	this.tpnum = argArray[6];
	this.coordx = argArray[7];
	this.coordy = argArray[8];
	this.osoite = argArray[9];
	this.tpid = argArray[10]; //ID toimipaikkakortista linkkejä varten

	// Mapponator-muuttujat *************************
	this.markerNumber = markerNum;
	this.myMap = mapRefe;
	
	//Behaviour -types (onClick): 
	//a = basic IW, b = ExtInfoWindow, c = onClick2Url@id
	this.behaviourType = behaviourType; 
	
	// GMaps-muuttujat ******************************
	this.addr = this.tpnimi + "@" + this.coordx + "," + this.coordy;
	this.gpoint = 0;
	this.geokoodaaja = 0;
	this.gicon = 0;
	this.gmarker = 0;
	
	//HTML-sisällöt ********************************** 
	this.getIWHTML = function() {
		var tmpStr = '<div class="karttaIW"><h1>';
		if (this.tpnimi.length > 1) {	tmpStr += this.tpnimi + '</h1>'; }
		if (this.paikkakunta.length > 1) {	tmpStr += this.paikkakunta; } //<div class="keskella">' + this.paikkakunta + '</div>
		
		tmpStr += '<table cellpadding="0" cellspacing="0">';
		if (this.raine.length > 1) {	tmpStr += '<tr><th>Raaka-aine:</th><td>' + this.raine + '</td></tr> '; }
		if (this.puhelin.length > 1) {	tmpStr += '<tr><th>Puhelin:</th><td>' + this.puhelin + '</td></tr>'; }
		if (this.ltietoja.length > 1) {	tmpStr += '<tr><th>Lisätietoja:</th><td>' + this.ltietoja + '</td></tr>'; }
		
		//Reittihakulinkit
		tmpStr += '<tr><th>Reittihaku: </th><td><a href="javascript:mapX.showiwtohere(0);">Tänne</a>&#160';
		tmpStr += '<a href="javascript:mapX.showiwfromhere(0);">Täältä</a><br/></td></tr>';
		
		tmpStr += '</table>';
		
		tmpStr += '<div class="height_padder"><br /></div>';
		
		/* tmpStr += '<div id="rudus_iw_beak2"></div>'; // tätä tarvitaan vain extended infowindow'n kanssa */
		/* <img src="/images/customer/rudus_iw_beak_wide.gif" />*/
		
		this.gmarker_iw_html = tmpStr;
	}
	
	this.getIWToHTML = function () {
		var tmpStr = this.gmarker_iw_html + 'Reittihaku toimipaikasta<br/>Syötä katuosoite ja kaupunki:<br/><span style="font-size: smaller; color: grey;">(esim.  Purotie 1, Lohja).</span><form action="javascript:mapX.getDirections(' + "'a'" + ');">' +
						   '<input type="text" SIZE="40" MAXLENGTH="40" name="rudus_daddr" id="rudus_daddr" value="" /><br/><INPUT class="reittiSubmit" value="Hae Reitti" TYPE="SUBMIT" />' +
						   '<input type="hidden" id="rudus_saddr" name="rudus_saddr" value="'+ this.addr + '"/></form><br/>';
		this.gmarker_iw_to_html = tmpStr; 
	}
	
	this.getIWFromHTML = function () {
		var tmpStr = this.gmarker_iw_html + 'Reittihaku toimipaikkaan<br/>Syötä katuosoite ja kaupunki:<br/><span style="font-size: smaller; color: grey;">(esim. Purotie 1, Lohja).</span><form action="javascript:mapX.getDirections(' + "'b'" + ');">' +
							'<input type="text" SIZE="40" MAXLENGTH="40" name="rudus_saddr" id="rudus_saddr" value="" /><br/><INPUT class="reittiSubmit" value="Hae Reitti" TYPE="SUBMIT" />' +
							'<input type="hidden" id="rudus_daddr" name="rudus_daddr" value="'+ this.addr + '"/></form><br/>';
		this.gmarker_iw_from_html	=  tmpStr; 
	}
	
	this.getIWHTML();
	this.getIWToHTML();
	this.getIWFromHTML();
    

	//markers ****************************************
	//Normaali Infowindow
	this.createMarkerWithInfoWindow = function(mapRef, point, htmlcontent) {
		//Ikoni ja InfoWindow -muotoilu
		
		//Icon
		ucon = new GIcon(G_DEFAULT_ICON); //this.createTpIcon();
		ucon.infoWindowAnchor = new GPoint(15, 0);	
		
		//GMarkerOptions
		markerOptions = { icon:ucon, title: this.tpnimi }; //TODO ICONREF
		
		//Marker
		this.gmarker = new GMarker(this.gpoint, markerOptions); 
		
		var tmpTp = this;
		
		//IW onclick listener
		GEvent.addListener(this.gmarker, "mouseover", function() {
				//Infowindow
				tmpTp.gmarker.openInfoWindow(tmpTp.gmarker_iw_html + "<br/>"); //toimii, ei tyylitetty
				tmpTp.myMap.setCenter(this.gpoint); //keskitys klikattuun markeriin?
		});
		
		mapRef.addOverlay(this.gmarker);
		
		return this.gmarker;
	}

	//Extended Info Window
	this.createMarkerWithExtInfoWindow = function(mapRef, point, htmlcontent) {
		//Ikoni ja InfoWindow -muotoilu
		
		//Icon
		ucon = new GIcon(G_DEFAULT_ICON); //this.createTpIcon();
		
		//GMarkerOptions
		markerOptions = { icon:ucon, title: this.tpnimi }; //TODO ICONREF
		
		//Marker
		this.gmarker = new GMarker(this.gpoint, markerOptions); 
		
		var tmpTp = this;
		
		//IW onclick listener
		GEvent.addListener(this.gmarker, "click", function() {
				tmpTp.gmarker.openExtInfoWindow(mapRef, "rudus_iw", tmpTp.gmarker_iw_html, {beakOffset: 3});
				tmpTp.myMap.setCenter(this.gpoint); //keskitys klikattuun markeriin? 
		});
		
		mapRef.addOverlay(this.gmarker);
		
		return this.gmarker;
	}
	
	//Normaali Infowindow
	this.createMarkerWithOnClickToUrl = function(mapRef, point) {
		//Ikoni ja InfoWindow -muotoilu
		
		//Icon
		ucon = new GIcon(G_DEFAULT_ICON); //this.createTpIcon();
		ucon.infoWindowAnchor = new GPoint(15, -35);	
		
		//GMarkerOptions
		markerOptions = { icon:ucon, title: this.tpnimi }; //TODO ICONREF
		
		//Marker
		this.gmarker = new GMarker(this.gpoint, markerOptions); 
		
		var tmpTp = this;
		
		//IW onclick listener
		GEvent.addListener(this.gmarker, "click", function() {
				//Klikatessa toinen sivu toimipaikkaolion idllä
				theUrl =  window.location.href + "/?intProductID=" + tmpTp.tpid;
				location.href = theUrl;
		});
		
		mapRef.addOverlay(this.gmarker);
		
		return this.gmarker;
	}

	
	//Marker openers ***********
	this.openInfoWindowExpHtml = function(mode) {
		if (mode=='a') {
			this.gmarker.openInfoWindow(this.gmarker_iw_html);
		}
		if (mode=='b') {
			this.gmarker.openInfoWindow(this.gmarker_iw_from_html);
		}
		if (mode=='c') {
			this.gmarker.openInfoWindow(this.gmarker_iw_to_html);
		}
	}
	
	this.openExtInfoWindowExpHtml = function(mode) {
		if (mode==0) {
			this.gmarker.openExtInfoWindow(this.myMap, "rudus_iw", this.gmarker_iw_html, {beakOffset: 3});
		}
		if (mode==1) {
			this.gmarker.openExtInfoWindow(this.myMap, "rudus_iw", this.gmarker_iw_to_html, {beakOffset: 3});
		}
		if (mode==2) {
			this.gmarker.openExtInfoWindow(this.myMap, "rudus_iw", this.gmarker_iw_from_html, {beakOffset: 3});		
		}
	}
	
	/* function closeExtInfoWindowHtml() {
		//todo, hide jos tarvitsee, tai offset off-map
	} */
	
	//Geokoodaaja ***********************************
	this.geoEncodeCallback = function(returnedArg) {
		if (!returnedArg) { //jos vastaus tyhjä
			//TODO Osoitetta ei löytynyt error on page
			this.myMap.printMsg("Osoitetta ei löytynyt");
			this.geokoodaaja = 0;
		} else {
			//alert("OUT: " +returnedArg + " urlval " + returnedArg.toUrlValue());
			this.gpoint = returnedArg;
			this.addr = '<xsl:value-of select="$kartta_nimi"/>@';
			this.addr += returnedArg.toUrlValue();
			this.geokoodaaja = 0;
		}
	}
	
	this.geoEncodeAddress = function (osoiteStr) {
		// Geokoodaaja osoitteen selvittämiseksi
		this.geokoodaaja = new GClientGeocoder();
		
		// sijainti osoitteella, vastausfunktio
		this.geokoodaaja.getLatLng(osoiteStr, this.geoEncodeCallback);
	}
	
	//ALUSTUS/INIT ***********************************
	//*************************************************
	
	//--coords from coords or address
	if (this.coordx.length>3 && this.coordy.length>3) { //Coords ok?
		//gpoint
		this.gpoint = new GLatLng(this.coordx, this.coordy);
		//addr
		this.addr = this.tpnimi + '@' + this.gpoint.toUrlValue();
	} else if (this.osoite.length>10) {	//else Address ok?
		//geocode
		this.geoEncodeAddress(this.osoite);
	}
	
	if (this.behaviourType=='a') { //Normal
		this.gmarker = this.createMarkerWithInfoWindow(this.myMap, this.gpoint, this.gmarker_iw_html);
	} else if (this.behaviourType=='b') { //Extended
		this.gmarker = this.createMarkerWithExtInfoWindow(this.myMap, this.gpoint, this.gmarker_iw_html);
	} else if (this.behaviourType=='c') { // On Click 2 Toimipaikka
		this.gmarker = this.createMarkerWithOnClickToUrl(this.myMap, this.gpoint);
	}
	
	return this;
	
}
//end toimipaikkaolio

/** Ikonit, Markerit, Infowindow:t */ 

function createCustomRudusIcon_OLD() {  //Deprec
       // Create a icon for all of our markers that specifies the
        // shadow, icon dimensions, etc.
        var thisIcon = new GIcon();
				/*thisIcon.image = "/images/customer/rudusmap_logo.gif"
        thisIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
        thisIcon.iconSize = new GSize(70, 39);
        thisIcon.shadowSize = new GSize(37, 34);
        thisIcon.iconAnchor = new GPoint(35, 20);
        thisIcon.infoWindowAnchor = new GPoint(35, 2);
        thisIcon.infoShadowAnchor = new GPoint(18, 25);*/

		return thisIcon;
}

