<?php

class ObjectArray{
    private $obj;

    public function __construct($array)
    {
        $this->obj = $array;
        return $this;
    }

    public function count($item = null){
        if($item == null){
            return count($this->obj);
        }else{
            $count = 0;
            foreach($this->obj as $i){
                if($i === $item){
                    $count++;
                }
            }
            return $count;
        }
    }

    public function cut($arg)
    {
        $clone = clone $this;
        $count = count($clone->obj);
        list($start, $end, $step) = explode(":", $arg);
        if($step == ''){
            $step = 1;
        }elseif($step == 0){
            die("ObjectPHP#Arr#cut: slice step cannot be zero");
        }
        if($step > 0){
            if($start == '') $start = 0;
            if($end == '') $end = $count;
            if($start < 0) $start = max(0, $count+$start);
            if($end < 0) $end = max(0, $count+$end);
            if($start == $end or $end == 0 or $start > $end){
                $clone->obj = [];
            }else{
                $clone->obj = array_slice($clone->obj, $start, $end - $start);
            }
        }elseif($step < 0){
            $clone->obj = array_reverse($clone->obj);
            if($start == '') $start = $count;
            if($end == '') $end = -$count - 1;
            if($start < 0){
                $start = min(-$start-1, $count);
            }else{
                $start = max(0, min($count - $start - 1, $count));
            }
            if($end < 0){
                $end = min(-$end-1, $count);
            }else{
                $end = min($count - $end - 1, $count);
            }
            if($start == $end or $end == 0 or $start > $end){
                $clone->obj = [];
            }else{
                $clone->obj = array_slice($clone->obj, $start, $end-$start);
            }
//            if($start < 0) $start = max(0, $count+$start);
//            if($end < 0) $end = max(0, $count+$end);
//            if($start == $end or $start == 0 or $start < $end){
//                $clone->obj = [];
//            }else{
//                $clone->obj = array_slice(array_reverse($clone->obj), $end, $end-$start);
//            }
        }
        return $clone;
    }

    public function each($func)
    {
        foreach($this->obj as $i){
            call_user_func($func, $i);
        }
    }

    public function filter($func)
    {
        $clone = clone $this;
        $clone->obj = array_filter($clone->obj, $func);
        return $clone;
    }

    public function first($num = 1)
    {
        if($num == 1){
            return $this->obj[0];
        }else{
            $clone = clone $this;
            $clone->obj = array_slice($clone->obj, 0, $num);
            return $clone;
        }
    }

    public function last($num = 1)
    {
        if($num == 1){
            $result = end($this->obj);
            reset($this->obj);
            return $result;
        }else{
            $clone = clone $this;
            $clone->obj = array_slice($clone->obj, -$num);
            return $clone;
        }
    }

    public function has($item)
    {
        return in_array($item, $this->obj);
    }

    public function in($container)
    {
        if(is_array($container)){
            return in_array($this->obj, $container);
        }elseif($container instanceof ObjectArray){
            return $container->has($this->obj);
        }
    }

    public function join($str = '')
    {
        return s(implode($str, $this->obj));
    }

    public function map($func)
    {
        $clone = clone $this;
        $clone->obj = array_map($func, $clone->obj);
        return $clone;
    }

    public function max()
    {
        return max($this->obj);
    }

    public function min()
    {
        return min($this->obj);
    }

    public function reverse()
    {
        $clone = clone $this;
        $clone->obj = array_reverse($clone->obj);
        return $clone;
    }

    public function sample($num = 1)
    {
        $clone = clone $this;
        shuffle($clone->obj);
        $clone->obj = array_slice($clone->obj, 0, $num);
        return $clone;
    }

    public function slice($offset, $length)
    {
        $clone = clone $this;
        $clone->obj = array_slice($clone->obj, $offset, $length);
        return $clone;
    }

    public function sort($arg)
    {
        $clone = clone $this;
        if(is_string($arg)){
            if($arg == "-1"){
                $clone->obj = array_reverse($clone->obj);
            }elseif(s($arg)->ltrim()->startwith("|")){
//                preg_match("/\|(.*)\|(.*)/is", $arg, $out);
//                list($z, $a, $b) = $out;
            }
        }elseif(is_callable($arg)){
            usort($clone->obj, $arg);
        }
        return $clone;
    }

    public function sum()
    {
        return array_sum($this->obj);
    }

    public function to_array()
    {
        return $this->obj;
    }

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

class ObjectString{
    private $obj;

    public function __construct($str)
    {
        $this->obj = $str;
        return $this;
    }

    public function endwith($str)
    {
        return substr($this->obj, -strlen($str)) == $str;
    }

    public function endiwith($str)
    {
        return strripos($this->obj, $str, 0) === strlen($this->obj) - strlen($str);
    }

    public function first($num = 1)
    {
        $clone = clone $this;
        $clone->obj = substr($clone->obj, 0, $num);
        return $clone;
    }

    public function has($str){
        return strpos($this->obj, $str) !== false;
    }

    public function in($container)
    {
        return strpos($container, $this->obj) !== false;
    }

    public function last($num = 1)
    {
        $clone = clone $this;
        $clone->obj = substr($clone->obj, -$num);
        return $clone;
    }

    public function ltrim($arg = null)
    {
        $clone = clone $this;
        if($arg){
            $clone->obj = ltrim($clone->obj, $arg);
        }else{
            $clone->obj = ltrim($clone);
        }
        return $clone;
    }

    public function replace($pattern, $replacement){
        $clone = clone $this;
        if($pattern[0] == '/'){
            $clone->obj = preg_replace($pattern, $replacement, $clone->obj);
        }else{
            $clone->obj = preg_replace("/{$pattern}/s", $replacement, $clone->obj);
        }
        return $clone;
    }

    public function replace_once($pattern, $replacement)
    {
        $clone = clone $this;
        if($pattern[0] == '/'){
            $clone->obj = preg_replace($pattern, $replacement, $clone->obj, 1);
        }else{
            $clone->obj = preg_replace("/{$pattern}/s", $replacement, $clone->obj, 1);
        }
        return $clone;
    }

    public function trim($arg = null)
    {
        $clone = clone $this;
        if($arg){
            $clone->obj = trim($clone->obj, $arg);
        }else{
            $clone->obj = trim($clone);
        }
        return $clone;
    }

    public function rtrim($arg = null)
    {
        $clone = clone $this;
        if($arg){
            $clone->obj = rtrim($clone->obj, $arg);
        }else{
            $clone->obj = rtrim($clone);
        }
        return $clone;
    }

    public function sample($num = 1)
    {
        $clone = clone $this;
        $clone->obj = substr(str_shuffle($clone->obj), 0, $num);
        return $clone;
    }

    public function split($arg = '')
    {
        if(is_integer($arg)){
            return a(str_split($this->obj, $arg));
        }elseif(is_string($arg)){
            if($arg == ''){
                return a(str_split($this->obj));
            }else{
                return a(explode($arg, $this->obj));
            }
        }
        return null;
    }

    public function startwith($str)
    {
        return strpos($this->obj, $str) === 0;
    }

    public function startiwith($str)
    {
        return stripos($this->obj, $str) === 0;
    }

    public function count($str = null)
    {
        if($str == null){
            return strlen($this->obj);
        }else{
            return (count(preg_split("/{$str}/s", $this->obj)) - 1);
        }
    }

    public function len(){return strlen($this->obj);}

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

class ObjectFile{}
class ObjectDir{}
class ObjectTime{}
class ObjectUrl{}
class ObjectPage extends ObjectUrl{}
class ObjectImage extends ObjectFile{}


function a($array){return new ObjectArray($array);}
function s($str){return new ObjectString($str);}
function t($time){return new ObjectTime($time);}
function ofile($file){return new ObjectFile($file);}
function odir($dir){return new ObjectDir($dir);}
function url($url){return new ObjectUrl($url);}
function page($page){return new ObjectTime($page);}
function image($image){return new ObjectImage($image);}

echo s("/abcdefg/")->split()->cut(":-10:")->join();

$range = range(-10, 10);
foreach($range as $x){
    foreach($range as $y){
        foreach(range(-1,1) as $z){
            if($z != 0){
                $z = '';
                $str1 = exec("python -c 'print \"/abcdefg/\"[{$x}:{$y}:{$z}]'");
                $str2 = s("/abcdefg/")->split()->cut("{$x}:{$y}:{$z}")->join();
                if($str1 != $str2){
//                    echo "\n\n";
                    echo "!!! [{$x}:{$y}:{$z}]";
                    echo "\n";
                }elseif($str1){
//                    echo "ok\n";
                }
            }
        }
    }
}