/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.sdm.infrastructure;

import com.orientechnologies.common.exception.OException;
import com.orientechnologies.orient.core.Orient;
import com.orientechnologies.orient.core.db.ODatabase.STATUS;
import com.orientechnologies.orient.core.db.OPartitionedDatabasePool;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.exception.ODatabaseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.scytl.products.ov.sdm.application.exception.DatabaseException;

/**
 * Initialization, open and close of database at startup.
 */
@Component
public class OldDatabaseManagerImpl implements OldDatabaseManager {

	private static final Logger LOGGER = LoggerFactory.getLogger(OldDatabaseManagerImpl.class);

	private ODatabaseDocumentTx db;

	private OPartitionedDatabasePool dbpool;

	/**
	 * Constructor.
	 * 
	 * @param databasePath the databasePath class containing the path to the database instance.
	 */
	@Autowired
	public OldDatabaseManagerImpl(DatabasePath databasePath) {
		super();
		try {
			dbpool = new OPartitionedDatabasePool(databasePath.getDatabasePath(), "admin", "admin");
			dbpool.setAutoCreate(true);
			getDatabaseInstance();
		} catch (ODatabaseException e) {
			throw new DatabaseException("Error with the database: ", e);
		}
	}

	// Get database instance
	private void getDatabaseInstance() {
		try {
			db = dbpool.acquire();
		} catch (ODatabaseException e) {
			throw new DatabaseException("Error with the database: ", e);
		}
	}

	/**
	 * Returns the database.
	 * 
	 * @return The database
	 */
	@Override
	public ODatabaseDocumentTx getDatabase() {
		try {
			if (db.getStatus().equals(STATUS.CLOSED)) {
				getDatabaseInstance();
			}
			db.activateOnCurrentThread();
			setDatabaseForCurrentThread(db);
			return db;
		} catch (OException e) {
			throw new DatabaseException("Error with the database: ", e);
		}
	}

	/**
	 * Set database for current thread.
	 * 
	 * @param db the database instance.
	 */
	@Override
	public void setDatabaseForCurrentThread(ODatabaseDocumentTx db) {
		try {
			db.activateOnCurrentThread();
		} catch (OException e) {
			throw new DatabaseException("Error with the database: ", e);
		}
	}

	/**
	 * @see com.scytl.products.ov.sdm.infrastructure.OldDatabaseManager#getStatus()
	 */
	@Override
	public String getStatus() {
		String result;
		try {
			if (db != null) {
				result = db.getStatus().name();
			} else {
			    result = STATUS.CLOSED.name();
            }

		} catch (OException e) {
			// log error
			LOGGER.error("Error getting the database state ", e);
			result = "ERROR";
		}
		return result;
	}

	@Override
	public void closeDatabase() {
		LOGGER.info("Shutting down the database... ");
		try {
			db.activateOnCurrentThread();
			db.freeze();
			db.close();
			dbpool.close();
			LOGGER.info("Database is: " + getStatus());
            //shutdown for real..
			Orient.instance().shutdown();
			db = null;
			dbpool = null;
		} catch (OException e) {
			// log error
			LOGGER.error("Error closing the database ", e);
		}
	}

}
