package ru.ydn.wicket.wicketorientdb.utils;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import com.google.common.collect.Iterators;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.record.impl.ODocument;

/**
 * Useful utils over schema related objects
 */
public class OSchemaUtils {
	
	private OSchemaUtils() {
		
	}
	
	/**
	 * Check first several items to resolve common {@link OClass}
	 * @param it {@link Iterable} over {@link ODocument}s
	 * @param probeLimit limit over iterable
	 * @return common {@link OClass} or null
	 */
	public static OClass probeOClass(Iterable<ODocument> it, int probeLimit) {
		return probeOClass(it.iterator(), probeLimit);
	}
	
	/**
	 * Check first several items to resolve common {@link OClass}
	 * @param it {@link Iterable} over {@link ODocument}s
	 * @param probeLimit limit over iterable
	 * @return common {@link OClass} or null
	 */
	public static OClass probeOClass(Iterator<ODocument> it, int probeLimit) {
		return getCommonOClass(Iterators.limit(it, probeLimit));
	}
	
	/**
	 * Returns common {@link OClass} for a set of documents
	 * @param it {@link Iterable} over {@link ODocument}s
	 * @return common {@link OClass} or null
	 */
	public static OClass getCommonOClass(Iterable<ODocument> it) {
		return getCommonOClass(it.iterator());
	}
	
	/**
	 * Returns common {@link OClass} for a set of documents
	 * @param it {@link Iterator} over {@link ODocument}s
	 * @return common {@link OClass} or null
	 */
	public static OClass getCommonOClass(Iterator<ODocument> it) {
    	Set<OClass> candidates =  null;
    	OClass ret = null;
    	while(it.hasNext() && (candidates==null || !candidates.isEmpty())) {
    		ODocument doc = it.next();
    		OClass thisOClass = doc.getSchemaClass();
    		if(candidates==null){
    			candidates = new HashSet<OClass>();
    			candidates.add(thisOClass);
    			candidates.addAll(thisOClass.getAllSuperClasses());
    			ret = thisOClass;
    		}
    		else {
    			if(ret!=null && (ret.equals(thisOClass) || ret.isSuperClassOf(thisOClass))) continue;
    			else if(ret!=null && thisOClass.isSuperClassOf(ret)) {
    				ret = thisOClass;
    				candidates.clear();
    				candidates.add(ret);
    				candidates.addAll(ret.getAllSuperClasses());
    			}
    			else {
    				ret = null;
    				candidates.retainAll(thisOClass.getAllSuperClasses());
    			}
    		}
    	}
    	
    	if(ret==null && candidates!=null && !candidates.isEmpty()) {
    		ret = getDeepestOClass(candidates);
    	}
    	
    	return ret;
    }
	
	/**
	 * Find the most deep {@link OClass} in a collection of classes
	 * @param classes {@link Iterable} with {@link OClass}es to handle
	 * @return deepest {@link OClass} or null
	 */
	public static OClass getDeepestOClass(Iterable<OClass> classes) {
		if(classes==null) return null;
		OClass ret=null;
		for(OClass oClass: classes) {
			if(ret==null) ret = oClass;
			else {
				if(!ret.equals(oClass) && oClass.isSubClassOf(ret)) ret = oClass;
			}
		}
		return ret;
	}
}

@@ -143,16 +143,71 @@
 l.Set;%0A%0A
+import ru.ydn.wicket.wicketorientdb.proto.IPrototype;%0A%0A
 import c
@@ -3158,10 +3158,362 @@
 ret;%0A%09%7D%0A
+%09%0A%09/**%0A%09 * Check whether object is not null or %7B@link IPrototype%7D. Useful if you want to be sure that you are working with real object%0A%09 * @param value object to check%0A%09 * @return true if object is not null and not a prototype%0A%09 */%0A%09public static boolean isNotNullOrPrototype(Object value) %7B%0A%09%09return !(value==null  %7C%7C value instanceof IPrototype);%0A%09%7D%0A
 %7D%0A

Add isNotNullOrPrototype method to OSchemaUtils