<?php

class AVForums_Competitions_Model_Competition extends XenForo_Model
{
	const FETCH_USER = 0x01;
	const FETCH_THREAD_USER = 0x02;
	const FETCH_ATTACHMENT = 0x04;

	public function getCompetitionById($competitionId, array $fetchOptions = array())
	{
		$joinOptions = $this->prepareCompetitionFetchOptions($fetchOptions);

		return $this->_getDb()->fetchRow('
			SELECT competition.*
				' . $joinOptions['selectFields'] . '
			FROM xf_avforums_competitions as competition
			' . $joinOptions['joinTables'] . '
			WHERE competition.competition_id = ?
		', $competitionId);
	}
	
	public function getCompetitionsByIds(array $competitionIds, array $conditions = array())
	{
	    if (!$competitionIds) {
	        return array();
	    }
	
	    return $this->fetchAllKeyed('
            SELECT competition.*
            FROM xf_avforums_competitions as competition
            WHERE competition.competition_id IN (' . $this->_getDb()->quote($competitionIds) . ')
        ', 'competition_id');
	}

	public function getCompetitionIdsInRange($start, $limit)
	{
		$db = $this->_getDb();

		return $db->fetchCol($db->limit('
			SELECT competition_id
			FROM xf_avforums_competitions
			WHERE competition_id > ?
			ORDER BY competition_id
		', $limit), $start);
	}

	public function getCompetitionByThreadId($threadId, array $fetchOptions = array())
	{
		$joinOptions = $this->prepareCompetitionFetchOptions($fetchOptions);

		return $this->_getDb()->fetchRow('
			SELECT competition.*
				' . $joinOptions['selectFields'] . '
			FROM xf_avforums_competitions as competition
			' . $joinOptions['joinTables'] . '
			WHERE competition.competition_thread_id = ?
		', $threadId);
	}

	public function getCompetitions(array $conditions = array(), array $fetchOptions = array())
	{
		$whereClause = $this->prepareCompetitionConditions($conditions, $fetchOptions);

		$joinOptions = $this->prepareCompetitionFetchOptions($fetchOptions);
		$limitOptions = $this->prepareLimitFetchOptions($fetchOptions);
		$sqlClauses = $this->prepareCompetitionFetchOptions($fetchOptions);

		return $this->fetchAllKeyed($this->limitQueryResults('
			SELECT competition.*
				' . $joinOptions['selectFields'] . '
			FROM xf_avforums_competitions AS competition
				' . $joinOptions['joinTables'] . '
				WHERE ' . $whereClause . '
				' . $sqlClauses['orderClause'] . '
			', $limitOptions['limit'], $limitOptions['offset']
		), 'competition_id');
	}

	public function countCompetitions(array $conditions = array(), array $fetchOptions = array())
	{
		$whereClause = $this->prepareCompetitionConditions($conditions, $fetchOptions);

		return $this->_getDb()->fetchOne('
			SELECT COUNT(*)
			FROM xf_avforums_competitions AS competition
			WHERE ' . $whereClause
		);
	}

	public function canViewCompetitions(&$errorPhraseKey = '', array $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (!XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'view'))
		{
			$errorPhraseKey = 'avforums_competitions_permission_view';
			return false;
		}

		return true;
	}

	public function canViewCompetitionsArchive(&$errorPhraseKey = '', array $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (!XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'viewArchive'))
		{
			$errorPhraseKey = 'avforums_competitions_error_archive';
			return false;
		}

		return true;
	}

	public function canDownloadCompetitionOptIns(&$errorPhraseKey = '', array $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (!XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'downloadOptIns'))
		{
			$errorPhraseKey = 'avforums_competitions_error_optins';
			return false;
		}

		return true;
	}

	public function canDownloadCompetitionWinners(&$errorPhraseKey = '', array $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (!XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'downloadWinners'))
		{
			$errorPhraseKey = 'avforums_competitions_error_winners';
			return false;
		}

		return true;
	}

	public function canViewAllCompetitions(&$errorPhraseKey = '', array $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (!XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'viewAll'))
		{
			$errorPhraseKey = 'permission_view';
			return false;
		}

		return true;
	}

	public function canEnterCompetition(array $competition, &$errorPhraseKey = '', array $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (!XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'view'))
		{
			$errorPhraseKey = 'permission_view';
			return false;
		}

		/* @var $userModel XenForo_Model_User */
		$userModel = $this->getModelFromCache('XenForo_Model_User');

		$restrictedViewGroups = false;
		if (!in_array('-1', $competition['view_user_groups']))
		{
			$restrictedViewGroups = true;
		}

		if ($restrictedViewGroups)
		{
			if (!$userModel->isMemberOfUserGroup($viewingUser, $competition['view_user_groups'], true))
			{
				$errorPhraseKey = 'permission_view';
				return false;
			}
		}

		if (!empty($competition['external_link']))
		{
			return true;
		}

		if (!$viewingUser['user_id'])
		{
			$errorPhraseKey = 'not_registered';
			return false;
		}

		if (!XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'enter'))
		{
			$errorPhraseKey = 'permission_enter';
			return false;
		}

		$restrictedEnterGroups = false;
		if (!in_array('-1', $competition['enter_user_groups']))
		{
			$restrictedEnterGroups = true;
		}

		if ($restrictedEnterGroups)
		{
			if (!$userModel->isMemberOfUserGroup($viewingUser, $competition['enter_user_groups'], true))
			{
				$errorPhraseKey = 'permission_enter';
				return false;
			}
		}

		$date = XenForo_Application::$time + $this->getTimeDifference();
		if ($date < $competition['competition_start'])
		{
			$errorPhraseKey = 'start_date';
			return false;
		}

		if ($date > $competition['competition_end'])
		{
			$errorPhraseKey = 'end_date';
			return false;
		}

		if ($competition['competition_state'] == 'closed')
		{
			$errorPhraseKey = 'closed';
			return false;
		}

		$restrictedTerritories = false;
		if (!in_array('-1', $competition['territories']))
		{
			$restrictedTerritories = true;
		}

		if ($restrictedTerritories)
		{
			$visitorInfo = $this->getVisitorLocation();

			if (!in_array(strtolower($visitorInfo), $competition['territories']))
			{
				$errorPhraseKey = 'outside_territory';
				return false;
			}
		}

		if (!empty($competition['minimum_age']))
		{
			/* @var $userProfileModel XenForo_Model_UserProfile */
			$userProfileModel = $this->getModelFromCache('XenForo_Model_UserProfile');

			$age = $userProfileModel->getUserAge($viewingUser, true);
			if (!$age)
			{
				$errorPhraseKey = 'incomplete_dob';
				return false;
			}

			if ($age < $competition['minimum_age'])
			{
				$errorPhraseKey = 'too_young';
				return false;
			}
		}

		$hasEntered = $this->getModelFromCache('AVForums_Competitions_Model_Entry')->getEntries(array(
			'competition_id' => $competition['competition_id'],
			'user_id' => XenForo_Visitor::getUserId()
		));

		if ($hasEntered)
		{
			$errorPhraseKey = 'has_entered';
			return false;
		}

		return true;
	}

	public function canCreateCompetition(&$errorPhraseKey = '', $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'create'))
		{
			return true;
		}

		$errorPhraseKey = '';
		return false;
	}

	public function canPublishCompetition(array $competition, &$errorPhraseKey = '', $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'publishAnyCompetition'))
		{
			return true;
		}

		if (!empty($competition['user_id']) && $competition['user_id'] == $viewingUser['user_id']
			&& XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'publishOwnCompetition')
		)
		{
			return true;
		}

		$errorPhraseKey = 'avforums_competitions_error_no_publish';
		return false;
	}

	public function canOpenCompetition(array $competition, &$errorPhraseKey = '', $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (!empty($competition['competition_state']) && $competition['competition_state'] == 'completed')
		{
			$errorPhraseKey = 'avforums_competitions_error_no_open';
			return false;
		}

		if (XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'openAnyCompetition'))
		{
			return true;
		}

		if (!empty($competition['user_id']) && $competition['user_id'] == $viewingUser['user_id']
			&& XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'openOwnCompetition')
		)
		{
			return true;
		}

		$errorPhraseKey = 'avforums_competitions_error_no_open';
		return false;
	}

	public function canEditCompetition(array $competition, &$errorPhraseKey = '', $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'editAnyCompetition'))
		{
			return true;
		}

		if ($competition['user_id'] == $viewingUser['user_id']
			&& XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'editOwnCompetition')
		)
		{
			return true;
		}

		$errorPhraseKey = 'avforums_competitions_error_no_edit';
		return false;
	}

	public function canDeleteCompetition(array $competition, &$errorPhraseKey = '', $viewingUser = null)
	{
		$this->standardizeViewingUserReference($viewingUser);

		if (XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'deleteAnyCompetition'))
		{
			return true;
		}

		if ($competition['user_id'] == $viewingUser['user_id']
			&& XenForo_Permission::hasPermission($viewingUser['permissions'], 'competitions', 'deleteOwnCompetition')
		)
		{
			return true;
		}

		$errorPhraseKey = 'avforums_competitions_error_no_delete';
		return false;
	}

	public function prepareCompetitionFetchOptions(array $fetchOptions)
	{
		$selectFields = '';
		$joinTables = '';
		$orderBy = 'competition.competition_date DESC';

		if (!empty($fetchOptions['join']))
		{
			if ($fetchOptions['join'] & self::FETCH_USER)
			{
				$selectFields .= ',
					user.*, user_profile.*, IF(user.username IS NULL, competition.username, user.username) AS username';
				$joinTables .= '
					LEFT JOIN xf_user AS user ON
						(user.user_id = competition.user_id)
					LEFT JOIN xf_user_profile AS user_profile ON
						(user_profile.user_id = competition.user_id)';
			}

			if ($fetchOptions['join'] & self::FETCH_THREAD_USER)
			{
				$selectFields .= ',
					thread_user.user_id, thread_user.username, IF(thread_user.username IS NULL, competition.competition_thread_username, thread_user.username) AS username';
				$joinTables .= '
					LEFT JOIN xf_user AS thread_user ON
						(thread_user.user_id = competition.user_id)';
			}

			if ($fetchOptions['join'] & self::FETCH_ATTACHMENT)
			{
				$this->getModelFromCache('XenForo_Model_Attachment'); // to get the updated $dataColumns, will not needed with [bd] Attachment Store 0.9.8+

				$selectFields .= ',
                    attachment.attachment_id, attachment.data_id, attachment.attach_date,' . XenForo_Model_Attachment::$dataColumns;
				$joinTables .= '
                    LEFT JOIN xf_attachment AS attachment ON
                        (attachment.content_type = \'avforums_competition\' AND attachment.attachment_id = competition.thumb_attachment_id)
                    LEFT JOIN xf_attachment_data AS data ON
                        (data.data_id = attachment.data_id)';
			}

			if (!empty($fetchOptions['order']))
			{
				if ($fetchOptions['order'] == 'rand')
				{
					$orderBy = 'RAND()';
				}
			}
		}

		return array(
			'selectFields' => $selectFields,
			'joinTables'   => $joinTables,
			'orderClause' => ($orderBy ? "ORDER BY $orderBy" : '')
		);
	}

	public function prepareCompetitionConditions(array $conditions, array &$fetchOptions)
	{
		$sqlConditions = array();
		$db = $this->_getDb();

		if (!empty($conditions['end_date']))
		{
			$sqlConditions[] = 'competition.competition_end <= ' . $db->quote($conditions['end_date']);
		}

		if (!empty($conditions['competition_id']))
		{
			if (is_array($conditions['competition_id']))
			{
				$sqlConditions[] = 'competition.competition_id IN (' . $db->quote($conditions['competition_id']) . ')';
			}
			else
			{
				$sqlConditions[] = 'competition.competition_id = ' . $db->quote($conditions['competition_id']);
			}
		}

		if (!empty($conditions['competition_state']))
		{
			if (is_array($conditions['competition_state']))
			{
				$sqlConditions[] = 'competition.competition_state IN (' . $db->quote($conditions['competition_state']) . ')';
			}
			else
			{
				$sqlConditions[] = 'competition.competition_state = ' . $db->quote($conditions['competition_state']);
			}
		}

		if (!empty($conditions['competition_published']))
		{
			$sqlConditions[] = 'competition.competition_published = ' . $db->quote($conditions['competition_published']);
		}

		if (!empty($conditions['force_thumbnail']))
		{
			$sqlConditions[] = 'competition.force_thumbnail = ' . $db->quote($conditions['force_thumbnail']);
		}

		if (isset($conditions['external_link']))
		{
			$sqlConditions[] = 'competition.external_link = ' . $db->quote($conditions['external_link']);
		}

		if (isset($conditions['winners_state']))
		{
			$sqlConditions[] = 'competition.winners_state = ' . $db->quote($conditions['winners_state']);
		}

		if (!empty($conditions['all']))
		{
			$sqlConditions[] = "competition.competition_published = 1 OR competition.competition_published = 0 OR competition.competition_state = 'closed' OR competition.competition_state = 'open' OR competition.competition_state = 'completed'";
		}
		else
		{
			/* Set a key on this condition that can be unset later.
			This forces the WHERE clause to only fetch OPEN or COMPLETED competitions and PUBLISHED competitions */
			$sqlConditions['openOnly'] = "(competition.competition_state = 'open' OR competition.competition_state = 'completed') AND competition.competition_published = '1'";
		}

		/* Remove the previous clause if this condition is set.
		This removes the forced conditions detailed above */
		if (!empty($conditions['pickingWinners']) || !empty($conditions['routineRun']))
		{
			unset ($sqlConditions['openOnly']);
		}

		if (!empty($conditions['cutOff']))
		{
			$sqlConditions[] = 'competition.competition_end >= ' . $db->quote($conditions['cutOff']);
		}

		return $this->getConditionsForClause($sqlConditions);
	}

	public function prepareCompetition(array $competition, array $attachments = null)
	{
		$competition['competition_answers'] = @unserialize($competition['competition_answers']);
		if (!$competition['competition_answers'])
		{
			$competition['competition_answers'] = array(
				'answers' => array()
			);
		}

		if ($attachments === null)
		{
			$attachmentIds = array(
				$competition['thumb_attachment_id'] => $competition['thumb_attachment_id'],
				$competition['image1_attachment_id'] => $competition['image1_attachment_id'],
				$competition['image2_attachment_id'] => $competition['image2_attachment_id'],
				$competition['image3_attachment_id'] => $competition['image3_attachment_id'],
				$competition['image4_attachment_id'] => $competition['image4_attachment_id']
			);

			$attachments = $this->getAttachmentsByAttachmentIds($attachmentIds);
		}

		$competition['view_user_groups'] = @unserialize($competition['view_user_groups']);
		$competition['enter_user_groups'] = @unserialize($competition['enter_user_groups']);
		$competition['territories'] = @unserialize($competition['territories']);
		$competition['competition_winners'] = @unserialize($competition['competition_winners']);

		$competition['competitionStart'] = gmdate('Y-m-d', $competition['competition_start']);
		$competition['competitionEnd'] = gmdate('Y-m-d', $competition['competition_end']);
		
		$competition['competitionStartTime'] = gmdate('H:i', $competition['competition_start']);
		$competition['competitionEndTime'] = gmdate('H:i', $competition['competition_end']);

		$competition['thumbnailUrl'] = '';
		if (!empty($competition['thumb_attachment_id']))
		{
			$attachment = $attachments[$competition['thumb_attachment_id']];

			$competition['thumbnailUrl'] = $this->getCompetitionImageUrl($attachment, 'thumb');
		}

		$competition['smallThumbnailUrl'] = '';
		if (!empty($competition['thumb_attachment_id']))
		{
			$attachment = $attachments[$competition['thumb_attachment_id']];

			$competition['smallThumbnailUrl'] = $this->getCompetitionImageUrl($attachment, 'thumb_s');
		}

		$competition['image1Url'] = '';
		if (!empty($competition['image1_attachment_id']))
		{
			$competition['image1Url'] = $this->getCompetitionImageUrl($attachments[$competition['image1_attachment_id']], 'image1');
		}

		$competition['image2Url'] = '';
		if (!empty($competition['image2_attachment_id']))
		{
			$competition['image2Url'] = $this->getCompetitionImageUrl($attachments[$competition['image2_attachment_id']], 'image2');
		}

		$competition['image3Url'] = '';
		if (!empty($competition['image3_attachment_id']))
		{
			$competition['image3Url'] = $this->getCompetitionImageUrl($attachments[$competition['image3_attachment_id']], 'image3');
		}

		$competition['image4Url'] = '';
		if (!empty($competition['image4_attachment_id']))
		{
			$competition['image4Url'] = $this->getCompetitionImageUrl($attachments[$competition['image4_attachment_id']], 'image4');
		}

		$competition['canOpen'] = $this->canOpenCompetition($competition);
		$competition['canPublish'] = $this->canPublishCompetition($competition);
		$competition['canEdit'] = $this->canEditCompetition($competition);
		$competition['canDelete'] = $this->canDeleteCompetition($competition);

		return $competition;
	}

	public function prepareCompetitions(array $competitions, $noCutOff = false)
	{
		$options = XenForo_Application::getOptions();

		$attachmentIds = array();
		foreach ($competitions AS $competitionId => $competition)
		{
			if (!$noCutOff)
			{
				$cutOff = $competition['competition_end'] + ($options->competitionDateThreshold * 86400);
				if (XenForo_Application::$time > $cutOff)
				{
					unset ($competitions[$competitionId]);
				}
			}

			$attachmentIds = $attachmentIds + array(
				$competition['thumb_attachment_id'] => $competition['thumb_attachment_id'],
				$competition['image1_attachment_id'] => $competition['image1_attachment_id'],
				$competition['image2_attachment_id'] => $competition['image2_attachment_id'],
				$competition['image3_attachment_id'] => $competition['image3_attachment_id'],
				$competition['image4_attachment_id'] => $competition['image4_attachment_id']
			);
		}

		$attachments = array();
		if ($attachmentIds)
		{
			$attachments = $this->getAttachmentsByAttachmentIds($attachmentIds);
		}

		foreach ($competitions AS &$competition)
		{
			$competition = $this->prepareCompetition($competition, $attachments);
		}

		return $competitions;
	}

	public function getCompetitionAttachments(array $competition)
	{
		$attachmentIds = array(
			$competition['thumb_attachment_id'],
			$competition['image1_attachment_id'],
			$competition['image2_attachment_id'],
			$competition['image3_attachment_id'],
			$competition['image4_attachment_id']
		);

		$attachments = $this->getAttachmentsByAttachmentIds($attachmentIds);

		return $attachments;
	}

	public function getCompetitionAttachmentIds(array $competition)
	{
		$attachmentIds = array(
			$competition['thumb_attachment_id'],
			$competition['image1_attachment_id'],
			$competition['image2_attachment_id'],
			$competition['image3_attachment_id'],
			$competition['image4_attachment_id']
		);

		return $attachmentIds;
	}

	public function getAttachmentsByAttachmentIds(array $attachmentIds)
	{
		return $this->fetchAllKeyed(
			'
				SELECT attachment.*, attachment_data.*
				FROM xf_attachment AS attachment
				INNER JOIN xf_attachment_data AS attachment_data ON
					(attachment_data.data_id = attachment.data_id)
				WHERE attachment.attachment_id IN (' . $this->_getDb()->quote($attachmentIds) . ')
			', 'attachment_id'
		);
	}

	public function getCompetitionImageUrl(array $data, $type)
	{
		return sprintf("%s/attachments/%d/%d-%s_$type.jpg",
			XenForo_Application::$externalDataUrl,
			floor($data['data_id'] / 1000),
			$data['data_id'],
			$data['file_hash']
		);
	}

	public function getCompetitionImagePath(array $data, $externalDataPath = null, $type)
	{
		if ($externalDataPath === null)
		{
			$externalDataPath = XenForo_Helper_File::getExternalDataPath();
		}

		return sprintf("%s/attachments/%d/%d-%s_$type.jpg",
			$externalDataPath,
			floor($data['data_id'] / 1000),
			$data['data_id'],
			$data['file_hash']
		);
	}

	public function getVisitorIpAddress()
	{
		$ipAddress = (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : false);

		return $ipAddress;
	}

	public function getVisitorLocation()
	{
		if (function_exists('geoip_country_code_by_name'))
		{
			return geoip_country_code_by_name($this->getVisitorIpAddress());
		}
		else
		{
			return false;
		}
	}

	public function logCompetitionView(array &$competition)
	{
		$competition['competition_view_count']++;
		return $this->_getDb()->update('xf_avforums_competitions', array('competition_view_count' => $competition['competition_view_count']), 'competition_id = ' . $competition['competition_id']);
	}

	/**
	 * Gets the set of attachment params required to allow uploading.
	 *
	 * @param array $contentData Information about the content, for URL building
	 * @param array|null $viewingUser
	 *
	 * @return array|bool
	 */
	public function getCompetitionAttachmentParams(array $contentData = array())
	{
		return array(
			'hash' => md5(uniqid('', true)),
			'content_type' => 'avforums_competition',
			'content_data' => $contentData
		);
	}

	/**
	 * Gets the normal attachment constraints.
	 *
	 * @return array
	 */
	public function getCompetitionAttachmentConstraints()
	{
		return array(
			'extensions' => array('jpg', 'jpeg', 'jpe', 'png', 'gif'),
			'width' => 800,
			'count' => 1
		);
	}
	
	public function getTimeDifference()
	{
		try
		{
			$timeStamp = new DateTime("now", new DateTimeZone(XenForo_Application::getOptions()->guestTimeZone));
		}
		catch (Exception $e) 
		{
			return 0;
		}

	    return $timeStamp->getOffset();
	}

	public function getTerritoriesForList()
	{
		return array(
			'gb' => 'United Kingdom',
			'ie' => 'Ireland',
			'us' => 'United States',
			'af' => 'Afghanistan',
			'ax' => 'Åland Islands',
			'al' => 'Albania',
			'dz' => 'Algeria',
			'as' => 'American Samoa',
			'ad' => 'Andorra',
			'ao' => 'Angola',
			'ai' => 'Anguilla',
			'aq' => 'Antarctica',
			'ag' => 'Antigua and Barbuda',
			'ar' => 'Argentina',
			'am' => 'Armenia',
			'aw' => 'Aruba',
			'au' => 'Australia',
			'at' => 'Austria',
			'az' => 'Azerbaijan',
			'bs' => 'Bahamas',
			'bh' => 'Bahrain',
			'bd' => 'Bangladesh',
			'bb' => 'Barbados',
			'by' => 'Belarus',
			'be' => 'Belgium',
			'bz' => 'Belize',
			'bj' => 'Benin',
			'bm' => 'Bermuda',
			'bt' => 'Bhutan',
			'bo' => 'Bolivia',
			'ba' => 'Bosnia and Herzegovina',
			'bw' => 'Botswana',
			'bv' => 'Bouvet Island',
			'br' => 'Brazil',
			'io' => 'British Indian Ocean Territory',
			'bn' => 'Brunei Darussalam',
			'bg' => 'Bulgaria',
			'bf' => 'Burkina Faso',
			'bi' => 'Burundi',
			'kh' => 'Cambodia',
			'cm' => 'Cameroon',
			'ca' => 'Canada',
			'cv' => 'Cape Verde',
			'ky' => 'Cayman Islands',
			'cf' => 'Central African Republic',
			'td' => 'Chad',
			'cl' => 'Chile',
			'cn' => 'China',
			'cx' => 'Christmas Island',
			'cc' => 'Cocos (Keeling) Islands',
			'co' => 'Colombia',
			'km' => 'Comoros',
			'cg' => 'Congo',
			'cd' => 'Democratic Republic of the Congo',
			'ck' => 'Cook Islands',
			'cr' => 'Costa Rica',
			'ci' => 'Cote D\'ivoire',
			'hr' => 'Croatia',
			'cu' => 'Cuba',
			'cy' => 'Cyprus',
			'cz' => 'Czech Republic',
			'dk' => 'Denmark',
			'dj' => 'Djibouti',
			'dm' => 'Dominica',
			'do' => 'Dominican Republic',
			'ec' => 'Ecuador',
			'eg' => 'Egypt',
			'sv' => 'El Salvador',
			'gq' => 'Equatorial Guinea',
			'er' => 'Eritrea',
			'ee' => 'Estonia',
			'et' => 'Ethiopia',
			'fk' => 'Falkland Islands (Malvinas)',
			'fo' => 'Faroe Islands',
			'fj' => 'Fiji',
			'fi' => 'Finland',
			'fr' => 'France',
			'gf' => 'French Guiana',
			'pf' => 'French Polynesia',
			'tf' => 'French Southern Territories',
			'ga' => 'Gabon',
			'gm' => 'Gambia',
			'ge' => 'Georgia',
			'de' => 'Germany',
			'gh' => 'Ghana',
			'gi' => 'Gibraltar',
			'gr' => 'Greece',
			'gl' => 'Greenland',
			'gd' => 'Grenada',
			'gp' => 'Guadeloupe',
			'gu' => 'Guam',
			'gt' => 'Guatemala',
			'gg' => 'Guernsey',
			'gn' => 'Guinea',
			'gw' => 'Guinea-bissau',
			'gy' => 'Guyana',
			'ht' => 'Haiti',
			'hm' => 'Heard Island and Mcdonald Islands',
			'va' => 'Holy See (Vatican City State)',
			'hn' => 'Honduras',
			'hk' => 'Hong Kong',
			'hu' => 'Hungary',
			'is' => 'Iceland',
			'in' => 'India',
			'id' => 'Indonesia',
			'ir' => 'Islamic Republic of Iran',
			'iq' => 'Iraq',
			'im' => 'Isle of Man',
			'il' => 'Israel',
			'it' => 'Italy',
			'jm' => 'Jamaica',
			'jp' => 'Japan',
			'je' => 'Jersey',
			'jo' => 'Jordan',
			'kz' => 'Kazakhstan',
			'ke' => 'Kenya',
			'ki' => 'Kiribati',
			'kp' => 'Democratic People\'s Republic of Korea',
			'kr' => 'Republic of Korea',
			'kw' => 'Kuwait',
			'kg' => 'Kyrgyzstan',
			'la' => 'Lao People\'s Democratic Republic',
			'lv' => 'Latvia',
			'lb' => 'Lebanon',
			'ls' => 'Lesotho',
			'lr' => 'Liberia',
			'ly' => 'Libyan Arab Jamahiriya',
			'li' => 'Liechtenstein',
			'lt' => 'Lithuania',
			'lu' => 'Luxembourg',
			'mo' => 'Macao',
			'mk' => 'The Former Yugoslav Republic of Macedonia',
			'mg' => 'Madagascar',
			'mw' => 'Malawi',
			'my' => 'Malaysia',
			'mv' => 'Maldives',
			'ml' => 'Mali',
			'mt' => 'Malta',
			'mh' => 'Marshall Islands',
			'mq' => 'Martinique',
			'mr' => 'Mauritania',
			'mu' => 'Mauritius',
			'yt' => 'Mayotte',
			'mx' => 'Mexico',
			'fm' => 'Federated States of Micronesia',
			'md' => 'Republic of Moldova',
			'mc' => 'Monaco',
			'mn' => 'Mongolia',
			'me' => 'Montenegro',
			'ms' => 'Montserrat',
			'ma' => 'Morocco',
			'mz' => 'Mozambique',
			'mm' => 'Myanmar',
			'na' => 'Namibia',
			'nr' => 'Nauru',
			'np' => 'Nepal',
			'nl' => 'Netherlands',
			'an' => 'Netherlands Antilles',
			'nc' => 'New Caledonia',
			'nz' => 'New Zealand',
			'ni' => 'Nicaragua',
			'ne' => 'Niger',
			'ng' => 'Nigeria',
			'nu' => 'Niue',
			'nf' => 'Norfolk Island',
			'mp' => 'Northern Mariana Islands',
			'no' => 'Norway',
			'om' => 'Oman',
			'pk' => 'Pakistan',
			'pw' => 'Palau',
			'ps' => 'Occupied Palestinian Territory',
			'pa' => 'Panama',
			'pg' => 'Papua New Guinea',
			'py' => 'Paraguay',
			'pe' => 'Peru',
			'ph' => 'Philippines',
			'pn' => 'Pitcairn',
			'pl' => 'Poland',
			'pt' => 'Portugal',
			'pr' => 'Puerto Rico',
			'qa' => 'Qatar',
			're' => 'Reunion',
			'ro' => 'Romania',
			'ru' => 'Russian Federation',
			'rw' => 'Rwanda',
			'sh' => 'Saint Helena',
			'kn' => 'Saint Kitts and Nevis',
			'lc' => 'Saint Lucia',
			'pm' => 'Saint Pierre and Miquelon',
			'vc' => 'Saint Vincent and The Grenadines',
			'ws' => 'Samoa',
			'sm' => 'San Marino',
			'st' => 'Sao Tome and Principe',
			'sa' => 'Saudi Arabia',
			'sn' => 'Senegal',
			'rs' => 'Serbia',
			'sc' => 'Seychelles',
			'sl' => 'Sierra Leone',
			'sg' => 'Singapore',
			'sk' => 'Slovakia',
			'si' => 'Slovenia',
			'sb' => 'Solomon Islands',
			'so' => 'Somalia',
			'za' => 'South Africa',
			'gs' => 'South Georgia and The South Sandwich Islands',
			'es' => 'Spain',
			'lk' => 'Sri Lanka',
			'sd' => 'Sudan',
			'sr' => 'Suriname',
			'sj' => 'Svalbard and Jan Mayen',
			'sz' => 'Swaziland',
			'se' => 'Sweden',
			'ch' => 'Switzerland',
			'sy' => 'Syrian Arab Republic',
			'tw' => 'Province of China Taiwan',
			'tj' => 'Tajikistan',
			'tz' => 'United Republic of Tanzania',
			'th' => 'Thailand',
			'tl' => 'Timor-leste',
			'tg' => 'Togo',
			'tk' => 'Tokelau',
			'to' => 'Tonga',
			'tt' => 'Trinidad and Tobago',
			'tn' => 'Tunisia',
			'tr' => 'Turkey',
			'tm' => 'Turkmenistan',
			'tc' => 'Turks and Caicos Islands',
			'tv' => 'Tuvalu',
			'ug' => 'Uganda',
			'ua' => 'Ukraine',
			'ae' => 'United Arab Emirates',
			'um' => 'United States Minor Outlying Islands',
			'uy' => 'Uruguay',
			'uz' => 'Uzbekistan',
			'vu' => 'Vanuatu',
			've' => 'Venezuela',
			'vn' => 'Viet Nam',
			'vg' => 'British Virgin Islands',
			'vi' => 'U.S. Virgin Islands',
			'wf' => 'Wallis and Futuna',
			'eh' => 'Western Sahara',
			'ye' => 'Yemen',
			'zm' => 'Zambia',
			'zw' => 'Zimbabwe'
		);
	}
}