<?php namespace ProcessWire;

/**
 * An Inputfield for handling "submit" buttons
 * 
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer
 * https://processwire.com
 * License: MPL 2.0
 * 
 * @property bool $header Whether or not button will also appear in header (default=false). 
 * @property bool $secondary Whether or not button is secondary (default=false). 
 * @property bool $small Whether or not button should be small, where supported (default=false). 
 * @property string $dropdownInputName #pw-internal
 *
 */
class InputfieldSubmit extends Inputfield {

	public static function getModuleInfo() {
		return array(
			'title' => __('Submit', __FILE__), // Module Title
			'summary' => __('Form submit button', __FILE__), // Module Summary
			'version' => 102,
			'permanent' => true, 
			);
	}

	/**
	 * Additional dropdown actions added to the button
	 * 
	 * @var array
	 * 
	 */
	protected $dropdownItems = array();

	/**
	 * Init
	 * 
	 */
	public function init() {
		parent::init();
		$this->attr('type', 'submit'); 
		$this->attr('name', 'submit'); 
		$this->attr('value', $this->_('Submit')); // Standard submit button label
		$this->attr('class', 'ui-button ui-widget ui-state-default ui-corner-all');
		$this->skipLabel = Inputfield::skipLabelBlank; 
		$this->set('small', false);
		
		// name of 'hidden' input that will receive the clicked dropdown item value
		$this->set('dropdownInputName', '_action_value');
	}
	
	public function set($key, $value) {
		if($key == 'header') {
			$this->showInHeader($value);
		} else if($key == 'secondary') {
			$this->setSecondary($value);
		}
		return parent::set($key, $value);
	}
	
	public function get($key) {
		if($key == 'header') return $this->hasClass('pw-head-button');
		if($key == 'secondary') return $this->hasClass('ui-priority-secondary');
		return parent::get($key);
	}

	/**
	 * Show another copy of this button in the header? 
	 * 
	 * @param bool $show True=yes, false=no (default=true)
	 * @return $this
	 * 
	 */
	public function showInHeader($show = true) {
		if($show) {
			$this->addClass('pw-head-button');
		} else {
			$this->removeClass('pw-head-button');
		}
		return $this;
	}

	/**
	 * Make this button secondary? (slightly faded)
	 * 
	 * Note: by default, buttons are not secondary
	 * 
	 * @param bool $secondary Default=true
	 * @return $this
	 * 
	 */
	public function setSecondary($secondary = true) {
		if($secondary) {
			$this->addClass('ui-priority-secondary');
		} else {
			$this->removeClass('ui-priority-secondary');
		}
		return $this;
	}
	
	/**
	 * Make this button small?
	 * 
	 * By default, buttons are regular size. This makes them small.
	 * Supported only for non-dropdown, non-header buttons. 
	 *
	 * @param bool $small Default=true
	 * @return $this
	 *
	 */
	public function setSmall($small = true) {
		$this->set('small', $small ? true : false);
		return $this;
	}

	/**
	 * Render ready
	 * 
	 * @param Inputfield|InputfieldWrapper|null The parent InputfieldWrapper that is rendering it, or null if no parent.
	 * @param bool $renderValueMode Specify true only if this is for `Inputfield::renderValue()` rather than `Inputfield::render()`.
	 * @return bool True if assets were just added, false if already added.
	 *
	 */
	public function renderReady(Inputfield $parent = null, $renderValueMode = false) {
		$class = $this->attr('class');	
		if(strpos($class, 'head_button_clone') !== false) {
			// if legacy class name used, convert to updated pw- class name to accomodate 3rd party usages
			$class = str_replace('head_button_clone', 'pw-head-button', $class);
			$this->attr('class', $class);
		}
		if($this->getSetting('small')) {
			$this->addClass('InputfieldSubmitSmall', 'wrapClass');
		}
		return parent::renderReady($parent, $renderValueMode);
	}

	/**
	 * Render the button
	 * 
	 * @return string
	 * 
	 */
	public function ___render() {
		$attrs  = $this->getAttributesString();
		$icon = $this->icon ? $this->sanitizer->name($this->icon) : '';
		$icon = $icon ? "<i class='fa fa-$icon'></i> " : '';
		$value = $this->entityEncode($this->attr('value'));
		$out = "<button $attrs><span class='ui-button-text'>$icon$value</span></button>";
		if($this->getSetting('small')) $out = "<small>$out</small>";
		if(count($this->dropdownItems)) $out .= $this->renderDropdown();
		return $out; 
	}

	/**
	 * Render the dropdown to accompany the button
	 * 
	 * @return string
	 * 
	 */
	protected function renderDropdown() {

		if($this->wire('input')->get('modal')) return '';
		
		$config = $this->wire('config');
		$file = $config->debug ? 'dropdown.js' : 'dropdown.min.js';
		$config->scripts->add($config->urls->InputfieldSubmit . $file);
		$numValues = 0;
		$dropdownID = $this->attr('id') . '_dropdown';
		$out  = "<ul id='$dropdownID' class='pw-button-dropdown' data-my='left top' data-at='left bottom+1'>";

		foreach($this->dropdownItems as $item) {
			
			// entity encode all the labels in the dropdown
			foreach($item as $k => $v) {
				if($k == 'type') continue;
				$item[$k] = htmlentities($v, ENT_QUOTES, "UTF-8");
			}
			
			if($item['type'] == 'link') {
				// direct link
				$out .= "<li><a href='$item[value]'>";
			} else {
				// populate hidden input with value before submit
				$out .= "<li><a data-pw-dropdown-value='$item[value]' href='#'>";
				$numValues++;
			}
			// icon to accompany label
			if($item['icon']) $out .= "<i class='fa fa-fw fa-$item[icon]'></i>";
					
			// label and finish item
			$out .= "$item[label]</a></li>";
		}
		
		$out .= "</ul>";
		
		if($numValues) {
			// there are values that can be populated to a hidden input
			$inputID = $dropdownID . '_value';
			$out = "<input type='hidden' name='{$this->dropdownInputName}' id='$inputID' value='' />" .
				str_replace("<ul ", "<ul data-pw-dropdown-input='#$inputID' ", $out);
		}
	
		// script to initialize this dropdown immediately
		$out .= "<script" . ">InputfieldSubmitDropdown.init('#{$this->id}')</script>";
		
		return $out; 
	}

	/**
	 * Process input
	 * 
	 * @param WireInputData $input
	 * @return $this
	 * 
	 */
	public function ___processInput(WireInputData $input) {
		// submit buttons don't need to process any input
		return $this; 
	}

	/**
	 * Add a dropdown item to this button
	 * 
	 * @param string $type Either 'link' or 'value'
	 * @param string|int $value
	 * @param string $label
	 * @param string $icon
	 * 
	 */
	protected function addActionItem($type, $value, $label, $icon) {
		if(!$icon) $icon = 'angle-double-right';
		$this->dropdownItems[] = array(
			'type' => $type,
			'value' => $value,
			'label' => $label,
			'icon' => $icon,
		);
	}

	/**
	 * Add a dropdown action item that populates a new 'value' for the submit button
	 * 
	 * This also populates the value to $_POST['_action_value']
	 * 
	 * @param string $value Value to populate to hidden input when dropdown item is selected/clicked.
	 * @param string $label Text label to accompany the item
	 * @param string $icon Icon name (optional)
	 * 
	 */
	public function addActionValue($value, $label, $icon = '') {
		$this->addActionItem('value', $value, $label, $icon);
	}

	/**
	 * Add a dropdown action item that links to a URL
	 *
	 * @param string $url URL to link to
	 * @param string $label Text label to accompany the item
	 * @param string $icon Icon name (optional)
	 *
	 */
	public function addActionLink($url, $label, $icon = '') {
		$this->addActionItem('link', $url, $label, $icon);
	}
	
}
