<?php

/*
 * admin side controller
 *
 * @since 1.2
 */
class PLL_Admin extends PLL_Base {
	public $pref_lang;
	public $settings_page, $filters, $filters_columns, $filters_post, $filters_term, $nav_menu, $sync, $filters_media;

	/*
	 * loads the polylang text domain
	 * setups filters and action needed on all admin pages and on plugins page
	 * loads the settings pages or the filters base on the request
	 * manages the admin language filter and the "admin preferred language"
	 *
	 * @since 1.2
	 *
	 * @param object $links_model
	 */
	public function __construct(&$links_model) {
		parent::__construct($links_model);

		// plugin i18n, only needed for backend
		load_plugin_textdomain('ait-languages', false, basename(POLYLANG_DIR) . '/languages');

		// adds the link to the languages panel in the wordpress admin menu
		add_action('admin_menu', array(&$this, 'add_menus'), 11);

		// setup js scripts and css styles
		add_action('admin_enqueue_scripts', array(&$this, 'admin_enqueue_scripts'));

		add_action('admin_print_footer_scripts', array(&$this, 'admin_print_footer_scripts'));

		if(is_admin_bar_showing()){
			add_action('admin_head', array($this, 'userLangSwitcherScript'));
		}
		add_action('wp_ajax_admin:switchUserLang', array($this, 'ajaxSwitchUserLang'));

		// adds a 'settings' link in the plugins table
		add_filter('plugin_action_links_' . POLYLANG_BASENAME, array(&$this, 'plugin_action_links'));
		add_action('in_plugin_update_message-' . POLYLANG_BASENAME, array(&$this, 'plugin_update_message'), 10, 2);
	}

	/*
	 * loads the polylang text domain
	 * setups filters and action needed on all admin pages and on plugins page
	 * loads the settings pages or the filters base on the request
	 * manages the admin language filter and the "admin preferred language"
	 *
	 * @since 1.2
	 *
	 * @param object $links_model
	 */
	public function init() {
		if (PLL_SETTINGS)
			$this->settings_page = new PLL_Settings($this->model);

		if (!$this->model->get_languages_list())
			return;

		// filter admin language for users
		// we must not call user info before WordPress defines user roles in wp-settings.php
		add_filter('setup_theme', array(&$this, 'init_user'));
		add_filter('locale', array(&$this, 'get_locale'));

		// adds the languages in admin bar
		// FIXME: OK for WP 3.2 and newer (the admin bar is not displayed on admin side for WP 3.1)
		add_action('admin_bar_menu', array(&$this, 'adminBarLanguageFilter'), 100);
		add_action('admin_bar_menu', array(&$this, 'adminBarLanguageSwitcher'), 2014);

		// setup filters for admin pages
		if (!PLL_SETTINGS)
			add_action('init', array(&$this, 'add_filters'));
	}

	/*
	 * adds the link to the languages panel in the wordpress admin menu
	 *
	 * @since 0.1
	 */
	public function add_menus()
	{
		if(current_theme_supports('ait-languages-plugin') and function_exists('aitConfig')){
			$defaultPage = aitConfig()->getDefaultAdminPage();
			add_submenu_page(
				"ait-{$defaultPage['slug']}",
				__('Languages', 'ait-languages'),
				__('Languages', 'ait-languages'),
				'publish_pages',
				'ait-languages',
				array($this->settings_page, 'languages_page')
			);
		}else{
			add_menu_page(
				__('Languages', 'ait-languages'),
				__('Languages', 'ait-languages'),
				'publish_pages',
				'ait-languages',
				array($this->settings_page, 'languages_page')
			);
		}
	}

	/**
	 * setup js scripts & css styles (only on the relevant pages)
	 *
	 * @since 0.6
	 */
	public function admin_enqueue_scripts()
	{
		$screen = get_current_screen();

		$scripts = array(
			'post'  => array(
				'loadOn' => array('post', 'media', 'async-upload', 'edit'),
				'deps' => array('jquery', 'wp-ajax-response'),
				'allwaysLoad' => 0
			),
			'term'  => array(
				'loadOn' => array('edit-tags'),
				'deps' => array('jquery', 'wp-ajax-response'),
				'allwaysLoad' => 0
			),
			'user'  => array(
				'loadOn' => array('profile', 'user-edit'),
				'deps' => array('jquery'),
				'allwaysLoad' => 0
			),
		);


		if(strpos($screen->base, 'ait-languages') !== false){
			wp_enqueue_script('pll_admin', POLYLANG_URL . "/assets/js/admin.js", array('jquery', 'wp-ajax-response', 'postbox'), POLYLANG_VERSION);
		}

		foreach($scripts as $script => $params){
			if((in_array($screen->base, $params['loadOn']))){
				wp_enqueue_script('pll_' . $script, POLYLANG_URL . "/assets/js/{$script}.js", $params['deps'], POLYLANG_VERSION);
			}
		}

		if(strpos($screen->base, 'ait-languages') !== false and current_theme_supports('ait-languages-plugin') and function_exists('aitPaths')){
			$assetsUrl = aitPaths()->url->admin . '/assets';
			wp_enqueue_style('ait-languages-admin-style', "{$assetsUrl}/css/style.css", array('media-views'));
		}else{
			wp_enqueue_style('ait-languages-admin-style', POLYLANG_URL . "/assets/css/admin.css", array(), POLYLANG_VERSION);
		}

		wp_enqueue_style('ait-languages-wp-admin-style', POLYLANG_URL . "/assets/css/wp-admin.css", array(), POLYLANG_VERSION);
	}


		/*
		 * sets pll_ajax_backend on all backend ajax request
		 *
		 * @since 1.4
		 */
	public function admin_print_footer_scripts()
	{
	?>

	<script type="text/javascript">
		if (typeof jQuery != 'undefined') {
			(function($){
				$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
					if (typeof options.data == 'string') {
						options.data = 'pll_ajax_backend=1&'+options.data;
					}else if(Object.prototype.toString.call(options.data) === "[object FormData]"){
						options.data.append('pll_ajax_backend', '1');
					}else {
						options.data = $.extend(options.data, {pll_ajax_backend: true});
					}
				});
			})(jQuery)
		}
	</script>
	<?php
	}



	public function userLangSwitcherScript()
	{
		$ajaxUrl = admin_url('admin-ajax.php');
		?>
		<script>
		jQuery(function($){
			$('#wp-admin-bar-ait-admin-languages-switcher li.ait-admin-lang').on('click', function(){
				var lang = 'en_US';
				var classes = jQuery(this).attr('class').split(/\s+/);
				if(classes.length == 2 ){
					lang = classes[1];
				}
				$.post('<?php echo $ajaxUrl ?>', {'action': 'admin:switchUserLang', 'lang': lang}, function(response){
					window.location.reload();
				});
			});
		});
		</script>
		<?php
	}



	public function ajaxSwitchUserLang()
	{
		$userId = get_current_user_id();
		self::download_mo($_POST['lang'], true);
		update_user_meta(get_current_user_id(), 'user_lang', $_POST['lang']);
		do_action('pll_after_language_switch', array('lang' => $_POST['lang'], 'user' => $userId));
	}



	/**
	 * adds a 'settings' link in the plugins table
	 *
	 * @since 0.1
	 *
	 * @param array $links list of links associated to the plugin
	 * @return array modified list of links
	 */
	public function plugin_action_links($links)
	{
		$link = sprintf('<a href="%s">%s</a>', admin_url('admin.php?page=ait-languages'), __('Settings', 'ait-languages'));
		array_unshift($links, $link);
		return $links;
	}

	/*
	 * adds the upgrade notice in plugins table
	 *
	 * @since 1.1.6
	 *
	 * @param array $plugin_data not used
	 * @param object $r plugin update data
	 */
	function plugin_update_message($plugin_data, $r) {
		if (isset($r->upgrade_notice))
			printf('<p style="margin: 3px 0 0 0; border-top: 1px solid #ddd; padding-top: 3px">%s</p>', $r->upgrade_notice);
	}

	/*
	 * defines the backend language and the admin language filter based on user preferences
	 *
	 * @since 1.2.3
	 */
	public function init_user() {
		// admin language filter
		if (!defined('DOING_AJAX') && !empty($_GET['lang']) && !is_numeric($_GET['lang']))
			update_user_meta(get_current_user_id(), 'ait_langs_content_filtering_lang', ($lang = $this->model->get_language($_GET['lang'])) ? $lang->slug : '');

		// set preferred language for use in filters
		$this->pref_lang = $this->model->get_language(($lg = get_user_meta(get_current_user_id(), 'ait_langs_content_filtering_lang', true)) ? $lg : $this->options['default_lang']);
		$this->pref_lang = apply_filters('pll_admin_preferred_language', $this->pref_lang);

		// inform that the admin language has been set
		// only if the admin language is one of the Polylang defined language
		if ($curlang = $this->model->get_language(get_locale())) {
			$GLOBALS['text_direction'] = $curlang->is_rtl ? 'rtl' : 'ltr'; // force text direction according to language setting
			do_action('pll_language_defined', $curlang->slug, $curlang);
		}
		else{
			do_action('pll_no_language_defined'); // to load overriden textdomains
		}
	}

	/**
	 * Get the locale based on user preference
	 *
	 * @since 0.4
	 *
	 * @param string $locale
	 * @return string modified locale
	 */
	public function get_locale($locale)
	{
		$userLang = get_user_meta(get_current_user_id(), 'user_lang', true);

		if($userLang){
			return $userLang;
		}elseif($defaultLang = $this->model->get_language($this->options['default_lang'])){
			return $defaultLang->locale;
		}

		return $locale;
	}

	/*
	 * setup filters for admin pages
	 *
	 * @since 1.2
	 */
	public function add_filters() {
		$this->links = new PLL_Links($this->links_model);
		$this->filters = new PLL_Admin_Filters($this->links_model, $this->pref_lang);
		$this->filters_columns = new PLL_Admin_Filters_Columns($this->model);
		$this->filters_post = new PLL_Admin_Filters_Post($this->model, $this->pref_lang);
		$this->filters_term = new PLL_Admin_Filters_Term($this->model, $this->pref_lang);
		$this->nav_menu = new PLL_Admin_Nav_Menu($this->model);
		$this->sync = new PLL_Admin_Sync($this->model);

		if ($this->options['media_support'])
			$this->filters_media = new PLL_Admin_Filters_Media($this->model, $this->pref_lang);
	}


	/**
	 * adds the languages list in admin bar for the admin languages filter
	 *
	 * @since 0.9
	 *
	 * @param object $wp_admin_bar
	 */
	public function adminBarLanguageFilter($wp_admin_bar)
	{
		$url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];

		$all_item = (object) array(
			'slug' => 'all',
			'name' => __('Show all languages', 'ait-languages'),
			'flag' => sprintf('<img src="%s" style="margin-bottom: -3px"/>', POLYLANG_URL .'/assets/flags/all.png')
		);

		// $_GET['lang'] is numeric when editing a language, not when selecting a new language in the filter
		if(!empty($_GET['lang']) and !is_numeric($_GET['lang']) and ($langObj = $this->model->get_language($_GET['lang']))){
			$selected = $langObj->slug;
		}else{
			if($langSlug = get_user_meta(get_current_user_id(), 'ait_langs_content_filtering_lang', true)){
				$selected = $langSlug;
			}else{
				$selected = 'all';
			}
		}

		$selectedLang = ($selected == 'all') ? $all_item : $this->model->get_language($selected);

		$wp_admin_bar->add_menu(array(
			'id'     => 'languages',
			'title'  => empty($selectedLang->flag) ? __('Filter', 'ait-admin') . ": " . esc_html($selectedLang->name) : __('Filter', 'ait-admin') . ": &nbsp;" .  $selectedLang->flag .  '&nbsp;'. esc_html($selectedLang->name),
			'meta'  => array('title' => __('Filters content by language', 'ait-languages')),
		));

		foreach (array_merge(array($all_item), $this->model->get_languages_list()) as $lang) {
			if ($selectedLang == $lang->slug)
				continue;

			$wp_admin_bar->add_menu(array(
				'parent' => 'languages',
				'id'     => $lang->slug,
				'title'  => empty($lang->flag) ? esc_html($lang->name) : $lang->flag .'&nbsp;'. esc_html($lang->name),
				'href'   => esc_url(add_query_arg('lang', $lang->slug, $url)),
			));
		}
	}



	public function adminBarLanguageSwitcher($wp_admin_bar)
	{
		$currentLang = $this->model->get_language(get_locale());

		if(!$currentLang){
			$currentLang = $this->model->get_language('en_US'); // default;
		}

		$wp_admin_bar->add_node(array(
			'id' => 'ait-admin-languages-switcher',
			'title'  =>  empty($currentLang->flag) ? esc_html(sprintf(__('Admin Language: %s', 'ait-languages'), $currentLang->name)) : sprintf(__('Admin Language: %s %s', 'ait-languages'), $currentLang->flag, esc_html($currentLang->name)),
			'parent' => 'top-secondary',
			'href' => '#',
		));

		foreach ($this->model->get_languages_list() as $lang){
			if ($currentLang->slug == $lang->slug) continue;

			$wp_admin_bar->add_menu(array(
				'parent' => 'ait-admin-languages-switcher',
				'id'     => "ait-lang-{$lang->slug}",
				'title'  => empty($lang->flag) ? esc_html($lang->name) : $lang->flag .'&nbsp;'. esc_html($lang->name),
				'href'   => '#',
				'meta' => array('class' => "ait-admin-lang {$lang->locale}"),
			));
		}
	}



	/*
	 * downloads mofiles from http://svn.automattic.com/wordpress-i18n/
	 * FIXME is it the best class for this?
	 * FIXME use language packs API coming with WP 3.7 instead
	 *
	 * @since 0.6
	 *
	 * @param string $locale locale to download
	 * @param bool $upgrade optional true if this is an upgrade, false if this is the first download, defaults to false
	 * @return bool true on success, false otherwise
	 */
	static public function download_mo($locale, $upgrade = false) {
		global $wp_version;
		$mofile = WP_LANG_DIR."/$locale.mo";

		// does file exists ?
		if ((file_exists($mofile) && !$upgrade) || $locale == 'en_US')
			return true;

		// does language directory exists ?
		if (!is_dir(WP_LANG_DIR)) {
			if (!@mkdir(WP_LANG_DIR))
				return false;
		}

		if(self::copyMo($locale)){
			return true;
		}

		// will first look in tags/ (most languages) then in branches/ (only Greek ?)
		$base = 'http://svn.automattic.com/wordpress-i18n/'.$locale;
		$bases = array($base.'/tags/', $base.'/branches/');

		foreach ($bases as $base) {
			// get all the versions available in the subdirectory
			$resp = wp_remote_get($base);
			if (is_wp_error($resp) || 200 != $resp['response']['code'])
				continue;

			preg_match_all('#>([0-9\.]+)\/#', $resp['body'], $matches);
			if (empty($matches[1]))
				continue;

			rsort($matches[1]); // sort from newest to oldest
			$versions = $matches[1];

			$newest = $upgrade ? $upgrade : $wp_version;
			foreach ($versions as $key=>$version) {
				// will not try to download a too recent mofile
				if (version_compare($version, $newest, '>'))
					unset($versions[$key]);
				// will not download an older version if we are upgrading
				if ($upgrade && version_compare($version, $wp_version, '<='))
					unset($versions[$key]);
			}

			$versions = array_splice($versions, 0, 5); // reduce the number of versions to test to 5
			$args = array('timeout' => 30, 'stream' => true);

			// try to download the file
			foreach ($versions as $version) {
				$resp = wp_remote_get($base."$version/messages/$locale.mo", $args + array('filename' => $mofile));
				if (is_wp_error($resp) || 200 != $resp['response']['code']) {
					unlink($mofile); // otherwise we download a gzipped 404 page
					continue;
				}
				// try to download ms and continents-cities files if exist (will not return false if failed)
				// with new files introduced in WP 3.4
				foreach (array('ms', 'continents-cities', 'admin', 'admin-network') as $file) {
					$resp = wp_remote_get($base."$version/messages/$file-$locale.mo", $args + array('filename' => WP_LANG_DIR."/$file-$locale.mo"));
					if (is_wp_error($resp) || 200 != $resp['response']['code'])
						unlink(WP_LANG_DIR."/$file-$locale.mo");
				}
				// try to download theme files if exist (will not return false if failed)
				// FIXME not updated when the theme is updated outside a core update
				foreach (array('twentyten', 'twentyeleven', 'twentytwelve', 'twentythirteen') as $theme) {
					if (!is_dir($theme_dir = get_theme_root()."/$theme/languages"))
						continue; // the theme is not present

					$resp = wp_remote_get($base."$version/messages/$theme/$locale.mo", $args + array('filename' => "$theme_dir/$locale.mo"));
					if (is_wp_error($resp) || 200 != $resp['response']['code'])
						unlink("$theme_dir/$locale.mo");
				}
				return true;
			}
		}
		// we did not succeeded to download a file :(
		return false;
	}



	public static function copyMo($locale)
	{
		$localeDir = POLYLANG_DIR . "/wp-languages/$locale";

		if(file_exists($localeDir)){
			$files = glob("$localeDir/*.*");

			if(!$files) return false;

			$allCopied = array();

			foreach($files as $file){
				$basename = basename($file);
				if(!file_exists(WP_LANG_DIR . "/$basename")){
					$allCopied[$basename] = @copy($file, WP_LANG_DIR . "/$basename");
				}
			}

			if(count(array_filter($allCopied)) == 0){
				return false; // all files were not copied
			}else{
				return true;
			}
		}else{
			return false;
		}
	}

}
