<?php

namespace nur {

  use nur\t\TestCase;

  class funcTest extends TestCase {
    function testIs_static() {
      self::assertFalse(func::is_static(null));
      self::assertFalse(func::is_static(""));
      self::assertFalse(func::is_static("::"));
      self::assertFalse(func::is_static("xxx::"));
      self::assertTrue(func::is_static("::xxx"));
      self::assertFalse(func::is_static([]));
      self::assertFalse(func::is_static([""]));
      self::assertTrue(func::is_static(["xxx"]));
      self::assertFalse(func::is_static([null, ""]));
      self::assertTrue(func::is_static([null, "yyy"]));
      self::assertFalse(func::is_static(["xxx", ""]));
      self::assertTrue(func::is_static(["xxx", "yyy"]));
      self::assertTrue(func::is_static([null, "yyy", "aaa"]));
      self::assertTrue(func::is_static(["xxx", "yyy", "aaa"]));
    }
    
    function testFix_static() {
      $class = "class";
      $func = null;
        func::fix_static($func, $class);
        self::assertSame(null, $func);
      $func = "";
        func::fix_static($func, $class);
        self::assertSame("", $func);
      $func = "::";
        func::fix_static($func, $class);
        self::assertSame("class::", $func);
      $func = "xxx::";
        func::fix_static($func, $class);
        self::assertSame("xxx::", $func);
      $func = "::xxx";
        func::fix_static($func, $class);
        self::assertSame("class::xxx", $func);
      $func = [];
        func::fix_static($func, $class);
        self::assertSame([], $func);
      $func = [""];
        func::fix_static($func, $class);
        self::assertSame(["class", ""], $func);
      $func = ["xxx"];
        func::fix_static($func, $class);
        self::assertSame(["class", "xxx"], $func);
      $func = ["xxx", ""];
        func::fix_static($func, $class);
        self::assertSame(["xxx", ""], $func);
      $func = [null, "yyy"];
        func::fix_static($func, $class);
        self::assertSame(["class", "yyy"], $func);
      $func = ["xxx", "yyy"];
        func::fix_static($func, $class);
        self::assertSame(["xxx", "yyy"], $func);
      $func = [null, "yyy", "aaa"];
        func::fix_static($func, $class);
        self::assertSame(["class", "yyy", "aaa"], $func);
      $func = ["xxx", "yyy", "aaa"];
        func::fix_static($func, $class);
        self::assertSame(["xxx", "yyy", "aaa"], $func);
    }

    function testIs_method() {
      self::assertFalse(func::is_method(null));
      self::assertFalse(func::is_method(""));
      self::assertFalse(func::is_method("->"));
      self::assertTrue(func::is_method("->xxx"));
      self::assertFalse(func::is_method([]));
      self::assertFalse(func::is_method([""]));
      self::assertTrue(func::is_method(["->xxx"]));
      self::assertTrue(func::is_method(["->xxx", "aaa"]));
      self::assertFalse(func::is_method([null, "->"]));
      self::assertTrue(func::is_method([null, "->yyy"]));
      self::assertFalse(func::is_method(["xxx", "->"]));
      self::assertTrue(func::is_method(["xxx", "->yyy"]));
      self::assertTrue(func::is_method([null, "->yyy", "aaa"]));
      self::assertTrue(func::is_method(["xxx", "->yyy", "aaa"]));
    }

    function testFix_method() {
      $object = new \stdClass();
      $func= null;
        func::fix_method($func, $object);
        self::assertSame(null, $func);
      $func= "";
        func::fix_method($func, $object);
        self::assertSame("", $func);
      $func= "->";
        func::fix_method($func, $object);
        self::assertSame("->", $func);
      $func= "->xxx";
        func::fix_method($func, $object);
        self::assertSame([$object, "xxx"], $func);
      $func= [];
        func::fix_method($func, $object);
        self::assertSame([], $func);
      $func= [""];
        func::fix_method($func, $object);
        self::assertSame([""], $func);
      $func= ["->xxx"];
        func::fix_method($func, $object);
        self::assertSame([$object, "xxx"], $func);
      $func= ["->xxx", "aaa"];
        func::fix_method($func, $object);
        self::assertSame([$object, "xxx", "aaa"], $func);
      $func= [null, "->"];
        func::fix_method($func, $object);
        self::assertSame([null, "->"], $func);
      $func= [null, "->yyy"];
        func::fix_method($func, $object);
        self::assertSame([$object, "yyy"], $func);
      $func= ["xxx", "->"];
        func::fix_method($func, $object);
        self::assertSame(["xxx", "->"], $func);
      $func= ["xxx", "->yyy"];
        func::fix_method($func, $object);
        self::assertSame([$object, "yyy"], $func);
      $func= [null, "->yyy", "aaa"];
        func::fix_method($func, $object);
        self::assertSame([$object, "yyy", "aaa"], $func);
      $func= ["xxx", "->yyy", "aaa"];
        func::fix_method($func, $object);
        self::assertSame([$object, "yyy", "aaa"], $func);
    }

    function testCall() {
      self::assertSame(36, func::call("func36"));
      self::assertSame(12, func::call(TC::class."::method"));
      self::assertSame(12, func::call([TC::class, "method"]));
      $closure = function() {
        return 21;
      };
      self::assertSame(21, func::call($closure));
    }

    function testCall_all() {
      $c1 = new C1();
      $c2 = new C2();
      $c3 = new C3();

      self::assertSameValues([11, 12], func::call_all(C1::class));
      self::assertSameValues([11, 12, 21, 22], func::call_all($c1));
      self::assertSameValues([13, 11, 12], func::call_all(C2::class));
      self::assertSameValues([13, 23, 11, 12, 21, 22], func::call_all($c2));
      self::assertSameValues([111, 13, 12], func::call_all(C3::class));
      self::assertSameValues([111, 121, 13, 23, 12, 22], func::call_all($c3));

      $options = "conf";
      self::assertSameValues([11], func::call_all(C1::class, $options));
      self::assertSameValues([11, 21], func::call_all($c1, $options));
      self::assertSameValues([11], func::call_all(C2::class, $options));
      self::assertSameValues([11, 21], func::call_all($c2, $options));
      self::assertSameValues([111], func::call_all(C3::class, $options));
      self::assertSameValues([111, 121], func::call_all($c3, $options));

      $options = ["prefix" => "conf"];
      self::assertSameValues([11], func::call_all(C1::class, $options));
      self::assertSameValues([11, 21], func::call_all($c1, $options));
      self::assertSameValues([11], func::call_all(C2::class, $options));
      self::assertSameValues([11, 21], func::call_all($c2, $options));
      self::assertSameValues([111], func::call_all(C3::class, $options));
      self::assertSameValues([111, 121], func::call_all($c3, $options));

      self::assertSameValues([11, 12], func::call_all($c1, ["include" => "x"]));
      self::assertSameValues([11, 21], func::call_all($c1, ["include" => "y"]));
      self::assertSameValues([11, 12, 21], func::call_all($c1, ["include" => ["x", "y"]]));

      self::assertSameValues([21, 22], func::call_all($c1, ["exclude" => "x"]));
      self::assertSameValues([12, 22], func::call_all($c1, ["exclude" => "y"]));
      self::assertSameValues([22], func::call_all($c1, ["exclude" => ["x", "y"]]));

      self::assertSameValues([12], func::call_all($c1, ["include" => "x", "exclude" => "y"]));
    }

    function testCons() {
      $obj1 = func::cons(Wocons::class, 1, 2, 3);
      self::assertInstanceOf(Wocons::class, $obj1);

      $obj2 = func::cons(Withemptycons::class, 1, 2, 3);
      self::assertInstanceOf(Withemptycons::class, $obj2);

      $obj3 = func::cons(Withcons::class, 1, 2, 3);
      self::assertInstanceOf(Withcons::class, $obj3);
      self::assertSame(1, $obj3->first);
    }
  }

  class Wocons {
  }
  class Withemptycons {
    function __construct() {
    }
  }
  class Withcons {
    public $first;
    function __construct($first) {
      $this->first = $first;
    }
  }

  class TC {
    static function method() {
      return 12;
    }
  }

  class C1 {
    static function confps1_xy() {
      return 11;
    }
    static function ps2_x() {
      return 12;
    }
    function confp1_y() {
      return 21;
    }
    function p2() {
      return 22;
    }
  }
  class C2 extends C1 {
    static function ps3() {
      return 13;
    }
    function p3() {
      return 23;
    }
  }
  class C3 extends C2 {
    static function confps1_xy() {
      return 111;
    }
    function confp1_y() {
      return 121;
    }
  }
}

namespace {
  function func36() {
    return 36;
  }
}
