<?php
namespace SabaiApps\Directories\Component\System\Helper;

use SabaiApps\Directories\Application;

/**
 * TextHelper provides various utility methods for text manipulation.
 */
class TextHelper {

	/**
	 * Summarizes the given text to the specified length.
	 *
	 * @param Application $application
	 * @param string      $text The text to summarize.
	 * @param int         $length The maximum length of the summary.
	 * @param string      $trimmarker The string to append if text is trimmed.
	 * @return string
	 */
	public function summarize( Application $application, $text, $length = 0, $trimmarker = '...' ) {
		if ( ! strlen( $text ) ) {
			return '';
		}

		$text = strip_tags(
			strtr(
				$text,
				array(
					"\r" => '',
					"\n" => ' ',
				)
			)
		);

		return empty( $length ) ? $text : $application->System_MB_strimwidth( $text, 0, $length, $trimmarker );
	}

	/**
	 * Extracts keywords from the input string.
	 *
	 * @param Application $application
	 * @param string      $input Input string to extract keywords from.
	 * @param int|null    $minLength Minimum keyword length.
	 * @param bool        $includeFull Whether to include the full input as a keyword.
	 * @param bool        $split Whether to split the input into keywords.
	 * @return array Array containing passed keywords, failed keywords, and the original input.
	 */
	public function keywords( Application $application, $input, $minLength = null, $includeFull = false, $split = true ) {
		if ( ! isset( $minLength ) ) {
			$minLength = 3;
		}
		$keywords = array();
		if ( $includeFull ) {
			$keywords[] = trim( $input, '"' );
		}
		if ( $split ) {
			$inputs = self::_splitString( $input, 15 );
			foreach ( $inputs as $keyword ) {
				if ( $quote_count = substr_count( $keyword, '"' ) ) { // check if any quotes
					$_keyword = explode( '"', $keyword );
					if ( isset( $fragment ) ) { // has a phrase open but not closed?
						$keywords[] = $fragment . ' ' . array_shift( $_keyword );
						unset( $fragment );
						if ( ! $quote_count % 2 ) {
							// the last quote is not closed
							$fragment = array_pop( $_keyword );
						}
					} elseif ( $quote_count % 2 ) {
							// the last quote is not closed
							$fragment = array_pop( $_keyword );
					}
					if ( ! empty( $_keyword ) ) {
						$keywords = array_merge( $keywords, $_keyword );
					}
				} elseif ( isset( $fragment ) ) {
					// has a phrase open but not closed?
						$fragment .= ' ' . $keyword;
				} else {
					$keywords[] = $keyword;
				}
			}
			// Add the last unclosed fragment if any, to the list of keywords
			if ( isset( $fragment ) ) {
				$keywords[] = $fragment;
			}
		}

		// Extract unique keywords that are not empty
		$keywords_passed = $keywords_failed = array();
		foreach ( $keywords as $keyword ) {
			if ( ( $keyword = trim( $keyword ) )
				&& ! isset( $keywords_passed[ $keyword ] )
				&& ! isset( $keywords_failed[ $keyword ] )
			) {
				if ( $application->System_MB_strlen( $keyword ) >= $minLength ) {
					$keywords_passed[ $keyword ] = $keyword;
				} else {
					$keywords_failed[ $keyword ] = $keyword;
				}
			}
		}

		return array( $keywords_passed, $keywords_failed, $input );
	}

	/**
	 * Splits a string into an array of words using whitespace.
	 *
	 * @param string $str
	 * @param int    $limit
	 * @return array
	 */
	protected static function _splitString( $str, $limit = -1 ) {
		if ( function_exists( 'mb_split' ) ) {
			return mb_split( '\s+', trim( function_exists( 'mb_convert_kana' ) ? mb_convert_kana( $str, 's', 'UTF-8' ) : $str ), $limit );
		}
		return preg_split( '/\s+/', $str, $limit );
	}

	/**
	 * Converts text to a slug.
	 *
	 * @param Application $application
	 * @param string      $text The text to slugify.
	 * @param int         $maxLength Maximum length of the slug.
	 * @param string      $separator Separator character for words.
	 * @return string
	 */
	public function slugify( Application $application, $text, $maxLength = 255, $separator = '-' ) {
		if ( ! $strlen = $application->System_MB_strlen( $text ) ) {
			return $text;
		}

		// transliterate
		if ( false === $slug = self::_transliterate( $text ) ) {
			// transliterate failed, return original but make sure the length does not exceed max limit
			return empty( $maxLength ) ? $text : ( function_exists( 'mb_strcut' ) ? mb_strcut( $text, 0, $maxLength ) : substr( $text, 0, $maxLength ) );
		}
		// replace non alnum chars with separator
		$slug = preg_replace( '/\W+/', $separator, $slug );
		// return original if more than 20% of original text has been stripped
		if ( strlen( $slug ) / $strlen < 0.8 ) {
			// make sure the length does not exceed max limit
			return empty( $maxLength ) ? $text : ( function_exists( 'mb_strcut' ) ? mb_strcut( $text, 0, $maxLength ) : substr( $text, 0, $maxLength ) );
		}
		// make sure the length does not exceed max limit
		if ( ! empty( $maxLength ) ) {
			$slug = substr( $slug, 0, $maxLength );
		}
		// trim
		$slug = trim( $slug, $separator );

		return strtolower( $slug );
	}

	/**
	 * Transliterates UTF-8 text to ASCII.
	 *
	 * @param string $text
	 * @return string|false
	 */
	protected static function _transliterate( $text ) {
		if ( false === $ret = iconv( 'utf-8', 'us-ascii//TRANSLIT', $text ) ) {
			return false;
		}
		// remove accents resulting from OSX iconv
		return str_replace( array( '\'', '`', '^' ), '', $ret );
	}
}
