package ru.ydn.wicket.wicketorientdb.utils;

import java.io.Serializable;

import ru.ydn.wicket.wicketorientdb.DefaultODatabaseThreadLocalFactory;
import ru.ydn.wicket.wicketorientdb.IOrientDbSettings;
import ru.ydn.wicket.wicketorientdb.OrientDbWebApplication;

import com.orientechnologies.orient.core.db.ODatabaseDocumentInternal;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.OPartitionedDatabasePoolFactory;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.record.impl.ODocument;

/**
 * Closure for execution of portion queries/command on database for different user (commonly, under admin)
 * @param <V> return type
 */
public abstract class DBClosure<V> implements Serializable
{
	private static final long serialVersionUID = 1L;
	private final String dbUrl;
	private final String username;
	private final String password;
	
	public DBClosure()
	{
		this(null, null, null);
	}
	
	public DBClosure(String username, String password)
	{
		this(null, username, password);
	}
	
	public DBClosure(String dbUrl, String username, String password)
	{
		this.dbUrl = dbUrl;
		this.username = username;
		this.password = password;
	}
	/**
	 * @return result of execution
	 */
	public final V execute()
	{
		ODatabaseDocument db = null;
		ODatabaseDocument oldDb = ODatabaseRecordThreadLocal.INSTANCE.getIfDefined();
		if(oldDb!=null) ODatabaseRecordThreadLocal.INSTANCE.remove(); //Required to avoid stack of transactions
		try
		{
			db = getSettings().getDatabasePoolFactory().get(getDBUrl(), getUsername(), getPassword()).acquire();
			db.activateOnCurrentThread();
			return execute(db);
		} 
		finally
		{
			if(db!=null) db.close();
			if(oldDb!=null) ODatabaseRecordThreadLocal.INSTANCE.set((ODatabaseDocumentInternal)oldDb);
			else ODatabaseRecordThreadLocal.INSTANCE.remove();
		}
	}
	
	protected String getDBUrl()
	{
		return dbUrl!=null?dbUrl:getSettings().getDBUrl();
	}
	
	protected String getUsername()
	{
		return username!=null?username:getSettings().getAdminUserName();
	}
	
	protected String getPassword()
	{
		return password!=null?password:getSettings().getAdminPassword();
	}
	
	protected IOrientDbSettings getSettings()
	{
		return OrientDbWebApplication.lookupApplication().getOrientDbSettings();
	}
	
	/**
	 * @param db temporal DB for other user
	 * @return results for execution on supplied DB
	 */
	protected abstract V execute(ODatabaseDocument db);
	
	
	/**
	 * Allow to save set of document under admin
	 * @param docs set of document to be saved
	 */
	public static void sudoSave(final ODocument... docs) {
		if(docs==null || docs.length==0) return;
		new DBClosure<Boolean>() {

			@Override
			protected Boolean execute(ODatabaseDocument db) {
				db.begin();
				for (ODocument doc : docs) {
					db.save(doc);
				}
				db.commit();
				return true;
			}
		}.execute();
	}
}

@@ -611,16 +611,80 @@
 ocument;
+%0Aimport com.orientechnologies.orient.core.type.ODocumentWrapper;
 %0A%0A/**%0A *
@@ -2997,10 +2997,452 @@
 e();%0A%09%7D%0A
+%09%0A%09/**%0A%09 * Allow to save set of document wrappers under admin%0A%09 * @param dws set of document to be saved%0A%09 */%0A%09public static void sudoSave(final ODocumentWrapper... dws) %7B%0A%09%09if(dws==null %7C%7C dws.length==0) return;%0A%09%09new DBClosure%3CBoolean%3E() %7B%0A%0A%09%09%09@Override%0A%09%09%09protected Boolean execute(ODatabaseDocument db) %7B%0A%09%09%09%09db.begin();%0A%09%09%09%09for (ODocumentWrapper dw : dws) %7B%0A%09%09%09%09%09dw.save();%0A%09%09%09%09%7D%0A%09%09%09%09db.commit();%0A%09%09%09%09return true;%0A%09%09%09%7D%0A%09%09%7D.execute();%0A%09%7D%0A
 %7D%0A

Add sudoSave method for ODocumentWrappers