<?php namespace ProcessWire;

/**
 * ProcessWire Float Fieldtype
 *
 * Field that stores a floating point number. 
 *
 * For documentation about the fields used in this class, please see:  
 * /wire/core/Fieldtype.php
 * 
 * ProcessWire 3.x, Copyright 2020 by Ryan Cramer
 * https://processwire.com
 *
 */

class FieldtypeFloat extends Fieldtype {

	public static function getModuleInfo() {
		return array(
			'title' => __('Float', __FILE__),
			'summary' => __('Field that stores a floating point (decimal) number', __FILE__),
			'version' => 106,
			'permanent' => true, 
		);
	}

	/**
	 * Get compatible Fieldtypes
	 * 
	 * @param Field $field
	 * @return null|Fieldtypes
	 * 
	 */
	public function ___getCompatibleFieldtypes(Field $field) {
		$fieldtypes = parent::___getCompatibleFieldtypes($field); 
		foreach($fieldtypes as $type) {
			if(!$type instanceof FieldtypeInteger && !$type instanceof FieldtypeFloat && $type != 'FieldtypeText') {
				$fieldtypes->remove($type); 
			}
		}
		return $fieldtypes; 
	}

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

	/**
	 * Is given value considered empty to this Fieldtype?
	 * 
	 * @param Field $field
	 * @param mixed $value
	 * @return bool
	 * 
	 */
	public function isEmptyValue(Field $field, $value) {
		if($value === "0" || $value === 0 || $value === "0.0" || $value === 0.0) {
			// when zeroNotEmpty option is set, we don't count a literal "0" is being a blank value
			if($field->get('zeroNotEmpty')) return false;
		}
		return empty($value);
	}

	/**
	 * Sanitize value
	 * 
	 * @param Page $page
	 * @param Field $field
	 * @param float|int|string $value
	 * @return float|string
	 * 
	 */
	public function sanitizeValue(Page $page, Field $field, $value) {
		if(!strlen("$value")) return '';
		if(!is_float($value) && !is_int($value)) {
			$value = $this->wire()->sanitizer->float((string) $value, array('blankValue' => ''));
		}
		$precision = $field->get('precision');
		if($precision === null || $precision === '') {
			$value = (float) $value;
		} else {
			$value = round((float) $value, $precision);
		}
		return $value; 
	}

	/**
	 * Get Inputfield for this Fieldtype
	 * 
	 * @param Page $page
	 * @param Field $field
	 * @return Inputfield
	 * 
	 */
	public function getInputfield(Page $page, Field $field) {
		/** @var InputfieldFloat $inputfield */
		$inputfield = $this->wire()->modules->get('InputfieldFloat'); 
		$inputfield->addClass($this->className());
		$inputfield->precision = $field->get('precision'); 
		return $inputfield; 
	}

	/**
	 * Sleep value for DB storage
	 * 
	 * @param Page $page
	 * @param Field $field
	 * @param string|float|int
	 * @return string
	 * 
	 */
	public function ___sleepValue(Page $page, Field $field, $value) {
		$precision = $field->get('precision'); 
		if(is_null($precision) || $precision === '') $precision = self::getPrecision($value); 
		if(!is_string($value)) $value = number_format($value, $precision, '.', '');
		return $value; 
	}

	/**
	 * Get precision of given value 
	 * 
	 * @param string|float $value
	 * @return int
	 * 
	 */
	public static function getPrecision($value) {
		$value = (float) $value;
		$remainder = ceil($value) - $value;
		$precision = strlen(ltrim($remainder, '0., '));
		if(!$precision) $precision = 1; 
		return $precision;
	}

	/**
	 * Get DB schema for this Fieldtype
	 * 
	 * @param Field $field
	 * @return array
	 * 
	 */
	public function getDatabaseSchema(Field $field) {
		$schema = parent::getDatabaseSchema($field); 
		$schema['data'] = 'float NOT NULL';
		return $schema;
	}

	/**
	 * Get field configuration
	 * 
	 * @param Field $field
	 * @return InputfieldWrapper
	 * 
	 */
	public function ___getConfigInputfields(Field $field) {
		$inputfields = parent::___getConfigInputfields($field);
		$precision = $field->get('precision');
		if($precision === null) $precision = 2; 

		/** @var InputfieldInteger $f */
		$f = $this->wire()->modules->get('InputfieldInteger');
		$f->attr('name', 'precision'); 
		$f->label = $this->_('Number of decimal digits to round to');
		if($precision !== '') $f->val($precision); 
		$f->attr('size', 8); 
		$inputfields->append($f);
	
		/** @var FieldtypeInteger $ft */
		$ft = $this->wire()->modules->get('FieldtypeInteger');
		// use the same 'zeroNotEmpty' setting as FieldtypeInteger
		$f = $ft->___getConfigInputfields($field)->getChildByName('zeroNotEmpty'); 
		if($f) $inputfields->add($f); 

		return $inputfields; 
	}

	/**
	 * Convert float string with commas to float value
	 * 
	 * @param string $str
	 * @return float|string
	 * @deprecated Use $sanitizer->float($value, [ 'blankValue' = '' ]) instead
	 * 
	 */
	public static function strToFloat($str) { 
		return wire('sanitizer')->float($str, array('blankValue' => ''));
	}
	
	/*
	public function formatValue(Page $page, Field $field, $value) {
		// @todo add support for number_format options
		return $value; 	
	}
	*/

	/*
	public function getMatchQuery($query, $table, $subfield, $operator, $value) {
		if(!is_int($value) && !is_float($value)) {
			$value = self::strToFloat((string) $value);
		}
		return parent::getMatchQuery($query, $table, $subfield, $operator, $value); 
	}
	*/


}

