<?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(abs($step) > 1){
            $arrtmp = [];
            $i = 0;
            foreach($clone->obj as $k=>$v){
                if($i%$step == 0){
                    $arrtmp[$k] = $v;
                }
                $i++;
            }
            $clone->obj = $arrtmp;
        }
        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("|")){
                #以后再添加的功能, jys
                //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 cut($arg)
    {
        $clone = clone $this;
        return $clone->split()->cut($arg)->join();
    }

    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);}