jQuery(document).ready(function($) {
	Date.prototype.addDays = function(days) {
		this.setDate(this.getDate() + parseInt(days));
		return this;
	};
	
	var currRequest = null;
	var rpRefreshed = false;
	
	var DATE_FORMAT_1 = /^(19|20)\d{2}-(0?[1-9]|1[0-2])-(0?[1-9]|1\d|2\d|3[01])$/;
	var DATE_FORMAT_2 = /^(0?[1-9]|1[0-2])\/(0?[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/;
	var weekDays = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
	//var holidays = [[1, 1, 'uk'], [12, 25, 'uk'], [12, 26, 'uk']];
	//var holidays = ["2016-06-15", "2016-07-05"];
	
	function thwcfe_setup_date_picker(form){
		form.find('.thwcfe-checkout-date-picker').each(function(){
			var dateFormat = $(this).data("date-format");		
			var defaultDate = $(this).data("default-date");
			var maxDate = $(this).data("max-date");
			var minDate = $(this).data("min-date");
			var yearRange = $(this).data("year-range");
			var numberOfMonths = $(this).data("number-months");
			var firstDay = $(this).data("first-day");
			
			maxDate = thwcfeMayParseDate(maxDate);
			minDate = thwcfeMayParseDate(minDate);
							
			dateFormat = dateFormat == '' ? 'dd/mm/yy' : dateFormat;
			defaultDate = defaultDate == '' ? null : defaultDate;
			maxDate = maxDate == '' ? null : maxDate;
			minDate = minDate == '' ? null : minDate;
			yearRange = yearRange == '' ? '-100:+1' : yearRange;
			numberOfMonths = numberOfMonths > 0 ? numberOfMonths : 1;
			
			var value = $(this).val();
			if(value.trim()){
				defaultDate = value;
			}
			
			//minDate = new Date().getHours() >= 2 ? 1 : 0;
			
			$(this).datepicker({
				defaultDate: defaultDate,
				maxDate: maxDate,
				minDate: minDate,
				yearRange: yearRange,
				numberOfMonths: numberOfMonths,
				showButtonPanel: true,
				changeMonth: true,
				changeYear: true			
			});
			$(this).datepicker("option", $.datepicker.regional[wcfe_checkout_fields.language]);
			$(this).datepicker("option", "dateFormat", dateFormat);
			$(this).datepicker("option", "beforeShowDay", disableDates);
			$(this).datepicker("option", "firstDay", firstDay);
			$(this).datepicker("setDate", defaultDate);

			if(wcfe_checkout_fields.readonly_date_field){
				$(this).prop('readonly', true);
			}
		});
	}
	
	function thwcfe_setup_time_picker(form){
		form.find('.thwcfe-checkout-time-picker').each(function(){
			var minTime = $(this).data("min-time");		
			var maxTime = $(this).data("max-time");
			var step    = $(this).data("step");
			var format  = $(this).data("format");
			var startTime = $(this).data("start-time");
			var linkedDate = $(this).data("linked-date");
							
			minTime = minTime ? minTime : '12:00am';
			maxTime = maxTime ? maxTime : '11:30pm';
			step 	= step ? step : '30';
			format 	= format ? format : 'h:i A';
			
			var args = {
				'minTime': minTime,
				'maxTime': maxTime,
				'step': step,
				'timeFormat': format,
				'forceRoundTime': true,
				//'showDuration':true,
				'disableTextInput': true,
				'disableTouchKeyboard': true,
				'lang': wcfe_checkout_fields.lang
			}		
			$(this).timepicker(args);
			//$(this).timepicker('option', 'minTime', tpMinTime(format, step, minTime, maxTime, startTime));
			
			if(linkedDate){
				var dp = $("#"+linkedDate);
				if( dp.length ) {
					thwcfeAdjustTimeSlotsBasedOnDateSelected(dp, $(this));
				}
			}else{
				thwcfeAdjustTimeSlotsBasedOnDateSelected(null, $(this));	
			}
		});
	}
	
	function thwcfe_setup_enhanced_select(form, class_selector){
		form.find('select.'+class_selector).each(function(){
			var ms = $(this);
			ms.select2({
				minimumResultsForSearch: 10,
				allowClear : true,
				placeholder: ms.data('placeholder'),
				maximumSelectionLength: ms.data('maxselections')
			}).addClass('enhanced');
		});
	}
		
	$(document).on('updated_checkout', function(){
		var review_wrapper = $('#order_review');
		thwcfe_setup_enhanced_select(review_wrapper, 'thwcfe-enhanced-select');
		thwcfe_setup_enhanced_select(review_wrapper, 'thwcfe-enhanced-multi-select');
	    thwcfe_setup_date_picker(review_wrapper);
	    thwcfe_setup_time_picker(review_wrapper);
		
		if(!rpRefreshed){
			rpRefreshed = true;
			
			if(wcfe_checkout_fields.rebind_all_cfields){
				$('.thwcfe-conditional-field').each(function(){
					validate_field_condition($(this), true);								 
				});
			}else{
				review_wrapper.find('.thwcfe-conditional-field').each(function(){
					validate_field_condition($(this), true);								 
				});
			}
		}else{
			rpRefreshed = false;
		}
		
		thwcfe_setup_price_fields(review_wrapper);
	});
	
	var checkout_form = $('form[name="checkout"]');
	thwcfe_setup_enhanced_select(checkout_form, 'thwcfe-enhanced-select');
	thwcfe_setup_enhanced_select(checkout_form, 'thwcfe-enhanced-multi-select');
	thwcfe_setup_date_picker(checkout_form);
	thwcfe_setup_time_picker(checkout_form);
		
	function thwcfeMayParseDate(dateStr){
		if(DATE_FORMAT_1.test(dateStr)){
			var date = new Date(dateStr);
			if(date){
				return date;
			}
		}
		return dateStr;
	}
	
	function tpMinTime(format, step, minTime, maxTime, startTime){
		if(startTime){
			var _startTime = thwcfeSplitHourMin(startTime);
			
			if(_startTime.length > 1){
				
				var suffixMinTime = thwcfeGetTimeSuffix(minTime);
				var suffixMaxTime = thwcfeGetTimeSuffix(maxTime);
				
				var _minTime = thwcfeSplitTimeString(minTime, suffixMinTime);
				var _maxTime = thwcfeSplitTimeString(maxTime, suffixMaxTime);
				
				if(_minTime.length > 1){
					var currTime = new Date();
					
					var minHour = _minTime[0];
					var minMin  = _minTime[1];
					
					var dateMin = new Date();
					dateMin.setHours(minHour, minMin);
					
					//if(currTime >= dateMin){
						var maxHour = _maxTime[0];
						var maxMin  = _maxTime[1];
						
						var currHour = currTime.getHours();
						var currMin  = currTime.getMinutes();
						
						var startHour = _startTime[0];
						var startMin  = _startTime[1];	
						
						currHour = currHour + startHour;
						currMin  = currMin + startMin;
						if(currMin >= 60){
							currHour += 1;
							//currMin = 00;
							currMin = currMin-60;
						}
						
						var dateStart = new Date();
						dateStart.setHours(currHour, currMin);
						var dateDiff = dateStart - dateMin;
						dateDiff = dateDiff/60000;
					
						if(step < 60){
							var ns = Math.floor(dateDiff/step);
							var newStartTime = (ns+1)*step;
							
							var newStartTimeHour = Math.floor(newStartTime/60);
							var newStartTimeMin = Math.floor(newStartTime%60);
							
							currHour = minHour + newStartTimeHour;
							currMin = minMin + newStartTimeMin;
							
							/*var ns = Math.floor(currMin/step);
							currMin = (ns+1)*step;*/
							
							if(currMin >= 60){
								currHour += 1;
								//currMin = 00;
								currMin = currMin-60;
							}
						}
						
						/*if(currHour > maxHour){
							maxHour = maxHour;
							currMin = maxMin;
						}else if(currHour = maxHour && currMin > maxMin){
							currMin = maxMin;
						}*/
						
						if(currHour < minHour || (currHour == minHour && currMin < minMin)){
							return minTime;
						}
						
						if(currHour > maxHour || (currHour == maxHour && currMin > maxMin)){
							return minTime;
							//maxMin += 1;
							//return maxHour+":"+maxMin;
						}
					
						currHour = padZero(currHour, 2);
						currMin  = padZero(currMin, 2);
						
						minTime  = currHour+":"+currMin;
					//}
				}
			}
		}
		
		return minTime;
	}
	
	function thwcfeSplitTimeString12Hr(time){
		var ampm = thwcfeGetTimeSuffix(time);
		return thwcfeSplitTimeString(time, ampm);
	}
	
	function thwcfeSplitTimeString(time, ampm){
		time = time.replace(/pm/gi, "");
		time = time.replace(/am/gi, "");
		var timeArr = time.split(":");
		
		var hours = parseInt(timeArr[0]);
		var minutes = parseInt(timeArr[1]);
		
		if(ampm == "pm" && hours < 12){
			hours = hours + 12;
		}else if(ampm == "am" && hours == 12){
			hours = hours - 12;
		}
		
		return [hours, minutes];
	}
	
	function thwcfeSplitHourMin(hourMinStr){
		var hours = 0;
		var minutes = 0;
		
		if(hourMinStr && (typeof hourMinStr === 'string' || hourMinStr instanceof String)){
			var _hourMin = hourMinStr.split(" ");
			
			if(_hourMin.length > 0){
				for(i = 0; i < _hourMin.length; i++) { 
					var x = _hourMin[i];
					x = x.toLowerCase();
					
					if(x.indexOf("h") != -1){
						x = x.replace(/h/gi, "");
						hours = parseInt(x);
					}else if(x.indexOf("m") != -1){
						x = x.replace(/m/gi, "");
						minutes = parseInt(x);
					}
				}
			}
			
			hours = hours ? hours : 0;
			minutes = minutes ? minutes : 0;
			
			if(minutes >= 60){
				hours = hours + 1;
				minutes = 0;
			}
		}
		
		return [hours, minutes];
	}
	
	function thwcfeGetTimeSuffix(time){
		time = time.toLowerCase();
		var suffix = "";
		if(time.indexOf("am") != -1){
			suffix = "am";
		}else if(time.indexOf("pm") != -1){
			suffix = "pm";
		}
		return suffix;
	}
	
	function thwcfeCalculateMinutesFromHrMin(_hour, _min){
		var minutes = null;
		if(isInt(_hour) && isInt(_min)){
			minutes = (_hour*60) + _min;
		}
		return minutes;
	}
	
	function thwcfeGetMinutesFromTime24hr(time){
		var minutes = null;
		var timeArr = time.split(":");
		if(timeArr.length == 2){
			var _hour = parseInt(timeArr[0]);
			var _min = parseInt(timeArr[1]);
			minutes = thwcfeCalculateMinutesFromHrMin(_hour, _min);
		}
		return minutes;
	}
	
	function thwcfeIsSameDate(date1, date2){
		var day1 = date1.getDate();
		var month1 = date1.getMonth() + 1;
		var year1 = date1.getFullYear();
		
		var day2 = date2.getDate();
		var month2 = date2.getMonth() + 1;
		var year2 = date2.getFullYear();
		
		var matchYear = isInt(day1) && isInt(day2) && (day1 == day2) ? true : false;
		var matchMonth = isInt(month1) && isInt(month2) && (month1 == month2) ? true : false;
		var matchDay = isInt(year1) && isInt(year2) && (year1 == year2) ? true : false;
		
		return matchYear && matchMonth && matchDay;
	}
	
	$('.thwcfe-checkout-date-picker').change(function() {
		var dp = $(this);
		var tp = $('.thwcfe-linked-date-'+dp.prop('id'));
		if( tp.length ) {
	    	thwcfeAdjustTimeSlotsBasedOnDateSelected(dp, tp);
		}
	});
	
	function thwcfeAdjustTimeSlotsBasedOnDateSelected(dp, tp){
		var dpDate = null;
		
		if(dp){
			var df = dp.data("date-format");
			var sd = dp.val();
			dpDate = prepare_date(sd, df, true);
		}
	   	
		var minTime = tp.data("min-time");
	   	var maxTime = tp.data("max-time");
		var startTime = tp.data("start-time");
		
		var startTimeArr = thwcfeGetStartHrMin(startTime);
		if(startTimeArr){
			var startDate = startTimeArr["startDate"];
			
			if(dp != null && dpDate < startDate){
				thwcfeDisableAllTimeSlots(tp, minTime, maxTime);
			}else if(dp != null && dpDate > startDate){
				tp.timepicker('option', 'disableTimeRanges', []);
			}else{
				// If dates are equal check for current time
				// If current time is gt maxTime then clear time slots
				// If current time is lt minTime the set original minTime as minTime
				// If current time is within in the allowed range then set minTime as next available slot.
				var minTimeArr = thwcfeSplitTimeString12Hr(minTime);
				var minHour = minTimeArr[0];
				var minMin = minTimeArr[1];
				
				var maxTimeArr = thwcfeSplitTimeString12Hr(maxTime);
				var maxHour = maxTimeArr[0];
				var maxMin = maxTimeArr[1];
				
				var startHour = startTimeArr["startHour"];
				var startMin = startTimeArr["startMin"];
						
				if(startHour > maxHour || (startHour == maxHour && startMin > maxMin)){
					if(wcfe_checkout_fields.restrict_time_slots_for_same_day){
						thwcfeDisableAllTimeSlots(tp, minTime, maxTime);
					}else{
						var disabledTimeRanges = thwcfeGetDisabledTimeRanges(minTimeArr, maxTimeArr, startTimeArr);
						tp.timepicker('option', 'disableTimeRanges', disabledTimeRanges);
					}
				}else if(startHour < minHour || (startHour == minHour && startMin < minMin)){
					tp.timepicker('option', 'disableTimeRanges', []);
				}else{
					var disabledTimeRanges = thwcfeGetDisabledTimeRanges(minTimeArr, maxTimeArr, startTimeArr);
					tp.timepicker('option', 'disableTimeRanges', disabledTimeRanges);
				}				
			}
		}
	}
	
	function thwcfeGetDisabledTimeRanges(minTime, maxTime, startTime){
		var minHour = minTime[0];
		var minMin = minTime[1];
		
		var maxHour = maxTime[0];
		var maxMin = maxTime[1];
		
		var currTime = new Date();
		var currHour = currTime.getHours();
		var currMin  = currTime.getMinutes();
		currTime.setSeconds(0, 0);
		
		var startHour = startTime["startHour"];
		var startMin = startTime["startMin"];
		var startDate = new Date();
		startDate.setHours(startHour, startMin, 0, 0);
				
		minHour = padZero(minHour, 2);
		minMin = padZero(minMin, 2);
		
		startHour = padZero(startHour, 2);
		startMin = padZero(startMin, 2);
		
		var disMinRange = minHour+":"+minMin;
		var disMaxRange = startHour+":"+startMin;
		
		var disRange = [[disMinRange, disMaxRange]];
		return disRange;
	}
	
	function thwcfeDisableAllTimeSlots(tp, minTime, maxTime){
		var suffixMaxTime = thwcfeGetTimeSuffix(maxTime);
		var maxTimeArr = thwcfeSplitTimeString(maxTime, suffixMaxTime);
		var maxHour = maxTimeArr[0];
		var maxMin  = maxTimeArr[1];
		
		maxHour = padZero(maxHour, 2);
		maxMin = padZero(parseInt(maxMin)+1, 2);
							
		var newMaxTime = maxHour+':'+maxMin;
		tp.timepicker('option', 'disableTimeRanges', [[minTime, newMaxTime]]);
		//TODO correct newMaxTime for border cases (24:00)
	}
		
	function thwcfeTimeInfoFromTimeString(timeStr){
		var timeInfo = {};
		if(timeStr){
			var suffix = thwcfeGetTimeSuffix(timeStr);
			var timeArr = thwcfeSplitTimeString(timeStr, suffix);
						
			if(timeArr.length > 1){
				timeInfo['suffix'] = suffix;
				timeInfo['hour'] = timeArr[0];
				timeInfo['min'] = timeArr[1];
				timeInfo['date'] = new Date().setHours(timeArr[0], timeArr[1]);
			}
		}
		return timeInfo;
	}
	
	function thwcfeGetStartHrMin(startTime){
		var timeInfo = {};
		if(startTime){
			var startTimeArr = thwcfeSplitHourMin(startTime);
			if(startTimeArr.length > 1){
				var currTime = new Date();
				var currHour = currTime.getHours();
				var currMin  = currTime.getMinutes();
				
				var _startHour = startTimeArr[0];
				var startDays = parseInt(_startHour/24);
				var startDate = new Date();
				startDate.addDays(startDays).setHours(0,0,0,0);
				var startHour = _startHour%24;
				var startMin  = startTimeArr[1];
				
				startHour = currHour+startHour;
				startMin  = currMin+startMin;
				if(startMin >= 60){
					startHour++;
					startMin = startMin-60;
				}else if(startMin < 0){
					startHour--;
					startMin = 60+startMin;
				}
				
				timeInfo['startDate'] = startDate;
				timeInfo['startDays'] = startDays;
				timeInfo['startHour'] = startHour;
				timeInfo['startMin'] = startMin;
				timeInfo['hour'] = startTimeArr[0];
				timeInfo['min'] = startTimeArr[1];
			}
		}
		return timeInfo;		
	}
	
	
   /******************************************
	***** DISABLE DATE FUNCTIONS - START *****
	******************************************/
	// start weeks from monday
	//$(".selector").datepicker({ firstDay: 1 });
	
	/*function noSpecificDays(date, dayIndex) {
		var day = date.getDay();
		return [day != dayIndex, ''];
	}*/
	function noSpecificDays(date, disableDays) {
		var day = date.getDay();
		var daystring = weekDays[day];
    	return [ disableDays.indexOf(daystring) == -1, '' ];
	}
	function noSpecificDates(date, datestring) {
		var day = date.getDate();
		var month = date.getMonth() + 1;
		var year = date.getFullYear();
		
		var dateArr = datestring.split("-");
		if(dateArr.length == 3){
			var matchYear = isInt(dateArr[0]) ? dateArr[0] == year : true;
			var matchMonth = isInt(dateArr[1]) ? dateArr[1] == month : true;
			var matchDay = isInt(dateArr[2]) ? dateArr[2] == day : true;
			
			if(isInt(dateArr[0]) || isInt(dateArr[1]) || isInt(dateArr[2])){
				return [!(matchYear && matchMonth && matchDay), ''];
			}else{
				return [true, ''];
			}
		}else{
			var _now = new Date();
			if(thwcfeIsSameDate(date, _now)){
				var _hour = _now.getHours();
				var _min = _now.getMinutes();
				
				var op = "eq";
				if(datestring.indexOf("+") != -1){
					op = "gt";
					datestring = datestring.replace("+", "");
				}else if(datestring.indexOf("-") != -1){
					op = "lt";
					datestring = datestring.replace("-", "");
				}
				
				var _minutes = thwcfeCalculateMinutesFromHrMin(_hour, _min);
				var minutes = thwcfeGetMinutesFromTime24hr(datestring);
				
				if(isInt(minutes) && isInt(_minutes)){
					if((op === "eq" && _minutes == minutes) || (op === "gt" && _minutes > minutes) || (op === "lt" && _minutes < minutes)){
						return [false, ''];
					}
				}
			}
		}
		return [true, ''];
		
		/*var matchYear = matchMonth = matchDay = false;
		if( isInt(dateArr[0]) && dateArr[0] === year ){
			matchYear = true;
		}
		if( isInt(dateArr[1]) && dateArr[1] === month ){
			matchMonth = true;
		}
		if( isInt(dateArr[2]) && dateArr[2] === day ){
			matchDay = true;
		}*/
		
		
		
		//var datestring = $.datepicker.formatDate('yy-mm-dd', date);
    	//return [ disableDates.indexOf(datestring) == -1, '' ];
	}
	
	
	
	function noSpecificDates1(date, disableDates) {
		var datestring = $.datepicker.formatDate('yy-mm-dd', date);
    	return [ disableDates.indexOf(datestring) == -1, '' ];
	}
	
	function noSundays(date) {
		var day = date.getDay();
		return [day != 0, ''];
	}
	function noSaturdays(date) {
		var day = date.getDay();
		return [day != 6, ''];
	}
	function noWeekends(date) {
		return $.datepicker.noWeekends(date);
	}
	function noChristmas(date) {
		var day = date.getDate();
		var month = date.getMonth() + 1;
		return [!(day === 25 && month === 12), ''];
	}
	function noNewYearsDay(date) {
		var day = date.getDate();
		var month = date.getMonth() + 1;
		return [!(day === 1 && month === 1), ''];
	}
	function noHolidays(date) {
		var datestring = $.datepicker.formatDate('yy-mm-dd', date);
    	return [ holidays.indexOf(datestring) == -1, '' ];
	}
	
	function noWeekendsOrHolidays(date) {
		var noWeekend = $.datepicker.noWeekends(date);
		if (noWeekend[0]) {
			return noHolidays(date);
		} else {
			return noWeekend;
		}
	}
	
	function disableDates(date){
		var disabledDays = $(this).data("disabled-days");
		
		if(disabledDays && disabledDays.length > 0){
			var daysArr = disabledDays.split(",");
			var disabledDay = noSpecificDays(date, daysArr);
			
			if(!disabledDay[0]) {
				return disabledDay;
			}
			
			/*if(daysArr.length > 0){
				for (i = 0; i < daysArr.length; i++) { 
					var dayIndex = weekDays.indexOf(daysArr[i].trim());
					
					var disabled = noSpecificDays(date, dayIndex);
					if(!disabled[0]) {
						return disabled;
					}
				}
			}*/
		}
		
		var disabledDates = $(this).data("disabled-dates");
		if(disabledDates && disabledDates.length > 0){
			var datesArr = disabledDates.split(",");
			/*var disabledDate = noSpecificDates(date, datesArr);
			
			if(!disabledDate[0]) {
				return disabledDate;
			}*/
			if(datesArr.length > 0){
				for (i = 0; i < datesArr.length; i++) { 
					var disabledDate = noSpecificDates(date, datesArr[i].trim());
					if(!disabledDate[0]) {
						return disabledDate;
					}
				}
			}
		}
		
		return [true, ''];
	}
	
	/*function disableDates(date){
		var noSunday = noSundays(date);
		if (noSunday[0]) {
			return noChristmas(date);
		} else {
			return noSunday;
		}
	}*/
   /******************************************
	***** DISABLE DATE FUNCTIONS - END *******
	******************************************/
	
	$.fn.getType = function(){
		try{
			return this[0].tagName == "INPUT" ? this[0].type.toLowerCase() : this[0].tagName.toLowerCase(); 
		}catch(err) {
			return 'E001';
		}
	}
	
	function padZero(s, len, c){
		s = ""+s;
		var c = c || '0';
		while(s.length< len) s= c+ s;
		return s;
	}
	
	function isInt(value) {
	  	return !isNaN(value) && parseInt(Number(value)) == value && !isNaN(parseInt(value, 10));
	}
	
	function isInputField(field){
		if(field && field.length > 0){
			var tagName = field[0].tagName.toLowerCase();
			if($.inArray(tagName, ["input", "select", "textarea"]) > -1){
				return true;
			}
		}
		return false;
	}
	
	function getInputField(key){
		var field = null;
		if(key){
			field = $('#'+key);
			if(!isInputField(field)){
				field = $("input[name='"+key+"']");
				if(!isInputField(field)){
					field = $("input[name='"+key+"[]']");
					if(!isInputField(field)){
						field = $("input[name='"+key+"[0]']");
					}
				}
			}
		}
		return field;
	}
    
   /*********************************************
    ------- CHARACTER COUNT - START -----
	*********************************************/
	$('.thwcfe-char-count').keyup(function(){
        display_char_count($(this), true);
	});
	
	$('.thwcfe-char-left').keyup(function(){
        display_char_count($(this), false);
	});
	
	function display_char_count(elm, isCount){
		var fid = elm.prop('id');
        var len = elm.val().length;
		var displayElm = $('#'+fid+"-char-count");
		
		if(isCount){
			displayElm.text('('+len+' characters)');
		}else{
			var maxLen = elm.prop('maxlength');
			var left = maxLen-len;
			displayElm.text('('+left+' characters left)');
			if(rem < 0){
				displayElm.css('color', 'red');
			}
		}
	}
   /*********************************************
    ------- CHARACTER COUNT - END -----
	*********************************************/
    
	
   /*********************************************
    ------- CONDITIONAL FIELD SETUP - START -----
	*********************************************/
	function thwcfe_set_field_value_by_id(elm, type, value){
		//TODO
	}
	function thwcfe_set_field_value_by_name(elm, type, value){
		//TODO
	}
	function thwcfe_set_field_value_by_elm(elm, type, value){
		switch(type){
			case 'radio':
				elm.val([value]);
				break;
			case 'checkbox':
				if(elm.data('multiple') == 1){
					value = value ? value : [];
					elm.val(value);
				}else{
					elm.val([value]);
				}
				break;
			case 'select':
				if(elm.prop('multiple')){
					elm.val(value);
				}else{
					elm.val([value]);
				}
				break;
			default:
				elm.val(value);
				break;
		}
	}
	
	function thwcfe_get_field_value(type, elm, name){
		var value = '';
		switch(type){
			case 'radio':
				value = $("input[type=radio][name='"+name+"']:checked").val();
				break;
			case 'checkbox':
				if(elm.data('multiple') == 1){
					var valueArr = [];
					$("input[type=checkbox][name='"+name+"[]']:checked").each(function(){
					   valueArr.push($(this).val());
					});
					value = valueArr;//.toString();
				}else{
					value = $("input[type=checkbox][name='"+name+"']:checked").val();
				}
				break;
			case 'select':
				value = elm.val();
				break;
			case 'multiselect':
				value = elm.val();
				break;
			default:
				value = elm.val();
				break;
		}
		return value;
	}
	
	
	/*$('.thwcfe-conditional-field').each(function(){
		validate_field_condition($(this), true);										 
	});*/
	
	function validate_field_condition(cfield, needSetup){
		var conditionalRules = cfield.data("rules");	
		var conditionalRulesAction = cfield.data("rules-action");
		var validations = cfield.data("validations");
		var valid = true;
		
		if(conditionalRules){
			try{
				jQuery.each(conditionalRules, function() {
					var ruleSet = this;	
					
					jQuery.each(ruleSet, function() {
						var rule = this;
						var validRS = false;
						
						jQuery.each(rule, function() {
							var conditions = this;								   	
							var validCS = true;
							
							jQuery.each(conditions, function() {
								validCS = validate_condition(this, validCS, needSetup, cfield);
							});
							
							validRS = validRS || validCS;
						});
						valid = valid && validRS;
					});
				});
			}catch(err) {
				alert(err);
			}
			
			if(conditionalRulesAction === 'hide'){
				if(valid){
					hide_field(cfield, validations);
				}else{
					show_field(cfield, validations);
				}
			}else{
				if(valid){
					show_field(cfield, validations);
				}else{
					hide_field(cfield, validations);
				}	
			}
		}
	}
	
	function hide_field(cfield, validations){
		var cinput = cfield.find(":input.thwcfe-input-field");
		if(cfield.getType() === 'hidden'){
			cinput = cfield;
		}
		var ftype = cinput.getType();
		
		var fid = cinput.prop('id');
		if(ftype == "radio"){
			fid = cinput.prop('name');
		}
		if(ftype == "checkbox"){
		    fid = cinput.prop('name');
		    fid = fid.replace("[]", "");   
		}
		
		cinput.data('current-value', thwcfe_get_field_value(ftype, cinput, fid));
		cfield.hide();	
		thwcfe_set_field_value_by_elm(cinput, ftype, '');
		cinput.addClass('thwcfe-disabled-field');
		cinput.change();
		
		if(ftype == "E001" && cfield.attr('data-name')){
			fid = cfield.data('name');
		}
		
		var disabled_fnames = $('#thwcfe_disabled_fields').val();
		var disabled_fnames_x = disabled_fnames ? disabled_fnames.split(",") : [];
		
		disabled_fnames_x.push(fid); 
		disabled_fnames = disabled_fnames_x.toString();
		
		$('#thwcfe_disabled_fields').val(disabled_fnames);
		
		//cfield.find(":input").val('mockvalthXXX'); //mockvalthXXX
		
		/**** COUNTRY field conditions issue workaround START ****/
		/*var cfieldId = cfield.prop('id');
		if(cfieldId == 'billing_country_field' || cfieldId == 'shipping_country_field'){
			var name = cfield.find("select").prop('id');
			if(name){
				var cssclass = name+'_hidden_field';
				if( cfield.find('.'+cssclass).length == 0 ){
					cfield.append( '<input type="hidden" id="'+name+'" name="'+name+'" value="mockvalthXXX" class="'+cssclass+'" />' );
				}
			}
		}*/
		/**** COUNTRY field conditions issue workaround END ****/
					
		//disable_field_ajax(cfield.find(":input").prop("name"));
		if(validations) {
			cfield.removeClass(validations);
			cfield.removeClass('woocommerce-validated woocommerce-invalid woocommerce-invalid-required-field');
		}
	}
	function show_field(cfield, validations){
		//var cinput = cfield.find(":input");
		var cinput = cfield.find(":input.thwcfe-input-field");
		if(cfield.getType() === 'hidden'){
			cinput = cfield;
		}
		var ftype = cinput.getType();
		
		var fid = cinput.prop('id');
		if(ftype == "radio"){
			fid = cinput.prop('name');
		}
		if(ftype == "checkbox"){
		    fid = cinput.prop('name');
		    fid = fid.replace("[]", "");   
		}
		
		cfield.show();	
		var fval = cinput.data('current-value');
		if(fval){
			thwcfe_set_field_value_by_elm(cinput, ftype, fval);
		}
		cinput.removeClass('thwcfe-disabled-field');
		cinput.change();
		//cfield.find(":input").val('');
		
		var disabled_fnames = $('#thwcfe_disabled_fields').val();
		var disabled_fnames_x = disabled_fnames ? disabled_fnames.split(",") : [];
		
		if(ftype == "E001" && cfield.attr('data-name')){
			fid = cfield.data('name');
		}
		
		disabled_fnames_x = jQuery.grep(disabled_fnames_x, function(value) {
		  	return value != fid; 
		});
		
		disabled_fnames = disabled_fnames_x.toString();
		
		$('#thwcfe_disabled_fields').val(disabled_fnames);
		
		/**** COUNTRY field conditions issue workaround START ****/
		/*var cfieldId = cfield.prop('id');
		if(cfieldId == 'billing_country_field' || cfieldId == 'shipping_country_field'){
			var name = cfield.find("select").prop('id');
			if(name){
				cfield.find('.'+name+'_hidden_field').remove();
			}
		}*/
		/**** COUNTRY field conditions issue workaround END ****/
		
		//enable_field_ajax(cfield.find(":input").prop("name"));
		cfield.removeClass('woocommerce-validated woocommerce-invalid woocommerce-invalid-required-field');
		if(validations) {
			cfield.addClass(validations);
		}
	}

	function validate_condition(condition, valid, needSetup, cfield){
		if(condition){
			var operand_type = condition.operand_type;
			var operand = condition.operand;
			var operator = condition.operator;
			var cvalue = condition.value;
			
			if(operand_type === 'field' && operand){
				jQuery.each(operand, function() {
					var field = getInputField(this);
					
					if(isInputField(field)){
						var ftype = field.getType();
						var value = thwcfe_get_field_value(ftype, field, this);//field.val();
												
						if(operator === 'empty' && value != ''){
							valid = false;
							
						}else if(operator === 'not_empty' && value == ''){
							valid = false;
							
						}else if(operator === 'value_eq' && value != cvalue){
							valid = false;
							
						}else if(operator === 'value_ne' && value == cvalue){
							valid = false;
							
						}else if(operator === 'value_gt'){
							if($.isNumeric(value) && $.isNumeric(cvalue)){
								valid = (Number(value) <= Number(cvalue)) ? false : valid;
							}else{
								valid = false;
							}
							
						}else if(operator === 'value_le'){
							if($.isNumeric(value) && $.isNumeric(cvalue)){
								valid = (Number(value) >= Number(cvalue)) ? false : valid;
							}else{
								valid = false;
							}
							
						}else if(operator === 'date_eq' && !is_date_eq(field, cvalue)){
							valid = false;
							
						}else if(operator === 'date_ne' && is_date_eq(field, cvalue)){
							valid = false;
							
						}else if(operator === 'date_gt' && !is_date_gt(field, cvalue)){
							valid = false;
							
						}else if(operator === 'date_lt' && !is_date_lt(field, cvalue)){
							valid = false;
							
						}else if(operator === 'day_eq' && !is_day_eq(field, cvalue)){
							valid = false;
							
						}else if(operator === 'day_ne' && is_day_eq(field, cvalue)){
							valid = false;
							
						}else if(operator === 'checked'){
							var checked = field.prop('checked');
							valid = checked ? valid : false;
							
						}else if(operator === 'not_checked'){
							var checked = field.prop('checked');
							valid = checked ? false : valid;
						}
						
						if(needSetup){
							var depFields = field.data("fields");
							if(depFields){
								var depFieldsArr = depFields.split(",");
								depFieldsArr.push(cfield.prop('id'));
								depFields = depFieldsArr.toString();
							}else{
								depFields = cfield.prop('id');
							}
							field.data("fields", depFields);
							add_field_value_change_handler(field);
						}
					}
				});
			}
		}
		return valid;
	}
	
	function add_field_value_change_handler(field){
		field.off("change", conditional_field_value_change_listner);
		field.on("change", conditional_field_value_change_listner);
	}
	
	function conditional_field_value_change_listner(event){
	    var depFields = $(this).data("fields");
		var depFieldsArr = depFields.split(",");
		depFieldsArr = remove_duplicates(depFieldsArr);
		jQuery.each(depFieldsArr, function() {
			if(this.length > 0){	
				var cfield = $('#'+this);
				validate_field_condition(cfield, false);	
			}
		});	
	}
	
	function remove_duplicates(arr){
	    var unique = arr.filter(function(elem, index, self) {
            return index == self.indexOf(elem);
        })   
        return unique;
	}
	
	function is_date_eq(field, cvalue){
		var result = compare_dates(field, cvalue);
		return (result != null && result === 0) ? true : false;
	}
	
	/*function is_date_ne(field, cvalue){
		var result = compare_dates(field, cvalue);
		return result ? true : false;
	}*/
	
	function is_date_gt(field, cvalue){
		var result = compare_dates(field, cvalue);
		return (result != null && result === 1) ? true : false;
	}
	
	function is_date_lt(field, cvalue){
		var result = compare_dates(field, cvalue);
		return (result != null && result === -1) ? true : false;
	}
	
	function is_day_eq(field, cvalue){
		var result = false;
		
		if(!isEmpty(cvalue)){
			var value = field.val();
			var format = field.data("date-format");
			var date = prepare_date(value, format, true);
			
			if(date){
				var day = date.getDay();
				//var daysArr = cvalue.split(",");
				if(isInt(cvalue)){
					cvalue = parseInt(cvalue);
					result = (day != null && day === cvalue) ? true : false;
				}else {
					cvalue = cvalue.toLowerCase();
					if($.inArray(cvalue, weekDays) >= 0){
						var daystring = weekDays[day];
						result = (daystring != null && daystring === cvalue) ? true : false;
					}
				}
			}
		}
		return result;
	}
	
	function compare_dates(field, cvalue){
		var result = null;
		var value = field.val();
		var format = field.data("date-format");
		
		if(isEmpty(value) || isEmpty(cvalue)){
			return null;
		}
		
		var d1 = prepare_date(value, format, true);
		var d2 = prepare_date(cvalue, format, false);
		
		if(d1 && d2){
			try{
				if(d1 > d2){
					result = 1; 
				}else if(d1 < d2){
					result = -1; 
				}else if(d1.getTime() === d2.getTime()){
					result = 0; 
				}
			}catch(err) {
				result = null;
			}
		}
		return result;
	}
	
	function prepare_date(dateStr, format, strict){
		var date = null;
		
		if(!isEmpty(dateStr)){
			try{
				date = $.datepicker.parseDate(format, dateStr);
				date.setHours(0,0,0,0);
			}catch(err) {
				if(!strict){
					var pattern = dateStr.split(" ");
					var years = null;
					var months = null;
					var days = null;
			
					if(pattern.length > 0){
						for(i = 0; i < pattern.length; i++) { 
							var x = pattern[i];
							x = x.toLowerCase();
							
							if(x.indexOf("y") != -1){
								x = x.replace(/y/gi, "");
								years = parseInt(x);
							}else if(x.indexOf("m") != -1){
								x = x.replace(/m/gi, "");
								months = parseInt(x);
							}else if(x.indexOf("d") != -1){
								x = x.replace(/d/gi, "");
								days = parseInt(x);
							}
						}
					}
					
					if(!isEmpty(years) || !isEmpty(months) || !isEmpty(days)){
						date = new Date();
						date.setHours(0,0,0,0);
						
						if(years && years != 0){
							date.setFullYear(date.getFullYear() + years);
						}
						if(months && months != 0){
							date.setMonth(date.getMonth() + months);
						}
						if(days && days != 0){
							date.setDate(date.getDate() + days);
						}
					}
				}
			}
		}
		
		return date;
	}
	
	function isEmpty(val){
		return (val === undefined || val == null || val.length <= 0) ? true : false;
	}
   /*********************************************
    ------- CONDITIONAL FIELD SETUP - END -------
	*********************************************/
	
   /****************************************
    ------- EXTRA COST FIELD - START -------
	****************************************/
	thwcfe_prepare_extra_cost_for_option_fields();
	//thwcfe_calculate_extra_cost();
	
	function thwcfe_setup_price_fields(wrapper){
		wrapper.find('.thwcfe-price-field').change(function(){
			//if(!$(this).hasClass("thwcfe-disabled-field")){																 
				var ftype = $(this).getType();	
				if(ftype == "select" || ftype == "radio"){
					thwcfe_prepare_extra_cost_from_selected_option($(this), ftype);
				}
				thwcfe_calculate_extra_cost();
			//}
			return false;
		});
	}
	thwcfe_setup_price_fields($('form[name="checkout"]'));
	
	/*$('.thwcfe-price-field').change(function(){
		//if(!$(this).hasClass("thwcfe-disabled-field")){																 
			var ftype = $(this).getType();	
			if(ftype == "select" || ftype == "radio"){
				thwcfe_prepare_extra_cost_from_selected_option($(this), ftype);
			}
			thwcfe_calculate_extra_cost();
		//}
        return false;
    });*/
	
	function thwcfe_prepare_extra_cost_for_option_fields(){
		$('.thwcfe-price-option-field').each(function(){										 
			thwcfe_prepare_extra_cost_from_selected_option($(this), 'select');
		});
	}
	
	function thwcfe_prepare_extra_cost_from_selected_option(elm, ftype){
		var option = elm.find(':selected');
		var oPrice = '';
		var oPriceType = '';
		
		if(elm.attr("multiple")){
			elm.find('option:selected').each(function(){
				oprice = $(this).data('price');
				opriceType = $(this).data('price-type');	
				if(oprice){
					opriceType = opriceType ? opriceType : 'normal';
					
					if(oPrice.trim()){
						oPrice += ',';
					}
					
					if(oPriceType.trim()){
						oPriceType += ',';
					}
					
					oPrice += oprice;
					oPriceType += opriceType;
				}
			});
		}else{
			oPrice = option.data('price');
			oPriceType = option.data('price-type');
			oPriceType = oPriceType ? oPriceType : 'normal';
		}
		
		if(oPrice){
			elm.data("price", oPrice);		
			elm.data("price-type", oPriceType);
		}else{
			if(ftype == "select"){
				elm.data("price", "");		
				elm.data("price-type", "");
			}
		}
	}
	
	function thwcfe_calculate_extra_cost(){
		var priceInfoArr = {};									 	
		$('.thwcfe-price-field:not(.thwcfe-disabled-field)').each(function(){	
			if(!$(this).hasClass("thwcfe-disabled-field")){
				var ftype = $(this).getType();
				var multiple = 0;
				
				var value = $(this).val();
				if(ftype == 'radio' || ftype == 'checkbox'){
					value = $(this).is(':checked') ? value : '';
				}else if(ftype == "select"){
					if($(this).attr("multiple")){
						multiple = 1;
					}
				}
				
				var name = $(this).prop("id");
				var label = $(this).data("price-label");
				var valueText = value;
				var qtyField = '';
				var price = $(this).data("price");		
				var priceType = $(this).data("price-type");
				var priceUnit = $(this).data("price-unit");
				var taxable = $(this).data("taxable");
				var tax_class = $(this).data("tax_class");
				
				if(priceType && priceType === 'dynamic'){
					if(!$.isNumeric(priceUnit) && $('#'+priceUnit).length){
						qtyField = $('#'+priceUnit).val();
						priceUnit = 1;
					}
				}else{
					priceUnit = 0;
				}
				
				if(value && name && (price || (priceType && priceType === 'custom'))){
					var priceInfo = {};
					priceInfo['name'] = name;
					priceInfo['label'] = label+' ('+valueText+')';
					priceInfo['price'] = price;
					priceInfo['price_type'] = priceType;
					priceInfo['price_unit'] = priceUnit;
					priceInfo['value'] = value;
					priceInfo['qty_field'] = qtyField;
					priceInfo['taxable'] = taxable;
					priceInfo['tax_class'] = tax_class;
					priceInfo['multiple'] = multiple;
					
					priceInfoArr[name] = priceInfo;
				}
			}
		});
		
		var data = {
            action: 'thwcfe_calculate_extra_cost',
			price_info: JSON.stringify(priceInfoArr)
        };

        currRequest = $.ajax({
            type: 'POST',
            url : wcfe_checkout_fields.ajax_url,
            data: data,
			beforeSend : function()    {           
				if(currRequest != null) {
					currRequest.abort();
				}
			},
            success: function(code){
            	$('body').trigger('update_checkout');
				//$( document.body ).trigger( 'update_checkout' );
				//wc_checkout_form.trigger_update_checkout();
            }
        });
	}
	
	setTimeout(function() { 
		$('.thwcfe-conditional-field').each(function(){
			validate_field_condition($(this), true);										 
		});
		thwcfe_calculate_extra_cost();
	}, 500);
   /****************************************
    ------- EXTRA COST FIELD - END ---------
	****************************************/
		
});