var thwcfe_public_base = (function($, window, document) {
	'use strict';
	
	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"];
	
	Date.prototype.addDays = function(days) {
		this.setDate(this.getDate() + parseInt(days));
		return this;
	};
	
	$.fn.getType = function(){
		try{
			return this[0].tagName == "INPUT" ? this[0].type.toLowerCase() : this[0].tagName.toLowerCase(); 
		}catch(err) {
			return 'E001';
		}
	}
	
	function remove_duplicates(arr){
	    var unique = arr.filter(function(elem, index, self) {
            return index == self.indexOf(elem);
        })   
        return unique;
	}
	
	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 isEmpty(val){
		return (val === undefined || val == null || val.length <= 0) ? true : false;
	}
				
	function may_parse_date(dateStr){
		if(DATE_FORMAT_1.test(dateStr)){
			var date = new Date(dateStr);
			if(date){
				return date;
			}
		}
		return dateStr;
	}
	
	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(var 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.getYear() + years);
						}
						if(months && months != 0){
							date.setMonth(date.getMonth() + months);
						}
						if(days && days != 0){
							date.setDate(date.getDate() + days);
						}
					}
				}
			}
		}
		return date;
	}
	
	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 isSameDate(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;
	}
	
	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 setup_enhanced_select(form, class_selector){
		form.find('select.'+class_selector).select2({
			minimumResultsForSearch: 10,
			allowClear : true,
			placeholder: $(this).data('placeholder')
		}).addClass('enhanced');
	}
	
	/******************************************
	***** DATE PICKER FUNCTIONS - START *******
	******************************************/
	function calculate_minutes_from_hr_min(_hour, _min){
		var minutes = null;
		if(isInt(_hour) && isInt(_min)){
			minutes = (_hour*60) + _min;
		}
		return minutes;
	}
	
	function get_minutes_from_time_24hr(time){
		var minutes = null;
		var timeArr = time.split(":");
		if(timeArr.length == 2){
			var _hour = parseInt(timeArr[0]);
			var _min = parseInt(timeArr[1]);
			minutes = calculate_minutes_from_hr_min(_hour, _min);
		}
		return minutes;
	}
	
	function no_sundays(date) {
		var day = date.getDay();
		return [day != 0, ''];
	}
	function no_saturdays(date) {
		var day = date.getDay();
		return [day != 6, ''];
	}
	function no_weekends(date) {
		return $.datepicker.noWeekends(date);
	}
	function no_christmas(date) {
		var day = date.getDate();
		var month = date.getMonth() + 1;
		return [!(day === 25 && month === 12), ''];
	}
	function no_new_years_day(date) {
		var day = date.getDate();
		var month = date.getMonth() + 1;
		return [!(day === 1 && month === 1), ''];
	}
	function no_holidays(date) {
		var datestring = $.datepicker.formatDate('yy-mm-dd', date);
    	return [ holidays.indexOf(datestring) == -1, '' ];
	}
	
	function no_weekends_or_holidays(date) {
		var noWeekend = $.datepicker.noWeekends(date);
		if (noWeekend[0]) {
			return no_holidays(date);
		} else {
			return noWeekend;
		}
	}
	
	function no_specific_days(date, disableDays) {
		var day = date.getDay();
		var daystring = weekDays[day];
    	return [ disableDays.indexOf(daystring) == -1, '' ];
	}
	
	function no_specific_dates(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(isSameDate(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 = calculate_minutes_from_hr_min(_hour, _min);
				var minutes = get_minutes_from_time_24hr(datestring);
				
				if(isInt(minutes) && isInt(_minutes)){
					if((op === "eq" && _minutes == minutes) || (op === "gt" && _minutes > minutes) || (op === "lt" && _minutes < minutes)){
						return [false, ''];
					}
				}
			}
		}
		return [true, ''];
	}
	
	function disable_dates(date){
		var disabledDays = $(this).data("disabled-days");
		if(disabledDays && disabledDays.length > 0){
			var daysArr = disabledDays.split(",");
			var disabledDay = no_specific_days(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 (var i = 0; i < datesArr.length; i++) { 
					var disabledDate = no_specific_dates(date, datesArr[i].trim());
					if(!disabledDate[0]) {
						return disabledDate;
					}
				}
			}
		}
		
		return [true, ''];
	}
	
	function setup_date_picker(form, class_selector, data){
		form.find('.'+class_selector).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");
			
			maxDate = may_parse_date(maxDate);
			minDate = may_parse_date(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[data.language]);
			$(this).datepicker("option", "dateFormat", dateFormat);
			$(this).datepicker("option", "beforeShowDay", disable_dates);
			$(this).datepicker("setDate", defaultDate);

			if(data.readonly_date_field){
				$(this).prop('readonly', true);
			}
		});
	}
	/******************************************
	***** DATE PICKER FUNCTIONS - END *********
	******************************************/
	
    /******************************************
	***** TIME PICKER FUNCTIONS - START *******
	******************************************/
	function split_hour_min(hourMinStr){
		var hours = 0;
		var minutes = 0;
		
		if(hourMinStr && (typeof hourMinStr === 'string' || hourMinStr instanceof String)){
			var _hourMin = hourMinStr.split(" ");
			
			if(_hourMin.length > 0){
				for(var 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 get_start_hr_min(startTime){
		var timeInfo = {};
		if(startTime){
			var startTimeArr = split_hour_min(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;		
	}
	
	function get_time_suffix(time){
		var suffix = "";
		if(time){
			time = time.toLowerCase();
			if(time.indexOf("am") != -1){
				suffix = "am";
			}else if(time.indexOf("pm") != -1){
				suffix = "pm";
			}
		}
		return suffix;
	}
		
	function split_time_string(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 split_time_string_12hr(time){
		var ampm = get_time_suffix(time);
		return split_time_string(time, ampm);
	}
	
	function get_disabled_time_ranges(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 disable_all_time_slots(tp, minTime, maxTime){
		var suffixMaxTime = get_time_suffix(maxTime);
		var maxTimeArr = split_time_string(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 adjust_time_slots_based_on_date_selected(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 = get_start_hr_min(startTime);
		if(startTimeArr){
			var startDate = startTimeArr["startDate"];
			
			if(dp != null && dpDate < startDate){
				disable_all_time_slots(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 = split_time_string_12hr(minTime);
				var minHour = minTimeArr[0];
				var minMin = minTimeArr[1];
				
				var maxTimeArr = split_time_string_12hr(maxTime);
				var maxHour = maxTimeArr[0];
				var maxMin = maxTimeArr[1];
				
				var startHour = startTimeArr["startHour"];
				var startMin = startTimeArr["startMin"];
						
				if(startHour > maxHour || (startHour == maxHour && startMin > maxMin)){
					disable_all_time_slots(tp, minTime, maxTime);					
				}else if(startHour < minHour || (startHour == minHour && startMin < minMin)){
					tp.timepicker('option', 'disableTimeRanges', []);
				}else{
					var disabledTimeRanges = get_disabled_time_ranges(minTimeArr, maxTimeArr, startTimeArr);
					tp.timepicker('option', 'disableTimeRanges', disabledTimeRanges);
				}				
			}
		}
	}
	
	function setup_time_picker(form, class_selector, data){
		form.find('.'+class_selector).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,
				'lang': data.lang
			}		
			$(this).timepicker(args);
			//$(this).timepicker('option', 'minTime', tpMinTime(format, step, minTime, maxTime, startTime));
			
			if(linkedDate){
				var dp = $("#"+linkedDate);
				if( dp.length ) {
					adjust_time_slots_based_on_date_selected(dp, $(this));
				}
			}else{
				adjust_time_slots_based_on_date_selected(null, $(this));	
			}
		});
	}
    /******************************************
	***** TIME PICKER FUNCTIONS - END *********
	******************************************/
	
	/********************************************
	***** CHARACTER COUNT FUNCTIONS - START *****
	********************************************/
	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 FUNCTIONS - END *****
	******************************************/
	
	function 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 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;
	}
	
	return {
		setup_enhanced_select : setup_enhanced_select,
		setup_date_picker : setup_date_picker,
		setup_time_picker : setup_time_picker,
		display_char_count : display_char_count,
		remove_duplicates : remove_duplicates,
		set_field_value_by_elm : set_field_value_by_elm,
		get_field_value : get_field_value,
		is_date_eq : is_date_eq,
		is_date_gt : is_date_gt,
		is_date_lt : is_date_lt,
		is_day_eq : is_day_eq,
	};
}(window.jQuery, window, document));

var thwcfe_public_conditions = (function($, window, document) {
	'use strict';
	
	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_public_base.get_field_value(ftype, cinput, fid));
		cfield.hide();	
		thwcfe_public_base.set_field_value_by_elm(cinput, ftype, '');
		cinput.addClass('thwcfe-disabled-field');
		cinput.change();
		
		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);
		
		//disable_field_ajax(cfield.find(":input").prop("name"));
		if(validations) {
			cfield.removeClass(validations);
			cfield.removeClass('woocommerce-validated woocommerce-invalid woocommerce-invalid-required-field'); //TODO check for correct class names
		}
		/*if(cinput.hasClass("thwcfe-price-field")){
			thwcfe_calculate_extra_cost();
		}*/
	}
	
	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_public_base.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(",") : [];
		
		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);
		
		//enable_field_ajax(cfield.find(":input").prop("name"));
		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 = false;
					
					if(this == 'product_variation'){
						if(cvalue != ''){
							var variation_arr = cvalue.split(":");
							if(variation_arr.length == 2){
								var fid = variation_arr[0] ? variation_arr[0].trim() : '';
								cvalue = variation_arr[1] ? variation_arr[1].trim() : '';
								if(fid){
									fid = fid.replace(/\s+/g, '-').toLowerCase();
									field = $('#'+fid);
								}
							}
						}
					}else{
						var field = $('#'+this);
						if(field.length == 0){
							field = $("input[name='"+this+"']");
							if(field.length == 0){
								field = $("input[name='"+this+"[]']");
							}
						}
					}
					
					if(field){
						var ftype = field.getType();
						var value = thwcfe_public_base.get_field_value(ftype, field, this);
											
						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' && !thwcfe_public_base.is_date_eq(field, cvalue)){
							valid = false;
							
						}else if(operator === 'date_ne' && thwcfe_public_base.is_date_eq(field, cvalue)){
							valid = false;
							
						}else if(operator === 'date_gt' && !thwcfe_public_base.is_date_gt(field, cvalue)){
							valid = false;
							
						}else if(operator === 'date_lt' && !thwcfe_public_base.is_date_lt(field, cvalue)){
							valid = false;
							
						}else if(operator === 'day_eq' && !thwcfe_public_base.is_day_eq(field, cvalue)){
							valid = false;
							
						}else if(operator === 'day_ne' && thwcfe_public_base.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 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 conditional_field_value_change_listner(event){
	    var depFields = $(this).data("fields");
		var depFieldsArr = depFields.split(",");
		depFieldsArr = thwcfe_public_base.remove_duplicates(depFieldsArr);
		
		jQuery.each(depFieldsArr, function() {
			if(this.length > 0){	
				var cfield = $('#'+this);
				validate_field_condition(cfield, false);	
			}
		});	
	}
	
	function add_field_value_change_handler(field){
		field.off("change", conditional_field_value_change_listner);
		field.on("change", conditional_field_value_change_listner);
	}
	
	return {
		validate_field_condition : validate_field_condition,
	};
}(window.jQuery, window, document));

var thwepo_public_price = (function($, window, document) {
	'use strict';
	
	var currRequest = null;
	
	function setup_price_fields(args){
		prepare_extra_cost_for_option_fields();
		//calculate_extra_cost(args);
		
		$('.thwcfe-price-field').change(function(){
			var ftype = $(this).getType();	
			if(ftype == "select" || ftype == "radio"){
				prepare_extra_cost_from_selected_option($(this), ftype);
			}
			calculate_extra_cost();
			return false;
		});
	}
	
	function prepare_extra_cost_for_option_fields(){
		$('.thwepo-price-option-field').each(function(){										 
			prepare_extra_cost_from_selected_option($(this), 'select');
		});
	}
	
	function 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(){
				var _oprice = $(this).data('price');
				var _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 calculate_extra_cost(args){
		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)
        };

        $.ajax({
            type: 'POST',
            url : wcfe_checkout_fields.ajax_url,
            data: data,
            success: function(code){
            	$('body').trigger('update_checkout');
				//$( document.body ).trigger( 'update_checkout' );
				//wc_checkout_form.trigger_update_checkout();
            }
        });
	}
	
	return {
		setup_price_fields : setup_price_fields,
		calculate_extra_cost : calculate_extra_cost,
	};
}(window.jQuery, window, document));

(function( $ ) {
	'use strict';

	function initialize_thwepo(){
		var extra_options_wrapper = $('.extra-options');
		if(extra_options_wrapper){
			thwepo_public_base.setup_enhanced_select(extra_options_wrapper, 'thwepo-enhanced-multi-select');
			thwepo_public_base.setup_enhanced_select(extra_options_wrapper, 'thwepo-enhanced-select');
			thwepo_public_base.setup_date_picker(extra_options_wrapper, 'thwepo-date-picker', thwepo_public_var);
			thwepo_public_base.setup_time_picker(extra_options_wrapper, 'thwepo-time-picker', thwepo_public_var);										 
					
			/***** CHARACTER COUNT - START -----***/
			$('.thwepo-char-count .thwepo-input-field').keyup(function(){
				thwepo_public_base.display_char_count($(this), true);
			});
			
			$('.thwepo-char-left .thwepo-input-field').keyup(function(){
				thwepo_public_base.display_char_count($(this), false);
			});
			
			/***** CONDITIONAL FIELD SETUP - START *****/
			$('.thwepo-conditional-field').each(function(){
				thwepo_public_conditions.validate_field_condition($(this), true);										 
			});
			
			/***** EXTRA COST FIELD - START -------***/
			// Fired when the user selects all the required dropdowns / attributes and a final variation is selected / shown
			$( ".single_variation_wrap" ).on( "show_variation", function ( event, variation ) {
				thwepo_public_price.calculate_extra_cost(thwepo_public_var);
			});
			thwepo_public_price.setup_price_fields(thwepo_public_var);
		}
	}
	
	/***----- INIT -----***/
	initialize_thwepo();
	
	if(thwepo_public_var.is_quick_view){
		$( document).on( "qv_loader_stop", function() {
			initialize_thwepo();
		});
	}

})( jQuery );
