package org.cafebabepy.runtime.module.builtins;

import org.cafebabepy.annotation.DefineCafeBabePyFunction;
import org.cafebabepy.annotation.DefineCafeBabePyModule;
import org.cafebabepy.runtime.PyObject;
import org.cafebabepy.runtime.Python;
import org.cafebabepy.runtime.module.AbstractCafeBabePyModule;

import java.util.HashSet;
import java.util.Set;

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

    @DefineCafeBabePyFunction(name = "issubclass")
    public PyObject isSubClass(PyObject clazz, PyObject classInfo) {
        if (clazz == null || !clazz.isType()) {
            throw this.runtime.newRaiseTypeError(
                    "issubclass() arg 1 must be a class");
        }

        Set<PyObject> classInfoSet = new HashSet<>();
        appendIntoClassInfoSet(classInfoSet, classInfo);

        if (classInfoSet.contains(classInfo)) {
            return this.runtime.True();
        } else {
            return this.runtime.False();
        }
    }

    private void appendIntoClassInfoSet(Set<PyObject> classInfoSet, PyObject classinfo) {
        if (classinfo == null || !classinfo.isType()) {
            throw this.runtime.newRaiseTypeError(
                    "issubclass() arg 2 must be a class or tuple of classes");

        } else if (classinfo.getType() instanceof PyTupleType) {
            this.runtime.iter(classinfo, c -> appendIntoClassInfoSet(classInfoSet, c));

        } else {
            classInfoSet.add(classinfo);
        }
    }
}

@@ -622,24 +622,24 @@
 me = %22is
-subclass
+instance
 %22)%0A    p
@@ -659,16 +659,16 @@
 t is
-SubClass
+Instance
 (PyO
@@ -673,21 +673,22 @@
 yObject 
-clazz
+object
 , PyObje
@@ -718,18 +718,22 @@
  if (cla
-zz
+ssInfo
  == null
@@ -740,14 +740,19 @@
  %7C%7C 
+(
 !cla
-zz
+ssInfo
 .isT
@@ -748,32 +748,69 @@
 assInfo.isType()
+ && classInfo instanceof PyTupleType)
 ) %7B%0A            
@@ -874,24 +874,24 @@
  %22is
-subclass
+instance
 () arg 
-1
+2
  mus
@@ -897,20 +897,37 @@
 st be a 
-clas
+type or tuple of type
 s%22);%0A   
@@ -956,25 +956,26 @@
 Object%3E 
-classInfo
+objectType
 Set = ne
@@ -1011,44 +1011,43 @@
 Into
-ClassInfoSet(classInfoSet, classInfo
+ObjectTypeSet(objectTypeSet, object
 );%0A%0A
@@ -1058,25 +1058,26 @@
     if (
-classInfo
+objectType
 Set.cont
@@ -1081,25 +1081,22 @@
 ontains(
-classInfo
+object
 )) %7B%0A   
@@ -1137,36 +1137,26 @@
 );%0A        %7D
- else %7B%0A    
+%0A%0A
         retu
@@ -1180,26 +1180,16 @@
 alse();%0A
-        %7D%0A
     %7D%0A%0A 
@@ -1210,33 +1210,34 @@
 d appendInto
-ClassInfo
+ObjectType
 Set(Set%3CPyOb
@@ -1242,25 +1242,26 @@
 Object%3E 
-classInfo
+objectType
 Set, PyO
@@ -1266,25 +1266,20 @@
 yObject 
-classinfo
+type
 ) %7B%0A    
@@ -1286,105 +1286,147 @@
     
-if (classinfo == null %7C%7C !classinfo.isType()) %7B%0A            throw this.runtime.newRaiseTypeError(
+objectTypeSet.add(type);%0A%0A        if (type instanceof PyTypeType) %7B%0A            if (objectTypeSet.contains(type)) %7B%0A                return;
 %0A   
@@ -1434,24 +1434,27 @@
         
+%7D%0A%0A
         
 %22issubcl
@@ -1449,66 +1449,136 @@
     
-%22issubclass() arg 2 must be a class or tuple of classes%22);
+%7D else if (type instanceof PyObjectType) %7B%0A            if (objectTypeSet.contains(type)) %7B%0A                return;%0A            %7D
 %0A%0A  
@@ -1598,27 +1598,12 @@
 if (
-classinfo.getT
+t
 ype
-()
  ins
@@ -1659,20 +1659,15 @@
 ter(
-classinfo, c
+type, t
  -%3E 
@@ -1680,41 +1680,42 @@
 Into
-ClassInfoSet(classInfo
+ObjectTypeSet(objectType
 Set, 
-c
+t
 ));%0A
-%0A
     
@@ -1723,15 +1723,9 @@
    %7D
- else %7B
+%0A
 %0A   
@@ -1733,50 +1733,85 @@
     
-    classInfoSet.add(classinfo);%0A        %7D
+type.getSuperTypes().forEach(t -%3E appendIntoObjectTypeSet(objectTypeSet, t));
 %0A   

Rename oops!! issubclass to isinstance