package ru.ydn.wicket.wicketorientdb;

import org.apache.wicket.Application;
import org.apache.wicket.ConverterLocator;
import org.apache.wicket.IApplicationListener;
import org.apache.wicket.IConverterLocator;
import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
import org.apache.wicket.protocol.http.WebApplication;

import ru.ydn.wicket.wicketorientdb.converter.ODocumentConverter;
import ru.ydn.wicket.wicketorientdb.converter.OIdentifiableConverter;
import ru.ydn.wicket.wicketorientdb.security.WicketOrientDbAuthorizationStrategy;

import com.orientechnologies.orient.core.Orient;
import com.orientechnologies.orient.core.db.ODatabase;
import com.orientechnologies.orient.core.db.ODatabaseInternal;
import com.orientechnologies.orient.core.db.ODatabaseLifecycleListener;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.hook.ORecordHook;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.record.impl.ODocument;

/**
 * {@link WebApplication} realization for applications on top of OrientDB
 */
public abstract class OrientDbWebApplication extends AuthenticatedWebApplication {
	private IOrientDbSettings orientDbSettings = new OrientDbSettings();

	@Override
	protected Class<? extends OrientDbWebSession> getWebSessionClass()
	{
		return OrientDbWebSession.class;
	}
	
	/**
	 * @return settings for the application
	 */
	public IOrientDbSettings getOrientDbSettings()
	{
		return orientDbSettings;
	}
	
	/**
	 * Explicit set of settings for the application. Doesn't recommended to use this method. Consider to use getOrientDBSettings().setXXX()
	 * @param orientDbSettings
	 */
	public void setOrientDbSettings(IOrientDbSettings orientDbSettings)
	{
		this.orientDbSettings=orientDbSettings;
	}
	
	public static OrientDbWebApplication get()
    {
        return (OrientDbWebApplication) WebApplication.get();
    }

	@Override
	protected void init() {
		super.init();
		Orient.instance().registerThreadDatabaseFactory(new DefaultODatabaseThreadLocalFactory(this));
		Orient.instance().addDbLifecycleListener(new ODatabaseLifecycleListener() {
			
			@Override
			public void onOpen(ODatabaseInternal iDatabase) {
				for (ORecordHook oRecordHook : getOrientDbSettings().getORecordHooks())
				{
					iDatabase.registerHook(oRecordHook);
				}
			}
			
			@Override
			public void onCreate(ODatabaseInternal iDatabase) {
				for (ORecordHook oRecordHook : getOrientDbSettings().getORecordHooks())
				{
					iDatabase.registerHook(oRecordHook);
				}
			}
			
			@Override
			public void onClose(ODatabaseInternal iDatabase) {
				for (ORecordHook oRecordHook : getOrientDbSettings().getORecordHooks())
				{
					iDatabase.unregisterHook(oRecordHook);
				}
			}
			
			public PRIORITY getPriority() {
				return PRIORITY.REGULAR;
			}

			@Override
			public void onCreateClass(ODatabaseInternal iDatabase, OClass iClass) {
				
			}

			@Override
			public void onDropClass(ODatabaseInternal iDatabase, OClass iClass) {
				
			}
		});
		getRequestCycleListeners().add(newTransactionRequestCycleListener());
		getRequestCycleListeners().add(new OrientDefaultExceptionsHandlingListener());
		getSecuritySettings().setAuthorizationStrategy(new WicketOrientDbAuthorizationStrategy(this));
		getApplicationListeners().add(new IApplicationListener() {
			
			
			@Override
			public void onAfterInitialized(Application application) {
				Orient.instance().removeShutdownHook();
			}
			@Override
			public void onBeforeDestroyed(Application application) {
				Orient.instance().shutdown();
			}
		});
	}
	
	protected TransactionRequestCycleListener newTransactionRequestCycleListener()
	{
		return new TransactionRequestCycleListener();
	}
	
	@Override
	protected IConverterLocator newConverterLocator()
	{
		ConverterLocator locator =  new ConverterLocator();
		locator.set(OIdentifiable.class, new OIdentifiableConverter<OIdentifiable>());
		locator.set(ODocument.class, new ODocumentConverter());
		return locator;
	}

}

@@ -1955,16 +1955,517 @@
 );%0A    %7D
+%0A%09%0A%09public static OrientDbWebApplication lookupApplication()%0A%09%7B%0A%09%09return lookupApplication(OrientDbWebApplication.class);%0A%09%7D%0A%09%0A%09protected static %3CT extends OrientDbWebApplication%3E T lookupApplication(Class%3CT%3E appClass)%0A%09%7B%0A%09%09Application app = Application.get();%0A%09%09if(app!=null && appClass.isInstance(app)) return (T)app;%0A%09%09else%0A%09%09%7B%0A%09%09%09for(String appKey: Application.getApplicationKeys())%0A%09%09%09%7B%0A%09%09%09%09app = Application.get(appKey);%0A%09%09%09%09if(appClass.isInstance(app)) return (T)app;%0A%09%09%09%7D%0A%09%09%7D%0A%09%09return null;%0A%09%7D
 %0A%0A%09@Over

Add function to lookup application in JVM, but not in current thread: usefull for internal hooks