<?php

namespace platyFramework;

/**
 * refs https://github.com/alecgorge/PHP-String-Class/blob/master/string.php
 */

// why doesn't this function exist?
if (!function_exists('mb_str_replace')) {
    function mb_str_replace($search, $replace, $subject)
    {
        return preg_replace('@' . preg_quote($search) . '@u', $replace, $subject);
    }
}
if (!function_exists('mb_str_split')) {
    function mb_str_split($str, $length = 1)
    {
        preg_match_all('/.{1,' . $length . '}/us', $str, $matches);
        return $matches[0];
    }
}

class ptyStaticString
{
    /* static methods wrapping multibyte */

    /**
     * Wrapper for substr
     */
    public static function substr($string, $start, $length = null)
    {
        if (ptyString::$multibyte) {
            return new ptyString(mb_substr($string, $start, $length, ptyString::$multibyte_encoding));
        }
        return new ptyString(substr($string, $start, $length));
    }

    /**
     * Equivelent of Javascript's String.substring
     * @link http://www.w3schools.com/jsref/jsref_substring.asp
     */
    public static function substring($string, $start, $end)
    {
        if (empty($length)) {
            return self::substr($string, $start);
        }
        return self::substr($string, $end - $start);
    }

    public function charAt($str, $point)
    {
        return self::substr($str, $point, 1);
    }

    public function charCodeAt($str, $point)
    {
        return ord(self::substr($str, $point, 1));
    }

    public static function concat()
    {
        $args = func_get_args();
        $r = "";
        foreach ($args as $arg) {
            $r .= (string)$arg;
        }
        return $arg;
    }

    public static function fromCharCode($code)
    {
        return chr($code);
    }

    public static function indexOf($haystack, $needle, $offset = 0)
    {
        if (ptyString::$multibyte) {
            return mb_strpos($haystack, $needle, $offset, ptyString::$multibyte_encoding);
        }
        return strpos($haystack, $needle, $offset);
    }

    public static function lastIndexOf($haystack, $needle, $offset = 0)
    {
        if (ptyString::$multibyte) {
            return mb_strrpos($haystack, $needle, $offset, ptyString::$multibyte_encoding);
        }
        return strrpos($haystack, $needle, $offset);
    }

    public static function match($haystack, $regex)
    {
        preg_match_all($regex, $haystack, $matches, PREG_PATTERN_ORDER);
        return new ptyArr($matches[0]);
    }

    public static function replace($haystack, $needle, $replace, $regex = false)
    {
        if ($regex) {
            $r = preg_replace($needle, $replace, $haystack);
        } else {
            if (ptyString::$multibyte) {
                $r = mb_str_replace($needle, $replace, $haystack);
            } else {
                $r = str_replace($needle, $replace, $haystack);
            }
        }
        return new ptyString($r);
    }

    public static function strlen($string)
    {
        if (ptyString::$multibyte) {
            return mb_strlen($string, ptyString::$multibyte_encoding);
        }
        return strlen($string);
    }

    public static function slice($string, $start, $end = null)
    {
        return self::substring($string, $start, $end);
    }

    public static function toLowerCase($string)
    {
        if (ptyString::$multibyte) {
            return new ptyString(mb_strtolower($string, ptyString::$multibyte_encoding));
        }
        return new ptyString(strtolower($string));
    }

    public static function toUpperCase($string)
    {
        if (ptyString::$multibyte) {
            return new ptyString(mb_strtoupper($string, ptyString::$multibyte_encoding));
        }
        return new ptyString(strtoupper($string));
    }

    public static function split($string, $at = '')
    {
        if (empty($at)) {
            if (ptyString::$multibyte) {
                return new Arr(mb_str_split($string));
            }
            return new ptyArr(str_split($string));
        }
        return new ptyArr(explode($at, $string));
    }

    /* end static wrapper methods */
}

class ptyString implements \ArrayAccess
{
    public static $multibyte_encoding = null;
    public static $multibyte = false;

    private $value;
    private static $checked = false;

    /* magic methods */
    public function __construct($string)
    {
        if (!self::$checked) {
            self::$multibyte = extension_loaded('mbstring');
        }
        if (is_null(self::$multibyte_encoding)) {
            if (self::$multibyte) {
                self::$multibyte_encoding = mb_internal_encoding();
            }
        }
        $this->value = (string)$string;
    }

    public function __toString()
    {
        return $this->value;
    }

    /* end magic methods */

    /* ArrayAccess Methods */

    /** offsetExists ( mixed $index )
     *
     * Similar to array_key_exists
     */
    public function offsetExists($index)
    {
        return !empty($this->value[$index]);
    }

    /* offsetGet ( mixed $index )
    *
    * Retrieves an array value
    */
    public function offsetGet($index)
    {
        return ptyStaticString::substr($this->value, $index, 1)->toString();
    }

    /* offsetSet ( mixed $index, mixed $val )
    *
    * Sets an array value
    */
    public function offsetSet($index, $val)
    {
        $this->value = ptyStaticString::substring($this->value, 0, $index) . $val . ptyStaticString::substring($this->value, $index + 1, ptyStaticString::strlen($this->value));
    }

    /* offsetUnset ( mixed $index )
    *
    * Removes an array value
    */
    public function offsetUnset($index)
    {
        $this->value = ptyStaticString::substr($this->value, 0, $index) . ptyStaticString::substr($this->value, $index + 1);
    }

    public static function create($obj)
    {
        if ($obj instanceof ptyString) return new ptyString($obj);
        return new ptyString($obj);
    }

    /* public methods */
    public function substr($start, $length)
    {
        return ptyStaticString::substr($this->value, $start, $length);
    }

    public function substring($start, $end)
    {
        return ptyStaticString::substring($this->value, $start, $end);
    }

    public function charAt($point)
    {
        return ptyStaticString::substr($this->value, $point, 1);
    }

    public function charCodeAt($point)
    {
        return ord(ptyStaticString::substr($this->value, $point, 1));
    }

    public function indexOf($needle, $offset)
    {
        return ptyStaticString::indexOf($this->value, $needle, $offset);
    }

    public function lastIndexOf($needle)
    {
        return ptyStaticString::lastIndexOf($this->value, $needle);
    }

    public function match($regex)
    {
        return ptyStaticString::match($this->value, $regex);
    }

    public function replace($search, $replace, $regex = false)
    {
        return ptyStaticString::replace($this->value, $search, $replace, $regex);
    }

    public function first()
    {
        return ptyStaticString::substr($this->value, 0, 1);
    }

    public function last()
    {
        return ptyStaticString::substr($this->value, -1, 1);
    }

    public function search($search, $offset = null)
    {
        return $this->indexOf($search, $offset);
    }

    public function slice($start, $end = null)
    {
        return ptyStaticString::slice($this->value, $start, $end);
    }

    public function toLowerCase()
    {
        return ptyStaticString::toLowerCase($this->value);
    }

    public function toUpperCase()
    {
        return ptyStaticString::toUpperCase($this->value);
    }

    public function toUpper()
    {
        return $this->toUpperCase();
    }

    public function toLower()
    {
        return $this->toLowerCase();
    }

    public function split($at = '')
    {
        return ptyStaticString::split($this->value, $at);
    }

    public function trim($charlist = null)
    {
        return new ptyString(trim($this->value, $charlist));
    }

    public function ltrim($charlist = null)
    {
        return new ptyString(ltrim($this->value, $charlist));
    }

    public function rtrim($charlist = null)
    {
        return new ptyString(rtrim($this->value, $charlist));
    }

    public function toString()
    {
        return $this->__toString();
    }

    public function ptyInt()
    {
        return intval($this->value);
    }
}

?>
