<?php
/*
 * Created on 25.02.2012
 * Oliver Soop(osoop1@ut.ee)
 */
 
include_once ("BaseCrawler.php");
include_once ("../utils/UrlParseUtil.php");
include_once ("../database/RSSDatabaseService.php");
include_once ("../database/URLDatabaseService.php");

class RSSUrlCrawler extends BaseCrawler {
	private $baseUrl;
	private $baseDomain;
	private $visitedUrls;
	private $rssFeeds;
	private $maxFeedCount = 5000;

	private static $urlAttribute = "href";
	private static $relAttribute = "rel";
	private static $typeAttribute = "type";
	private static $relAttributeValue = "alternate";
	private static $typeAttributeValue = "rss+xml";
	private static $urlTag = "a";
	private static $rssTag = "rss";
	private static $linkTag = "link";
	private static $seconds;

	private static $urlsToCheck;

	public function __construct($baseUrl) {
		$this->baseUrl = $baseUrl;
		$this->baseDomain = UrlParseUtil :: getDomain($baseUrl);
		$this->visitedUrls = array ();
		$this->rssFeeds = array ();
		$this->urlsToCheck = array ();
		array_push($this->urlsToCheck, $baseUrl);
	}
	
	/**
 	* Funktsioon määramaks PHP skripi käivitusperioodi pikkust, mille vaikimisi väärtus määratakse
 	* php.ini failis
 	*/
	public function setTimeLimit($seconds) {
		$this->seconds = $seconds;
		set_time_limit($seconds);
	}

	/**
	 * Põhifunktsioon, mis käivitatakse, et RSS-vooge otsida.
	 */
	public function crawl() {
		if ($this->baseUrl == null) {
			return;
		}
		$maxCrawlTime = strtotime("+".($this->seconds - 30)." seconds");
		while (count($this->urlsToCheck) > 0 && count($this->rssFeeds) < $this->maxFeedCount && time() < $maxCrawlTime) {
			$url = array_shift($this->urlsToCheck);
			if (!URLDatabaseService :: checkIfUrlIsCrawled($url)) {
				$resource = parent :: getWebPage($url);
				if ($resource != null) {
					$this->getAllUrlsInHtml(parent :: getWebPage($url), $url);
					URLDatabaseService :: addCrawledUrl($url);
					array_push($this->visitedUrls, $url);
				}

			}
		}
		return $this->rssFeeds;
	}

	/**
	 * Funktsioon leidmaks HTML dokumendist kõik kirjeldatud URL-id,
	 * mis lisatakse roomatavate URL-ide nimekirja.
	 */
	private function getAllUrlsInHtml($html, $url) {
		$document = new DOMDocument();
		@ $document->loadHtml($html->getContent());

		//Kontrollime, kas on RSS feed
		if (RSSUrlCrawler :: isRSS($document)) {
			if (!in_array($url, $this->rssFeeds)) {
				array_push($this->rssFeeds, $url);
				RSSDatabaseService :: addFeedUrl($this->getValidUrl($url, $this->baseUrl));

			}
		}

		//Kontrollime, kas on võimalik esitada HTML-i RSS feedina
		$rssAlternative = RSSUrlCrawler :: hasRSSAlternative($document);
		if ($rssAlternative != null) {
			$rssAlternative = $this->getValidUrl($rssAlternative, $this->baseUrl);
			if (!in_array($rssAlternative, $this->rssFeeds)) {
				array_push($this->rssFeeds, $rssAlternative);
				RSSDatabaseService :: addFeedUrl($rssAlternative);
			}
		}
		//Kontrollime domeeni piiri
		if (UrlParseUtil :: compareDomains($this->baseUrl, $url)) {
			$urls = $document->getElementsByTagName("a");
			foreach ($urls as $val) {
				if (!$this->checkInput($val->getAttribute(self :: $urlAttribute))) {
					continue;
				}
				$foundUrl = $this->getValidUrl($val->getAttribute(self :: $urlAttribute), $this->baseUrl);
				array_push($this->urlsToCheck, $foundUrl);
			}
		}

	}

	/**
	 * Funktsioon kontrollimaks, kas laetud dokument kirjeldab RSS voogu
	 */
	public function isRSS($document) {
		//Kontrollime, kas dokumendis olevate tag-ide hulgas on RSS tag-e
		if ($document->getElementsByTagName(self :: $rssTag)->length > 0) {
			return true;
		}
		return false;
	}

	/**
	 * Funktsioon, mis tagastab, kas antud dokumendil on alternatiivne v�imalus kuvada RSS-voona
	 */
	public function hasRSSAlternative($document) {
		$linkArray = $document->getElementsByTagName(self :: $linkTag);
		foreach ($linkArray as $link) {
			if (strcasecmp($link->getAttribute(self :: $relAttribute), self :: $relAttributeValue) == 0) {
				if (strpos($link->getAttribute(self :: $typeAttribute), self :: $typeAttributeValue) === false) {
					continue;
				}
				return $link->getAttribute(self :: $urlAttribute);
			}
		}
		return null;
	}

	/**
	 * Funktsioon, mis kontrollib URL-i, kas tegemist on "kvaliteetse" urliga
	 */
	public function checkInput($value) {
		$validUrl = $this->getValidUrl($value, $this->baseUrl);
		if (strlen($value) == 0 || $value == "/" || $value == "#" || in_array($validUrl, $this->visitedUrls) || in_array($validUrl, $this->urlsToCheck)) {
			return false;
		}
		return true;
	}

	/**
	 * Funktsioon, mis tagastab URL-i korrektsel kujul
	 * St relatiivsetele URL-idele lisab domeeni
	 */
	public function getValidUrl($url, $base) {
		$string = parse_url($url, PHP_URL_HOST);
		if (empty ($string)) {
			if (preg_match("/^\//", $url)) {
				return $this->baseDomain . $url;
			} else {
				return $base . "/" . $url;
			}

		}
		return $url;
	}

	/**
	 * Funktsioon kontrollimaks, kas sisend URL-i domeen on sama, mis esialgne domeen
	 */
	public function isSameDomain($url) {
		$domain = UrlParseUtil :: getDomain($url);
	}
	
	/**
	 * Funktsioon, millega saab piirata leitavate RSS-voogude arvu
	 */
	public function setMaxFeedCount($count) {
		$this->maxFeedCount = $count;
	}
}
?>
