<?php namespace ProcessWire;

/**
 * ProcessWire Checkbox Fieldtype
 *
 * This Fieldtype stores an ON/OFF toggle via a single checkbox. The ON value is 1 and OFF value is 0.
 *
 * For documentation about the fields used in this class, please see:  
 * /wire/core/Fieldtype.php
 * 
 * ProcessWire 3.x, Copyright 2023 by Ryan Cramer
 * https://processwire.com
 *
 */

class FieldtypeCheckbox extends Fieldtype {

	public static function getModuleInfo() {
		return array(
			'title' => 'Checkbox',
			'version' => 101,
			'summary' => 'This Fieldtype stores an ON/OFF toggle via a single checkbox. The ON value is 1 and OFF value is 0.',
			'permanent' => true, 
		);
	}

	/**
	 * Get blank value for field
	 * 
	 * @param Page $page
	 * @param Field $field
	 * @return int
	 * 
	 */
	public function getBlankValue(Page $page, Field $field) {
		return 0; 
	}

	/**
	 * Sanitize value for field
	 * 
	 * @param Page $page
	 * @param Field $field
	 * @param mixed $value
	 * @return int
	 * 
	 */
	public function sanitizeValue(Page $page, Field $field, $value) {
		return $value ? 1 : 0; 
	}

	/**
	 * Get markup value for field
	 * 
	 * @param Page $page
	 * @param Field $field
	 * @param int|null $value
	 * @param string $property
	 * @return string
	 * 
	 */
	public function ___markupValue(Page $page, Field $field, $value = null, $property = '') {
		if(is_null($value)) $value = $page->get($field->name); 
		$checked = $value ? " checked='checked'" : "";
		if($this->wire()->page->template->name === 'admin') {
			// use fa-icon for checkbox in the admin
			$out = $checked ? wireIconMarkup('check-square-o') : wireIconMarkup('square-o');
		} else {
			// use disabled checkbox outside of the admin
			$out = "<input type='checkbox' $checked disabled='disabled' />";
		}
		// note: the span below ensures a value survives even if markupValue has tags stripped from it
		$textValue = $checked ? '☒' : '☐'; // utf-8 checkbox (the ☑ also works for checked, but not quite as visible)
		return $out . "<span style='display:none'>$textValue</span>";
	}

	/**
	 * Get Inputfield for field
	 * 
	 * @param Page $page
	 * @param Field $field
	 * @return InputfieldCheckbox
	 * 
	 */
	public function getInputfield(Page $page, Field $field) {
		/** @var InputfieldCheckbox $inputfield */
		$inputfield = $this->wire()->modules->get('InputfieldCheckbox'); 
		$inputfield->set('checkedValue', 1); 
		$inputfield->set('uncheckedValue', 0); 
		$value = $page->get($field->name); 
		if($value) $inputfield->attr('checked', 'checked'); 
		$inputfield->addClass($this->className());
		return $inputfield; 
	}

	/**
	 * Get database schema for field
	 * 
	 * @param Field $field
	 * @return array
	 * 
	 */
	public function getDatabaseSchema(Field $field) {
		$schema = parent::getDatabaseSchema($field); 
		$schema['data'] = "tinyint NOT NULL";
		$schema['keys']['data'] = 'KEY data (data)'; 
		return $schema;
	}

	/**
	 * Get match query for PageFinder
	 * 
	 * @param PageFinderDatabaseQuerySelect|DatabaseQuerySelect $query
	 * @param string $table
	 * @param string $subfield
	 * @param string $operator
	 * @param mixed $value
	 * @return DatabaseQuery|DatabaseQuerySelect
	 *
	 */
	public function getMatchQuery($query, $table, $subfield, $operator, $value) {
		if(!empty($value) && ($operator === '!=' || $operator === '<>')) {
			// allow for matching test_checkbox!=1 since non-checked rows don't appear in database
			static $n = 0;
			$_table = $table . '_ckbx' . (++$n);
			$query->leftjoin("$table AS $_table ON $_table.pages_id=pages.id");
			$query->where("$_table.pages_id IS NULL"); 
		} else {
			$query = parent::getMatchQuery($query, $table, $subfield, $operator, $value);
		}
		return $query;
	}

	/**
	 * Return array with information about what properties and operators can be used with this field
	 * 
	 * @param Field $field
	 * @param array $data
	 * @return array
	 *
	 */
	public function ___getSelectorInfo(Field $field, array $data = array()) {
		$info = parent::___getSelectorInfo($field, $data); 
		$info['input'] = 'checkbox';
		return $info; 
	}
	
	/**
	 * Get an array of Fieldtypes that are compatible with this one
	 *
	 * This represents the list of Fieldtype modules that the user is allowed to change to from this one.
	 *
	 * @param Field $field
	 * @return Fieldtypes|null
	 *
	 */
	public function ___getCompatibleFieldtypes(Field $field) {
		$fieldtypes = $this->wire(new Fieldtypes());
		$toggleClass = 'FieldtypeToggle';
		$allowToggle = $this->wire()->modules->isInstalled($toggleClass);
		
		foreach($this->wire()->fieldtypes as $fieldtype) {
			if($fieldtype instanceof FieldtypeCheckbox) {
				$fieldtypes->add($fieldtype); 
			} else if($allowToggle && wireInstanceOf($fieldtype, $toggleClass)) {
				$fieldtypes->add($fieldtype); 
			}
		}
		
		return $fieldtypes;
	}

}
