<?php

class Point extends Model
{
	const statusModeration = 'moderation';
	const statusPublished = 'published';
	const statusDel = 'del';

	function __construct($fromArray = array())
	{
		$this->_tableName_ = 'points';
		parent::__construct($fromArray);
		$this->setRelation('category', 'categoryId', 'Category', 'id', self::TO_ONE);
		$this->setRelation('authorUser', 'author', 'User', 'id', self::TO_ONE);
		$this->setRelation('photos', 'id', 'Photo', 'pointId', self::TO_MANY);
	}

	static function model()
	{
		return new self();
	}

	public function getImg($size = 'small')
	{
		$img = $this->img;
		if ($img == '') {
			$photos = $this->photos;
			$img = array_shift($photos);

			if (!$img)
				return null;

			$img = '/photos/' . $size . '/' . $img->name;
		}

		return $img;
	}

	public function getRandom()
	{
		$res = App::DB()->query("SELECT FLOOR(RAND() * COUNT(*)) AS `offset` FROM `" . $this->_tableName_ . '` WHERE `status` = "published"')->fetch(PDO::FETCH_ASSOC);
		$offset = $res['offset'];

		$res = App::DB()->query('SELECT `id` FROM ' . $this->_tableName_ . ' WHERE `status` = "published" LIMIT ' . $offset . ',1;')->fetch(PDO::FETCH_ASSOC);
		$pointId = $res['id'];

		return $this->getByPK($pointId);
	}

	public function getClosestPoints($pointId, $categoryNot = 0)
	{
		$degrees = 1;

		$point = Point::model()->getByPK($pointId);
		$lat = floatval($point->lat);
		$lng = floatval($point->lng);

		$delta = (1+abs(SIN($lat/100)*SIN($lat/100)*5))*$degrees;

		$query = '
			SELECT *, (
			(POW(`lat`-:lat,2)+POW(`lng`-:lng,2))
			) AS `dist` FROM `' . $this->_tableName_ . '`
			WHERE
			`status` = "published"
			AND
			`categoryId` != ' . $categoryNot . '
			AND
			`lat` BETWEEN :minLat AND :maxLat
			AND
			`lng` BETWEEN :minLng AND :maxLng
			AND
			`lat` <> :lat
			AND
			`lng` <> :lng
			ORDER BY `dist`
			LIMIT 6;';

		$res = App::DB()->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
		$res->execute(array(':lat' => $lat, ':lng' => $lng, ':minLat' => $lat - $degrees, ':minLng' => $lng - $delta, ':maxLat' => $lat + $degrees, ':maxLng' => $lng + $delta));

		$ready = array();
		$calledClass = get_called_class();
		while ($res && $row = $res->fetch(PDO::FETCH_ASSOC)) {
			$ready[] = new $calledClass($row);
		}

		return $ready;
	}

	public function getSortedByDistance($lat, $lng)
	{
		$lat = floatval($lat);
		$lng = floatval($lng);

		$query = '
			SELECT *, (
			(POW(`lat`-:lat,2)+POW(`lng`-:lng,2))
			) AS `dist` FROM `' . $this->_tableName_ . '`
			WHERE
			`status` = "published"
			ORDER BY `dist`;';

		$res = App::DB()->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
		$res->execute(array(':lat' => $lat, ':lng' => $lng));

		$ready = array();
		$calledClass = get_called_class();
		while ($res && $row = $res->fetch(PDO::FETCH_ASSOC)) {
			$ready[] = new $calledClass($row);
		}

		return $ready;
	}

	public function getCountByUser($userId)
	{
		$res = App::DB()->query('SELECT count(`id`) AS `cnt` FROM ' . $this->_tableName_ . ' WHERE `author` = ' . $userId . ' AND `status` = "published";')->fetch(PDO::FETCH_ASSOC);
		return $res['cnt'];
	}

	public function searchByString($search)
	{
		return $this->getAll(array('where' => "`name` LIKE '%$search%' OR `description` LIKE '%$search%'", 'limit' => 20));
	}

	public function getAllPublished($bounds = false, $minEditDate = 0)
	{
		$userId = App::$user ? intval(App::$user->id) : 0;
		$minEditDate = intval($minEditDate);
		if ($bounds) {
			$b0 = $bounds[0] < $bounds[2] ? $bounds[0] : $bounds[2];
			$b2 = $bounds[0] < $bounds[2] ? $bounds[2] : $bounds[0];
			$b1 = $bounds[1] < $bounds[3] ? $bounds[1] : $bounds[3];
			$b3 = $bounds[1] < $bounds[3] ? $bounds[3] : $bounds[1];

			return $this->getAll(array('where' => "((`status` = '" . Point::statusPublished . "') OR (`status` = '" . Point::statusModeration . "' AND `author` = $userId)) AND (`dateEdit` >= $minEditDate) AND (`lat` BETWEEN '$b0' AND '$b2') AND(`lng` BETWEEN '$b1' AND '$b3')"));
		} else {
			return $this->getAll(array('where' => "((`status` = '" . Point::statusPublished . "') OR (`status` = '" . Point::statusModeration . "' AND `author` = $userId)) AND (`dateEdit` >= $minEditDate)"));
		}
	}

	public function getExtraParams()
	{
		return ExtraParams::model()->getAll(array(
			'where' => '`pointId` = '.$this->id,
			'order' => '`id` ASC',
		));
	}

	public function getCountMyPointsToday()
	{
		if (!App::$user->id) {
			return 0;
		}

		$time = strtotime(date('Y-m-d'));
		$userId = App::$user->id;
		$res = App::DB()->query('SELECT count(`id`) AS `cnt` FROM ' . $this->_tableName_ . ' WHERE `author` = ' . $userId . ' AND `date` >= ' . $time . ';')->fetch(PDO::FETCH_ASSOC);
		return (int)$res['cnt'];
	}

	public static function getStatusByString($status)
	{
		switch (strtolower($status)) {
			case 'del':
				return self::statusDel;
				break;
			case 'published':
				return self::statusPublished;
				break;
			default:
				return self::statusModeration;
		}
	}

	public function isPaid()
	{
		return Category::isPaidCategory($this->categoryId);
	}
}
