<?php

class ObjectArray{
	private $obj;

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

	public function add($arr)
	{
		$clone = clone $this;
		foreach($arr as $v){
			array_push($clone->obj, $v);
		}
		return $clone;
	}

	public function append($item){
		$clone = clone $this;
		array_push($clone->obj, $item);
		return $clone;
	}

	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 add($str)
	{
		$clone = clone $this;
		$clone->obj .= $str;
		return $clone;
	}

	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 find($arg)
	{
		if($arg[0]=='/'){
			preg_match($arg, $this->obj, $out);
			return $out[0];
		}else{
			return strpos($this->obj, $arg) !== false;
		}
	}

	public function findall($reg)
	{
		preg_match_all($reg, $this->obj, $out);
		return $out[0];
	}

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

	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, $limit=0){
		$clone = clone $this;
		if(is_callable($replacement)){
			$clone->obj = preg_replace_callback($pattern, $replacement, $clone->obj, $limit);
		}elseif($pattern[0] == '/'){
			$clone->obj = preg_replace($pattern, $replacement, $clone->obj, $limit);
		}else{
			$clone->obj = preg_replace("/{$pattern}/s", $replacement, $clone->obj, $limit);
		}
		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 = '', $limit=null, $flag=0)
	{
		if(is_integer($arg)){
			return a(str_split($this->obj, $arg));
		}elseif(is_string($arg)){
			if($arg == ''){
				return a(str_split($this->obj));
			}elseif($arg[0]=='/'){
				if($limit==null) $limit = -1;
				return preg_split($arg, $this->obj, $limit, $flag);
			}else{
				if($limit==null){
					return a(explode($arg, $this->obj));
				}else{
					return a(explode($arg, $this->obj, $limit));
				}
			}
		}
		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("good")->add(s("haha"));
print_r(a([1,2,3])->add([4,5])->to_array());