public function generateReport($accountID, $start, $end = false, $options = array(), $maxpages = 1)
	{
		if ($this->isAuthenticated())
		{
			if (\is_int($start))
			{
				$startobj = new DateTime;
				$startobj->setTimestamp($start);
			}
			elseif (\is_string($start))
			{
				$startobj = new DateTime($start);
			}
			elseif (is_a($start, 'DateTime'))
			{
				$startobj = $start;
			}
			else
			{
				throw new InvalidArgumentException('Invalid start time.');
			}

			if (!$end)
			{
				$endobj = new DateTime;
			}
			elseif (\is_int($end))
			{
				$endobj = new DateTime;
				$endobj->setTimestamp($end);
			}
			elseif (\is_string($end))
			{
				$endobj = new DateTime($end);
			}
			elseif (is_a($end, 'DateTime'))
			{
				$endobj = $end;
			}
			else
			{
				throw new InvalidArgumentException('Invalid end time.');
			}

			$options['startDate'] = $startobj->format('Y-m-d');
			$options['endDate']   = $endobj->format('Y-m-d');

			$begin = array_key_exists('startIndex', $options) ? $options['startIndex'] : 0;
			unset($options['startIndex']);

			$url = 'https://www.googleapis.com/adsense/v1.1/accounts/' . urlencode($accountID) . '/reports?' . http_build_query($options);

			if (strpos($url, '&'))
			{
				$url .= '&';
			}

			$i            = 0;
			$data['rows'] = array();

			do
			{
				$jdata   = $this->query($url . 'startIndex=' . \count($data['rows']));
				$newdata = json_decode($jdata->body, true);

				if ($newdata && array_key_exists('rows', $newdata))
				{
					$newdata['rows'] = array_merge($data['rows'], $newdata['rows']);
					$data            = $newdata;
				}
				else
				{
					throw new UnexpectedValueException("Unexpected data received from Google: `{$jdata->body}`.");
				}

				$i++;
			}
			while (\count($data['rows']) < $data['totalMatchedRows'] && $i < $maxpages);

			return $data;
		}

		return false;
	}