package org.cafebabepy.runtime.module.builtins;

import org.cafebabepy.runtime.PyObject;
import org.cafebabepy.runtime.Python;
import org.cafebabepy.runtime.module.AbstractCafeBabePyModule;
import org.cafebabepy.runtime.module.DefinePyFunction;
import org.cafebabepy.runtime.module.DefinePyModule;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by yotchang4s on 2017/05/12.
 */
@DefinePyModule(name = "builtins")
public class PyBuiltinsModule extends AbstractCafeBabePyModule {
    public PyBuiltinsModule(Python runtime) {
        super(runtime);
    }

    @DefinePyFunction(name = "isinstance")
    public PyObject isinstance(PyObject object, PyObject classInfo) {
        if (!classInfo.isType() && !(classInfo instanceof PyTupleType)) {
            throw this.runtime.newRaiseTypeError(
                    "isinstance() arg 2 must be a type or tuple of types");
        }

        return issubclass(object.getType(), classInfo);
    }

    @DefinePyFunction(name = "issubclass")
    public PyObject issubclass(PyObject clazz, PyObject classInfo) {
        if (!clazz.isType()
                || (!classInfo.isType() && !(classInfo instanceof PyTupleType))) {
            throw this.runtime.newRaiseTypeError(
                    "issubclass() arg 2 must be a type or tuple of types");
        }

        List<PyObject> types = new ArrayList<>();
        types.addAll(clazz.getTypes());

        /*
        // FIXME 再帰的にtupleを見る
        if (classInfo instanceof PyTupleType) {
            this.runtime.iter(classInfo, types::add);
        }
        */

        for (PyObject type : types) {
            if (type == classInfo) {
                return this.runtime.True();
            }
        }

        return this.runtime.False();
    }

    // FIXME Same CPython
    @DefinePyFunction(name = "print")
    public PyObject print(PyObject objects) {
        System.out.println(objects.toJava(String.class));

        return this.runtime.None();
    }

    @DefinePyFunction(name= "chr")
    public PyObject chr(PyObject i) {
        int value = i.toJava(int.class);
        if(value < 0 || 0x10FFFF < value) {
            throw this.runtime.newRaiseException("builtins.ValueError", "chr() arg not in range(0x110000)");
        }

        return this.runtime.str(new String(new int[] { value }, 0, 1));
    }
}

@@ -344,16 +344,74 @@
 .List;%0A%0A
+import static org.cafebabepy.util.ProtocolNames.__len__;%0A%0A
 /**%0A * C
@@ -2056,16 +2056,17 @@
 ion(name
+ 
 = %22chr%22)
@@ -2066,16 +2066,16 @@
  %22chr%22)%0A
-
     publ
@@ -2155,16 +2155,17 @@
       if
+ 
 (value %3C
@@ -2366,17 +2366,14 @@
 nt%5B%5D
- %7B 
+%7B
 value
- 
 %7D, 0
@@ -2384,11 +2384,317 @@
 );%0A    %7D
+%0A%0A    @DefinePyFunction(name = %22len%22)%0A    public PyObject len(PyObject s) %7B%0A        PyObject len = this.runtime.getattrOptional(s, __len__).orElseThrow(() -%3E%0A                this.runtime.newRaiseTypeError(%22object of type '%22 + s.getFullName() + %22' has no len()%22)%0A        );%0A%0A        return len.call();%0A    %7D
 %0A%7D%0A

Add len function