/**
 * Copyright 2006-2007 Ye Zheng
 * Distributed under the GNU General Public License 2.0
 */

package com.xruby.runtime.lang;

class ClassFactory {
    private static boolean isValidDefinedClass(RubyClass klass, RubyClass superclass) {
        RubyClass realSuperClass = klass.getSuperClass().getRealClass();
        if (realSuperClass == superclass) {
            return true;
        }

        if (superclass == null && realSuperClass == RubyRuntime.ObjectClass) {
            return true;
        }

        return klass == RubyRuntime.ObjectClass && superclass == null;

    }
    public static RubyClass defineClass(String name, RubyClass superclass) {
        if (superclass == null) {
          superclass = RubyRuntime.ObjectClass;
        }else{
            if(superclass.getName().equals("Class")){
                throw new RubyException(RubyRuntime.TypeErrorClass,"can't make subclass of Class");
            } 
        }
        
        
        RubyValue value = RubyRuntime.ObjectClass.getConstant(name);
        if (value != null) {
            if (!(value instanceof RubyClass)) {
                throw new RubyException(RubyRuntime.TypeErrorClass, name + " is not a class");
            }

            RubyClass klass = (RubyClass)value;

            if (!isValidDefinedClass(klass, superclass)) {
                throw new RubyException(RubyRuntime.NameErrorClass, name + " is already defined");
            }

            // FIXME: remove this method
            klass.setAccessPublic();

            return klass;
        }

//        if (superclass == null) {
//            superclass = RubyRuntime.ObjectClass;
//        }

        RubyClass klass = createRubyClass(name, superclass);
        new RubySingletonClass(klass, superclass.getRubyClass());
        RubyRuntime.ObjectClass.setConstant(name, klass);

        return klass;
    }

    public static RubyModule defineModule(String name) {
        RubyValue value = RubyRuntime.ObjectClass.getConstant(name);
        if (value != null) {
            if (value instanceof RubyModule) {
                RubyModule module = ((RubyModule)value);
                if (module.isRealModule()) {
                    return module;
                }
            }

            throw new RubyException(RubyRuntime.TypeErrorClass, name + " is not a module");
        }

        RubyModule module = createRubyModule(name);
        RubyRuntime.ObjectClass.setConstant(name, module);

        return module;
    }

    /**
	 * Define a boot class.
	 *
	 * name, the name of the boot class to be defined.
	 * superclass, the super class of the boot class to be defined.
	 */
	static RubyClass defineBootClass(String name, RubyClass superclass) {
		RubyClass obj = createRubyClass(name, superclass);
        RubyClass constObj = (RubyRuntime.ObjectClass != null) ? RubyRuntime.ObjectClass : obj;
		constObj.setConstant(name, obj);
		return obj;
	}

    private static RubyClass createRubyClass(String name, RubyClass superclass) {
        RubyClass klass = new RubyClass(name, superclass, null);
        klass.setName(name);
        klass.setRubyClass(RubyRuntime.ClassClass);
        return klass;
    }

    private static RubyModule createRubyModule(String name) {
        RubyModule module = new RubyModule(name, null);
        module.setName(name);
        module.setRubyClass(RubyRuntime.ModuleClass);
        return module;
    }

    private ClassFactory() {
    }
}

@@ -1884,24 +1884,64 @@
  klass);%0D%0A%0D%0A
+        inheritedBy(klass,superclass);%0D%0A
         retu
@@ -3533,32 +3533,325 @@
  module;%0D%0A    %7D%0D
+%0A    %0D%0A    private static void inheritedBy(RubyClass klass,RubyClass superclass)%7B%0D%0A        if(!RubyRuntime.isBuiltinClass(klass.getName()))%7B%0D%0A            RubyID mid = StringMap.intern(%22inherited%22);%0D%0A            RubyAPI.callOneArgMethod(superclass, klass, null, mid);%0D%0A        %7D        %0D%0A    %7D%0D
 %0A%0D%0A    private C

add inheritedBy method to support inherited function