<?php namespace ProcessWire;

/**
 * ProcessWire Language Field Tabs
 *
 * Organizes Language Fields into tabs for a cleaner easier to use interface
 *
 * By Adamspruijt and Ryan Cramer, Copyright 2013/2014
 * 
 * ProcessWire 3.x, Copyright 2023 by Ryan Cramer
 * https://processwire.com
 * 
 * @property string $tabField Name of field/property to use for tab labels.
 * 
 *
 */

class LanguageTabs extends WireData implements Module, ConfigurableModule {

	public static function getModuleInfo() {
		return array(
			'title' => 'Languages Support - Tabs',
			'version' => 117,
			'summary' => 'Organizes multi-language fields into tabs for a cleaner easier to use interface.',
			'author' => 'adamspruijt, ryan, flipzoom', 
			'singular' => true,
			'autoload' => "template=admin",
			'requires' => 'LanguageSupport'
		);
	}

	/**
	 * Temporary storage of tabs created from addTab() method
	 * 
	 * @var array of strings
	 * 
	 */
	protected $tabs = array();

	/**
	 * Cached settings
	 * 
	 * @var array
	 * 
	 */
	protected $settings = array();

	/**
	 * Construct
	 * 
	 */
	public function __construct() {
		parent::__construct();
		$this->set('tabField', 'title');
	}

	/**
	 * Add hooks, setup JS config, and determine active tab
	 * 
	 */
	public function ready() {
		if($this->wire()->page->template->name !== 'admin') return;
		$this->addHookAfter('InputfieldForm::render', $this, 'hookRenderInputfieldForm'); 
	}

	/**
	 * Get language tab settings
	 * 
	 * @return array
	 * 
	 */
	public function getSettings() {
		
		if(!empty($this->settings)) return $this->settings;
		
		$language = null;
		$input = $this->wire()->input;
		$languages = $this->wire()->languages; 
		
		// allow for specifying language in your "edit" page link, from front-end
		// so if you want to focus on the Spanish tabs when the user clicks "edit"
		// from /es/path/to/page/, then you can by using a page edit link like:
		// <a href='{$config->urls->admin}page/edit/?id=$page->id&language=$user->language'>Edit</a>
		$id = (int) $input->get('language');
		if($id) $language = $languages->get($id);

		// if language is not specified as a GET variable, then use the user's language
		if(!$language || !$language->id) $language = $this->wire()->user->language;

		// determine the index of the tab for the user's language	
		$activeTab = 0;
		foreach($languages as $index => $lang) {
			if($lang->id == $language->id) $activeTab = $index;
		}

		$defaults = array(
			'jQueryUI' => true,  // use jQuery UI tabs?
			'labelOpen' => $this->_('Expand Language Tabs'),
			'labelClose' => $this->_('Collapse/Convert Back to Tabs'),
			'activeTab' => $activeTab,
			'ulClass' => '',
			'ulAttrs' => '',
			'liActiveClass' => '',
			'liDisabledClass' => '',
			'liEmptyClass' => '',
			'aClass' => '',
			'loadStyles' => true,
			'loadScripts' => true,
			'tabField' => $this->get('tabField'),
			'requestId' => ((string) $this->wire()->process) . (int) $input->get('id'),
		);
		
		$config = $this->wire()->config;
		$settings = $config->get('LanguageTabs');
		
		if(is_array($settings)) {
			$this->settings = array_merge($defaults, $settings);
		} else {
			$this->settings = $defaults;
		}

		$config->js('LanguageTabs', $this->settings);
		
		return $this->settings;
	}

	/**
	 * Init language tabs in form immediately after form render
	 * 
	 * @param HookEvent $e
	 * 
	 */
	public function hookRenderInputfieldForm(HookEvent $e) {
		
		$settings = $this->getSettings();
		$config = $this->wire()->config;
		$info = self::getModuleInfo();
		
		if($settings['jQueryUI']) {
			$adminTheme = $this->wire()->adminTheme;
			if($adminTheme) $adminTheme->addBodyClass('LanguageTabsJqueryUI');
		}
		
		if($settings['loadStyles']) {
			$config->styles->add($config->urls('LanguageTabs') . "LanguageTabs.css?v=$config->version-$info[version]");
		}
		if($settings['loadScripts']) {
			$config->scripts->add($config->urls('LanguageTabs') . "LanguageTabs.js?v=$config->version-$info[version]");
		}

		/** @var JqueryCore $jQueryCore */
		$jQueryCore = $this->wire()->modules->get('JqueryCore');
		$jQueryCore->use('longclick');
		$jQueryCore->use('cookie');
		
		if(strpos($e->return, 'LanguageSupport') === false) return;
		
		/** @var InputfieldForm $form */
		$form = $e->object;
		$id = $form->attr('id'); 
		$func = "setupLanguageTabs($('#$id'));";
		$e->return .= "<script>$func</script>";
	}

	/**
	 * Clear any stored tabs
	 * 
	 */
	public function resetTabs() {
		$this->tabs = array();
	}

	/**
	 * Add a new tab, to be later retrieved by renderTabs()
	 * 
	 * @param Inputfield $inputfield
	 * @param Language $language
	 * 
	 */
	public function addTab(Inputfield $inputfield, Language $language) {
		$settings = $this->getSettings();
		$liClasses = array();
		$aClasses = array('langTabLink', 'langTab' . $language->id);
		$title = $language->get(empty($settings['tabField']) ? $this->tabField : $settings['tabField']);
		if(empty($title)) $title = $language->get("$this->tabField|name");
		$title = $this->wire()->sanitizer->entities1($title);
		if(!$this->wire()->languages->editable($language)) {
			$title = "<s>$title</s>";
			$liClasses[] = 'LanguageNotEditable'; 
			$liClasses[] = $settings['liDisabledClass'];
		}
		if($inputfield->isEmpty()) {
			$liClasses[] = 'langTabEmpty';
			$liClasses[] = $settings['liEmptyClass'];
		}
		$id = $inputfield->attr('id'); 
		$liClass = implode(' ', $liClasses);
		$aClass = implode(' ', $aClasses);
		/** @noinspection HtmlUnknownAnchorTarget */
		$this->tabs[] = 
			"<li class='$liClass'>" . 
				"<a data-lang='$language->id' class='$aClass' href='#langTab_$id'>$title</a>" . 
			"</li>";
	}

	/**
	 * Render output for all added tabs
	 * 
	 * Note that if only 1 tab has been added, tabs won't be displayed (no point in it).
	 * This method automatically calls resetTabs() after rendering. 
	 * 
	 * @param Inputfield $inputfield
	 * @param string $content Content that will have the tabs 
	 * @return string Modified $content with tabs
	 * 
	 */
	public function renderTabs(Inputfield $inputfield, $content) {
		$settings = $this->getSettings();
		if(count($this->tabs) > 1) { 
			$inputfield->wrapClass .= " hasLangTabs";
			$inputfield->contentClass .= " langTabsContainer";
			$tabs = implode('', $this->tabs);
			$id = $inputfield->attr('id');
			$note = "<small class='langTabsNote detail'><i class='fa fa-fw fa-angle-double-left'></i>" . 
				$this->_('click twice to change all tabs') . "</small>";
			$attrs = $settings['ulAttrs']; 
			$attrs .= $settings['ulClass'] ? " class='$settings[ulClass]'" : "";
			$attrs = strlen($attrs) ? " " . trim($attrs) : "";
			$content = "<div class='langTabs' id='langTabs_$id'>$note<ul$attrs>$tabs</ul>$content</div>";
		} else {
			// do nothing, just return content because there was only 1 tab (no render necessary)
		}
		$this->resetTabs();
		return $content; 
	}

	/**
	 * Module config
	 * 
	 * @param InputfieldWrapper $inputfields
	 * 
	 */
	public function getModuleConfigInputfields(InputfieldWrapper $inputfields) {
		/** @var InputfieldSelect $f */
		$f = $this->wire()->modules->get('InputfieldSelect'); 
		$f->attr('name', 'tabField');
		$f->label = $this->_('Field to use for tab labels');
		$f->addOption('name');
		foreach($this->wire()->templates->get('language')->fieldgroup as $field) {
			/** @var Field $field */
			if($field->type instanceof FieldtypeMulti) continue;
			$f->addOption($field->name);
		}
		$f->attr('value', $this->tabField);
		$f->required = true;
		$inputfields->add($f);
	}

}
