<?php

/* 

 * phpMyVisites : website statistics and audience measurements

 * Copyright (C) 2002 - 2006

 * http://www.phpmyvisites.net/ 

 * phpMyVisites is free software (license GNU/GPL)

 * Authors : phpMyVisites team

*/



// $Id: ArchivePeriod.class.php 102 2006-10-01 16:28:30Z matthieu_ $





/**

 * Used for misc periods, weeks, months, and years

 * Can archive a period using the DAYS of the period, or the MONTHS,

 * depending on the var periodType value

 */

class ArchivePeriod extends Archive

{

	

	var $subPeriodValues = array();

	var $archiveDay;

	

	function ArchivePeriod($site, $s_date, $s_date2, $typePeriod)

	{

		parent::Archive($site);

		$this->setPeriodType($typePeriod);

		$this->date = $this->offsetDate(new Date($s_date));

		$this->date2 = $this->offsetDate(new Date($s_date2));

	}

	

	function setDate($s_date)

	{

		$this->reset();

		$this->getPeriodDatesLimit($s_date);

		

		if($this->date->isPeriodFinished($this->periodType))

		{

			$this->state = DB_ARCHIVES_DONE;

		}

		else

		{

			$this->state = DB_ARCHIVES_TEMP;

		}

		

		

		$this->setLiteralDate();

	}

	

	function reset()

	{

		

		$this->date = null;

		$this->toRecord = null;

		$this->idArchives = null; 

		$this->state = null;

		

		$this->date2 = null;

		$this->subPeriodValues = null;

	}

	

	/**

	 * If period isn't archived, then it assign var state, var archiveSubPeriod,

	 * and each subperiod values in subPeriodValues array 

	 * If period is already archived, true

	 * 

	 * @return bool 

	 */

	function isArchived()

	{		

		$r = query("SELECT idarchives 

					FROM ".T_ARCHIVES."

			 		WHERE idsite = ".$this->site->getId()."

					AND date1 = '".$this->date->get()."'

					AND date2 = '".$this->date2->get()."'

					AND period = ".$this->periodType."

					AND done <> ".DB_ARCHIVES_FAIL

			);



		// not archived

		if(mysql_num_rows($r) == 0)

		{

			// if YEAR, we use Months for processing

			if( $this->periodType ===  DB_ARCHIVES_PERIOD_YEAR)

			{

				$this->archiveSubPeriod = new ArchiveMonth($this->site);

				$a_subPeriod = getDayOfMonthBetween($this->date->get(), $this->date2->get());

			}

			// in the other cases, we use Days for processing

			else

			{

				$this->archiveSubPeriod = new ArchiveDay($this->site);

				$a_subPeriod = getDaysBetween($this->date->get(), $this->date2->get());

				printDebug("Not archive... launch computation for ");

				printDebug($a_subPeriod);

			}

			

			

			foreach($a_subPeriod as $subPeriod)

			{

				// printDebug("<br>avant set date : ".$this->archiveSubPeriod->date->get());

				$this->archiveSubPeriod->setDate($subPeriod);

				//printDebug("<br>apres set date : devrait etre $subPeriod et est ".$this->archiveSubPeriod->date->get());

								

				// if any of the days in period is temp, then the whole period is set to temp

				if($this->archiveSubPeriod->state === DB_ARCHIVES_TEMP)

				{

					$this->state = DB_ARCHIVES_TEMP;

				}

				

				// store in ->subPeriodValues[] days to compute and select * for each day

				$l = $this->archiveSubPeriod->getArchived();

				

				// if subperiod is the day, stocke KEY = DATE

				// else if period, stock KEY = IDARCHIVES

				// needed for computing nb_uniq_vis

				if($this->periodType ===  DB_ARCHIVES_PERIOD_YEAR)

				{

					$key = $l['idarchives'];

				}

				else

				{

					$key = $subPeriod;

				}

				

				$this->subPeriodValues[$key] = $l; 

			}

			//printDebug("OK we have all datas<br>");

			//printDebug($this->subPeriodValues);

			

			return false;

		}

		// if the period date, date2 is known, means ever archived, it's ok

		// because the period is only computed ONCE for each couple (date, date2)

		else

		{

			printDebug("<u>Period known ! Don't archive</u><br>");

			$l = mysql_fetch_assoc($r);

			

			$this->idArchives = $l['idarchives'];

			return true;

		}

	}

	

	/**

	 * returns 'select *' for current period

	 * 

	 * @return array SELECT * FROM archives [...]

	 */

	function getArchived()

	{

		if(!$this->isArchived())

		{

			printDebug("Compute new period...");

			$this->compute();

		}

		else

		{ 

			printDebug("period already computed...");

		}

		$r = query("SELECT * 

					FROM ".T_ARCHIVES."

					WHERE idarchives = ".$this->idArchives ."

					ORDER BY idarchives DESC

					LIMIT 1"

		);

		

		return mysql_fetch_assoc($r);

	}



		

	/**

	 * Computes datas for all subPeriodValues values 

	 * and saves it in a new row in the database table archives

	 * 

	 * @return void

	 */

	function compute()

	{			

		if(CURRENT_PERIOD_SIMPLE_ARCHIVE && $this->state === DB_ARCHIVES_TEMP)

		{

			$this->toRecord['simple'] = 1;

		}

		else

		{

			$this->toRecord['simple'] = 0;

		}

		// date in the IN(...) SQL field for unique visitors

		$inIdArchives = '';

		$this->toRecord['vis_pag_grp'] = array();

		

		// init 

		$toInitInt = $this->intValuesToSum;

		$toInitArray = array_merge($this->arrayOneDimToSum, 

									$this->arrayPmvSumToSum, 

									$this->arrayIntToSum);

		foreach($toInitInt as $value)

		{

			$this->toRecord[$value] = 0;

		}

		foreach($toInitArray as $value)

		{

			$this->toRecord[$value] = array();

		}

		

		

		// for each subPeriod, sum all values

		foreach($this->subPeriodValues as $idArchives => $subPeriodValues)

		{			

			

			foreach($this->intValuesToSum as $name)

			{

				$this->toRecord[$name] += $subPeriodValues[$name];

			}

			

			// case we don't want a SIMPLE archiving 

			if($this->toRecord['simple'] == 0)

			{

				//printDebug("Sum2 : <br>");

				foreach ($this->arrayOneDimToSum as $name) 

				{

					if(!isset($subPeriodValues[$name]))

					{

						$subPeriodValues[$name] = compress(serialize(array()), $subPeriodValues['compressed']);

					}

					$this->toRecord[$name] = 

							getArrayOneDimVeryVeryVerySpecialSum($this->toRecord[$name], 

								unserialize(uncompress($subPeriodValues[$name], $subPeriodValues['compressed'])), "sum");

	

				}

				

				//printDebug("Sum3 : <br>");

				foreach($this->arrayPmvSumToSum as $name)

				{

					if(!isset($subPeriodValues[$name]))

					{

						$subPeriodValues[$name] = compress(serialize(array()), $subPeriodValues['compressed']);

					}

	

						$this->toRecord[$name] = 

							getArrayOneDimVeryVeryVerySpecialSum($this->toRecord[$name], 

									unserialize(uncompress($subPeriodValues[$name], $subPeriodValues['compressed'])), "sumArray");

				}

				

				//printDebug("Sum4 : <br>");

				foreach($this->arrayIntToSum as $name)

				{

					if(!isset($subPeriodValues[$name]))

					{

						$subPeriodValues[$name] = compress(serialize(array()), $subPeriodValues['compressed']);

					}

	

					$this->toRecord[$name] = 

						getArrayOneDimVeryVeryVerySpecialSum($this->toRecord[$name], 

								unserialize(uncompress($subPeriodValues[$name], $subPeriodValues['compressed'])), "sumArray");

				}

				

				//printDebug("<h1>Sum5  $idArchives: </h1><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>");

				//printDebug("table to add");

				//printDebug(unserialize($subPeriodValues['vis_pag_grp']));

				if(!is_string($subPeriodValues['vis_pag_grp']))

					$subPeriodValues['vis_pag_grp'] = compress(serialize(array()), $subPeriodValues['compressed']);

					

				$this->toRecord['vis_pag_grp'] = getPagGrpArrayMultiDimSum($this->toRecord['vis_pag_grp'],

													unserialize(uncompress($subPeriodValues['vis_pag_grp'], $subPeriodValues['compressed'])));

			}



			$inIdArchives .= "'".$idArchives."', ";

		}

		

		//printDebug($this->toRecord['vis_pag_grp']); 

		//exit;

		/*

		 * Sorting arrays

		 */

		

		$this->sortAndLimitToRecord();

		

		$inIdArchives = substr($inIdArchives, 0, strlen($inIdArchives) - 2);

				

		// if year, look for info averaging month archives

		if($this->periodType === DB_ARCHIVES_PERIOD_YEAR)

		{

			$r = query("SELECT sum(nb_uniq_vis) as nb_uniq_vis, max(nb_max_pag) as nb_max_pag

					FROM ".T_ARCHIVES."

					WHERE idarchives IN (".$inIdArchives.")"

					);

					

			// unique visitors returning sum on the period

			$nb_uniq_vis_returning = query("SELECT sum(nb_uniq_vis_returning) as nb_uniq_vis_returning

											FROM ".T_ARCHIVES."

											WHERE idarchives IN (".$inIdArchives.")"

											);

			// returning visitors

			$returning = query("SELECT nb_vis_returning as s, idarchives as pseudodate, 

									nb_pag_returning as sp, date1 as pseudodate2

						FROM ".T_ARCHIVES."

						WHERE idsite = ".$this->site->getId()."

						AND idarchives IN (".$inIdArchives.")

						GROUP BY pseudodate

						");

			

		}

		// but for other periods, look directly into logs tables

		// CAREFUL : WONT WORK FOR PERIOD OLDER THAN 1 MONTH !!

		else

		{

			$r = query("SELECT count(distinct idcookie) as nb_uniq_vis, max(total_pages) as nb_max_pag

				FROM ".T_VISIT."

				WHERE idsite = ".$this->site->getId()."

				AND server_date IN (".$inIdArchives.")"

				);

				

			

			// unique visitors returning sum on the period

			$nb_uniq_vis_returning = query("SELECT count(distinct idcookie) as nb_uniq_vis_returning	

											FROM ".T_VISIT."

											WHERE idsite = ".$this->site->getId()."

											AND server_date IN (".$inIdArchives.")

											AND returning = 1

				 							GROUP BY returning"

											);



			// returning visitors

			$returning = query("SELECT count(*) as s, server_date as pseudodate, 

										sum(total_pages) as sp

						FROM ".T_VISIT."

						WHERE idsite = ".$this->site->getId()."

						AND server_date IN (".$inIdArchives.")

						AND returning = 1

						GROUP BY pseudodate"); 

			

			// for each returning visit, how many time did they return?			

			$f1 = query("SELECT count(*) as s

						FROM ".T_VISIT."

						WHERE idsite = ".$this->site->getId()."

						AND server_date IN (".$inIdArchives.")

						GROUP BY idcookie");	

			$res = array();					

			while($fx = mysql_fetch_assoc($f1))

			{

				@$res[(int)$fx['s']]++;

			}

			ksort($res);		

			$this->toRecord['vis_nb_vis'] = $res;

			

		}	

		$nb_uniq_vis_returning = mysql_fetch_assoc($nb_uniq_vis_returning);

		$this->toRecord['nb_uniq_vis_returning'] = $nb_uniq_vis_returning['nb_uniq_vis_returning'];	

			

		$l = mysql_fetch_assoc($r);

		$this->toRecord['nb_uniq_vis'] = $l['nb_uniq_vis'];

		$this->toRecord['nb_max_pag']  = $l['nb_max_pag'];

		

		// visits per period, new vs returning, and pages hits

		$returningTotal = 0;

		$returningPag = 0;

		$this->toRecord['vis_period'] = array();

		while($l2 = mysql_fetch_assoc($returning))

		{

			$visitsTotal = $this->subPeriodValues[$l2['pseudodate']]['nb_vis'];

			$pagesTotal =  $this->subPeriodValues[$l2['pseudodate']]['nb_pag'];

			$returningVisits = $l2['s'];

			

			$returningPag += $l2['sp'];

			

			$returningTotal += $returningVisits;

			

			$this->toRecord['vis_period'][isset($l2['pseudodate2'])?$l2['pseudodate2']:$l2['pseudodate']] = array(

						ARRAY_INDEX_RETURNING_COUNT => (int)$returningVisits,

						ARRAY_INDEX_NEW_COUNT => $visitsTotal - $returningVisits,

						ARRAY_INDEX_PAGES_COUNT => (int)$pagesTotal

						);

		}

		ksort($this->toRecord['vis_period']);

		// number of returning visits

		$this->toRecord['nb_vis_returning'] = $returningTotal;

		$this->toRecord['nb_pag_returning'] = $returningPag;

			

		//printDebug("TO RECORD<br>");

		//printDebug($this->toRecord);

				

		/*

		 * init

		 */

		 

		$this->initDb();

		

		/*

		 * final save, close your eyes and prey 

		 */

		 $this->saveDb();

		 

		 /**

		  * delete all visit/month records

		  */

		  

		$this->deleteOldRecords();

	}

	

	// TODO protéger le champ pmv_sum des mots clés	

	function deleteOldRecords()

	{

		parent::deleteOldRecords();

		

		// delete records in VISIT that are useless 

		// (means when week AND month using these records are archived)

		if(

			($this->periodType === DB_ARCHIVES_PERIOD_MONTH

				|| $this->periodType === DB_ARCHIVES_PERIOD_WEEK)

			&& $this->state !== DB_ARCHIVES_TEMP)

		{

			// select all weeks and months begin and end

			$r = query("SELECT date1, date2, idsite, period, idarchives

						FROM ".T_ARCHIVES."

						WHERE done = ".DB_ARCHIVES_DONE."

							AND (period = ".DB_ARCHIVES_PERIOD_WEEK."

								OR period = ".DB_ARCHIVES_PERIOD_MONTH."

								)

						"); 

			while($l = mysql_fetch_assoc($r))

			{

				// stock all dates between these two in an array

				$dateBetween = getDaysBetween( $l['date1'], $l['date2']);

				

				//print($l['idarchives'] ."<br>");

				//print( $l['date1'].",". $l['date2']." id=:". $l['idsite']." period=:". $l['period']." "	);

				//print_r($dateBetween); print("<br> which is ".sizeof($dateBetween)." elements <br><br>");

				

				if(isset($flag[$l['idsite']][$l['period']][$l['date1']]))

				{

					$c = $flag[$l['idsite']][$l['period']][$l['date1']];

					if(sizeof($c) < sizeof($dateBetween)

						&& sizeof($dateBetween) >= 7)

					{

						$flag[$l['idsite']][$l['period']][$l['date1']] = $dateBetween;

					}

				}

				else

				{

					$flag[$l['idsite']][$l['period']][$l['date1']] = $dateBetween;

				}

			}

			//exit;

			

			foreach($flag as $idsite => $a_idsite)

			{

				foreach($a_idsite as $period => $a_period)

				{

					foreach($a_period as $a_date)

					{

						foreach($a_date as $d)

						{

							if(!isset($toCheck[$idsite][$d]))

							{

								$toCheck[$idsite][$d] = 1;

							}

							else

							{

								$toCheck[$idsite][$d]++;

							}

						}

					}

				}

			}

			//print("<pre>Apres sommes des dates <br>");

			//print_r($toCheck);

			

			$deleted = 0;

			foreach($toCheck as $idsite => $a_date)

			{

				foreach($a_date as $date => $hits)

				{

					// for the days who have 2 hits (mean that weeks and month that contain 

					// this day are archived)

					// delete these day records!

					if($hits > 1)

					{

						$r = query("DELETE

									FROM ".T_VISIT."

									WHERE server_date = '".$date."'

										AND idsite = $idsite

										");

						$deleted+=mysql_affected_rows();

					}

				}

			}

			//print("rows deleted = $deleted");

			if(time()%3==0)

			{

				$r = query("OPTIMIZE TABLE ".T_VISIT);

			}

		}

	}	

}

?>