var typesVillages = {
    RESERVE_ADULTE: 2,
    SANS_ENCADREMENT_ENFANT: 4,
    AVEC_ENCADREMENT_ENFANT: 1
};
var encadrements = {
    FROM_4_TO_23_MONTH: 1,
    FROM_2_TO_3_YEARS: 2,
    FROM_4_TO_12_YEARS: 4,
    ABOVE_12_YEARS: 8
};
var saisons = {
    TOUTES_SAISONS: true,
    ETE_UNIQUEMENT: "summer",
    HIVERS_UNIQUEMENT: "winter"
};
var plaisirs = {
    VIVRE_EXCEPTIONNEL: 1,
    SE_DEPENSER: 2,
    SE_RESSOURCER: 4,
    VIVRE_200: 8,
    GOUTER_A_TOUT: 16,
    DECOUVRIR: 32
};
var tridents = {
    VILLAS_LUXE: 32,
    VILLAGES_5T: 16,
    VILLAGES_4T: 8,
    VILLAGES_3T: 4,
    VILLAGES_2T: 2
};
var regions = {
    AMERIQUE_NORD: "Amérique du Nord",
    CARAIBES: "Caraïbes",
    AMERIQUE_SUD: "Amérique du Sud",
    EUROPE: "Europe",
    ALPES: "Alpes",
    AFRIQUE: "Afrique",
    ASIE: "Asie",
    OCEANIE: "Océanie",
    OCEAN_INDIEN: "Océan Indien"
};

/*
 * Utility that returns the season for the village given as argument
 * base on the currently selected date.
 */
function currentSeason(village) {
    var current_date = getCurrentDate();

    if(!current_date && village.currentSeason) {
        return village.currentSeason.season;
    }
    if(current_date && village.summer && (compare(village.summer.from, current_date) == -1) && (compare(village.summer.to, current_date) == 1)) {
        return "summer";
    } else if(current_date && village.winter && (compare(village.winter.from, current_date) == -1) && (compare(village.winter.to, current_date) == 1)) {
        return "winter";
    } else {
        return null;
    }
}
// ZOMIG ! august and september yield 08 and 09 parsed as octal -> converted to decimal 0, bug!
function getDecimalInteger(str) {
    return parseInt(str, 10);
}
function getCurrentDate() {
    if(!searchform  ||  !searchform.departure) {
		if (!document.getElementById('resa_datedepartRMC')) {
			return;
		} else {
			searchform.departure= {'date':$('resa_datedepartRMC'),delta:$('delta-depart'),duration:$('duration'),durationHidden:$('durationHidden')};
		}
	}
    var date_split = searchform.departure.date.value.split("/");
	if (!date_split || isNaN(date_split[0])  || isNaN(parseInt(date_split[1])) || isNaN(parseInt(date_split[2])) ) return;
    // bug: javascript's Date's Month is 0-indexed and not 1-indexed! Stupid!
	var formatDate_split = formatDateRMC.split('/');
	var $jq = jQuery.noConflict();
	var day = date_split[$jq.inArray('DD', formatDate_split)];
	var month = date_split[$jq.inArray('MM', formatDate_split)];
	var year = date_split[$jq.inArray('YYYY', formatDate_split)];
	var date = new Date(year, month-1, day);
    return date;
}
function getIsoCurrentDate() {
    return toISODate(getCurrentDate());
}

function inter(a1,a2) {
    var intersect = new Array();
    for(var i=0; i<a1.length; ++i) {
        for(var j=0; j<a2.length; ++j) {
            if(0 == compare(a1[i], a2[j])) {
                intersect.push(a1[i]);
            }
        }
    }
    return intersect;
}

function isWithin(arrival, departure, opening, closing) {
    return (compare(arrival, opening) >= 0)
        && (compare(arrival, closing) <= 0)
        && (compare(departure, opening) >= 0)
        && (compare(departure, closing) <= 0)
}
function isVillageOpen(village, arrival, departure) {
    var out = false;
    if(village['summer']) {
        out = out || isWithin(arrival, departure, village.summer.from, village.summer.to);
    }
    if(!out && village['winter']) {
        out = out || isWithin(arrival, departure, village.winter.from, village.winter.to);
    }
    return out;
}

/*
 * FilterBy is a predicates factory.
 * One needs to call the right factory method with the filtering
 * arguments, and the predicate will be generated to drop into
 * a filter.
 */
function FilterBy() {
    this.plaisir = function (plaisir) {
        return function (village) {
            if(!village[currentSeason(village)]) return false;

            return Boolean(plaisir & village[currentSeason(village)].plaisir);
        }
    }
	this.confort = function (confort) {
        return function (village) {
            if(!village[currentSeason(village)]) return false;
			if ( (confort&tridents.VILLAGES_5T)  &&  village[currentSeason(village)].tridents==tridents.VILLAGES_4T  &&  village[currentSeason(village)].esp5Trid>0 )
				return true;
            return Boolean(confort & village[currentSeason(village)].tridents);
        }
    }
	this.typeOfVillage = function (types) {
		return function (village) {
            if(!village[currentSeason(village)]) return false;
            return  (((types&4)==4) && 0==village[currentSeason(village)].typeVillage)  //  village SANS encadrement Enfants
					||  Boolean(types & village[currentSeason(village)].typeVillage); // Village adulte ou AVEC encadrement
        }
	};
	this.withChildrenSurveillance = function () {
        return function (village) {
            if(!village[currentSeason(village)]) return false;

            return village[currentSeason(village)].typeVillage == typesVillages.AVEC_ENCADREMENT_ENFANT;
        };
    };
    this.spokenLang = function () {
        return function (village) {
            if(!village[currentSeason(village)]) return false;

            return village[currentSeason(village)].spokenLang;
        };
    };
    this.seasons = function (season) {
        return function (village) {
            //if(!village[currentSeason(village)]) return false;

            if(season == saisons.TOUTES_SAISONS) {
                return true;
            } else if(season == saisons.ETE_UNIQUEMENT) {
                return !village.isWinter;
            } else if(season == saisons.HIVERS_UNIQUEMENT) {
                return village.isWinter;
            }
            return false;
        };
    };
    this.childrenCare = function (age_ranges) {
        return function (village) {
            if(!village.currentSeason) return false;
            if(!FilterBy.withChildrenSurveillance()(village)) {
                return false;
            }
            return (village.currentSeason.encadrements & age_ranges) == age_ranges;
        };
    };
	this.budget = function(range) {
        return function (village) {
			var cost = -1;
			try {
				cost = prices[village.id][0]; // price for an adult
			}catch(e) {
			} 
			switch (range) {
				//case -1:  alert(village.id);return true; 
				case 1: if (cost <= $('budget_1').getAttribute('min')) return true; else return false; 
				case 2: if (cost <= $('budget_2').getAttribute('min')) return true; else return false; 
				case 3: if (cost <= $('budget_3').getAttribute('min')) return true; else return false; 
				case 4: if (cost >= $('budget_4').getAttribute('min')) return true; else return false; 
				default: return true;
			}
			return false;
		};
	};
    this.activities = function (activities) {
        return function (village) {
            if(!village[currentSeason(village)]) return false;
            var result = (0 == compare(activities, inter(activities, village[currentSeason(village)].activities)));

            return result;
        };
    };
    this.dates = function (arrival, stay_length, delta) {
        return function (village) {
            var early_arrival = MochiKit.DateTime.isoDate(arrival);
            early_arrival.setDate(early_arrival.getDate() - delta);
            var late_arrival = MochiKit.DateTime.isoDate(arrival);
            late_arrival.setDate(late_arrival.getDate() + delta);
            var spot_arrival = MochiKit.DateTime.isoDate(arrival);

            var early_departure = MochiKit.DateTime.isoDate(arrival);
            early_departure.setDate(early_departure.getDate() + stay_length - delta);
            var late_departure = MochiKit.DateTime.isoDate(arrival);
            late_departure.setDate(late_departure.getDate() + stay_length + delta);
            var spot_departure = MochiKit.DateTime.isoDate(arrival);
            spot_departure.setDate(spot_arrival.getDate() + stay_length);

            return isVillageOpen(village, spot_arrival, spot_departure)
                    || isVillageOpen(village, early_arrival, early_departure)
                    || isVillageOpen(village, late_arrival, late_departure);
        };
    };
    this.location = function (continent, country, lower, upper) {
		// Continent + country stored into village
        // timezone_delta extracted from `from` or `to` dates, in hours,
        //  equivalent to GMT timezone deltas.
        return function (village) {
            if(!village[currentSeason(village)]){ return false;}
            var output = true;
            if(continent  &&  continent != "null"  &&  continent._event != "null" ) {
                output = output && Boolean((new RegExp(""+continent+"", "i")).test(village[currentSeason(village)].region));
            }
            if(country && country != "null") {
                output = output && Boolean((new RegExp("^"+country+"$","i")).test(village[currentSeason(village)].pays));
            }
            if((lower || upper) && lower != -1 && upper != -1) {
                output = output
                        && ((Math.abs(village[currentSeason(village)].timezone) >= lower)
                        && (Math.abs(village[currentSeason(village)].timezone) <= upper));
            }
            return output;
        }
    };
}
FilterBy = new FilterBy();

/**
 * Filters an object or an array of objects against a serie of predicates
 */
var trs = 0;
var fls = 0;
function Filter(to_clone) {
    var predicates = (to_clone?to_clone.getPredicates():new Array());

    this.apply = function (objects) {
        trs = fls = 0;
        return filter(this.testObject, objects);
    }

    this.testObject = function (object) {
        for(var i=0, len = predicates.length; i<len; ++i) {
            if(!predicates[i](object)) {
                fls++;
                return false;
            }
        }
        trs++;
        return true;
    };

    this.addPredicate = function (pred) {
        predicates.push(pred);
    };
    this.addPredicates = function () {
        for(var i=0,len=arguments.length; i<len; ++i) {
            this.addPredicate(arguments[i]);
        }
    };
    this.getPredicates = function () {
        return predicates.slice();
    }
    this.clear = function () {
        predicates = new Array();
    };
}

