Server : LiteSpeed
System : Linux server104.web-hosting.com 4.18.0-513.24.1.lve.1.el8.x86_64 #1 SMP Thu May 9 15:10:09 UTC 2024 x86_64
User : saleoqej ( 6848)
PHP Version : 8.0.30
Disable Function : NONE
Directory :  /home/saleoqej/public_html/wp-content/plugins/thrive-leads/inc/
Upload File :
Current Directory [ Writeable ] Root Directory [ Writeable ]


Current File : /home/saleoqej/public_html/wp-content/plugins/thrive-leads/inc/data.php
<?php
/**
 * contains all data-related functions for the plugin
 *
 */

/**
 *
 * get all the existing lead groups
 *
 * @param array $filter    {
 *                         Optional. Arguments to retrieve lead groups. Available options:
 *
 * @type bool   $full_data - whether to retrieve or not the full data (including form_types)
 *                         }
 * @return array list of all saved groups
 */
function tve_leads_get_groups( $filter = array() ) {
	global $tvedb;
	$defaults = array(
		'full_data'       => true,
		'tracking_data'   => true,
		'completed_tests' => true,
		'active_tests'    => true,
		'no_content'      => false,
	);

	$filter = array_merge( $defaults, $filter );

	$posts = get_posts( array(
		'posts_per_page' => - 1,
		'post_type'      => TVE_LEADS_POST_GROUP_TYPE,
		'meta_key'       => 'tve_group_order',
		'orderby'        => 'meta_value_num',
		'order'          => 'ASC',
	) );

	foreach ( $posts as $post ) {
		if ( ! empty( $filter['tracking_data'] ) ) {
			$post->impressions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_UNIQUE_IMPRESSION );
			$post->conversions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_CONVERSION );
			$post->conversion_rate = tve_leads_conversion_rate( $post->impressions, $post->conversions );
		}
		if ( ! empty( $filter['active_tests'] ) ) {
			$post->active_tests = tve_leads_get_group_active_tests( $post->ID );
		}
		if ( ! empty( $filter['completed_tests'] ) ) {
			$post->completed_tests = tve_leads_get_group_completed_tests( $post->ID );
		}
		$post->order = intval( get_post_meta( $post->ID, 'tve_group_order', true ) );
		if ( ! empty( $filter['full_data'] ) ) {
			$post->form_types = tve_leads_get_form_types( array(
				'lead_group_id'  => $post->ID,
				'tracking_data'  => $filter['tracking_data'],
				'get_variations' => true,
				'no_content'     => $filter['no_content'],
			) );

			$total_form_types  = 0;
			$display_on_mobile = 0;
			$display_status    = 0;
			foreach ( $post->form_types as $form ) {
				$total_form_types  += empty( $form->ID ) ? 0 : 1;
				$display_on_mobile += isset( $form->display_on_mobile ) ? $form->display_on_mobile : 0;
				$display_status    += isset( $form->display_status ) ? $form->display_status : 0;
			}

			if ( $display_on_mobile == 0 ) {
				$post->display_on_mobile = __( 'No', 'thrive-leads' );
			} else if ( $display_on_mobile == $total_form_types ) {
				$post->display_on_mobile = __( 'Yes', 'thrive-leads' );
			} else {
				$post->display_on_mobile = __( 'Custom', 'thrive-leads' );
			}

			if ( $display_status == 0 ) {
				$post->display_status = __( 'No', 'thrive-leads' );
			} else if ( $display_status == $total_form_types ) {
				$post->display_status = __( 'Yes', 'thrive-leads' );
			} else {
				$post->display_status = __( 'Custom', 'thrive-leads' );
			}
		}
		$post->has_display_settings = $tvedb->has_display_settings( $post->ID ) == null ? 0 : 1;
	}

	return $posts;
}

/**
 * get a list of ids from all the existing lead groups
 *
 * @return array
 */
function tve_leads_get_group_ids() {
	$groups          = array();
	$all_lead_groups = tve_leads_get_groups( array(
		'full_data'       => false,
		'tracking_data'   => false,
		'active_tests'    => false,
		'completed_tests' => false,
	) );
	foreach ( $all_lead_groups as $lead_group ) {
		array_push( $groups, $lead_group->ID );
	}

	return $groups;
}

/**
 *
 * get one lead group by id
 *
 * @param int   $id        id of the group
 * @param array $filter    {
 *                         Optional. Arguments to retrieve lead groups. Available options:
 *
 * @type bool   $full_data - whether to retrieve or not the full data (including form_types)
 *                         }
 * @return WP_Post|null
 */
function tve_leads_get_group( $id, $filter = array() ) {
	$defaults = array(
		'full_data'       => true,
		'get_variations'  => true,
		'tracking_data'   => false,
		'completed_tests' => false,
		'active_tests'    => false,
	);

	$filter = array_merge( $defaults, $filter );
	$post   = get_post( $id );
	if ( empty( $post ) ) {
		return null;
	}

	if ( ! empty( $filter['tracking_data'] ) ) {
		$post->impressions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_UNIQUE_IMPRESSION );
		$post->conversions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_CONVERSION );
		$post->conversion_rate = tve_leads_conversion_rate( $post->impressions, $post->conversions );
	}
	if ( ! empty( $filter['active_tests'] ) ) {
		$post->active_tests = tve_leads_get_group_active_tests( $post->ID );
	}
	if ( ! empty( $filter['completed_tests'] ) ) {
		$post->completed_tests = tve_leads_get_group_completed_tests( $post->ID );
	}
	$post->order = (int) get_post_meta( $post->ID, 'tve_group_order', true );
	if ( ! empty( $filter['full_data'] ) ) {
		$post->form_types  = tve_leads_get_form_types( array(
			'lead_group_id'  => $post->ID,
			'tracking_data'  => $filter['tracking_data'],
			'get_variations' => $filter['get_variations'],
		) );
		$display_on_mobile = 0;
		foreach ( $post->form_types as $form ) {
			$display_on_mobile += isset( $form->display_on_mobile ) ? $form->display_on_mobile : 1;
		}
		if ( $display_on_mobile == 0 ) {
			$post->display_on_mobile = __( 'No', 'thrive-leads' );
		} else if ( $display_on_mobile == 5 ) {
			$post->display_on_mobile = __( 'Yes', 'thrive-leads' );
		} else {
			$post->display_on_mobile = __( 'Custom', 'thrive-leads' );
		}
	}

	return $post;
}

/**
 * Gets the tve_leads_shortcode posts from database and returns them
 *
 * @return array
 */
function tve_leads_get_shortcodes( $filter = array() ) {

	$defaults = array(
		'active_test'    => false,
		'tracking_data'  => false,
		'get_variations' => false,
	);

	$filter = array_merge( $defaults, $filter );

	$posts = get_posts( array(
		'posts_per_page' => - 1,
		'post_type'      => TVE_LEADS_POST_SHORTCODE_TYPE,
		'orderby'        => 'meta_value_num',
		'order'          => 'ASC',
	) );

	foreach ( $posts as $post ) {
		if ( ! empty( $filter['active_test'] ) ) {
			$post->active_test = tve_leads_get_form_active_test( $post->ID, array(
				'test_type' => TVE_LEADS_SHORTCODE_TEST_TYPE,
			) );
		}
		if ( ! empty( $filter['tracking_data'] ) ) {
			$post->impressions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_UNIQUE_IMPRESSION );
			$post->conversions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_CONVERSION );
			$post->conversion_rate = tve_leads_conversion_rate( $post->impressions, $post->conversions );
		}
		if ( ! empty( $filter['get_variations'] ) ) {
			$post->variations = tve_leads_get_form_variations( $post->ID, array(
				'tracking_data' => false,
			) );
		}

		$post->content_locking = get_post_meta( $post->ID, 'tve_content_locking', true );
		$post->content_locking = $post->content_locking == '' ? 0 : intval( $post->content_locking );
		$post->shortcode_code  = ( $post->content_locking == 1 ) ? '[thrive_lead_lock id=\'' . $post->ID . '\']Hidden Content[/thrive_lead_lock]' : '[thrive_leads id=\'' . $post->ID . '\']';
	}

	return $posts;
}

/**
 * Gets the tve_leads_two_step_lightbox posts from database and returns them
 *
 * @param array $filter allows a way to control the output
 *
 * @return array
 */
function tve_leads_get_two_step_lightboxes( $filter = array() ) {
	$defaults = array(
		'active_test'    => false,
		'tracking_data'  => false,
		'get_variations' => false,
	);

	$filter = array_merge( $defaults, $filter );

	$posts = get_posts( array(
		'posts_per_page' => - 1,
		'post_type'      => TVE_LEADS_POST_TWO_STEP_LIGHTBOX,
		'orderby'        => 'meta_value_num',
		'order'          => 'ASC',
	) );

	foreach ( $posts as $post ) {
		if ( ! empty( $filter['active_test'] ) ) {
			$post->active_test = tve_leads_get_form_active_test( $post->ID, array(
				'test_type' => TVE_LEADS_TWO_STEP_LIGHTBOX_TEST_TYPE,
			) );
		}
		if ( ! empty( $filter['tracking_data'] ) ) {
			$post->impressions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_UNIQUE_IMPRESSION );
			$post->conversions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_CONVERSION );
			$post->conversion_rate = tve_leads_conversion_rate( $post->impressions, $post->conversions );
		}
		if ( ! empty( $filter['get_variations'] ) ) {
			$post->variations = tve_leads_get_form_variations( $post->ID, array(
				'tracking_data' => false,
			) );
		}
	}

	return $posts;
}

/**
 * Gets the tve_leads_two_step_lightbox posts from database and returns them
 *
 * @param array $filter allows a way to control the output
 *
 * @return array
 */
function tve_leads_get_asset_groups( $filter = array() ) {
	$defaults = array(
		'active_test' => false,
	);

	$filter = array_merge( $defaults, $filter );

	$posts = get_posts( array(
		'posts_per_page' => - 1,
		'post_type'      => TVE_LEADS_POST_ASSET_GROUP,
		'orderby'        => 'meta_value_num',
		'order'          => 'ASC',
	) );

	foreach ( $posts as $post ) {
		$post->order        = intval( get_post_meta( $post->ID, 'tve_asset_group_order', true ) );
		$post->files        = get_post_meta( $post->ID, 'tve_asset_group_files', true );
		$post->post_subject = get_post_meta( $post->ID, 'tve_asset_group_subject', true );
	}

	return $posts;
}

/**
 * Gets the tve_leads_one_click_signup posts from database and returns them
 *
 * @return array
 */
function tve_leads_get_one_click_signups() {
	$posts = get_posts( array(
		'posts_per_page' => - 1,
		'post_type'      => TVE_LEADS_POST_ONE_CLICK_SIGNUP,
		'orderby'        => 'meta_value_num',
		'order'          => 'ASC',
	) );

	foreach ( $posts as $post ) {
		$post->post_link       = get_permalink( $post->ID );
		$post->redirect_url    = (object) get_post_meta( $post->ID, 'tve_leads_redirect_url', true );
		$post->api_connections = get_post_meta( $post->ID, 'tve_leads_api_connections', true );
		$post->signups         = get_post_meta( $post->ID, 'tve_leads_signups', true );
	}

	return $posts;
}

/**
 * Get shortcode
 *
 * @param       $id
 * @param array $filters
 *
 * @return WP_Post shortcode
 */
function tve_leads_get_shortcode( $id, $filters = array() ) {
	$defaults = array(
		'get_variations'      => false,
		'variations_archived' => false,
		'completed_tests'     => false,
	);

	$filters = array_merge( $defaults, $filters );

	$shortcode = get_post( $id );

	if ( ! $shortcode || ! $shortcode->ID || get_post_type( $shortcode ) !== TVE_LEADS_POST_SHORTCODE_TYPE ) {
		return null;
	}

	if ( ! empty( $filters['get_variations'] ) ) {
		$shortcode->variations = tve_leads_get_form_variations( $id, array(
			'tracking_data' => true,
		) );
	}

	if ( ! empty( $filters['variations_archived'] ) ) {
		$shortcode->variations_archived = tve_leads_get_form_variations( $id, array(
			'tracking_data' => true,
			'post_status'   => TVE_LEADS_STATUS_ARCHIVED,
		) );
	}

	if ( ! empty( $filters['completed_tests'] ) ) {
		$shortcode->completed_tests = tve_leads_get_completed_form_test( $shortcode, TVE_LEADS_SHORTCODE_TEST_TYPE );
	}

	$shortcode->content_locking = get_post_meta( $shortcode->ID, 'tve_content_locking', true );
	$shortcode->content_locking = empty( $shortcode->content_locking ) ? 0 : intval( $shortcode->content_locking );

	return $shortcode;
}


/**
 * @param       $type
 * @param array $filter {
 *                      pass in additional filters for retrieving the data
 *                      }
 *
 * TODO: I think we'll need to cache this somehow
 *
 * @return mixed the value
 */
function tve_leads_get_tracking_data( $type, $filter = array() ) {
	global $tvedb;

	$column = $type === TVE_LEADS_CONVERSION ? 'conversion' : 'impression';

	return $tvedb->get_summary_count( $column, $filter );
}

/**
 * get all "form_type" posts based on a $params filter
 * usually, $params should hold the parent Lead Group id
 *
 * @param $params
 *
 * @return mixed
 */
function tve_leads_get_form_types( $params = array() ) {
	$defaults = array(
		'tracking_data'  => true,
		'get_variations' => false,
		'no_content'     => false,
	);

	$posts = get_posts( array(
		'numberposts' => - 1,
		'post_type'   => TVE_LEADS_POST_FORM_TYPE,
		'post_parent' => isset( $params['lead_group_id'] ) ? $params['lead_group_id'] : 0,
		/* #perf removed `meta_key` - this only causes an extra join with the postmeta table which will be slow on a website with many posts */
		/*'meta_key'         => 'tve_form_type',*/
	) );

	$params = array_merge( $defaults, $params );

	$available = tve_leads_get_default_form_types();
	$existing  = array();

	foreach ( $posts as $post ) {
		if ( ! empty( $params['tracking_data'] ) ) {
			$post->impressions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_UNIQUE_IMPRESSION );
			$post->conversions     = tve_leads_get_post_tracking_data( $post, TVE_LEADS_CONVERSION );
			$post->conversion_rate = tve_leads_conversion_rate( $post->impressions, $post->conversions );
			$post->active_test     = tve_leads_get_form_active_test( $post->ID );

			//by default, when an option is not set, a form type is displayed on mobile
			$display_on_mobile       = get_post_meta( $post->ID, 'display_on_mobile', true );
			$post->display_on_mobile = $display_on_mobile == '' ? 1 : intval( $display_on_mobile );

			//by default, when an option is not set, a form type status is enabled
			$display_status       = get_post_meta( $post->ID, 'display_status', true );
			$post->display_status = $display_status == '' ? 1 : intval( $display_status );
		}
		$post->tve_form_type = get_post_meta( $post->ID, 'tve_form_type', true );
		if ( ! empty( $params['get_variations'] ) ) {
			$post->variations = tve_leads_get_form_variations( $post->ID, array(
				'tracking_data' => false,
				'no_content'    => $params['no_content'],
			) );
		}

		if ( isset( $available[ $post->tve_form_type ]['video_link'] ) ) {
			$post->video_link = $available[ $post->tve_form_type ]['video_link'];
		}

		$existing[ $post->tve_form_type ] = $post;
	}

	$actual = array_merge( $available, $existing );

	return array_values( $actual );
}

/**
 * get all published form variations for a FormType
 *
 * @param int   $ID the FormType id
 * @param array $filters
 *
 * @return mixed
 */
function tve_leads_get_form_variations( $ID, $filters = array() ) {
	global $tvedb;

	$defaults = array(
		'tracking_data'      => true,
		'post_status'        => TVE_LEADS_STATUS_PUBLISH,
		'get_control'        => false,
		'active_for_test_id' => false,
	);

	$filters = array_merge( $defaults, $filters );

	$variations = $tvedb->get_form_variations( array(
		'post_parent'        => $ID,
		'post_status'        => $filters['post_status'],
		'limit'              => empty( $filters['get_control'] ) ? null : 1,
		'offset'             => 0,
		'order'              => 'key ASC',
		'active_for_test_id' => $filters['active_for_test_id'],
	), false );

	foreach ( $variations as $k => $variation ) {
		if ( ! empty( $filters['tracking_data'] ) ) {
			$variations[ $k ]['impressions'] = $impressions = tve_leads_get_variation_tracking_data( $variation, TVE_LEADS_UNIQUE_IMPRESSION );
			$variations[ $k ]['conversions'] = $conversions = tve_leads_get_variation_tracking_data( $variation, TVE_LEADS_CONVERSION );
			if ( ! empty( $variation['save_flag'] ) ) {
				$tvedb->update_variation_fields( $variations[ $k ], array(
					'cache_impressions' => $impressions,
					'cache_conversions' => $conversions,
				) );
			}
			$variations[ $k ]['conversion_rate'] = tve_leads_conversion_rate( $impressions, $conversions );
		}

		if ( ! empty( $filters['no_content'] ) ) {
			$variations[ $k ]['content'] = ! empty( $variations[ $k ]['content'] );
		}

		$variations[ $k ]['tcb_edit_url']    = tve_leads_get_editor_url( $ID, $variation['key'] );
		$variations[ $k ]['tcb_preview_url'] = tve_leads_get_preview_url( $ID, $variation['key'] );

		if ( empty( $variation['trigger'] ) ) {
			$variation['trigger'] = $variations[ $k ]['trigger'] = 'page_load';
		}

		$variations[ $k ]['trigger_nice_name']           = tve_leads_trigger_nice_name( $variation );
		$variations[ $k ]['display_frequency_nice_name'] = tve_leads_frequency_nice_name( $variation );
		$variations[ $k ]['display_position_nice_name']  = tve_leads_position_nice_name( $variation );
		$variations[ $k ]['display_animation_nice_name'] = tve_leads_animation_nice_name( $variation );
		$variations[ $k ]['content_lock_display']        = in_array( $variation['display_animation'], array(
			'hide',
			'blur',
		) ) ? $variation['display_animation'] : 'hide';

		$variations[ $k ]['is_control'] = ! isset( $control ); // the first one is always the control
		if ( ! empty( $filters['get_control'] ) ) {
			return $variations[ $k ];
		}
		$control = false;
	}

	return $variations;
}

/**
 * Return an array of variation keys that do don't have a template selected
 *
 * @param $form_id
 *
 * @return array ids
 */
function tve_leads_get_form_empty_variations( $form_id ) {
	$variations = tve_leads_get_form_variations( $form_id, array( 'tracking_data' => false ) );
	$ids        = array();
	foreach ( $variations as $v ) {
		if ( ! empty( $v[ TVE_LEADS_FIELD_TEMPLATE ] ) ) {
			continue;
		}
		$ids [] = (int) $v['key'];
	}

	return $ids;
}

/**
 * Return an array of the form_types that don't have a design in the specified group
 *
 * @param $group_id The group id where we search for forms with no design
 *
 * @return array
 */
function tve_leads_get_group_empty_form_variations( $group_id ) {

	$form_types = tve_leads_get_form_types( array(
		'lead_group_id'  => $group_id,
		'tracking_data'  => false,
		'get_variations' => true,
	) );

	$ids = array();
	foreach ( $form_types as $form ) {
		if ( isset( $form->variations ) ) {
			foreach ( $form->variations as $variation ) {
				if ( $variation['is_control'] && empty( $variation[ TVE_LEADS_FIELD_TEMPLATE ] ) ) {
					$ids [] = (int) $form->ID;
					break;
				}
			}
		}
	}

	return $ids;
}

/**
 * Delete posts like Group, Shortcode, 2 Step Lightbox and Asset Group (new name: ThriveBox)
 *
 * @param $group_id
 *
 * @return mixed
 */
function tve_leads_delete_post( $group_id ) {
	$post = get_post( $group_id );
	if ( empty( $post ) ) {
		return $group_id;
	}

	global $tvedb;

	if ( $post->post_type === TVE_LEADS_POST_GROUP_TYPE ) {
		$tvedb->delete_display_settings( array( 'group' => $group_id ) );

		// also delete Form Types under this group
		foreach ( tve_leads_get_form_types( array( 'lead_group_id' => $group_id, 'tracking_data' => false ) ) as $form_type ) {
			if ( is_a( $form_type, 'WP_Post' ) && ! empty( $form_type->ID ) ) {
				tve_leads_delete_post( $form_type->ID );
			}
		}
	}

	$tvedb->delete_tests( array( 'main_group_id' => $group_id ), array( 'delete_items' => true ) );
	$tvedb->delete_logs( array( 'main_group_id' => $group_id ) );
	$post->post_status = 'trash';

	do_action( 'tve_leads_delete_post', $post->ID );

	return wp_update_post( $post );
}

/**
 * Delete post meta (File relations) form Asset Groups (new name: ThriveBox)
 *
 * @param $post_id
 * @param $meta_id
 *
 * @return mixed
 */
function tve_leads_delete_asset_file( $post_id, $meta_id ) {
	$post_meta = get_post_meta( $post_id, 'tve_asset_group_files', true );

	foreach ( $post_meta as $k => $v ) {
		if ( $v["ID"] == $meta_id ) {
			unset( $post_meta[ $k ] );
		}
	}
	$new_meta = array_values( $post_meta );

	update_post_meta( $post_id, 'tve_asset_group_files', $new_meta );

	return $meta_id;
}

/**
 * create or update a Lead Group post
 *
 * can also be used to delete a lead group "internally", by setting the post_status to 'trash'
 *
 * @param $model
 *
 * @return int|WP_Error
 */
function tve_leads_save_group( $model ) {
	if ( ! empty( $model['ID'] ) ) {
		$lead_group = get_post( $model['ID'] );
		if ( $lead_group && get_post_type( $lead_group ) === TVE_LEADS_POST_GROUP_TYPE ) {
			wp_update_post( $model );
		}
		$id = $model['ID'];
	} else {
		$default = array(
			'post_type'   => TVE_LEADS_POST_GROUP_TYPE,
			'post_status' => 'publish',
		);
		$id      = wp_insert_post( array_merge( $default, $model ) );
		/**
		 * save these from here, as they will be 0 for new Lead Groups
		 */
		update_post_meta( $id, 'tve_leads_impressions', 0 );
		update_post_meta( $id, 'tve_leads_conversions', 0 );
	}

	if ( isset( $model['order'] ) ) {
		update_post_meta( $id, 'tve_group_order', (int) $model['order'] );
	}

	return $id;
}

/**
 * create or update a Lead Shortcode post
 *
 * can also be used to delete a lead group "internally", by setting the post_status to 'trash'
 *
 * @param $model
 *
 * @return int|WP_Error
 */
function tve_leads_save_shortcode( $model ) {
	if ( ! empty( $model['ID'] ) ) {
		$lead_shortcode = get_post( $model['ID'] );
		if ( $lead_shortcode && get_post_type( $lead_shortcode ) === TVE_LEADS_POST_SHORTCODE_TYPE ) {
			wp_update_post( $model );
		}
		$ID = $model['ID'];
	} else {
		$default = array(
			'post_type'   => TVE_LEADS_POST_SHORTCODE_TYPE,
			'post_status' => 'publish',
		);
		$ID      = wp_insert_post( array_merge( $default, $model ) );
		/**
		 * save these from here, as they will be 0 for new Shortcodes
		 */
		update_post_meta( $ID, 'tve_leads_impressions', 0 );
		update_post_meta( $ID, 'tve_leads_conversions', 0 );
	}

	if ( isset( $ID ) ) {
		update_post_meta( $ID, 'tve_form_type', 'shortcode' );
		update_post_meta( $ID, 'tve_content_locking', $model['content_locking'] );
	}

	return $ID;
}

/**
 * create or update a 2 Step Lightbox post (new name: ThriveBox)
 *
 * can also be used to delete a lead group "internally", by setting the post_status to 'trash'
 *
 * @param $model
 *
 * @return int|WP_Error
 */
function tve_leads_save_two_step_lightbox( $model ) {
	if ( ! empty( $model['ID'] ) ) {
		$two_step_lightbox = get_post( $model['ID'] );
		if ( $two_step_lightbox && get_post_type( $two_step_lightbox ) === TVE_LEADS_POST_TWO_STEP_LIGHTBOX ) {
			wp_update_post( $model );
		}
		$ID = $model['ID'];
	} else {
		$default = array(
			'post_type'   => TVE_LEADS_POST_TWO_STEP_LIGHTBOX,
			'post_status' => 'publish',
		);
		$ID      = wp_insert_post( array_merge( $default, $model ) );
		/**
		 * save these from here, as they will be 0 for newly created 2-step Lightboxes
		 */
		update_post_meta( $ID, 'tve_leads_impressions', 0 );
		update_post_meta( $ID, 'tve_leads_conversions', 0 );
	}

	if ( isset( $ID ) ) {
		update_post_meta( $ID, 'tve_form_type', 'two_step_lightbox' );
	}

	return $ID;
}

/**
 * create or update a Asset Group post (new name: ThriveBox)
 *
 * can also be used to delete a lead group "internally", by setting the post_status to 'trash'
 *
 * @param $model
 *
 * @return int|WP_Error
 */
function tve_leads_save_asset_group( $model ) {

	if ( ! empty( $model['ID'] ) ) {
		$asset_group = get_post( $model['ID'] );
		if ( $asset_group && get_post_type( $asset_group ) === TVE_LEADS_POST_ASSET_GROUP ) {
			wp_update_post( $model );
			if ( ! empty( $model['post_subject'] ) ) {
				update_post_meta( $model['ID'], 'tve_asset_group_subject', $model['post_subject'] );
			}
		}
		$ID = $model['ID'];
	} else {
		$default = array(
			'post_type'   => TVE_LEADS_POST_ASSET_GROUP,
			'post_status' => 'publish',
		);
		$ID      = wp_insert_post( array_merge( $default, $model ) );
	}

	return $ID;
}

function tve_leads_update_asset_files( $model ) {
	if ( ! empty( $model['ID'] ) || $model['ID'] == "0" ) {
		$ID          = $model['parent_ID'];
		$asset_group = get_post( $ID );
		if ( $asset_group && get_post_type( $asset_group ) === TVE_LEADS_POST_ASSET_GROUP ) {
			$existing_meta = get_post_meta( $ID, 'tve_asset_group_files', true );
			unset( $model['parent_ID'] );
			foreach ( $existing_meta as $k => $v ) {
				if ( $v['ID'] == $model['ID'] ) {
					$existing_meta[ $k ]['name']        = $model['name'];
					$existing_meta[ $k ]['link_anchor'] = $model['link_anchor'];
				}
			}
			update_post_meta( $ID, 'tve_asset_group_files', $existing_meta );
		}

		$index = $model['ID'];
	} else {
		$ID          = $model['parent_ID'];
		$asset_group = get_post( $ID );
		if ( $asset_group && get_post_type( $asset_group ) === TVE_LEADS_POST_ASSET_GROUP ) {
			$existing_meta = get_post_meta( $ID, 'tve_asset_group_files', true );
			unset( $model['parent_ID'] );
			if ( empty( $existing_meta ) ) {
				$index       = 0;
				$model["ID"] = $index;
				update_post_meta( $ID, 'tve_asset_group_files', array( $model ) );
			} else {
				$max   = 0;
				$index = 0;
				foreach ( $existing_meta as $k => $v ) {

					if ( $v['ID'] > $max ) {
						$max   = $v['ID'];
						$index = $v['ID'];
					}
				}
				$index ++;
				$model['ID'] = $index;
				$new_meta    = array_merge( $existing_meta, array( $model ) );

				update_post_meta( $ID, 'tve_asset_group_files', $new_meta );
			}
		}
	}

	return $index;
}

function tve_leads_add_wizard_group( $model ) {
	$default = array(
		'post_type'   => TVE_LEADS_POST_ASSET_GROUP,
		'post_status' => 'publish',
	);
	$ID      = wp_insert_post( array_merge( $default, $model ) );
	update_post_meta( $ID, 'tve_asset_group_files', $model['files'] );

	return ( $ID );
}

/**
 * create or update a One Click Signup post (new name: Signup Segue)
 *
 * can also be used to delete a lead group "internally", by setting the post_status to 'trash'
 *
 * @param $model
 *
 * @return int|WP_Error
 */
function tve_leads_save_one_click_signup( $model ) {
	if ( ! empty( $model['ID'] ) ) {
		$one_click_signup = get_post( $model['ID'] );
		if ( $one_click_signup && get_post_type( $one_click_signup ) === TVE_LEADS_POST_ONE_CLICK_SIGNUP ) {
			wp_update_post( $model );
		}
		$ID = $model['ID'];
		foreach ( $model['api_connections'] as $key => $api_connection ) {
			if ( isset ( $model['api_connections'][ $key ]['activecampaign_tags'] ) ) {
				$model['api_connections'][ $key ]['activecampaign_tags'] = urldecode( $api_connection['activecampaign_tags'] );
			}
		}
		update_post_meta( $ID, 'tve_leads_redirect_url', $model['redirect_url'] );
		update_post_meta( $ID, 'tve_leads_api_connections', $model['api_connections'] );
	} else {
		$default = array(
			'post_type'   => TVE_LEADS_POST_ONE_CLICK_SIGNUP,
			'post_status' => 'publish',
		);
		$ID      = wp_insert_post( array_merge( $default, $model ) );
		/**
		 * save these from here, as they will be 0 for newly created one click signup (new name: Signup Segue)
		 */
		update_post_meta( $ID, 'tve_leads_signups', 0 );
		update_post_meta( $ID, 'tve_leads_redirect_url', new stdClass() );
		update_post_meta( $ID, 'tve_leads_api_connections', array() );
	}


	if ( isset( $ID ) ) {
		update_post_meta( $ID, 'tve_form_type', 'one_click_signup' );
	}
	$post_link = get_permalink( $ID );

	return json_encode( array( "ID" => $ID, "post_link" => $post_link ) );
}

/**
 * create or update a Form Type post
 *
 * can also be used to delete a form type "internally", by setting the post_status to 'trash'
 *
 * @param $model
 *
 * @return int|WP_Error
 */
function tve_leads_save_form_type( $model ) {
	if ( ! empty( $model['ID'] ) ) {
		$form_type = get_post( $model['ID'] );
		if ( $form_type && get_post_type( $form_type ) === TVE_LEADS_POST_FORM_TYPE ) {
			wp_update_post( $model );
			$id = $model['ID'];
		}
	} else {
		/**
		 * check if the group already has a form type of the same type added elsewhere(new window)
		 */
		if ( ! empty( $model['post_parent'] ) ) {
			$q = new WP_Query( array(
				'post_parent__in' => array( $model['post_parent'] ),
				'post_type'       => TVE_LEADS_POST_FORM_TYPE,
				'meta_key'        => 'tve_form_type',
				'meta_value'      => $model['tve_form_type'],
			) );

			$posts = $q->get_posts();
			if ( ! empty( $posts ) ) {
				return $posts[0]->ID;
			}
		}

		$default = array(
			'post_type'   => TVE_LEADS_POST_FORM_TYPE,
			'post_status' => 'publish',
		);
		$id      = wp_insert_post( array_merge( $default, $model ) );
		/**
		 * these will be 0 for new form types
		 */
		update_post_meta( $id, 'tve_leads_impressions', 0 );
		update_post_meta( $id, 'tve_leads_conversions', 0 );
	}

	if ( isset( $id ) ) {
		update_post_meta( $id, 'tve_form_type', $model['tve_form_type'] );
		update_post_meta( $id, 'display_on_mobile', $model['display_on_mobile'] );
		update_post_meta( $id, 'display_status', $model['display_status'] );
	}

	return isset( $id ) ? $id : 0;
}

/**
 * get form type by ID and load any necessary extra data, such as form variations
 *
 * @param       $ID
 *
 * @param array $filters offers a way to control the returned value
 *
 * @return null|WP_Post
 */
function tve_leads_get_form_type( $ID, $filters = array() ) {
	$defaults = array(
		'active_test'     => false,
		'completed_tests' => false,
		'get_variations'  => true,
	);
	$filters  = array_merge( $defaults, $filters );

	$form_type = get_post( $ID );
	$post_type = get_post_type( $ID );
	if ( ! $form_type || ! $form_type->ID
	     || ! in_array( $post_type, array(
			TVE_LEADS_POST_FORM_TYPE,
			TVE_LEADS_POST_SHORTCODE_TYPE,
			TVE_LEADS_POST_TWO_STEP_LIGHTBOX,
			TVE_LEADS_POST_ONE_CLICK_SIGNUP,
		) )
	) {
		return null;
	}

	if ( ! empty( $filters['get_variations'] ) ) {
		$form_type->variations          = tve_leads_get_form_variations( $ID );
		$form_type->variations_archived = tve_leads_get_form_variations( $ID, array(
			'post_status' => 'archived',
		) );
	}

	if ( ! empty( $filters['active_test'] ) ) {
		$form_type->active_test = tve_leads_get_form_active_test( $form_type->ID, array(
			'test_type' => tve_leads_get_test_type_from_post_type( $post_type ),
		) );
	}

	$form_type->tve_form_type = get_post_meta( $ID, 'tve_form_type', true );

	return $form_type;
}

/**
 * get a form variation based on $form_type_id and $variation_key
 *
 * @param int   $form_type_id
 * @param int   $variation_key
 *
 * @param array $filter allows fetching tracking data and other (possible) required data
 *
 * @return array|null the variation or null if it couldn't be found
 */
function tve_leads_get_form_variation( $form_type_id, $variation_key, $filter = array() ) {
	global $tvedb;

	$defaults = array(
		'tracking_data' => false,
	);
	$filter   = array_merge( $defaults, $filter );

	$variation = $tvedb->get_form_variation( $variation_key );

	if ( empty( $variation ) ) {
		return null;
	}

	if ( ! empty( $filter['tracking_data'] ) ) {
		$variation['impressions'] = $impressions = tve_leads_get_variation_tracking_data( $variation, TVE_LEADS_UNIQUE_IMPRESSION );
		$variation['conversions'] = $conversions = tve_leads_get_variation_tracking_data( $variation, TVE_LEADS_CONVERSION );
		if ( ! empty( $variation['save_flag'] ) ) {
			$tvedb->update_variation_fields( $variation, array(
				'cache_impressions' => $impressions,
				'cache_conversions' => $conversions,
			) );
		}
		$variation['conversion_rate'] = tve_leads_conversion_rate( $impressions, $conversions );
	}
	if ( empty( $variation['trigger'] ) ) {
		$variation['trigger'] = 'page_load';
	}
	$variation['trigger_nice_name']           = tve_leads_trigger_nice_name( $variation );
	$variation['display_frequency_nice_name'] = tve_leads_frequency_nice_name( $variation );
	$variation['display_position_nice_name']  = tve_leads_position_nice_name( $variation );
	$variation['display_animation_nice_name'] = tve_leads_animation_nice_name( $variation );

	return $variation;
}

/**
 * Insert new split test in database
 *
 * @param $model
 *
 * @return int
 */
function tve_leads_save_test( $model ) {
	global $tvedb;

	$defaults = array(
		'status'       => 'running',
		'date_added'   => date( "Y-m-d H:i:s" ),
		'date_started' => date( "Y-m-d H:i:s" ),
	);

	if ( isset( $model['item_ids'] ) ) {
		$item_ids = $model['item_ids'];
		unset( $model['item_ids'] );
	}

	if ( isset( $model['items'] ) ) {
		$items = $model['items'];
		unset( $model['items'] );
	}

	if ( ! $model['auto_win_enabled'] ) {
		$model['auto_win_enabled'] = intval( $model['auto_win_enabled'] );
	}

	if ( ! empty( $model['id'] ) ) {
		return $tvedb->save_test( $model );
	}

	$model = array_merge( $defaults, $model );

	//insert into DB group test
	if ( isset( $model['form_types'] ) ) {
		$form_types = $model['form_types'];
		unset( $model['form_types'] );
	}

	$test_id = $tvedb->save_test( $model );

	if ( $test_id ) {
		$model['id']         = $test_id;
		$model['form_types'] = isset( $form_types ) ? $form_types : null;
		$test_items_ids      = tve_leads_save_test_items( $model );
	}

	return $model;
}

function tve_leads_delete_test( $id ) {
	global $tvedb;
	$tvedb->delete( tve_leads_table_name( 'split_test' ), array( 'ID' => $id ) );

	return $tvedb->delete( tve_leads_table_name( 'split_test_items' ), array( 'test_id' => $id ) );

}

/**
 * Insert new slit test ITEMS base on test_model
 *
 * @param $test_model array
 *
 * @return item_ids array of integers
 */
function tve_leads_save_test_items( $test_model ) {
	global $tvedb;

	$item_ids = array();

	switch ( $test_model['test_type'] ) {
		//insert test items for each variation
		case     TVE_LEADS_VARIATION_TEST_TYPE:
			$form_type         = tve_leads_get_form_type( $test_model['main_group_id'] );
			$default_test_item = array(
				'test_id'       => $test_model['id'],
				'main_group_id' => $form_type->post_parent,
				'form_type_id'  => $test_model['main_group_id'],
			);

			foreach ( $form_type->variations as $variation ) {
				$test_item  = array_merge( $default_test_item, array(
					'variation_key' => $variation['key'],
					'is_control'    => intval( $variation['is_control'] ),
				) );
				$item_ids[] = $tvedb->save_test_item( $test_item );
			}

			return $item_ids;
			break;

		//insert test items for each form type in test_model
		case TVE_LEADS_GROUP_TEST_TYPE:
			if ( empty( $test_model['form_types'] ) ) {
				return;
			}

			//insert test items for each form type
			$default_test_item = array(
				'test_id'       => $test_model['id'],
				'main_group_id' => $test_model['main_group_id'],
			);

			foreach ( $test_model['form_types'] as $key => $form_id ) {
				$test                  = $default_test_item;
				$test['form_type_id']  = $form_id;
				$control_variation     = tve_leads_get_form_variations( $form_id, array(
					'tracking_data' => false,
					'get_control'   => true,
				) );
				$test['variation_key'] = $control_variation['key'];
				$test['is_control']    = $key === 0 ? 1 : 0;
				$item_ids[]            = $tvedb->save_test_item( $test );
			}

			return $item_ids;
			break;

		case TVE_LEADS_SHORTCODE_TEST_TYPE:
		case TVE_LEADS_TWO_STEP_LIGHTBOX_TEST_TYPE:
			$variations        = tve_leads_get_form_variations( $test_model['main_group_id'] );
			$default_test_item = array(
				'test_id'       => $test_model['id'],
				'main_group_id' => $test_model['main_group_id'],
				'form_type_id'  => $test_model['main_group_id'],
			);
			foreach ( $variations as $variation ) {
				$test_item  = array_merge( $default_test_item, array(
					'variation_key' => $variation['key'],
					'is_control'    => intval( $variation['is_control'] ),
				) );
				$item_ids[] = $tvedb->save_test_item( $test_item );
			}

			return $item_ids;
			break;
	}

	return false;

}

/**
 * Save test item and if the test item is_winner
 * do_action for setting up a winner is called
 *
 * @param array $test_item
 *
 * @return bool
 */
function tve_leads_save_test_item( $test_item ) {
	global $tvedb;

	if ( $saved = $tvedb->save_test_item( $test_item ) && $test_item['is_winner'] ) {
		$test_model       = tve_leads_get_test( $test_item['test_id'], array( 'load_test_items' => true ) );
		$winner_test_item = (object) $test_item;

		/*If there are stop variations merge them into the items array to archive them.*/
		if ( ! empty( $test_model->stopped_items ) ) {
			$test_model->items = array_merge( $test_model->items, $test_model->stopped_items );
		}

		foreach ( $test_model->items as $_item ) {
			if ( $_item->id == $test_item['id'] ) {
				/* this might be cleaner */
				$winner_test_item = $_item;
				break;
			}
		}
		/**
		 * in case of a group level test, we need to archive all the variations that are not related to the winner form type
		 * in case of a form type level test, we need to archive all other variations
		 */
		$test        = clone $test_model;
		$winner_item = clone $winner_test_item;

		$test->url              = admin_url( 'admin.php?page=thrive_leads_dashboard' ) . '#test/' . $test->id;
		$test->trigger_source   = 'leads';
		$winner_item->variation = $tvedb->get_form_variation( $winner_item->variation_key );

		do_action( TVE_LEADS_ACTION_SET_TEST_ITEM_WINNER, $winner_item, $test );
	}

	return $saved;
}

/**
 * save the form variation as a meta field for the FormType
 *
 * @return false|array $model the saved variation array, false in case of invalid parameters
 */
function tve_leads_save_form_variation( $model ) {
	global $tvedb;

	if ( empty( $model['post_parent'] ) ) {
		return false;
	}

	$form_type = get_post( $model['post_parent'] );
	$post_type = get_post_type( $form_type );

	if ( ! $form_type || ! $form_type->ID
	     || ! in_array( $post_type, array(
			TVE_LEADS_POST_FORM_TYPE,
			TVE_LEADS_POST_SHORTCODE_TYPE,
			TVE_LEADS_POST_TWO_STEP_LIGHTBOX,
		) )
	) {
		return false;
	}

	$_type = get_post_meta( $form_type->ID, 'tve_form_type', true );

	if ( ! isset( $model['display_frequency'] ) ) {
		$model['display_frequency'] = tve_leads_get_default_display_frequency( $_type );
	}
	if ( ! isset( $model['position'] ) ) {
		$model['position'] = tve_leads_get_default_position( $_type );
	}
	if ( empty( $model['display_animation'] ) ) {
		$model['display_animation'] = tve_leads_get_default_animation( $_type );
	}

	if ( empty( $model['key'] ) ) { /* add as new one */

		$data = array(
			'post_status'       => 'publish',
			'post_parent'       => $form_type->ID,
			'post_title'        => '',
			'trigger'           => 'page_load',
			'trigger_config'    => array(),
			'tcb_fields'        => array(),
			'content'           => '',
			'cache_impressions' => 0,
			'cache_conversions' => 0,
		);

	} else {
		$data = tve_leads_get_form_variation( $form_type->ID, $model['key'] );
	}

	if ( isset( $data ) ) {

		/**
		 * at first, when a new form is created, we'll have to leave the template and content fields empty,
		 * so that the template chooser will open by default
		 */

		//TODO: find a better way of handling these
		$data['post_title']        = $model['post_title'];
		$data['trigger']           = $model['trigger'];
		$data['trigger_config']    = $model['trigger_config'];
		$data['post_status']       = $model['post_status'];
		$data['display_frequency'] = $model['display_frequency'];
		$data['position']          = $model['position'];
		$data['display_animation'] = $model['display_animation'];
		if ( isset( $model['parent_id'] ) ) {
			$data['parent_id'] = $model['parent_id'];
		}
		if ( isset( $model['state_order'] ) ) {
			$data['state_order'] = $model['state_order'];
		}
		if ( isset( $model['form_state'] ) ) {
			$data['form_state'] = $model['form_state'];
		}

		foreach ( tve_leads_get_editor_fields() as $field ) {
			if ( ! isset( $model[ $field ] ) ) {
				continue;
			}
			if ( $field == TVE_LEADS_FIELD_SAVED_CONTENT ) { // the content is saved directly in the variation array
				$data[ $field ] = $model[ $field ];
			} else { // everything else goes into the 'tcb_fields' array
				$data['tcb_fields'][ $field ] = $model[ $field ];
			}
		}

		if ( isset( $data['tcb_fields'][ TVE_LEADS_FIELD_HAS_MASONRY ] ) ) {
			/**
			 * update the masonry option also in the parent post, because if the lazy-load option is set, we need to include masonry in the main page
			 */
			update_post_meta( $data['post_parent'], 'tve_leads_masonry', $data['tcb_fields'][ TVE_LEADS_FIELD_HAS_MASONRY ] );
			if ( ! empty( $form_type->post_parent ) ) {
				update_post_meta( $form_type->post_parent, 'tve_leads_masonry', $data['tcb_fields'][ TVE_LEADS_FIELD_HAS_MASONRY ] );
			}
		}

		if ( isset( $data['tcb_fields'][ TVE_LEADS_FIELD_HAS_TYPEFOCUS ] ) ) {
			/**
			 * update the typefocus option also in the parent post, because if the lazy-load option is set, we need to include typist in the main page
			 */
			update_post_meta( $data['post_parent'], 'tve_leads_typefocus', $data['tcb_fields'][ TVE_LEADS_FIELD_HAS_TYPEFOCUS ] );
			if ( ! empty( $form_type->post_parent ) ) {
				update_post_meta( $form_type->post_parent, 'tve_leads_typefocus', $data['tcb_fields'][ TVE_LEADS_FIELD_HAS_TYPEFOCUS ] );
			}
		}

		$parent = $tvedb->save_form_variation( $data );

		if ( ! empty( $model['form_child_states'] ) ) {
			/**
			 * recreate all child states for the new form - used for cloning and re-adding of archived forms
			 */
			tve_leads_clone_form_states( $parent, $model['form_child_states'] );
		}

		return $parent;
	}

	return false;
}

/**
 * clone an array of form variation states (children) of the $original_parent_key and add them as states of the $parent_form
 *
 * @param array $parent_form the new parent form
 * @param array $original_children
 */
function tve_leads_clone_form_states( $parent_form, $original_children ) {
	if ( empty( $original_children ) ) {
		return;
	}

	$original_parent_key = $original_children[0]['parent_id'];

	/**
	 * we need this for parsing each of the form contents and replace event configuration IDs
	 */
	$form_key_map = array(
		$original_parent_key => $parent_form['key'],
	);

	$to_replace = array( $parent_form );

	foreach ( $original_children as $child ) {
		$original_child_key = $child['key'];
		unset( $child['key'] );
		$child['post_title']                 = $parent_form['post_title'];
		$child['parent_id']                  = $parent_form['key'];
		$child                               = tve_leads_save_form_variation( $child );
		$form_key_map[ $original_child_key ] = $child['key'];

		$to_replace [] = $child;
	}

	$event_config_pattern = '#__TCB_EVENT_\[\{(.+?):(&quot;)?____old_ID____(&quot;)?(.*?)\}\]_TNEVE_BCT__#ms';
	$event_replacement    = '__TCB_EVENT_[{$1:${2}____new_ID____${3}$4}]_TNEVE_BCT__';

	/**
	 * another pass through all forms and replace the old state ID with the new one in the event manager configuration
	 */
	foreach ( $to_replace as $form ) {
		foreach ( $form_key_map as $original_key => $new_key ) {
			$pattern         = str_replace( '____old_ID____', $original_key, $event_config_pattern );
			$replacement     = str_replace( '____new_ID____', $new_key, $event_replacement );
			$form['content'] = preg_replace( $pattern, $replacement, $form['content'], - 1, $count );
			if ( $count ) {
				tve_leads_save_form_variation( $form );
			}
		}
	}
}

/**
 * Get active test from a form group
 * $param $ID - id of the group
 *
 */

function tve_leads_get_form_active_test( $ID, $filter = array() ) {
	$defaults = array(
		'test_type'     => TVE_LEADS_VARIATION_TEST_TYPE,
		'status'        => 'running',
		'main_group_id' => $ID,
		'get_items'     => true,
	);
	$filter   = array_merge( $defaults, $filter );

	global $tvedb;
	$test = $tvedb->tve_leads_get_test( $filter );

	//set variation keys to $test->item_ids
	if ( $test && ! empty( $filter['get_items'] ) ) {
		$test_items = tve_leads_get_test_items( array(
			'test_id'      => $test->id,
			'form_type_id' => $ID,
		) );
		foreach ( $test_items as $item ) {
			$test->item_ids[] = $item->variation_key;
		}
	}

	return $test;
}

function tve_leads_get_group_active_tests( $group_id ) {

	$filter = array(
		'test_type'     => TVE_LEADS_GROUP_TEST_TYPE,
		'status'        => TVE_LEADS_STATUS_RUNNING,
		'main_group_id' => $group_id,
	);

	global $tvedb;

	$active_tests = $tvedb->tve_leads_get_tests( $filter );

	//set form type ids to each test
	foreach ( $active_tests as $test ) {
		$test_items = tve_leads_get_test_items( array(
			'test_id' => $test->id,
		) );
		foreach ( $test_items as $item ) {
			$test->item_ids[] = $item->form_type_id;
		}
	}

	return $active_tests;
}

/**
 * Return active test for a shortcode id
 *
 * @param       $main_group_id
 * @param array $filters
 *
 * @return StdClass test
 */
function tve_leads_get_shortcode_active_test( $main_group_id, $filters = array() ) {
	$defaults = array(
		'test_type'     => TVE_LEADS_SHORTCODE_TEST_TYPE,
		'main_group_id' => $main_group_id,
		'status'        => TVE_LEADS_STATUS_RUNNING,
	);
	$filters  = array_merge( $defaults, $filters );

	global $tvedb;

	$test = $tvedb->tve_leads_get_test( $filters );

	return $test;
}

/**
 * Just return 1 running test by main_group_id
 *
 * @param       $main_group_id
 * @param array $filters
 *
 * @return mixed
 */
function tve_leads_get_running_tests( $main_group_id, $filters = array() ) {
	$defaults = array(
		'main_group_id' => $main_group_id,
		'status'        => TVE_LEADS_STATUS_RUNNING,
	);
	$filters  = array_merge( $defaults, $filters );

	global $tvedb;

	$test = $tvedb->tve_leads_get_test( $filters );

	return $test;
}

function tve_leads_get_group_completed_tests( $group_id ) {
	$filter = array(
		'test_type'     => TVE_LEADS_GROUP_TEST_TYPE,
		'status'        => TVE_LEADS_STATUS_ARCHIVED,
		'main_group_id' => $group_id,
	);

	global $tvedb;

	$completed_tests = $tvedb->tve_leads_get_tests( $filter );

	//set form type ids to each test
	foreach ( $completed_tests as $test ) {
		$test_items = tve_leads_get_test_items( array(
			'test_id' => $test->id,
		) );
		foreach ( $test_items as $item ) {
			$test->item_ids[] = $item->form_type_id;
		}
	}

	return $completed_tests;
}

/**
 * Return data for the conversion report chart and table
 *
 * @param $filter
 *
 * @return array
 */
function tve_leads_get_conversion_report_data( $filter ) {
	$defaults = array(
		'group_by'     => array( 'main_group_id', 'date_interval' ),
		'data_group'   => 'main_group_id',
		'event_type'   => TVE_LEADS_CONVERSION,
		'unique_email' => 0,
	);

	$filter = array_merge( $defaults, $filter );

	global $tvedb, $tve_leads_chart_colors;

	//get raw report data
	$report_data = $tvedb->tve_leads_get_report_data_count_event_type( $filter );
	$lead_groups = get_posts( array(
		'posts_per_page' => - 1,
		'post_type'      => array(
			TVE_LEADS_POST_GROUP_TYPE,
			TVE_LEADS_POST_SHORTCODE_TYPE,
			TVE_LEADS_POST_TWO_STEP_LIGHTBOX,
		),
	) );

	//store group name and id
	$group_names = array();
	$colors      = array();
	$count       = count( $tve_leads_chart_colors );
	foreach ( $lead_groups as $i => $group ) {
		$group_names[ $group->ID ] = $group->post_title;
		$colors[ $group->ID ]      = $tve_leads_chart_colors[ $i % $count ];
	}

	//generate interval to fill empty dates.
	$dates = tve_leads_generate_dates_interval( $filter['start_date'], $filter['end_date'], $filter['interval'] );

	$chart_data_temp = array();
	foreach ( $report_data as $interval ) {
		//Group all report data by main_group_id
		if ( ! isset( $chart_data_temp[ $interval->data_group ] ) ) {
			$chart_data_temp[ $interval->data_group ]['id']   = intval( $interval->data_group );
			$chart_data_temp[ $interval->data_group ]['name'] = $group_names[ intval( $interval->data_group ) ];
			$chart_data_temp[ $interval->data_group ]['data'] = array();
			if ( $filter['unique_email'] == 1 ) {
				$chart_data_temp[ $interval->data_group ]['new_leads'] = array();
			}
		}

		if ( $filter['interval'] == 'day' ) {
			$interval->date_interval = date( "d M, Y", strtotime( $interval->date_interval ) );
		}

		$chart_data_temp[ $interval->data_group ]['data'][ $interval->date_interval ] = intval( $interval->log_count );

		if ( $filter['unique_email'] == 1 ) {
			$chart_data_temp[ $interval->data_group ]['new_leads'][ $interval->date_interval ] = intval( $interval->leads );
		}
	}

	$chart_data = array();
	foreach ( $group_names as $key => $name ) {
		//when user selects only one group, we don't display the other ones.
		if ( $filter['main_group_id'] > 0 && $filter['main_group_id'] != $key ) {
			continue;
		}
		if ( ! isset( $chart_data[ $key ] ) ) {
			$chart_data[ $key ]['id']    = $key;
			$chart_data[ $key ]['name']  = $name;
			$chart_data[ $key ]['color'] = $colors[ $key ];
			$chart_data[ $key ]['data']  = array();

			if ( $filter['unique_email'] == 1 ) {
				$chart_data[ $key ]['new_leads'] = array();
			}
		}
		foreach ( $dates as $date ) {
			//complete missing data with zero
			$chart_data[ $key ]['data'][] = isset( $chart_data_temp[ $key ]['data'][ $date ] ) ? $chart_data_temp[ $key ]['data'][ $date ] : 0;

			if ( $filter['unique_email'] == 1 ) {
				$chart_data[ $key ]['new_leads'][] = isset( $chart_data_temp[ $key ]['new_leads'][ $date ] ) ? $chart_data_temp[ $key ]['new_leads'][ $date ] : 0;
			}
		}
	}

	$filter['select_fields'] = array(
		'user',
		'date',
		'main_group_id',
		'form_type_id',
		'variation_key',
	);
	$count_table_data        = $tvedb->tve_leads_get_log_data_info( $filter, true );

	return array(
		'chart_title'  => __( 'Number of lead generation conversions over time', 'thrive-leads' ),
		'chart_data'   => $chart_data,
		'chart_x_axis' => $dates,
		'chart_y_axis' => __( 'Conversions', 'thrive-leads' ),
		'table_data'   => array( 'count_table_data' => $count_table_data ),
	);
}

/**
 * Get data for Growth Chart with the option to select cumulative or not.
 * We already have those function implemented for the conversion report so what we'll is just get
 * the data from them and add the data from all the groups
 *
 * @param array   $filter
 * @param boolean $cumulative
 *
 * @return array $data
 */
function tve_leads_get_list_growth( $filter, $cumulative = false ) {
	//we select the data from all groups
	$filter['main_group_id'] = - 1;
	$filter['unique_email']  = 1;

	if ( $cumulative === true ) {
		$data = tve_leads_get_cumulative_conversion_report_data( $filter );
	} else {
		$data = tve_leads_get_conversion_report_data( $filter );
	}

	global $tve_leads_chart_colors;

	$conversions_data = array(
		'id'    => $cumulative ? 1 : 2, //this is more or less useless
		'name'  => $cumulative ? __( 'Total conversions since start date', 'thrive-leads' ) : __( 'Conversions Growth', 'thrive-leads' ),
		'color' => $tve_leads_chart_colors[0], //we just use the first color
		'data'  => array_fill( 0, count( $data['chart_x_axis'] ), 0 ), //fill array with 0
	);

	$lead_data = array(
		'id'    => $cumulative ? 3 : 4, //just to differentiate between the data series for the chart
		'name'  => $cumulative ? __( 'Total leads since start date', 'thrive-leads' ) : __( 'Lead Growth', 'thrive-leads' ),
		'color' => $tve_leads_chart_colors[1], //we use the second color
		'data'  => array_fill( 0, count( $data['chart_x_axis'] ), 0 ), //fill array with 0
	);

	foreach ( $data['chart_data'] as $group ) {
		foreach ( $group['data'] as $key => $growth ) {
			$conversions_data['data'][ $key ] += $growth;
			$lead_data['data'][ $key ]        += $group['new_leads'][ $key ];
		}
	}

	$data['chart_data'] = array( $conversions_data, $lead_data );

	if ( $filter['load_annotations'] ) {
		$flag_data            = tve_leads_get_chart_annotations( $filter, $conversions_data['data'] );
		$data['chart_data'][] = $flag_data;
	}

	$title                = __( 'Total number of opt-ins across all forms and lead groups', 'thrive-leads' ) . ( $cumulative ? __( '(cumulative)', 'thrive-leads' ) : '' );
	$data['chart_title']  = __( $title, 'thrive-leads' );
	$data['chart_y_axis'] = __( 'Leads', 'thrive-leads' );

	return $data;
}

/**
 * Return table data for the conversion report table
 *
 * @param $filter
 *
 * @return Requested
 */
function tve_leads_get_conversion_report_table_data( $filter ) {
	global $tvedb;
	global $tve_leads_chart_colors;
	$defaults = array(
		'itemsPerPage'  => 10,
		'page'          => 1,
		'select_fields' => array( 'user', 'date', 'main_group_id', 'form_type_id', 'variation_key', 'referrer' ),
		'event_type'    => TVE_LEADS_CONVERSION,
	);

	$lead_groups = get_posts( array(
		'posts_per_page' => - 1,
		'post_type'      => array(
			TVE_LEADS_POST_GROUP_TYPE,
			TVE_LEADS_POST_SHORTCODE_TYPE,
			TVE_LEADS_POST_TWO_STEP_LIGHTBOX,
		),
	) );

	//we store the colors that were used in the chart so we can match the group id
	$colors      = array();
	$color_count = count( $tve_leads_chart_colors );
	foreach ( $lead_groups as $key => $group ) {
		$colors[ $group->ID ] = $tve_leads_chart_colors[ $key % $color_count ];
	}

	$filter = array_merge( $defaults, $filter );

	$table_data = $tvedb->tve_leads_get_log_data_info( $filter );

	$group_titles = array();
	$form_titles  = array();
	$preview_urls = array();

	foreach ( $table_data as $key => $value ) {

		if ( ! isset( $group_titles[ $value->main_group_id ] ) ) {
			$group_titles[ $value->main_group_id ] = get_the_title( $value->main_group_id );
		}
		if ( ! isset( $form_titles[ $value->form_type_id ] ) ) {
			$form_titles[ $value->form_type_id ] = get_the_title( $value->form_type_id );
		}
		if ( ! isset( $preview_urls[ $value->variation_key ] ) ) {
			$preview_urls[ $value->variation_key ] = tve_leads_get_preview_url( $value->form_type_id, $value->variation_key );
		}

		$table_data[ $key ]->date       = tve_leads_format_date( $value->date );
		$table_data[ $key ]->link       = $preview_urls[ $value->variation_key ];
		$table_data[ $key ]->lead_group = $group_titles[ $value->main_group_id ];
		$table_data[ $key ]->form_type  = $form_titles[ $value->form_type_id ];
		$table_data[ $key ]->color      = $colors[ intval( $value->main_group_id ) ];

		//we unset those values so we don't send too much data.
		unset( $table_data[ $key ]->form_type_id );
		unset( $table_data[ $key ]->main_group_id );
		unset( $table_data[ $key ]->variation_key );
	}

	return $table_data;
}


/**
 * Return data for the cumulative report chart and table
 *
 * @param $filter
 *
 * @return array
 */
function tve_leads_get_cumulative_conversion_report_data( $filter ) {
	$defaults = array(
		'group_by'     => array( 'main_group_id', 'date_interval' ),
		'data_group'   => 'main_group_id',
		'event_type'   => TVE_LEADS_CONVERSION,
		'unique_email' => 0,
	);
	$filter   = array_merge( $defaults, $filter );

	global $tvedb, $tve_leads_chart_colors;
	$report_data = $tvedb->tve_leads_get_report_data_count_event_type( $filter );

	$lead_groups = get_posts( array(
		'posts_per_page' => - 1,
		'post_type'      => array(
			TVE_LEADS_POST_GROUP_TYPE,
			TVE_LEADS_POST_SHORTCODE_TYPE,
			TVE_LEADS_POST_TWO_STEP_LIGHTBOX,
		),
	) );
	//store group names and id
	$group_names = $colors = array();
	$count       = count( $tve_leads_chart_colors );
	foreach ( $lead_groups as $i => $group ) {
		$group_names[ $group->ID ] = $group->post_title;
		$colors[ $group->ID ]      = $tve_leads_chart_colors[ $i % $count ];
	}

	//generate interval to fill empty dates.
	$dates = tve_leads_generate_dates_interval( $filter['start_date'], $filter['end_date'], $filter['interval'] );

	$chart_data_temp = array();
	foreach ( $report_data as $interval ) {
		//Group all report data by main_group_id
		if ( ! isset( $chart_data_temp[ $interval->data_group ] ) ) {
			$chart_data_temp[ $interval->data_group ]['id']   = intval( $interval->data_group );
			$chart_data_temp[ $interval->data_group ]['name'] = $group_names[ intval( $interval->data_group ) ];
			$chart_data_temp[ $interval->data_group ]['data'] = array();
			if ( $filter['unique_email'] == 1 ) {
				$chart_data_temp[ $interval->data_group ]['new_leads'] = array();
			}
		}

		if ( $filter['interval'] == 'day' ) {
			$interval->date_interval = date( "d M, Y", strtotime( $interval->date_interval ) );
		}

		$chart_data_temp[ $interval->data_group ]['data'][ $interval->date_interval ] = $interval->log_count;
		if ( $filter['unique_email'] == 1 ) {
			$chart_data_temp[ $interval->data_group ]['new_leads'][ $interval->date_interval ] = intval( $interval->leads );
		}
	}

	$chart_data = array();
	foreach ( $group_names as $key => $name ) {
		//when user selects only one group, we don't display the other ones.
		if ( $filter['main_group_id'] > 0 && $filter['main_group_id'] != $key ) {
			continue;
		}
		if ( ! isset( $chart_data[ $key ] ) ) {
			$chart_data[ $key ]['id']    = $key;
			$chart_data[ $key ]['name']  = $name;
			$chart_data[ $key ]['color'] = $colors[ $key ];
			$chart_data[ $key ]['data']  = array();
			$last_val                    = 0;

			if ( $filter['unique_email'] == 1 ) {
				$last_lead_val                   = 0;
				$chart_data[ $key ]['new_leads'] = array();
			}
		}
		foreach ( $dates as $date ) {
			//complete missing data with zero
			$last_val                     += isset( $chart_data_temp[ $key ]['data'][ $date ] ) ? $chart_data_temp[ $key ]['data'][ $date ] : 0;
			$chart_data[ $key ]['data'][] = $last_val;

			if ( $filter['unique_email'] == 1 ) {
				$last_lead_val                     += isset( $chart_data_temp[ $key ]['new_leads'][ $date ] ) ? $chart_data_temp[ $key ]['new_leads'][ $date ] : 0;
				$chart_data[ $key ]['new_leads'][] = $last_lead_val;
			}
		}
	}
	$filter['select_fields'] = array(
		'user',
		'date',
		'main_group_id',
		'form_type_id',
		'variation_key',
	);
	$count_table_data        = $tvedb->tve_leads_get_log_data_info( $filter, true );

	return array(
		'chart_title'  => __( 'Cumulative lead generation conversions over time', 'thrive-leads' ),
		'chart_data'   => $chart_data,
		'chart_x_axis' => $dates,
		'chart_y_axis' => __( 'Signups', 'thrive-leads' ),
		'table_data'   => array( 'count_table_data' => $count_table_data ),
	);
}

/**
 * Return data for the test chart
 *
 * @param $filter
 *
 * @return array
 */
function tve_leads_get_conversion_rate_test_data( $filter ) {
	$defaults = array(
		'group_by'   => array( 'main_group_id', 'date_interval' ),
		'data_group' => 'main_group_id',
	);
	$filter   = array_merge( $defaults, $filter );

	global $tvedb;
	$report_data = $tvedb->get_summary_count_for_reports( $filter );

	//set names for the series in the chart - variation, form type or group
	if ( empty( $filter['group_names'] ) ) {
		$lead_groups = get_posts( array(
			'posts_per_page' => - 1,
			'post_type'      => array(
				TVE_LEADS_POST_GROUP_TYPE,
				TVE_LEADS_POST_SHORTCODE_TYPE,
				TVE_LEADS_POST_TWO_STEP_LIGHTBOX,
			),
		) );
		$group_names = array();
		foreach ( $lead_groups as $group ) {
			$group_names[ $group->ID ] = $group->post_title;
		}
	} else {
		$group_names = $filter['group_names'];
	}
	//generate interval to fill empty dates.
	$dates = tve_leads_generate_dates_interval( $filter['start_date'], $filter['end_date'], $filter['interval'] );

	$chart_data_temp = array();
	foreach ( $report_data as $interval ) {
		//Group all report data by main_group_id
		if ( ! isset( $chart_data_temp[ $interval->data_group ] ) ) {
			$chart_data_temp[ $interval->data_group ]['id']   = (int) $interval->data_group;
			$chart_data_temp[ $interval->data_group ]['name'] = $group_names[ $interval->data_group ];
			$chart_data_temp[ $interval->data_group ]['data'] = array();
		}

		$chart_data_temp[ $interval->data_group ][ $interval->date_interval ]['impression_count'] = $interval->impression_count;
		$chart_data_temp[ $interval->data_group ][ $interval->date_interval ]['conversion_count'] = $interval->conversion_count;
		$chart_data_temp[ $interval->data_group ][ $interval->date_interval ]['conversion_rate']  = $interval->conversion_rate;
	}

	$chart_data = array();
	foreach ( $group_names as $key => $name ) {
		//when user selects only one group, we don't display the other ones.
		if ( ! empty( $filter['main_group_id'] ) && $filter['main_group_id'] > 0 && $filter['main_group_id'] != $key ) {
			continue;
		}
		if ( ! isset( $chart_data[ $key ] ) ) {
			$chart_data[ $key ]['id']               = $key;
			$chart_data[ $key ]['name']             = $name;
			$chart_data[ $key ]['data']             = array();
			$chart_data[ $key ]['impression_count'] = array();
			$chart_data[ $key ]['conversion_count'] = array();
		}
		//complete missing data with zero
		foreach ( $dates as $date ) {
			if ( ! isset( $chart_data_temp[ $key ][ $date ] ) ) {
				$chart_data[ $key ]['data'][] = 0;
			} else {
				$chart_data[ $key ]['data'][] = (float) $chart_data_temp[ $key ][ $date ]['conversion_rate'];
			}
			/**
			 * count impressions and conversions so we can use those values in the "cumulative" report shown on the test screen
			 */
			$chart_data[ $key ]['impression_count'][] = isset( $chart_data_temp[ $key ][ $date ] ) ? $chart_data_temp[ $key ][ $date ]['impression_count'] : 0;
			$chart_data[ $key ]['conversion_count'][] = isset( $chart_data_temp[ $key ][ $date ] ) ? $chart_data_temp[ $key ][ $date ]['conversion_count'] : 0;
		}
	}

	$conversions = 0;
	$impressions = 0;
	foreach ( $chart_data_temp as $key ) {
		$conversions += isset( $key['conversion_count'] ) ? array_sum( $key['conversion_count'] ) : 0;
		$impressions += isset( $key['impression_count'] ) ? array_sum( $key['impression_count'] ) : 0;
	}
	$average_rate = (float) tve_leads_conversion_rate( $impressions, $conversions, '', 2 );

	return array(
		'chart_title'  => __( 'Lead generation conversion rate over time', 'thrive-leads' ),
		'chart_data'   => $chart_data,
		'chart_x_axis' => $dates,
		'chart_y_axis' => __( 'Conversion Rate', 'thrive-leads' ) . ' (%)',
		'table_data'   => array(
			'count_table_data' => count( $dates ),
			'average_rate'     => $average_rate,
		),
	);
}

/**
 * Return conversion rate chart data for reporting view.
 * Conversion Rate is calculated related to days so unique user impressions are used instead of forms unique impressions
 *
 * @param $filter
 *
 * @return array
 */
function tve_leads_get_conversion_rate_report_chart( $filter ) {
	$defaults = array(
		'group_by'      => array( 'date_interval' ),
		'data_group'    => 'main_group_id',
		'is_unique'     => 1,
		'main_group_id' => - 1,
	);

	$filter                  = array_merge( $defaults, $filter );
	$filter['main_group_id'] = - 1;

	global $tvedb;
	$dates = tve_leads_generate_dates_interval( $filter['start_date'], $filter['end_date'], $filter['interval'] );

	$report_data = $tvedb->get_summary_count_for_reports( $filter, 'date_interval' );

	$impressions = 0;
	$conversions = 0;

	$chart_data   = array(
		'id'   => - 1,
		'data' => array_map( function ( $date ) use ( $report_data, &$impressions, &$conversions ) {
			if ( isset( $report_data[ $date ] ) ) {
				$impressions += $report_data[ $date ]->impression_count;
				$conversions += $report_data[ $date ]->conversion_count;

				return (float) $report_data[ $date ]->conversion_rate;
			}

			return 0;
		}, $dates ),
		'name' => __( 'Conversion Rate', 'thrive-leads' ),
	);
	$average_rate = (float) tve_leads_conversion_rate( $impressions, $conversions, '', 2 );

	return array(
		'chart_title'  => __( 'Lead generation conversion rate over time', 'thrive-leads' ),
		'chart_data'   => array( $chart_data ),
		'chart_x_axis' => $dates,
		'chart_y_axis' => __( 'Conversion Rate', 'thrive-leads' ) . ' (%)',
		'table_data'   => array(
			'count_table_data' => count( $dates ),
			'average_rate'     => $average_rate,
		),
	);
}


/**
 * Return table data for the conversion rate report
 *
 * @param $filter
 *
 * @return mixed
 */
function tve_leads_get_conversion_rate_report_table_data( $filter ) {
	$defaults = array(
		'group_by'     => array( 'date_interval' ),
		'data_group'   => 'main_group_id',
		'itemsPerPage' => 10,
		'page'         => 1,
		'is_unique'    => 1,
	);

	$filter = array_merge( $defaults, $filter );
	global $tvedb;

	$dates       = tve_leads_generate_dates_interval( $filter['start_date'], $filter['end_date'], $filter['interval'] );
	$report_data = $tvedb->get_summary_count_for_reports( $filter, 'date_interval' );

	$table_data = array_map( function ( $date ) use ( $report_data ) {
		return array(
			'date' => $date,
			'rate' => isset( $report_data[ $date ] ) ? $report_data[ $date ]->conversion_rate : 0,
		);
	}, $dates );

	if ( ! empty( $table_data ) ) {
		$table_pages = array_chunk( $table_data, $filter['itemsPerPage'] );

		return $table_pages[ $filter['page'] - 1 ];
	}

	return array();
}

/**
 * Return data for the comparison report pie data and table
 *
 * @param $filter
 *
 * @return array
 */
function tve_leads_get_comparison_report_data( $filter ) {
	$filter['main_group_id'] = - 1;
	$defaults                = array(
		'group_by'   => array( 'main_group_id' ),
		'data_group' => 'main_group_id',
		'event_type' => TVE_LEADS_CONVERSION,
	);
	$filter                  = array_merge( $defaults, $filter );

	global $tvedb;
	$report_data = $tvedb->tve_leads_get_report_data_count_event_type( $filter );

	$lead_groups = get_posts( array(
		'posts_per_page' => - 1,
		'post_type'      => array(
			TVE_LEADS_POST_GROUP_TYPE,
			TVE_LEADS_POST_SHORTCODE_TYPE,
			TVE_LEADS_POST_TWO_STEP_LIGHTBOX,
		),
	) );
	//store group name and id
	$group_names = array();
	foreach ( $lead_groups as $group ) {
		$group_names[ $group->ID ] = $group->post_title;
	}

	$chart_data  = array();
	$table_data  = array();
	$conversions = 0;
	foreach ( $report_data as $interval ) {
		$chart_data[] = array( $group_names[ intval( $interval->data_group ) ], intval( $interval->log_count ) );
		$conversions  += intval( $interval->log_count );
	}

	foreach ( $report_data as $interval ) {
		$table_data[] = array(
			'lead_group' => $group_names[ intval( $interval->data_group ) ],
			'percentage' => round( 100 * intval( $interval->log_count ) / $conversions, 1 ) . '%',
		);
		unset( $group_names[ intval( $interval->data_group ) ] );
	}
	//fill the table data with the empty groups
	foreach ( $group_names as $names ) {
		$table_data[] = array(
			'lead_group' => $names,
			'percentage' => '0%',
		);
	}

	return array(
		'chart_title'  => __( 'How the total number of opt ins is distributed between Lead Groups and individual forms', 'thrive-leads' ),
		'chart_data'   => $chart_data,
		'chart_y_axis' => '',
		'chart_x_axis' => '',
		'table_data'   => $table_data,
	);
}

/**
 * Return data for the Lead Referral Report table
 *
 * @param $filter Array containing parameters for filtering the data logs
 *
 * @return array
 */
function tve_leads_get_lead_referral_report_data( $filter ) {
	$defaults = array(
		'count'         => true,
		'itemsPerPage'  => 10,
		'page'          => 1,
		'event_type'    => TVE_LEADS_CONVERSION,
		'referral_type' => 'domain',
	);
	$filter   = array_merge( $defaults, $filter );

	global $tvedb;
	$lead_referral = $tvedb->tve_leads_get_top_referring_links( $filter, $filter['count'] );

	if ( $filter['referral_type'] == 'domain' && $filter['count'] == false ) {
		$temp = array();
		foreach ( $lead_referral as $referrer ) {
			$domain = parse_url( $referrer->referring_url, PHP_URL_HOST );
			$domain = str_replace( 'www.', '', $domain );
			if ( empty( $temp[ $domain ] ) ) {
				$temp[ $domain ]                = new stdClass();
				$temp[ $domain ]->conversions   = 0;
				$temp[ $domain ]->referring_url = $domain;
			}
			$temp[ $domain ]->conversions += $referrer->conversions;
		}
		$lead_referral = array_values( $temp );
	}

	/* sort the result */
	if ( $filter['count'] == false && ! empty( $filter['order_dir'] ) ) {
		for ( $i = 0; $i < count( $lead_referral ) - 1; $i ++ ) {
			for ( $j = $i + 1; $j < count( $lead_referral ); $j ++ ) {
				if ( ( $filter['order_by'] == 'url' && strcmp( $lead_referral[ $i ]->referring_url, $lead_referral[ $j ]->referring_url ) > 0 )
				     || ( $filter['order_by'] == 'conversions' && ( $lead_referral[ $i ]->conversions - $lead_referral[ $j ]->conversions > 0 ) )
				) {
					$aux                 = $lead_referral[ $i ];
					$lead_referral[ $i ] = $lead_referral[ $j ];
					$lead_referral[ $j ] = $aux;
				}
			}
		}
		if ( $filter['order_dir'] == 'DESC' ) {
			$lead_referral = array_reverse( $lead_referral );
		}
	}

	if ( $filter['count'] == true ) {
		return array( 'table_data' => array( 'count_table_data' => $lead_referral ) );
	} else {
		return $lead_referral;
	}
}

/**
 * Return data for the Lead Referral Report table
 *
 * @param $filter Array containing parameters for filtering the data logs
 *
 * @return array
 */
function tve_leads_get_lead_source_report_data( $filter ) {
	$defaults = array(
		'count'        => true,
		'itemsPerPage' => 500,
		'page'         => 1,
		'source_type'  => 0,
		'order_by'     => '',
		'order_dir'    => '',
	);
	$filter   = array_merge( $defaults, $filter );

	global $tvedb;
	$lead_report = $tvedb->tve_leads_get_lead_source_data( $filter, $filter['count'] );

	$result = array();
	foreach ( $lead_report as $row ) {
		list( $url, $type, $name ) = tve_get_current_screen_for_reporting_table( $row->screen_type, $row->screen_id );
		$result[] = array(
			'url'         => $url,
			'type'        => $type,
			'name'        => $name,
			'conversions' => $row->conversions,
			'leads'       => $row->leads,
		);
	}

	if ( $filter['count'] == true ) {
		return array( 'table_data' => array( 'count_table_data' => count( $result ) ) );
	}

	return $result;
}

/**
 * Return data for the Lead Referral Report table
 *
 * @param $filter Array containing parameters for filtering the data logs
 *
 * @return array
 */
function tve_leads_get_lead_tracking_report_data( $filter ) {
	$defaults = array(
		'count'         => true,
		'itemsPerPage'  => 10,
		'page'          => 1,
		'tracking_type' => 'all',
		'event_type'    => TVE_LEADS_CONVERSION,
	);
	$filter   = array_merge( $defaults, $filter );

	global $tvedb;
	$lead_tracking = $tvedb->tve_leads_get_tracking_links( $filter, $filter['count'] );
	if ( $filter['count'] == true ) {
		return array( 'table_data' => array( 'count_table_data' => $lead_tracking ) );
	} else {
		return $lead_tracking;
	}


}

/**
 * @param $test_id  ID of the test we want to get data from
 * @param $interval can be 'day', 'week', or 'month' - the date interval of the chart
 *
 * @return array
 */
function tve_leads_get_test_chart_data( $test_id, $interval ) {
	$filter = array(
		'ID' => $test_id,
	);
	global $tvedb;
	$test = $tvedb->tve_leads_get_test( $filter );
	list( $test_items, $test_item_ids ) = tve_leads_get_test_items_with_names( $test_id );

	//set the group by for the log data depending on the test type
	switch ( $test->test_type ) {
		case TVE_LEADS_SHORTCODE_TEST_TYPE:
		case TVE_LEADS_TWO_STEP_LIGHTBOX_TEST_TYPE:
		case TVE_LEADS_VARIATION_TEST_TYPE:
			$group_by   = array( 'variation_key', 'date_interval' );
			$data_group = 'variation_key';
			break;
		case TVE_LEADS_GROUP_TEST_TYPE:
		default:
			$group_by   = array( 'form_type_id', 'date_interval' );
			$data_group = 'form_type_id';
			break;

	}

	$filter = array(
		'interval'    => $interval,
		'group_names' => $test_items,
		'data_group'  => $data_group,
		'group_ids'   => array_keys( $test_items ),
		'start_date'  => $test->date_started,
		'end_date'    => $test->date_completed && $test->status === 'archived' ? $test->date_completed : date( 'Y-m-d' ),
		'group_by'    => $group_by,
	);

	$chart_data = tve_leads_get_conversion_rate_test_data( $filter );

	foreach ( $chart_data['chart_data'] as $main_id => $item ) {
		foreach ( $item['data'] as $index => $conversion_rate ) {
			// calculate the new conversion rate as a sum of the total numbers from the beginning of the test until at this point
			$impressions = $conversions = 0;
			for ( $i = 0; $i <= $index; $i ++ ) {
				$impressions += $item['impression_count'][ $i ];
				$conversions += $item['conversion_count'][ $i ];
			}
			$chart_data['chart_data'][ $main_id ]['data'][ $index ] = (float) tve_leads_conversion_rate( $impressions, $conversions, '' );
			unset( $chart_data['chart_data'][ $main_id ]['impression_count'], $chart_data['chart_data'][ $main_id ]['conversion_count'] );
		}
	}

	$temp = array();
	asort( $test_item_ids );
	foreach ( $test_item_ids as $main_id => $order ) {
		if ( ! isset( $chart_data['chart_data'][ $main_id ] ) ) {
			continue;
		}
		$temp [] = $chart_data['chart_data'][ $main_id ];
	}
	$chart_data['chart_data'] = $temp;

	unset( $chart_data['table_data'] );

	return $chart_data;
}

function tve_leads_get_test( $test_id, $filters = array() ) {
	$defaults = array(
		'load_test_items' => false,
		'load_form_data'  => false,
	);

	$filters = array_merge( $defaults, $filters );

	global $tvedb;
	$test             = $tvedb->tve_leads_get_test( array( 'ID' => $test_id ) );
	$test->form_title = get_the_title( $test->main_group_id );
	if ( ! $test ) {
		return;
	}

	//load items
	if ( ! empty( $filters['load_test_items'] ) ) {
		$test->items         = tve_leads_get_test_items( array(
			'test_id' => $test_id,
		) );
		$test->stopped_items = array();
		//load item names
		foreach ( $test->items as $index => $item ) {
			$item->index = $index;
			//we need the conversion rate in both cases
			$item->conversion_rate = tve_leads_conversion_rate( $item->unique_impressions, $item->conversions, '' );

			if ( ! empty( $filters['load_form_data'] ) ) {
				if ( $test->test_type == TVE_LEADS_VARIATION_TEST_TYPE || $test->test_type == TVE_LEADS_SHORTCODE_TEST_TYPE || $test->test_type == TVE_LEADS_TWO_STEP_LIGHTBOX_TEST_TYPE ) {
					$variation            = tve_leads_get_form_variation( $item->form_type_id, $item->variation_key );
					$item->name           = $variation['post_title'];
					$item->trigger_name   = tve_leads_trigger_nice_name( $variation );
					$item->animation_name = tve_leads_animation_nice_name( $variation );
					$item->preview_url    = tve_leads_get_preview_url( $item->form_type_id, $item->variation_key );
					$item->edit_url       = tve_leads_get_editor_url( $item->form_type_id, $item->variation_key );
				} else {
					$variation_control    = tve_leads_get_form_variation( $item->form_type_id, $item->variation_key );
					$form_type            = tve_leads_get_form_type( $item->form_type_id );
					$item->name           = $variation_control['post_title'];
					$item->trigger_name   = tve_leads_trigger_nice_name( $variation_control );
					$item->animation_name = tve_leads_animation_nice_name( $variation_control );
					$item->preview_url    = tve_leads_get_preview_url( $item->form_type_id, $variation_control['key'] );
					$item->form_type      = $form_type->post_title;
				}
			}

			$item->conversion_rate = tve_leads_conversion_rate( $item->unique_impressions, $item->conversions, '' );
			//we don't calculate for the control item
			if ( $index > 0 ) {
				//Percentage improvement = conversion rate of variation - conversion rate of control
				if ( is_numeric( $item->conversion_rate ) && is_numeric( $test->items[0]->conversion_rate ) ) {
					$item->percentage_improvement = round( ( ( $item->conversion_rate - $test->items[0]->conversion_rate ) * 100 ) / $test->items[0]->conversion_rate, 2 );
				} else {
					$item->percentage_improvement = 'N/A';
				}

				$item->beat_original = tve_leads_test_item_beat_original( $item->conversion_rate, $item->unique_impressions, $test->items[0]->conversion_rate, $test->items[0]->unique_impressions );
			}

			if ( $item->active == 0 && $item->is_control == 0 ) {
				$item->stopped_date    = date( 'd-m-Y', strtotime( $item->stopped_date ) );
				$test->stopped_items[] = $item;
				unset( $test->items[ $index ] );
			}
		}

		/*Reset the test items IDS*/
		$test->items = array_values( $test->items );
	}

	return $test;
}

/**
 * Get an array with all the items of a test having the ID as a key and the name as value
 *
 * @param $test_id
 *
 * @return array
 */
function tve_leads_get_test_items_with_names( $test_id ) {
	global $tvedb;
	$test       = $tvedb->tve_leads_get_test( array( 'ID' => $test_id ) );
	$test_items = $tvedb->get_test_items( array( 'test_id' => $test_id ) );

	$test_item_names = array();
	$test_item_ids   = array();
	switch ( $test->test_type ) {
		case TVE_LEADS_VARIATION_TEST_TYPE:
		case TVE_LEADS_SHORTCODE_TEST_TYPE:
		case TVE_LEADS_TWO_STEP_LIGHTBOX_TEST_TYPE:
			$test_items_id = array();
			foreach ( $test_items as $item ) {
				$test_items_id[]                       = $item->variation_key;
				$test_item_ids[ $item->variation_key ] = $item->is_control ? - 1 : $item->id;
			}
			$variations = tve_leads_get_form_variations( $test->main_group_id, array(
				'tracking_data' => false,
				'post_status'   => null,
			) );
			foreach ( $variations as $variation ) {
				if ( in_array( $variation['key'], $test_items_id ) ) {
					$test_item_names[ $variation['key'] ] = $variation['post_title'];
				}
			}

			return array( $test_item_names, $test_item_ids );

		case TVE_LEADS_GROUP_TEST_TYPE:
			$test_items_id = array();
			foreach ( $test_items as $item ) {
				$test_items_id[]                      = $item->form_type_id;
				$test_item_ids[ $item->form_type_id ] = $item->is_control ? - 1 : $item->id;
			}

			$form_types = tve_leads_get_form_types( array(
				'lead_group_id' => $test->main_group_id,
				'tracking_data' => false,
			) );
			foreach ( $form_types as $form_type ) {
				if ( ! isset( $form_type->ID ) ) {
					continue;
				}
				if ( in_array( $form_type->ID, $test_items_id ) ) {
					$test_item_names[ $form_type->ID ] = $form_type->post_title;
				}
			}

			return array( $test_item_names, $test_item_ids );
	}

	return array();
}

/**
 * General function that reads DB and returns test items by filters
 *
 * @param $filters
 *
 * @return test Items
 */
function tve_leads_get_test_items( $filters ) {
	global $tvedb;

	$defaults = array(
		'test_id'       => null,
		'main_group_id' => null,
		'form_type_id'  => null,
	);

	$filters = array_merge( $defaults, $filters );

	$test_items = $tvedb->get_test_items( $filters );

	return $test_items;
}

function tve_leads_get_completed_form_test( WP_Post $form_type, $test_type = null ) {
	global $tvedb;

	$filters = array(
		'test_type'     => $test_type,
		'main_group_id' => $form_type->ID,
		'status'        => TVE_LEADS_STATUS_ARCHIVED,
	);

	$tests = $tvedb->tve_leads_get_tests( $filters );

	return $tests;
}

/**
 * Stops underperforming variations
 *
 * @param $test_id
 */
function tve_leads_stop_underperforming_variations( $test_id ) {
	if ( empty( $test_id ) ) {
		return;
	}

	$test_model = tve_leads_get_test( $test_id, array( 'load_test_items' => true ) );
	if ( empty( $test_model ) || empty( $test_model->auto_win_enabled ) || $test_model->status != TVE_LEADS_TEST_STATUS_RUNNING ) {
		return;
	}

	if ( ! empty( $test_model->auto_win_min_duration ) ) {
		/* check if this amount of time has passed -> if not, no need for further processing */
		if ( time() < strtotime( $test_model->date_started . ' +' . $test_model->auto_win_min_duration . 'days' ) ) {
			return;
		} /* The time interval has passed, we can check the other conditions */
	}

	/*Minimum conversion check*/
	global $tvedb;
	$total_test_data = $tvedb->get_total_test_data( $test_id );

	if ( intval( $total_test_data->total_conversions ) < intval( $test_model->auto_win_min_conversions ) ) {
		return;
	}

	foreach ( $test_model->items as $test_item ) {
		if ( $test_item->is_control ) {
			$control = $test_item;
			break;
		}
	}

	/*Stop if there are no conversions on control*/
	if ( empty( $control ) ) {
		return;
	}

	if ( empty( $control->conversions ) ) {
		return;
	}

	$variations_beat_original = 100.0 - (float) $test_model->auto_win_chance_original;
	foreach ( $test_model->items as $test_item ) {
		if ( $test_item->is_control ) {
			continue;
		}

		if ( (float) $test_item->beat_original < $variations_beat_original ) {
			tve_leads_stop_test_item( $test_item->id, $test_id );
		}
	}

}

/**
 * check if the automatic winner settings are enabled for a test and automatically
 * detect the winner item if the conditions are met
 *
 * @param int $test_id
 */
function tve_leads_test_check_winner( $test_id ) {
	if ( empty( $test_id ) ) {
		return;
	}

	$test_model = tve_leads_get_test( $test_id, array( 'load_test_items' => true ) );
	if ( empty( $test_model ) || empty( $test_model->auto_win_enabled ) || $test_model->status != TVE_LEADS_TEST_STATUS_RUNNING ) {
		return;
	}
	if ( ! empty( $test_model->auto_win_min_duration ) ) {
		/* check if this amount of time has passed -> if not, no need for further processing */
		if ( time() < strtotime( $test_model->date_started . ' +' . $test_model->auto_win_min_duration . 'days' ) ) {
			return;
		} /* The time interval has passed, we can check the other conditions */
	}

	/*MINIMUM CONVERSION CHECK*/
	global $tvedb;
	$total_test_data = $tvedb->get_total_test_data( $test_id );
	if ( intval( $total_test_data->total_conversions ) < intval( $test_model->auto_win_min_conversions ) ) {
		return;
	}

	/* check the number of conversions of each item, and the chance to beat original */
	$test_item_win_array = array();
	foreach ( $test_model->items as $test_item ) {
//		if ( $minimum_conversions > $test_item->conversions ) {
//			continue;
//		}

		if ( $test_item->is_control ) {
			$variations_beat_original = 100.0 - (float) $test_model->auto_win_chance_original;
			$control_win              = true;

			foreach ( $test_model->items as $var ) {
				if ( $var->is_control ) {
					continue;
				}

				if ( $variations_beat_original < floatval( $var->beat_original ) || empty( $var->beat_original ) ) {
					$control_win = false;
				}
			}

			if ( $control_win ) {
				$test_item->is_winner = 1;
				tve_leads_save_test_item( (array) $test_item );
				break;
			}
		} else {
			if ( (float) $test_item->beat_original > (float) $test_model->auto_win_chance_original ) {
				$test_item_win_array[] = $test_item;
//				$test_item->is_winner = 1;
//				tve_leads_save_test_item( (array) $test_item );
//				break;
			}
		}

	}
	if ( ! empty( $test_item_win_array ) ) {
		$winner_test_item = $test_item_win_array[0];
		foreach ( $test_item_win_array as $var_win_arr ) {
			if ( $winner_test_item->auto_win_chance_original <= $var_win_arr->auto_win_chance_original ) {
				$winner_test_item = $var_win_arr;
			}
		}
		/*Set the winner to the highest beat original*/
		$winner_test_item->is_winner = 1;
		tve_leads_save_test_item( (array) $winner_test_item );
	}
}


/**
 * in case of a group level test, we need to archive all the variations that are not related to the winner form type
 * in case of a form type level test, we need to archive all other variations
 *
 * @param stdClass $winner_test_item
 *
 * @return stdClass $test_model
 */
function tve_leads_set_test_item_winner( $winner_test_item, $test_model ) {
	global $tvedb;

	$to_be_updated = array();

	foreach ( $test_model->items as $test_item ) {
		if ( $test_item->id == $winner_test_item->id ) {
			continue;
		}
		$variations = tve_leads_get_form_variations( $test_item->form_type_id, array(
			'tracking_data' => false,
		) );

		/* set all variations as archived, except for the one that's either the winner, or the control of the form type winner */
		foreach ( $variations as $i => $variation ) {
			if ( $variation['key'] != $winner_test_item->variation_key ) {
				$to_be_updated [] = $variation['key'];
			}
		}
	}

	$tvedb->mass_update_field( 'form_variations', 'post_status', TVE_LEADS_STATUS_ARCHIVED, $to_be_updated, 'key' );

	/* finally, mark the test as completed */
	$test_model->status         = TVE_LEADS_STATUS_ARCHIVED;
	$test_model->date_completed = date( 'Y-m-d H:i:s' );

	$tvedb->save_test( $test_model );

}

/**
 * get all the child states for a variation key (it does not include the default state)
 *
 * @param int $variation_key
 *
 * @return array
 */
function tve_leads_get_form_child_states( $variation_key ) {
	global $tvedb;

	return $tvedb->get_form_variations( array(
		'parent_id' => $variation_key,
		'order'     => 'state_order ASC',
	) );
}

/**
 * get all the related states for a form variation
 * $variation can be either a state or the main form variation
 *
 * @param array $variation
 *
 * @return array all the related states
 */
function tve_leads_get_form_related_states( $variation ) {
	if ( is_numeric( $variation ) ) {
		$variation = tve_leads_get_form_variation( null, $variation );
	}

	if ( empty( $variation['parent_id'] ) ) {
		$parent = $variation;
	} else {
		$parent = tve_leads_get_form_variation( null, $variation['parent_id'] );
	}

	$variations = array( $parent );
	$variations = array_merge( $variations, tve_leads_get_form_child_states( $parent['key'] ) );

	/**
	 * Nice-names for each of the possible states
	 */
	$state_names = array(
		'lightbox'           => __( 'Lightbox', 'thrive-leads' ),
		'already_subscribed' => __( 'Already Subscribed', 'thrive-leads' ),
		'default'            => __( 'State', 'thrive-leads' ),
	);
	$indexes     = array();
	foreach ( $variations as $k => $variation ) {
		if ( ! isset( $indexes[ $variation['form_state'] ] ) ) {
			$indexes[ $variation['form_state'] ] = 1;
		}
		$state_name = empty( $variation['parent_id'] ) ? __( 'Default State', 'thrive-leads' ) : $state_names[ $variation['form_state'] ];
		if ( $variation['form_state'] && $variation['form_state'] != 'already_subscribed' ) {
			$state_name .= " {$indexes[$variation['form_state']]}";
		}
		$variations[ $k ]['state_name'] = $state_name;

		$indexes[ $variation['form_state'] ] ++;
	}

	return $variations;
}

/**
 * get the form type string for a variation
 * if the variation is a state, then we first check if it's state === 'lightbox' and if true, the form_type returned will be lightbox
 * by default it will return the form type of the variation parent (tve_form_type or shortcode etc)
 *
 * @param int|array $variation
 * @param bool      $get_from_parent optional, allows forcing the function to return the form_type of the variation parent form (or shortcode etc)
 * @param bool      $map_type        if true, it will match the type with its template association (e.g. two_step => lightbox)
 *
 * @return string
 */
function tve_leads_get_form_type_from_variation( $variation, $get_from_parent = false, $map_type = true ) {
	if ( is_numeric( $variation ) ) {
		$variation = tve_leads_get_form_variation( null, $variation );
	}

	if ( ! $get_from_parent && ! empty( $variation['form_state'] ) && $variation['form_state'] == 'lightbox' ) {
		return 'lightbox';
	}

	$form_type = get_post_meta( $variation['post_parent'], 'tve_form_type', true );
	if ( $map_type ) {
		$form_type = Thrive_Leads_Template_Manager::tpl_type_map( $form_type );
	}

	return $form_type;
}

/**
 * finds and returns the 'already_subscribed' state for a variation, if present (there can only be 1 subscribed state / veriation)
 *
 * @param array $default_state the parent (default state) variation
 *
 * @return array|null
 */
function tve_leads_get_already_subscribed_state( $default_state ) {
	global $tvedb;

	return $tvedb->get_variation_already_subscribed_state( $default_state['key'] );
}

/**
 * check if form has already subscribed state
 *
 * @param array $form_id
 *
 * @return array|null
 */
function tve_leads_has_already_subscribed_state( $form_id ) {
	global $tvedb;

	return $tvedb->form_has_already_subscribed_state( $form_id );
}


/**
 * get the tracking data for a post from the post-meta option
 * if no value is present there, count the logs and update the meta option value with that number
 *
 * applies to: Lead Groups, Form Types, Shortcodes, 2-step Shortcodes
 *
 * @param WP_Post|int $post
 * @param int         $event_type
 * @param bool        $fetch_if_not_found whether or not to count the logs if there is no entry in the cache
 *
 * @return int
 */
function tve_leads_get_post_tracking_data( $post, $event_type = TVE_LEADS_UNIQUE_IMPRESSION, $fetch_if_not_found = true ) {
	$post_id = $post;
	if ( is_array( $post ) ) {
		$post_id = $post['ID'];
	} elseif ( is_a( $post, 'WP_Post' ) ) {
		$post_id = $post->ID;
	}

	$meta_key = 'tve_leads_' . ( $event_type === TVE_LEADS_UNIQUE_IMPRESSION ? 'impressions' : 'conversions' );

	$value = get_post_meta( $post_id, $meta_key, true );

	if ( $value === '' && $fetch_if_not_found === true ) {
		$value = tve_leads_get_tracking_data( $event_type, array( $post->post_type === TVE_LEADS_POST_FORM_TYPE ? 'form_type_id' : 'main_group_id' => $post->ID ) );
		update_post_meta( $post_id, $meta_key, $value );
	}

	return $value;
}

/**
 * get tracking data for a form variation (design). Form variations are stored in a separate table, so we cannot use the WP post_meta API
 *
 * applies to: Form Variations
 *
 * @param array $variation
 * @param int   $event_type
 *
 * @return int
 */
function tve_leads_get_variation_tracking_data( &$variation, $event_type = TVE_LEADS_UNIQUE_IMPRESSION ) {
	$key = 'cache_' . ( $event_type === TVE_LEADS_UNIQUE_IMPRESSION ? 'impressions' : 'conversions' );

	if ( $variation[ $key ] === null ) {
		$variation[ $key ]      = (int) tve_leads_get_tracking_data( $event_type, array( 'variation_key' => $variation['key'] ) );
		$variation['save_flag'] = true;
	}

	return $variation[ $key ];
}

/**
 * update the cached impression or conversion count for a post
 *
 * applies to: Lead Groups, Form Types, Shortcodes, 2-step Lightboxes
 *
 * @param mixed $post
 * @param int   $value
 * @param int   $event_type
 *
 * @return int|bool
 */
function tve_leads_set_post_tracking_data( $post, $value, $event_type = TVE_LEADS_UNIQUE_IMPRESSION ) {
	$post_id = $post;
	if ( is_array( $post ) ) {
		$post_id = $post['ID'];
	} elseif ( is_a( $post, 'WP_Post' ) ) {
		$post_id = $post->ID;
	}

	$meta_key = 'tve_leads_' . ( $event_type === TVE_LEADS_UNIQUE_IMPRESSION ? 'impressions' : 'conversions' );

	return update_post_meta( $post_id, $meta_key, $value );
}

/**
 * reset all cached impression and conversion count for a post (Lead Group / Form Type / Shortcode / 2-step Lightbox
 *
 * @param WP_Post $post
 *
 * @return bool
 */
function tve_leads_reset_post_tracking_data( $post ) {
	global $tvedb;

	if ( $post->post_parent ) {
		/**
		 * if this is a Form Type, we need to also update the parent cached impression count
		 */
		$impressions = tve_leads_get_post_tracking_data( $post, TVE_LEADS_UNIQUE_IMPRESSION );
		$conversions = tve_leads_get_post_tracking_data( $post, TVE_LEADS_CONVERSION );

		$parent_impressions = tve_leads_get_post_tracking_data( $post->post_parent, TVE_LEADS_UNIQUE_IMPRESSION, false );
		$parent_conversions = tve_leads_get_post_tracking_data( $post->post_parent, TVE_LEADS_CONVERSION, false );

		if ( $parent_impressions !== '' ) {
			$parent_impressions -= $impressions;
			tve_leads_set_post_tracking_data( $post->post_parent, $parent_impressions, TVE_LEADS_UNIQUE_IMPRESSION );
		}

		if ( $parent_conversions !== '' ) {
			$parent_conversions -= $conversions;
			tve_leads_set_post_tracking_data( $post->post_parent, $parent_conversions, TVE_LEADS_CONVERSION );
		}
	}

	tve_leads_set_post_tracking_data( $post, 0, TVE_LEADS_UNIQUE_IMPRESSION );
	tve_leads_set_post_tracking_data( $post, 0, TVE_LEADS_CONVERSION );

	/**
	 * also, we need to reset the data for all variations that have $post as post_parent
	 */
	$variations = tve_leads_get_form_variations( $post->ID, array(
		'tracking_data' => false,
		'post_status'   => array( TVE_LEADS_STATUS_PUBLISH, TVE_LEADS_STATUS_ARCHIVED ),
	) );
	foreach ( $variations as $v ) {
		$tvedb->update_variation_fields( $v, array(
			'cache_impressions' => 0,
			'cache_conversions' => 0,
		) );
	}

	return true;
}

/**
 * reset the cached tracking data for a variation and also update the cached tracking data for its parents (the Form Type and the Lead Group, if any)
 *
 * @param array $variation
 */
function tve_leads_reset_variation_tracking_data( $variation ) {
	global $tvedb;

	/**
	 * reset the cached variation logs
	 */
	$tvedb->update_variation_fields( $variation['key'], array(
		'cache_impressions' => 0,
		'cache_conversions' => 0,
	) );

	/**
	 * decrease the number of impressions and conversions from the parent cached variations (if any)
	 */
	$parent_impressions = tve_leads_get_post_tracking_data( $variation['post_parent'], TVE_LEADS_UNIQUE_IMPRESSION, false );
	$parent_conversions = tve_leads_get_post_tracking_data( $variation['post_parent'], TVE_LEADS_CONVERSION, false );

	/**
	 * update only if there actually is some cached data
	 */
	if ( $parent_impressions !== '' ) {
		$parent_impressions -= $variation['impressions'];
		tve_leads_set_post_tracking_data( $variation['post_parent'], $parent_impressions, TVE_LEADS_UNIQUE_IMPRESSION );
	}

	if ( $parent_conversions !== '' ) {
		$parent_conversions -= $variation['conversions'];
		tve_leads_set_post_tracking_data( $variation['post_parent'], $parent_conversions, TVE_LEADS_CONVERSION );
	}

	/**
	 * go a level higher, and change the cached data for the Lead Group, if any is found
	 */
	$parent = get_post( $variation['post_parent'] );
	if ( $parent && $parent->post_parent ) {
		$parent_impressions = tve_leads_get_post_tracking_data( $parent->post_parent, TVE_LEADS_UNIQUE_IMPRESSION, false );
		$parent_conversions = tve_leads_get_post_tracking_data( $parent->post_parent, TVE_LEADS_CONVERSION, false );

		if ( $parent_impressions !== '' ) {
			$parent_impressions -= $variation['impressions'];
			tve_leads_set_post_tracking_data( $parent->post_parent, $parent_impressions, TVE_LEADS_UNIQUE_IMPRESSION );
		}

		if ( $parent_conversions !== '' ) {
			$parent_conversions -= $variation['conversions'];
			tve_leads_set_post_tracking_data( $parent->post_parent, $parent_conversions, TVE_LEADS_CONVERSION );
		}
	}
}

/**
 * Prepare the file for download.
 *
 * @param $type
 * @param $filters
 *
 * @return array|void
 */
function tve_leads_process_contact_download( $type, $filters ) {
	require_once dirname( __FILE__, 2 ) . '/admin/inc/classes/Thrive_Leads_Export.php';

	$filename = "contacts-export-" . date( 'Y-m-d_H-i-s' );
	switch ( $type ) {
		case 'excel':
			$exporter = new ThriveLeadsExportDataExcel( 'browser', "$filename.xls" );
			break;

		case 'csv':
			$exporter = new ThriveLeadsExportDataCSV( 'browser', "$filename.csv" );
			break;
	}

	if ( empty( $exporter ) ) {
		return array(
			'response' => __( 'Invalid export type.', 'thrive-leads' ),
		);
	}

	$exporter->initialize();

	global $tvedb;
	/* get contacts needed for export */
	$contacts = $tvedb->tve_leads_get_contacts_stored( $filters );

	/* build file header with custom fields */
	$contacts_header = array(
		__( "Name", "thrive-leads" ),
		__( "Email", "thrive-leads" ),
		__( "Date and Time", "thrive-leads" ),
	);
	$custom_header   = array();
	foreach ( $contacts as $contact ) {
		$custom_fields = json_decode( $contact->custom_fields );
		foreach ( $custom_fields as $k => $v ) {
			if ( ! in_array( $k, $custom_header ) ) {
				$custom_header [] = $k;
			}
		}
	}
	$exporter->addRow( array_merge( $contacts_header, $custom_header ) );

	foreach ( $contacts as $contact ) {
		$fields = array( $contact->name, $contact->email, date( 'd M, Y G:i', strtotime( $contact->date ) ) );

		$custom_fields = json_decode( $contact->custom_fields, true );
		foreach ( $custom_header as $field ) {
			if ( isset( $custom_fields[ $field ] ) ) {
				$fields[] = $custom_fields[ $field ];
			} else {
				$fields[] = "";
			}
		}
		$exporter->addRow( $fields );
	}

	$exporter->finalize();

	wp_die();
}

/**
 * Return chart data for annotations
 *
 * @param $filter
 * @param $chart_data
 *
 * @return array
 */
function tve_leads_get_chart_annotations( $filter, $chart_data ) {
	$grow        = 0;
	$grows_count = 0;
	/* Calculate the medium growth so we can set a threshold for which to display annotations */
	for ( $i = 1; $i < count( $chart_data ); $i ++ ) {
		if ( $chart_data[ $i - 1 ] < $chart_data[ $i ] ) {
			$grow += $chart_data[ $i ] - $chart_data[ $i - 1 ];
			$grows_count ++;
		}
	}

	$data = array(
		'type'     => 'scatter',
		'id'       => 'flags',
		'zIndex'   => 2,
		'name'     => __( 'Marketing Events', 'thrive-leads' ),
		'color'    => '#800080',
		'onSeries' => 'dataseries',
		'shape'    => 'triangle',
		'data'     => array(),
	);

	if ( $grows_count ) {
		$medium_growth = $grow / $grows_count;
	} else {
		return $data;
	}

	$dates = tve_leads_generate_dates_interval( $filter['start_date'], $filter['end_date'], $filter['interval'] );

	/* We find the date interval where we have a growth bigger than the medium and we search events that we want to display */
	for ( $i = 1; $i < count( $chart_data ); $i ++ ) {
		if ( $chart_data[ $i ] - $chart_data[ $i - 1 ] > $medium_growth ) {

			$current_date = $dates[ $i - 1 ];

			if ( $i == count( $chart_data ) - 1 ) {
				/* If we're at the last value, we set the end date to today. */
				$end_date = date( 'Y-m-d' );
			}

			if ( strpos( $current_date, 'Week' ) !== false ) {
				$current_date = preg_replace( "/Week (\d*), (.\d*)/", "$2W$1", $current_date );
			}
			/* Convert the chart date in mysql date format so we can search posts in that period */
			$filter['start_date'] = date( 'Y-m-d', strtotime( $current_date ) ) . ' 00:00:00';
			$filter['end_date']   = date( 'Y-m-d', strtotime( $current_date ) ) . ' 23:59:59';

			$args = array(
				'post_type'      => array(
					'tve_lead_group',
					'tve_lead_shortcode',
					'tve_lead_2s_lightbox',
					'post',
					'page',
				),
				'posts_per_page' => - 1,
				'orderby'        => 'date',
				'order'          => 'ASC',
				'date_query'     => array(
					array(
						'after'     => $filter['start_date'],
						'before'    => $filter['end_date'],
						'inclusive' => true,
					),
				),
			);

			$query = new WP_query();
			$posts = $query->query( $args );

			$events = array(
				'post'                 => array(),
				'page'                 => array(),
				'tests'                => array(),
				'tve_lead_group'       => array(),
				'tve_lead_shortcode'   => array(),
				'tve_lead_2s_lightbox' => array(),
			);

			foreach ( $posts as $post ) {
				$_type = get_post_type( $post->ID );
				if ( ! empty( $post->post_title ) && $_type && isset( $events[ $_type ] ) ) {
					$events[ $_type ][] = $post->post_title;
				}
			}

			global $tvedb;
			$tests = $tvedb->tve_leads_get_tests( $filter );

			foreach ( $tests as $test ) {
				$events['tests'][] = $test->title;
			}

			if ( ! empty( $events['post'] ) || ! empty( $events['page'] ) || ! empty( $events['tests'] ) || ! empty( $events['tve_lead_group'] ) || ! empty( $events['tve_lead_shortcode'] ) || ! empty( $events['tve_lead_2s_lightbox'] ) ) {
				$title = '';
				$title .= empty( $events['post'] ) ? '' : '<span class="tve-data-label-posts"><b>' . __( 'Posts Created: ' ) . '</b>' . implode( ', ', $events['post'] ) . '</span><br>';
				$title .= empty( $events['page'] ) ? '' : '<span class="tve-data-label-pages"><b>' . __( 'Pages Created: ' ) . '</b>' . implode( ', ', $events['page'] ) . '</span><br>';
				$title .= empty( $events['tve_lead_group'] ) ? '' : '<span class="tve-data-label-groups"><b>' . __( 'Groups Created: ' ) . '</b>' . implode( ', ', $events['tve_lead_group'] ) . '</span><br>';
				$title .= empty( $events['tve_lead_shortcode'] ) ? '' : '<span class="tve-data-label-shortcodes"><b>' . __( 'Shortcodes Created: ' ) . '</b>' . implode( ', ', $events['tve_lead_shortcode'] ) . '</span><br>';
				$title .= empty( $events['tve_lead_2s_lightbox'] ) ? '' : '<span class="tve-data-label-thriveboxes"><b>' . __( 'ThriveBoxes Created: ' ) . '</b>' . implode( ', ', $events['tve_lead_2s_lightbox'] ) . '</span><br>';
				$title .= empty( $events['tests'] ) ? '' : '<span class="tve-data-label-tests"><b>' . __( 'Tests started: ' ) . '</b>' . implode( ', ', $events['tests'] ) . '</span>';

				/* We display the annotation between the points that indicate a growth at the middle */
				$data['data'][] = array(
					'x'          => $i - 0.5,
					'y'          => ( $chart_data[ $i ] - $chart_data[ $i - 1 ] ) / 2 + $chart_data[ $i - 1 ],
					'dataLabels' => array(
						'useHTML'       => true,
						'enabled'       => true,
						'format'        => $title,
						'verticalAlign' => 'bottom',
						'y'             => - 10,
					),
				);
			}
		}
	}


	return $data;

}

/**
 * Get data for asset wizard to decide if the wizard should show, list of connected apis, email templates,  and file/group proprieties
 *
 * @param array $asset_groups
 *
 * @return mixed
 */
function tve_leads_get_wizard_proprieties( $asset_groups = array() ) {
	$connected_apis = Thrive_List_Manager::get_available_apis( true, [ 'include_types' => [ 'email' ] ] );
	if ( empty( $connected_apis ) ) {
		$proprieties['connections'] = 0;
	} else {
		$proprieties['connections'] = 1;
	}
	$template_subject = get_option( 'tve_leads_asset_mail_subject' );
	$template_body    = get_option( 'tve_leads_asset_mail_body' );
	if ( empty( $template_subject ) || empty( $template_body ) ) {
		$proprieties['template'] = 0;
	} else {
		$proprieties['template'] = 1;
	}
	if ( empty( $asset_groups ) ) {
		$proprieties['files'] = 0;
	} else {
		foreach ( $asset_groups as $asset_group ) {
			if ( ! empty( $asset_group->files ) ) {
				$proprieties['files'] = 1;
			} else {
				$proprieties['files'] = 0;
			}
		}
	}

	return $proprieties;
}

/**
 * Fetch the user's full name
 *
 * @return string
 */
function tve_leads_assets_get_admin_name() {
	global $current_user;
	wp_get_current_user();

	return $current_user->user_firstname . " " . $current_user->user_lastname;
}

/**
 * Get the asset email template
 *
 * @return mixed
 */
function tve_leads_assets_get_email_data() {
	$email_data['template_subject'] = get_option( 'tve_leads_asset_mail_subject', '' );
	$email_data['template_body']    = get_option( 'tve_leads_asset_mail_body', '' );

	return $email_data;
}

/**
 * Sets the email template for asset delivery
 *
 * @param $data
 *
 * @return bool
 */
function tve_leads_set_email_template( $data ) {
	update_option( 'tve_leads_asset_mail_subject', stripslashes( $data['post_subject'] ) );
	update_option( 'tve_leads_asset_mail_body', stripslashes( $data['post_content'] ) );

	return true;
}

/**
 * Gets the running tests for inconclusive test check
 *
 * @return array|void
 */
function tve_get_running_inconclusive_tests() {
	/* @var Tho_Db */
	global $tvedb;

	$return       = array();
	$active_tests = $tvedb->tve_leads_get_tests( array(
		'status'           => TVE_LEADS_STATUS_RUNNING,
		'auto_win_enabled' => 1,
	) );

	if ( empty( $active_tests ) ) {
		return;
	}

	foreach ( $active_tests as $active_test ) {

		$test_items = $tvedb->get_test_items( array( 'test_id' => $active_test->id ) );

		$conversions = 0;
		foreach ( $test_items as $item ) {
			$conversions += intval( $item->conversions );
		}

		$minimum_duration_doubled = intval( $active_test->auto_win_min_duration ) * 2;
		if ( $active_test->auto_win_min_conversions * 2 <= $conversions && date( 'Y-m-d', strtotime( $active_test->date_started . ' + ' . $minimum_duration_doubled . ' days' ) ) <= date( 'Y-m-d' ) ) {
			$return[] = $active_test;
		}
	}

	return $return;
}

/**
 * Stops a test item and sets the variation as winner if it's the last variation
 *
 * @param $item_id
 * @param $test_id
 *
 * @return bool
 */
function tve_leads_stop_test_item( $item_id, $test_id ) {
	/* @var Tho_Db */
	global $tvedb;

	$return = $tvedb->stop_test_item( $item_id );
	if ( $return ) {
		$test_items = $tvedb->get_test_items( array( 'test_id' => $test_id, 'active' => 1 ) );
		if ( count( $test_items ) == 1 ) {
			$test_items[0]->is_winner = 1;
			tve_leads_save_test_item( (array) $test_items[0] );
		}

		return true;
	}

	return false;
}

/**
 * Read all asset delivery groups from DB and return them
 *
 * @param $arguments array filter the posts
 *
 * @param $arguments
 *
 * @return array of WP_Post groups
 */
function tve_leads_get_asset_delivery_groups( $arguments = array() ) {

	if ( ! is_array( $arguments ) ) {
		$arguments = array();
	}

	$defaults = array(
		'post_type'      => 'tve_lead_asset_group',
		'post_status'    => 'publish',
		'orderby'        => 'date',
		'order'          => 'ASC',
		'posts_per_page' => - 1,
	);

	$arguments = array_merge( $defaults, $arguments );

	return $posts_array = get_posts( $arguments );
}