/**
 * 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) {
        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() {
    }
}

@@ -669,32 +669,335 @@
  superclass) %7B%0D%0A
+        if (superclass == null) %7B%0D%0A          superclass = RubyRuntime.ObjectClass;%0D%0A        %7Delse%7B%0D%0A            if(superclass.getName().equals(%22Class%22))%7B%0D%0A                throw new RubyException(RubyRuntime.TypeErrorClass,%22can't make subclass of Class%22);%0D%0A            %7D %0D%0A        %7D%0D%0A        %0D%0A        %0D%0A
         RubyValu
@@ -1585,32 +1585,34 @@
 ;%0D%0A        %7D%0D%0A%0D%0A
+//
         if (supe
@@ -1622,32 +1622,34 @@
 ass == null) %7B%0D%0A
+//
             supe
@@ -1675,32 +1675,34 @@
 e.ObjectClass;%0D%0A
+//
         %7D%0D%0A%0D%0A   

fix a bug in defineClass method:can't make subclass of Class