<?php



class Statsdata {


	/** Generates JSON of impressions for ad, groups, ad clicks for a series of dates back
	 * @param null $days_back Number of days back from present
	 * @return string json encoded array for graphing
	 */
	public function DashboardGraphAdGroupJson($days_back = 7){
		$date_start = date('Ymd', strtotime('-'.$days_back.' days'));
		$date_end = date('Ymd');

		$cacheKey = 'DashboardGraphAdGroupJson.dash';
		$cache = \Cache::instance();
		$storedData = $cache->get($cacheKey);
		if (!empty($storedData)) return $storedData;

		/** @var Base */
		$f3 = \Base::instance();

		/** @var $statad Models\Statad */
		$statad_res = new \Models\Statad();
		$statads = $statad_res->find(array('date > ? AND date <= ? AND ad_id > 0', $date_start, $date_end), null, 30);

		/** @var $statgroup Models\Statgroup */
		$statgroup_res = new \Models\Statgroup();
		$statgroups = $statgroup_res->find(array('date > ? AND date <= ? AND group_id > 0', $date_start, $date_end), null, 30);


		$jsonArray = array();
		$jsonArray['cols'][] = array('label' => $f3->get('lang_day'), 'type' => 'string');
		$jsonArray['cols'][] = array('label' => $f3->get('lang_ad_impressions'), 'type' => 'number');
		$jsonArray['cols'][] = array('label' => $f3->get('lang_group_impressions'), 'type' => 'number');
		$jsonArray['cols'][] = array('label' => $f3->get('lang_ad_clicks'), 'type' => 'number');

		for ($d = $days_back - 1; $d >= 0; $d--){
			$curr_date = date('Ymd', strtotime('-'.$d.' days'));

			$adImpressions = 0;
			$adClicks = 0;
			if (!empty($statads)){
				foreach($statads as $statad){
					if (($statad->date == $curr_date) && (!empty($statad->impressions))) {
						$adImpressions += $statad->impressions;
						$adClicks += $statad->clicks;
					}
				}
			}

			$groupImpressions = 0;
			if (!empty($statgroups)){
				foreach($statgroups as $statgroup){
					if (($statgroup->date == $curr_date) && (!empty($statgroup->impressions))) { $groupImpressions += $statgroup->impressions;  }
				}
			}

			$jsonArray['rows'][]['c'] = array(
					array('v' => date('Y-m-d', strtotime('-'.$d.' days'))),
					array('v' => $adImpressions),
					array('v' => $groupImpressions),
					array('v' => $adClicks)
			);

		}

		$data = json_encode($jsonArray);
		$cache->set($cacheKey, $data, 600);

		return ($data);
	}


	/** Generates JSON of impressions for sales and landing pages for a series of dates back
	 * @param null $days_back Number of days back from present
	 * @return string json encoded array for graphing
	 */
	public function DashboardGraphSalesLandingPageJson($days_back = 7){
		$date_start = date('Ymd', strtotime('-'.$days_back.' days'));
		$date_end = date('Ymd');

		$cacheKey = 'DashboardGraphSalesLandingPageJson.dash';
		$cache = \Cache::instance();
		$storedData = $cache->get($cacheKey);
		if (!empty($storedData)) return $storedData;

		/** @var Base */
		$f3 = \Base::instance();

		/** @var $statsale Models\Statsale */
		$statsale_res = new \Models\Statsale();
		$statsales = $statsale_res->find(array('date > ? AND date <= ? AND sale_id > 0', $date_start, $date_end), null, 30);


		/** @var $statlandingpage Models\Statlandingpage */
		$statlandingpage_res = new \Models\Statlandingpage();
		$statlandingpages = $statlandingpage_res->find(array('date > ? AND date <= ?', $date_start, $date_end), null, 30);

		$jsonArray = array();
		$jsonArray['cols'][] = array('label' => $f3->get('lang_day'), 'type' => 'string');
		$jsonArray['cols'][] = array('label' => $f3->get('lang_sales'), 'type' => 'number');
		$jsonArray['cols'][] = array('label' => $f3->get('lang_landing_page_impressions'), 'type' => 'number');

		for ($d = $days_back - 1; $d >= 0; $d--){
			$curr_date = date('Ymd', strtotime('-'.$d.' days'));

			$sales = 0;
			if (!empty($statsales)){
				foreach($statsales as $statsale){
					if (($statsale->date == $curr_date) && (!empty($statsale->sales))) {
						$sales += $statsale->sales;
					}
				}
			}

			$landingpageImpressions = 0;
			if (!empty($statlandingpages)){
				foreach($statlandingpages as $statlandingpage){
					if (($statlandingpage->date == $curr_date) && (!empty($statlandingpage->impressions))) { $landingpageImpressions += $statlandingpage->impressions; }
				}
			}

			$jsonArray['rows'][]['c'] = array(
					array('v' => date('Y-m-d', strtotime('-'.$d.' days'))),
					array('v' => $sales),
					array('v' => $landingpageImpressions)
			);

		}


		$data = json_encode($jsonArray);
		$cache->set($cacheKey, $data, 600);

		return ($data);
	}


	/** Generates Array of top ads
	 * @param null $days_back Number of days back from present
	 * @param null $slice True to limit to 9
	 * @return array Array of top ads
	 */
	public function DashboardTopAds($days_back = 7, $slice = true){

		$date_start = date('Ymd', strtotime('-'.$days_back.' days'));
		$date_end = date('Ymd');

		$cacheKey = 'DashboardTopAds.dash.'.$days_back.'.'.(int)$slice;
		$cache = \Cache::instance();
		$storedData = $cache->get($cacheKey);
		if (!empty($storedData)) return $storedData;

		/** @var $statad Models\Statad */
		$statad_res = new \Models\Statad();
		$statads = $statad_res->find(array('date > ? AND date <= ? AND ad_id > 0', $date_start, $date_end),
				array('order'=>'impressions DESC'), 30);

		$topAds = array();
		if (empty($statads)) return ($topAds);

		foreach($statads as $statad){
			if (empty($statad->ad_id)) continue;

			$key = $statad->ad_id->_id;
			
			if (array_key_exists($statad->ad_id->_id, $topAds) === false) {
				$topAds[$key] = array();
				$topAds[$key]['title'] = $statad->ad_id->title;
			}

			$topAds[$key]['impressions'] = array_key_exists('impressions', $topAds[$key]) ? $topAds[$key]['impressions'] + $statad->impressions : $statad->impressions;
			$topAds[$key]['clicks'] = array_key_exists('clicks', $topAds[$key]) ? $topAds[$key]['clicks'] + $statad->clicks : $statad->clicks;
			if ($topAds[$key]['impressions'] > 0){
				$topAds[$key]['ctr'] = round(($topAds[$key]['clicks'] / $topAds[$key]['impressions']) * 100, 2);
			}
		}

		if ($slice) $topAds = array_slice($topAds, 0, 9, true);
		$cache->set($cacheKey, $topAds, 600);

		return ($topAds);
	}


	/** Generates Array of top groups
	 * @param null $days_back Number of days back from present
	 * @return array Array of top groups
	 */
	public function DashboardTopGroups($days_back = 7, $limit = 10){

		$date_start = date('Ymd', strtotime('-'.$days_back.' days'));
		$date_end = date('Ymd');

		$cacheKey = 'DashboardTopGroups.dash';
		$cache = \Cache::instance();
		$storedData = $cache->get($cacheKey);
		if (!empty($storedData)) return $storedData;

		/** @var $statgroup Models\Statgroup */
		$statgroup_res = new \Models\Statgroup();
		$statgroups = $statgroup_res->find(array('date > ? AND date <= ? AND group_id > 0', $date_start, $date_end), array('order'=>'impressions DESC'), 30);

		$topGroups = array();
		if (empty($statgroups)) return ($topGroups);

		foreach($statgroups as $statgroup){
			if (empty($statgroup->group_id)) continue;

			$key = $statgroup->group_id->_id;
			
			if (array_key_exists($statgroup->group_id->_id, $topGroups) === false) {
				$topGroups[$key] = array();
				$topGroups[$key]['title'] = $statgroup->group_id->title;
			}

			$topGroups[$key]['impressions'] = array_key_exists('impressions', $topGroups[$key]) ? $topGroups[$key]['impressions'] + $statgroup->impressions : $statgroup->impressions;
		}

		$cache->set($cacheKey, $topGroups, 600);

		return ($topGroups);
	}


	/** Generates Array of top sales
	 * @param null $days_back Number of days back from present
	 * @return array Array of top sales
	 */
	public function DashboardTopSales($days_back = 7, $limit = 10){

		$date_start = date('Ymd', strtotime('-'.$days_back.' days'));
		$date_end = date('Ymd');

		$cacheKey = 'DashboardTopSales.dash';
		$cache = \Cache::instance();
		$storedData = $cache->get($cacheKey);
		if (!empty($storedData)) return $storedData;

		/** @var $statsale Models\Statsale */
		$statsale_res = new \Models\Statsale();
		$statsales = $statsale_res->find(array('date > ? AND date <= ? AND sale_id > 0', $date_start, $date_end), array('order'=>'sales DESC'), 1);


		$topSales = array();
		if (empty($statsales)) return ($topSales);

		foreach($statsales as $statsale){
			if (empty($statsale->sale_id)) continue;

			$key = $statsale->sale_id->_id;

			if (array_key_exists($key, $topSales) === false) {
				$topSales[$key] = array();
				$topSales[$key]['title'] = $statsale->sale_id->title;
				$topSales[$key]['currency'] = $statsale->sale_id->pricing_currency;
			}

			$topSales[$key]['clicks'] = array_key_exists('clicks', $topSales[$key]) ? $topSales[$key]['clicks'] +
					$statsale->clicks : $statsale->clicks;
			$topSales[$key]['sales'] = array_key_exists('sales', $topSales[$key]) ? $topSales[$key]['sales'] +
					$statsale->sales : $statsale->sales;

			$paymentAmount = $this->_getSalesRecordPaymentAmount($date_start, $date_end, $key);
			$topSales[$key]['revenue'] = array_key_exists('revenue', $topSales[$key]) ? number_format($paymentAmount, 2) : number_format($paymentAmount, 2);
		}

		$cache->set($cacheKey, $topSales, 600);

		return ($topSales);
	}


	/** Generates string of sparkline data, overall change, percent change
	 * @return string of sparkline data, overall change, percent change
	 */
	public function DashboardWeeklyImpressions(){

		$date_start = date('Ymd', strtotime('-14 days'));
		$date_end = date('Ymd');

		$cacheKey = 'DashboardWeeklyImpressions.dash';
		$cache = \Cache::instance();
		$storedData = $cache->get($cacheKey);
		if (!empty($storedData)) return $storedData;

		/** @var $statad Models\Statad */
		$statad_res = new \Models\Statad();
		$statads = $statad_res->find(array('date > ? AND date <= ? AND ad_id > 0', $date_start, $date_end), array('order'=>'date ASC'), 1);

		$weeklyAds = array();
		$lastWeekTotal = 0;
		$currWeekTotal = 0;
		$weeklyAds['spark_week_ads'] = '';
		$weeklyAds['overall_num'] = 0;
		$weeklyAds['overall_per'] = 0.00;
		$weeklyAds['sign'] = 'up';

		if (empty($statads)) return ($weeklyAds);

		for ($d = 6; $d >= 0; $d--){
			$curr_week_date = date('Ymd', strtotime('-'.$d.' days'));
			$last_week_date = date('Ymd', strtotime('-'.($d + 7).' days'));

			$curr_week_impressions = 0;
			$last_week_impressions = 0;
			foreach($statads as $statad){
				if (($statad->date == $curr_week_date) && (!empty($statad->impressions))) {
					$curr_week_impressions += $statad->impressions;
					$currWeekTotal += $statad->impressions;
				}
				if (($statad->date == $last_week_date) && (!empty($statad->impressions))) {
					$last_week_impressions += $statad->impressions;
					$lastWeekTotal += $statad->impressions;
				}
			}
			$weeklyAds['spark_week_ads'] .= $curr_week_impressions - $last_week_impressions . ',';

		}
		$weeklyAds['spark_week_ads'] = trim($weeklyAds['spark_week_ads'], ',');
		$weeklyAds['overall_num'] = number_format($currWeekTotal - $lastWeekTotal);
		if ($currWeekTotal > $lastWeekTotal) $weeklyAds['overall_num'] = '+'.$weeklyAds['overall_num'];
		$weeklyAds['overall_per'] = $lastWeekTotal == 0 ? 0 : round((($currWeekTotal - $lastWeekTotal)/$lastWeekTotal) * 100, 2 );
		$weeklyAds['sign'] = $currWeekTotal < $lastWeekTotal ? 'down' : 'up';


		$cache->set($cacheKey, $weeklyAds, 600);

		return ($weeklyAds);
	}


	/** Generates string of sparkline data, overall change, percent change
	 * @return string of sparkline data, overall change, percent change
	 */
	public function DashboardWeeklyCTR(){

		$date_start = date('Ymd', strtotime('-14 days'));
		$date_end = date('Ymd');

		$cacheKey = 'DashboardWeeklyCTR.dash';
		$cache = \Cache::instance();
		$storedData = $cache->get($cacheKey);
		if (!empty($storedData)) return $storedData;

		/** @var $statad Models\Statad */
		$statad_res = new \Models\Statad();
		$statads = $statad_res->find(array('date > ? AND date <= ? AND ad_id > 0', $date_start, $date_end), array('order'=>'date ASC'), 1);

		$weeklyCTR = array();
		$lastWeekTotalImpressions = 0;
		$lastWeekTotalClicks = 0;
		$currWeekTotalClicks = 0;
		$currWeekTotalImpressions = 0;
		$weeklyCTR['spark_week_ctr'] = '';
		$weeklyCTR['overall_num'] = 0;
		$weeklyCTR['overall_per'] = 0.00;
		$weeklyCTR['sign'] = 'up';

		// Used for weekly stats email
		$weeklyCTR['week_total_impressions'] = 0;
		$weeklyCTR['week_change_impressions'] = '';
		$weeklyCTR['week_total_clicks'] = 0;
		$weeklyCTR['week_change_clicks'] = '';

		if (empty($statads)) return ($weeklyCTR);

		for ($d = 6; $d >= 0; $d--){
			$curr_week_date = date('Ymd', strtotime('-'.$d.' days'));
			$last_week_date = date('Ymd', strtotime('-'.($d + 7).' days'));

			$curr_week_impressions = 0;
			$curr_week_clicks = 0;
			$last_week_impressions = 0;
			$last_week_clicks = 0;
			foreach($statads as $statad){

				if (($statad->date == $curr_week_date) && (!empty($statad->impressions))) {
					$curr_week_impressions += $statad->impressions;
					$curr_week_clicks += empty($statad->clicks) ? 0 : $statad->clicks;
					$currWeekTotalImpressions += $statad->impressions;
					$currWeekTotalClicks += empty($statad->clicks) ? 0 : $statad->clicks;
				}
				if (($statad->date == $last_week_date) && (!empty($statad->impressions))) {
					$last_week_impressions += $statad->impressions;
					$last_week_clicks += empty($statad->clicks) ? 0 : $statad->clicks;
					$lastWeekTotalImpressions += $statad->impressions;
					$lastWeekTotalClicks += empty($statad->clicks) ? 0 : $statad->clicks;
				}
			}

			$curr_week_ctr = $curr_week_impressions > 0 ? ($curr_week_clicks / $curr_week_impressions) * 100 : 0;
			$last_week_ctr = $last_week_impressions > 0 ? ($last_week_clicks / $last_week_impressions) * 100 : 0;

			//$weeklyCTR['spark_week_ctr'] .= round ($curr_week_ctr - $last_week_ctr, 2) . ',';
			$weeklyCTR['spark_week_ctr'] .= ($curr_week_impressions-$last_week_impressions).':'.($curr_week_clicks-$last_week_clicks).',';

		}
		$weeklyCTR['spark_week_ctr'] = trim($weeklyCTR['spark_week_ctr'], ',');

		$weeklyCTR['week_total_impressions'] = $currWeekTotalImpressions;
		$weeklyCTR['week_change_impressions'] = $lastWeekTotalImpressions == 0 ? '0%' : round((($currWeekTotalImpressions - $lastWeekTotalImpressions)/$lastWeekTotalImpressions) * 100, 2 ) . '%';
		$weeklyCTR['week_total_clicks'] = $currWeekTotalClicks;
		$weeklyCTR['week_change_clicks'] = $lastWeekTotalClicks == 0 ? '0%' : round((($currWeekTotalClicks - $lastWeekTotalClicks)/$lastWeekTotalClicks) * 100, 2 ) . '%';

		$currWeekTotalCTR = $currWeekTotalImpressions > 0 ? ($currWeekTotalClicks / $currWeekTotalImpressions) : 0;
		$lastWeekTotalCTR = $lastWeekTotalImpressions > 0 ? ($lastWeekTotalClicks / $lastWeekTotalImpressions) : 0;
		$weeklyCTR['overall_num'] = round($currWeekTotalCTR - $lastWeekTotalCTR, 2) * 100;
		if ($currWeekTotalCTR > $lastWeekTotalCTR) $weeklyCTR['overall_num'] = '+'.$weeklyCTR['overall_num'];

		$weeklyCTR['overall_per'] = $lastWeekTotalCTR == 0 ? 0 : round((($currWeekTotalCTR - $lastWeekTotalCTR)/$lastWeekTotalCTR) * 100, 2 );
		$weeklyCTR['sign'] = $currWeekTotalCTR < $lastWeekTotalCTR ? 'down' : 'up';

		$cache->set($cacheKey, $weeklyCTR, 600);

		return ($weeklyCTR);
	}


	/** Generates string of sparkline data, overall change, percent change
	 * @return string of sparkline data, overall change, percent change
	 */
	public function DashboardWeeklySales(){

		$date_start = date('Ymd', strtotime('-14 days'));
		$date_end = date('Ymd');

		$cacheKey = 'DashboardWeeklySales.dash';
		$cache = \Cache::instance();
		$storedData = $cache->get($cacheKey);
		if (!empty($storedData)) return $storedData;

		/** @var $statsale Models\Statsale */
		$statsale_res = new \Models\Statsale();
		$statsales = $statsale_res->find(array('date > ? AND date <= ? AND sale_id > 0', $date_start, $date_end), array('order'=>'sales DESC'), 1);

		$weeklySales = array();
		$lastWeekTotal = 0;
		$currWeekTotal = 0;
		$lastWeekTotalRevenue = 0;
		$currWeekTotalRevenue = 0;
		$weeklySales['spark_week_sales'] = '';
		$weeklySales['overall_num'] = 0;
		$weeklySales['overall_per'] = 0.00;
		$weeklySales['sign'] = 'up';

		// Used for weekly stats email
		$weeklySales['week_total_sales'] = 0;
		$weeklySales['week_change_sales'] = '';
		$weeklySales['week_total_revenue'] = 0.00;
		$weeklySales['week_change_revenue'] = '';

		if (empty($statsales)) return ($weeklySales);

		for ($d = 6; $d >= 0; $d--){
			$curr_week_date = date('Ymd', strtotime('-'.$d.' days'));
			$last_week_date = date('Ymd', strtotime('-'.($d + 7).' days'));

			$curr_week_sales = 0;
			$last_week_sales = 0;
			$curr_week_revenue = 0;
			$last_week_revenue = 0;
			foreach($statsales as $statsale){

				if (($statsale->date == $curr_week_date) && (!empty($statsale->sale_id->_id))) {
					$paymentAmount = $this->_getSalesRecordPaymentAmount($curr_week_date, $curr_week_date, $statsale->sale_id->_id);

					$currWeekTotal += $statsale->sales;

					$curr_week_revenue += $paymentAmount;
					$currWeekTotalRevenue  += $paymentAmount;
				}
				if (($statsale->date == $last_week_date) && (!empty($statsale->sale_id->_id))) {
					$paymentAmount = $this->_getSalesRecordPaymentAmount($last_week_date, $last_week_date, $statsale->sale_id->_id);

					$lastWeekTotal += $statsale->sales;

					$last_week_revenue += $paymentAmount;
					$lastWeekTotalRevenue  += $paymentAmount;
				}
			}
			$weeklySales['spark_week_sales'] .= $curr_week_revenue - $last_week_revenue . ',';

		}
		$weeklySales['spark_week_sales'] = trim($weeklySales['spark_week_sales'], ',');

		$weeklySales['week_total_sales'] = $currWeekTotal;
		$weeklySales['week_change_sales'] = $lastWeekTotal == 0 ? '0%' : round((($currWeekTotal - $lastWeekTotal)/$lastWeekTotal) * 100, 2 ) . '%';
		$weeklySales['week_total_revenue'] = number_format($currWeekTotalRevenue, 2);
		$weeklySales['week_change_revenue'] = $lastWeekTotalRevenue == 0 ? '0%' : round((($currWeekTotalRevenue - $lastWeekTotalRevenue)/$lastWeekTotalRevenue) * 100, 2 ) . '%';


		$weeklySales['overall_num'] = number_format($currWeekTotalRevenue - $lastWeekTotalRevenue, 2);
		if ($currWeekTotalRevenue > $lastWeekTotalRevenue) $weeklySales['overall_num'] = '+'.$weeklySales['overall_num'];
		$weeklySales['overall_per'] = $lastWeekTotalRevenue == 0 ? 0 : round((($currWeekTotalRevenue - $lastWeekTotalRevenue)/$lastWeekTotalRevenue) * 100, 2 );
		$weeklySales['sign'] = $currWeekTotalRevenue < $lastWeekTotalRevenue ? 'down' : 'up';

		$cache->set($cacheKey, $weeklySales, 600);

		return ($weeklySales);
	}


	/** Pulls all available ads, groups, sales
	 * @return array Array of 'ads', 'groups', and 'sales'
	 */
	public function GetSelectList() {

		$selects = array();

		$f3 = \Base::instance();
		if ($f3->get('USER')->role > 7){
			// Load available ads for listing
			$res_ads = new \Models\Ad();
			$selects['ads'] = $res_ads->find(null, array('order'=>'title'));

			// Load available groups for listing
			$res_groups = new \Models\Group();
			$selects['groups'] = $res_groups->find(null, array('order'=>'title'));

			// Load available sales for listing
			$res_sales = new \Models\Sale();
			$selects['sales'] = $res_sales->find(null, array('order'=>'title'));

			// Load available users for listing
			$res_users = new \Models\User();
			$selects['users'] = $res_users->find(array('role < 9 AND enabled = 1'), array('order'=>'username'));
		} else {
			// Load available users for listing
			$res_users = new \Models\User();
			$selects['users'] = $res_users->find(array('_id=?', $f3->get('USER')->_id), array('order'=>'username'));
		}



		return ($selects);
	}


	public function GetStats($startDateTime, $endDateTime, $typeSelect, $id){

		$startDate = date('Ymd', $startDateTime);
		$endDate = date('Ymd', $endDateTime);
		$dateQuery = $startDate == $endDate ? 'date='.$startDate : 'date >= '.$startDate.' AND date <= '.$endDate;

		$stats = array();

		$f3 = \Base::instance();
		//Don't allow people below admin/super-admin to see other stats
		if ($f3->get('USER')->role < 8){
			if (($typeSelect != 'user') || ($id != $f3->get('USER')->_id)) return ($stats);
		}

		switch ($typeSelect){
			case 'ad':
				/** @var $statads Models\Statad */
				$statad_res = new \Models\Statad();
				$idSql = $id > 0 ? 'ad_id = '.$id : 'ad_id > 0';
				$statads = $statad_res->find(array($dateQuery.' AND '.$idSql), null, 120);
				$stats['stats_totals'] = $this->StatsTotals($statads, $typeSelect);
				$stats['stats_graph'] = $this->StatsGraph($startDateTime, $endDateTime, $typeSelect, $statads);
				$stats['data_table'] = $this->StatsTable($startDateTime, $endDateTime, $typeSelect, $statads);
				$stats['stats_geo_graph'] = $this->StatsGeoGraph($startDateTime, $endDateTime, $typeSelect, $statads);
				$stats['stats_general'] = $this->StatsGeneral($statads);
				break;

			case 'group':
				/** @var $statgroup Models\Statgroup */
				$statgroup_res = new \Models\Statgroup();
				$idSql = $id > 0 ? 'group_id = '.$id : 'group_id > 0';
				$statgroups = $statgroup_res->find(array($dateQuery.' AND '.$idSql), null, 120);
				$stats['stats_totals'] = $this->StatsTotals($statgroups, $typeSelect);
				$stats['stats_graph'] = $this->StatsGraph($startDateTime, $endDateTime, $typeSelect, $statgroups);
				$stats['data_table'] = $this->StatsTable($startDateTime, $endDateTime, $typeSelect, $statgroups);
				$stats['stats_geo_graph'] = '';
				$stats['stats_general'] = '';
				break;

			case 'sale':
				/** @var $statsale Models\Statsale */
				$statsale_res = new \Models\Statsale();
				$idSql = $id > 0 ? 'sale_id = '.$id : 'sale_id > 0';
				$statsales = $statsale_res->find(array($dateQuery.' AND '.$idSql), null, 120);

				/** @var $statlandingpage Models\Statlandingpage */
				$statlandingpage_res = new \Models\Statlandingpage();
				$statlandingpages = $statlandingpage_res->find(array('date > ? AND date <= ?', $startDate, $endDate), null, 120);
				$stats['stats_totals'] = $this->StatsTotals($statsales, $typeSelect, $statlandingpages);
				$stats['stats_graph'] = $this->StatsGraph($startDateTime, $endDateTime, $typeSelect, $statsales, $statlandingpages);
				$stats['data_table'] = $this->StatsTable($startDateTime, $endDateTime, $typeSelect, $statsales, $statlandingpages);
				$stats['stats_geo_graph'] = $this->StatsGeoGraph($startDateTime, $endDateTime, $typeSelect, $statlandingpages);
				$stats['stats_general'] = $this->StatsGeneral($statlandingpages);
				break;

			case 'user':
				$statads = array();
				/** @var $ad_res Models\Ad */
				$ad_res = new \Models\Ad();
				$usersAds = $ad_res->find(array('user_id = ? OR advertiser = ?', $id, $id), null, 120);
				if (!empty($usersAds)){
					$usersAdIds = '(';
					foreach ($usersAds as $usersAd) {
						$usersAdIds .= $usersAd->_id .',';
					}
					$usersAdIds = trim($usersAdIds,',').')';

					/** @var $statad Models\Statad */
					$statad_res = new \Models\Statad();
					$statads = $statad_res->find(array($dateQuery.' AND ad_id IN '.$usersAdIds), null, 120);
				}

				$stats['stats_totals'] = $this->StatsTotals($statads, $typeSelect);
				$stats['stats_graph'] = $this->StatsGraph($startDateTime, $endDateTime, $typeSelect, $statads);
				$stats['data_table'] = $this->StatsTable($startDateTime, $endDateTime, $typeSelect, $statads);
				$stats['stats_geo_graph'] = $this->StatsGeoGraph($startDateTime, $endDateTime, $typeSelect, $statads);
				$stats['stats_general'] = $this->StatsGeneral($statads);
				break;
		}

		return ($stats);
	}


	/** Generates totals for each type
	 * @param object $objects stat object
	 * @param string $type type of object
	 * @param null $objects2 stat object (landing page)
	 * @return array array of array of totals
	 */
	public function StatsTotals($objects, $type, $objects2 = null){

		/** @var Base */
		$f3 = \Base::instance();

		//Get totals per type
		$totalArray = array();
		$totalArray['impressions']['name'] = $f3->get('lang_ad_impressions');
		$totalArray['impressions']['font'] = 'fa-users';
		$totalArray['impressions']['value'] = 0;
		$totalArray['clicks']['name'] = $f3->get('lang_ad_clicks');
		$totalArray['clicks']['font'] = 'fa-share';
		$totalArray['clicks']['value'] = 0;
		if (empty($objects)) return ($totalArray);

		switch ($type){
			case 'ad':
			case 'user':
				$impressions = 0;
				$clicks = 0;
				foreach ($objects as $object) {
					$impressions += $object->impressions;
					$clicks += $object->clicks;
				}
			$totalArray['impressions']['name'] = $f3->get('lang_ad_impressions');
			$totalArray['impressions']['font'] = 'fa-users';
			$totalArray['impressions']['value'] = $impressions;
			$totalArray['clicks']['name'] = $f3->get('lang_ad_clicks');
			$totalArray['clicks']['font'] = 'fa-share';
			$totalArray['clicks']['value'] = $clicks;

				//$totalArray['object'] = array($f3->get('lang_ad_impressions') => $impressions,
				//		$f3->get('lang_ad_clicks') => $clicks);
				break;
			case 'group':
				$impressions = 0;
				foreach ($objects as $object) {
					$impressions += $object->impressions;
				}
				$totalArray['impressions']['name'] = $f3->get('lang_group_impressions');
				$totalArray['impressions']['font'] = 'fa-users';
				$totalArray['impressions']['value'] = $impressions;
				break;
			case 'sale':
				$impressions = 0;
				$sales = 0;
				foreach ($objects as $object) {
					$sales += $object->sales;
				}
				foreach ($objects2 as $object) {
					$impressions += $object->impressions;
				}
				$totalArray['impressions']['name'] = $f3->get('lang_landing_page_impressions');
				$totalArray['impressions']['font'] = 'fa-users';
				$totalArray['impressions']['value'] = $impressions;
				$totalArray['sales']['name'] = $f3->get('lang_sales');
				$totalArray['sales']['font'] = 'fa-shopping-cart';
				$totalArray['sales']['value'] = $sales;
				break;
		}

		return ($totalArray);
	}


	/** Generates JSON of impressions for a series of dates back
	 * @param string $fromDate Starting date
	 * @param string $toDate Ending date
	 * @param string $type type of object (ad, group, sale, user)
	 * @param array $object object (ad, group, sale, user)
	 * @param array $object2 object when passing sale and landing page
	 * @return string json encoded array for graphing
	 */
	public function StatsGraph($startDateTime, $endDateTime, $type, $object, $object2 = null){

		$numOfDays = $this->_days_diff($startDateTime, $endDateTime);
		/** @var Base */
		$f3 = \Base::instance();

		$jsonArray = array();
		$jsonArray['cols'][] = array('label' => $f3->get('lang_day'), 'type' => 'string');

		//Get cols per class type
		switch ($type){
			case 'ad':
				$jsonArray['cols'][] = array('label' => $f3->get('lang_ad_impressions'), 'type' => 'number');
				$jsonArray['cols'][] = array('label' => $f3->get('lang_ad_clicks'), 'type' => 'number');
				break;
			case 'group':
				$jsonArray['cols'][] = array('label' => $f3->get('lang_group_impressions'), 'type' => 'number');
				break;
			case 'sale':
				$jsonArray['cols'][] = array('label' => $f3->get('lang_landing_page_impressions'), 'type' => 'number');
				$jsonArray['cols'][] = array('label' => $f3->get('lang_sales'), 'type' => 'number');
				break;
			case 'user':
				$jsonArray['cols'][] = array('label' => $f3->get('lang_ad_impressions'), 'type' => 'number');
				$jsonArray['cols'][] = array('label' => $f3->get('lang_ad_clicks'), 'type' => 'number');
				break;
		}

		for ($d = 0; $d <= $numOfDays; $d++){
			$curr_date = date('Ymd', strtotime('+'.$d.' days', $startDateTime));

			switch ($type){
				case 'ad':
				case 'user':
					$adImpressions = 0;
					$adClicks = 0;
					if (!empty($object)){
						foreach($object as $statad){
							if (($statad->date == $curr_date) && (!empty($statad->impressions))) {
								$adImpressions += $statad->impressions;
								$adClicks += $statad->clicks;
							}
						}
					}
					$jsonArray['rows'][]['c'] = array(
							array('v' => date('Y-m-d', strtotime('+'.$d.' days', $startDateTime))),
							array('v' => $adImpressions),
							array('v' => $adClicks)
					);
					break;
				case 'group':
					$groupImpressions = 0;
					if (!empty($object)){
						foreach($object as $statgroup){
							if (($statgroup->date == $curr_date) && (!empty($statgroup->impressions))) { $groupImpressions += $statgroup->impressions; }
						}
					}
					$jsonArray['rows'][]['c'] = array(
							array('v' => date('Y-m-d', strtotime('+'.$d.' days', $startDateTime))),
							array('v' => $groupImpressions)
					);
					break;
				case 'sale':

					$sales = 0;
					if (!empty($object)){
						foreach($object as $statsale){
							if (($statsale->date == $curr_date) && (!empty($statsale->sales))) {
								$sales += $statsale->sales;
							}
						}
					}

					$landingpageImpressions = 0;
					if (!empty($object2)){
						foreach($object2 as $statlandingpage){
							if (($statlandingpage->date == $curr_date) && (!empty($statlandingpage->impressions))) { $landingpageImpressions += $statlandingpage->impressions; }
						}
					}

					$jsonArray['rows'][]['c'] = array(
							array('v' => date('Y-m-d', strtotime('+'.$d.' days', $startDateTime))),
							array('v' => $sales),
							array('v' => $landingpageImpressions)
					);
					break;
			}


		}

		return (json_encode($jsonArray));
	}


	/** Generates JSON of unique impressions for a series of dates back for geo
	 * @param string $fromDate Starting date
	 * @param string $toDate Ending date
	 * @param string $type type of object (ad, group, landing page, user)
	 * @param array $object object (ad, group, landing page, user)
	 * @return string json encoded array for graphing
	 */
	public function StatsGeoGraph($startDateTime, $endDateTime, $type, $object){

		$numOfDays = $this->_days_diff($startDateTime, $endDateTime);
		/** @var Base */
		$f3 = \Base::instance();

		if (empty($object)) return ('');
		$jsonArray = array();
		$jsonArray['cols'][] = array('label' => $f3->get('lang_region'), 'type' => 'string');

		//Get cols per class type
		switch ($type){
			case 'ad':
				$jsonArray['cols'][] = array('label' => $f3->get('lang_ad_impressions'), 'type' => 'number');
				break;
			case 'group':
				$jsonArray['cols'][] = array('label' => $f3->get('lang_group_impressions'), 'type' => 'number');
				break;
			case 'sale':
				$jsonArray['cols'][] = array('label' => $f3->get('lang_landing_page_impressions'), 'type' => 'number');
				break;
			case 'user':
				$jsonArray['cols'][] = array('label' => $f3->get('lang_ad_impressions'), 'type' => 'number');
				break;
		}

		for ($d = 0; $d <= $numOfDays; $d++){
			$curr_date = date('Ymd', strtotime('+'.$d.' days', $startDateTime));

			$geoI = array();
			switch ($type){
				case 'ad':
				case 'user':
					$adImpressions = 0;
					if (!empty($object)){
						foreach($object as $statad){

							if (($statad->date == $curr_date) && (!empty($statad->impressions)) && (!empty($statad->geos))) {

								foreach ($statad->geos as $geoKey => $geoValue){

									if (substr_count($geoKey,'|') <= 1){
										$geoKeyArray = explode('|',$geoKey);
										$country = '';
										$region = '';
										if (!empty($geoKeyArray[0])) {
											$country = \Geo::getCountryName($geoKeyArray[0]);
										}
										if ($country == '') continue;
										if ((count($geoKeyArray) > 1) && (!empty($geoKeyArray[1]))) {
											$region = \Geo::getRegionName($geoKeyArray[0],$geoKeyArray[1]);
											
											$geoICountryKey = str_replace("'","", $country.'-');
											if (array_key_exists($geoICountryKey, $geoI)){
												$geoI[$geoICountryKey] -= $geoValue;
											}
										}
										if (empty($region)) continue;
										$geoIKey = str_replace("'","", $country.'-'.$region);

										if (array_key_exists($geoIKey, $geoI)) {
											$geoI[$geoIKey] += $geoValue;
										} else {
											$geoI[$geoIKey] = $geoValue;
										}

									}
								}

							}
						}
					}

					if (count($geoI) > 0){
						foreach($geoI as $geoIKey => $geoIValue){
							$jsonArray['rows'][]['c'] = array(
									array('v' => $geoIKey),
									array('v' => $geoIValue)
							);
						}

					}

					break;
				case 'sale':

					$landingpageImpressions = 0;
					if (!empty($object)){
						foreach($object as $statlandingpage){

							if (($statlandingpage->date == $curr_date) && (!empty($statlandingpage->impressions)) && (!empty($statlandingpage->geos))) {

								foreach ($statlandingpage->geos as $geoKey => $geoValue){

									if (substr_count($geoKey,'|') == 1){
										$geoKeyArray = explode('|',$geoKey);
										$country = '';
										$region = '';
										if (!empty($geoKeyArray[0])) {
											$country = \Geo::getCountryName($geoKeyArray[0]);
										}
										if ($country == '') continue;
										if (!empty($geoKeyArray[1])) {
											$region = \Geo::getRegionName($geoKeyArray[0],$geoKeyArray[1]);									
										}
										if (empty($region)) continue;
										$geoIKey = $country.'-'.$region;

										if (array_key_exists($geoIKey, $geoI)) {
											$geoI[$geoIKey] += $geoValue;
										} else {
											$geoI[$geoIKey] = $geoValue;
										}

									}
								}

							}
						}
					}

					if (count($geoI) > 0){
						foreach($geoI as $geoIKey => $geoIValue){
							$jsonArray['rows'][]['c'] = array(
									array('v' => $geoIKey),
									array('v' => $geoIValue)
							);
						}
					}
					break;
			}


		}

		return json_encode($jsonArray);
	}


	/** Generates Array of table stats
	 * @param string $startDateTime Starting date
	 * @param string $endDateTime Ending date
	 * @param string $type type of object (ad, group, sale, user)
	 * @param array $object object (ad, group, sale, user)
	 * @param array $object2 object when passing sale and landing page
	 * @return array Array of table data
	 */
	public function StatsTable($startDateTime, $endDateTime, $type, $object, $object2 = null){

		$numOfDays = $this->_days_diff($startDateTime, $endDateTime);
		/** @var Base */
		$f3 = \Base::instance();

		$tableData = array();
		$tableData['cols'][] = $f3->get('lang_day');

		//Get cols per class type
		switch ($type){
			case 'ad':
				$tableData['cols'][] = $f3->get('lang_ad');
				$tableData['cols'][] = $f3->get('lang_ad_impressions');
				$tableData['cols'][] = $f3->get('lang_ad_clicks');
				$tableData['cols'][] = $f3->get('lang_ctr');
				break;
			case 'group':
				$tableData['cols'][] = $f3->get('lang_group');
				$tableData['cols'][] = $f3->get('lang_group_impressions');
				break;
			case 'sale':
				$tableData['cols'][] = $f3->get('lang_sales_spots');
				$tableData['cols'][] = $f3->get('lang_landing_page_impressions');
				$tableData['cols'][] = $f3->get('lang_clicks');
				$tableData['cols'][] = $f3->get('lang_sales');
				$tableData['cols'][] = $f3->get('lang_revenue');
				break;
			case 'user':
				$tableData['cols'][] = $f3->get('lang_ad');
				$tableData['cols'][] = $f3->get('lang_ad_impressions');
				$tableData['cols'][] = $f3->get('lang_ad_clicks');
				break;
		}

		$tableData['rows'] = array();

		for ($d = 0; $d <= $numOfDays; $d++){
			$curr_date = date('Ymd', strtotime('+'.$d.' days', $startDateTime));

			switch ($type){
				case 'ad':
				case 'user':
					try{
						if (!empty($object)){
							foreach($object as $statad){
								if (empty($statad->ad_id)) continue;

								if (($statad->date == $curr_date) && (!empty($statad->impressions))) {

									$key = $curr_date.$statad->ad_id->_id;

									if (array_key_exists($key, $tableData['rows']) === false) {
										$tableData['rows'][$key] = array();
										$tableData['rows'][$key][1] = date('Y-m-d', strtotime('+'.$d.' days', $startDateTime));
										$tableData['rows'][$key][2] = $statad->ad_id->title;
									}

									$tableData['rows'][$key][3] = array_key_exists(3, $tableData['rows'][$key]) ? $tableData['rows'][$key][3] + $statad->impressions : $statad->impressions;
									$tableData['rows'][$key][4] = array_key_exists(4, $tableData['rows'][$key]) ? $tableData['rows'][$key][4] + $statad->clicks : $statad->clicks;
									if ($tableData['rows'][$key][3] > 0){
										$tableData['rows'][$key][5] = round(($tableData['rows'][$key][4] / $tableData['rows'][$key][3]) * 100, 2);
									}

								}

							}
						}
					} catch (Exception $e){
						\Utils::Logger("[StatsTable]Error with ad/user in loop - ".$e);
					}
					break;

				case 'group':
					try{
						if (!empty($object)){
							foreach($object as $statgroup){
								if (empty($statgroup->group_id)) continue;

								if (($statgroup->date == $curr_date) && (!empty($statgroup->impressions))) {

									$key = $curr_date.$statgroup->group_id->_id;

									if (array_key_exists($key, $tableData['rows']) === false) {
										$tableData['rows'][$key] = array();
										$tableData['rows'][$key][1] = date('Y-m-d', strtotime('+'.$d.' days', $startDateTime));
										$tableData['rows'][$key][2] = $statgroup->group_id->title;
									}

									$tableData['rows'][$key][3] = array_key_exists(3, $tableData['rows'][$key]) ? $tableData['rows'][$key][3] + $statgroup->impressions : $statgroup->impressions;

								}

							}
						}
					} catch (Exception $e){
						\Utils::Logger("[StatsTable]Error with group in loop - ".$e);
					}
					break;

				case 'sale':

					try{
						if (!empty($object)){
							foreach($object as $statsale){
								if (empty($statsale->sale_id)) continue;

								if ($statsale->date == $curr_date) {

									$key = $curr_date.$statsale->sale_id->_id;

									if (array_key_exists($key, $tableData['rows']) === false) {
										$tableData['rows'][$key] = array();
										$tableData['rows'][$key][1] = date('Y-m-d', strtotime('+'.$d.' days', $startDateTime));
										$tableData['rows'][$key][2] = $statsale->sale_id->title;
									}

									$landingpage_res = new \Models\Statlandingpage();
									$landingpage = $landingpage_res->load(array('date=? AND site_key=?',$curr_date, $statsale->sale_id->site_key));
									if (!empty($landingpage)){
										$tableData['rows'][$key][3] = array_key_exists(3, $tableData['rows'][$key]) ? $tableData['rows'][$key][3] + $landingpage->impressions : $landingpage->impressions;
									}

									$tableData['rows'][$key][4] = array_key_exists(4, $tableData['rows'][$key]) ? $tableData['rows'][$key][4] + $statsale->clicks : $statsale->clicks;
									$tableData['rows'][$key][5] = array_key_exists(5, $tableData['rows'][$key]) ? $tableData['rows'][$key][5] + $statsale->sales : $statsale->sales;
									$paymentAmount = 0.00;
									if (!empty($statsale->sales)){
										$paymentAmount = $this->_getSalesRecordPaymentAmount($curr_date,$curr_date,$statsale->sale_id->_id);
									}
									$tableData['rows'][$key][6] = array_key_exists(6, $tableData['rows'][$key]) ? number_format($tableData['rows'][$key][6] + $paymentAmount, 2) : number_format($paymentAmount, 2);
								}

							}
						}
					} catch (Exception $e){
						\Utils::Logger("[StatsTable]Error with landingpages in loop - ".$e);
					}

					break;
			}



		}

		return ($tableData);

	}


	/** Generates Array of General stats
	 * @param object $objects Statad,group,keywords,landing page
	 * @return array Array of general which includes hostname, referer, etc
	 */
	public function StatsGeneral($objects){

		$generalArray = array();
		$generalArray['referers'] = null;
		$generalArray['hostnames'] = null;
		$generalArray['browsers'] = null;
		$generalArray['oss'] = null;
		$generalArray['devices'] = null;
		if (empty($objects)) return ($generalArray);

		$refererArray = array();
		$refererTotal = 0;
		$hostnameArray = array();
		$hostnameTotal = 0;
		$browserArray = array();
		$browserTotal = 0;
		$osArray = array();
		$osTotal = 0;
		$deviceArray = array();
		$deviceTotal = 0;
		foreach ($objects as $object) {

			// Referers
			if (!empty($object->referers)){
				foreach($object->referers as $rKey => $rValue){
					$key = md5(strtolower(trim($rKey)));
	
					if (array_key_exists($key, $refererArray) === false) {
						$refererArray[$key] = array();
						$refererArray[$key]['title'] = htmlspecialchars_decode(htmlspecialchars($rKey), ENT_QUOTES);
					}
					$refererArray[$key]['impressions'] = array_key_exists('impressions', $refererArray[$key]) ? $refererArray[$key]['impressions'] + $rValue : $rValue;
					$refererTotal += $rValue;
				}
			}

			// Hostnames
			if (!empty($object->hostnames)){
				foreach($object->hostnames as $rKey => $rValue){
					$key = md5(strtolower(trim($rKey)));

					if (array_key_exists($key, $hostnameArray) === false) {
						$hostnameArray[$key] = array();
						$hostnameArray[$key]['title'] = htmlspecialchars_decode(htmlspecialchars($rKey), ENT_QUOTES);
					}
					$hostnameArray[$key]['impressions'] = array_key_exists('impressions', $hostnameArray[$key]) ? $hostnameArray[$key]['impressions'] + $rValue : $rValue;
					$hostnameTotal += $rValue;
				}
			}

			// Browsers
			if (!empty($object->browsers)){
				foreach($object->browsers as $rKey => $rValue){
					$key = md5(strtolower(trim($rKey)));

					if (array_key_exists($key, $browserArray) === false) {
						$browserArray[$key] = array();
						$browserArray[$key]['title'] = $rKey;
					}
					$browserArray[$key]['impressions'] = array_key_exists('impressions', $browserArray[$key]) ? $browserArray[$key]['impressions'] + $rValue : $rValue;
					$browserTotal += $rValue;
				}
			}

			// Oss
			if (!empty($object->oss)){
				foreach($object->oss as $rKey => $rValue){
					$key = md5(strtolower(trim($rKey)));

					if (array_key_exists($key, $osArray) === false) {
						$osArray[$key] = array();
						$osArray[$key]['title'] = $rKey;
					}
					$osArray[$key]['impressions'] = array_key_exists('impressions', $osArray[$key]) ? $osArray[$key]['impressions'] + $rValue : $rValue;
					$osTotal += $rValue;
				}
			}

			// Browsers
			if (!empty($object->devices)){
				foreach($object->devices as $rKey => $rValue){
					$key = md5(strtolower(trim($rKey)));

					if (array_key_exists($key, $deviceArray) === false) {
						$deviceArray[$key] = array();
						$deviceArray[$key]['title'] = $rKey;
					}
					$deviceArray[$key]['impressions'] = array_key_exists('impressions', $deviceArray[$key]) ? $deviceArray[$key]['impressions'] + $rValue : $rValue;
					$deviceTotal += $rValue;
				}
			}
			
		}
		
		foreach($refererArray as $rKey => $rValue){
			$refererArray[$rKey]['percentage'] = $refererTotal > 0 ? number_format(($rValue['impressions']/$refererTotal), 2) * 100 : 0;
		}
		$generalArray['referers'] = $refererArray;

		foreach($hostnameArray as $rKey => $rValue){
			$hostnameArray[$rKey]['percentage'] = $hostnameTotal > 0 ? number_format(($rValue['impressions']/$hostnameTotal), 2) * 100 : 0;
		}
		$generalArray['hostnames'] = $hostnameArray;

		foreach($browserArray as $rKey => $rValue){
			$browserArray[$rKey]['percentage'] = $browserTotal > 0 ? number_format(($rValue['impressions']/$browserTotal), 2) * 100 : 0;
		}
		$generalArray['browsers'] = $browserArray;

		foreach($osArray as $rKey => $rValue){
			$osArray[$rKey]['percentage'] = $osTotal > 0 ? number_format(($rValue['impressions']/$osTotal), 2) * 100 : 0;
		}
		$generalArray['oss'] = $osArray;

		foreach($deviceArray as $rKey => $rValue){
			$deviceArray[$rKey]['percentage'] = $deviceTotal > 0 ? number_format(($rValue['impressions']/$deviceTotal), 2) * 100 : 0;
		}
		$generalArray['devices'] = $deviceArray;

		return ($generalArray);
	}



	private function _getSalesRecordPaymentAmount($date_start, $date_end, $saleId){
		$paymentAmount = 0.00;

		/** @var $salerecords Models\Salerecord */
		$salerecord_res = new \Models\Salerecord();
		$dateQuery = $date_start == $date_end ? 'date='.$date_start : 'date > '.$date_start.' AND date <= '.$date_end;
		$salerecords = $salerecord_res->find(array($dateQuery.' AND sale_id=?', $saleId), null, 1);
		$f3 = \Base::instance();
		if (!empty($salerecords)){
			foreach ($salerecords as $salerecord) {
				$paymentAmount += $salerecord->payment_amount;
			}
		}

		return ($paymentAmount);
	}


	private function _days_diff($first_date, $second_date)
	{
		$later = new DateTime(date('Y-m-d',$second_date));
		$then = new DateTime(date('Y-m-d',$first_date));

		if ($later == $then) return 0;
		return $then->diff($later)->days;
	}
	

} 