package com.capgemini.reports.database.manager;

import com.capgemini.reports.database.javabean.IPersistedObject;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import java.util.ArrayList;
import java.util.List;

/**
 * Common methods for all Hibernate managers.
 *
 * @param <T> The type of {@link IPersistedObject} which is meing managed
 **/
public abstract class AbstractHibernateManager<T extends IPersistedObject> {

  private static final String KEY_COLUMN_VALUE = "colValue1";
  private static final String FROM = "FROM ";

  /**
   * Common method for searching object by its ID.
   */
  public T searchById(Session session, final Long aTechnicalId) {
    @SuppressWarnings("unchecked")
    T entry = (T) session.load(getManagedClass(), aTechnicalId);
    return entry;
  }

  /**
   * Parent method for coding easily a search query on a specific column.
   */
  T searchBy(Session session, final String aColumn, final String aColumnValue) {
    Query query = session.createQuery(FROM + getManagedClass().getName() + " r where r." + aColumn + "= :" + KEY_COLUMN_VALUE);
    query.setString(KEY_COLUMN_VALUE, aColumnValue);

    List<?> list = query.list();
    T theResult = null;
    if (!list.isEmpty()) {
      theResult = getManagedClass().cast(list.get(0));
    }
    return theResult;
  }

  /**
   * Parent method for coding easily a search query on a specific column.
   */
  List<T> searchAndReturnAllValues(Session session, final String aColumn, final Long aColumnValue) {
    Query query = session.createQuery(FROM + getClassName() + " r where r." + aColumn + " = :" + KEY_COLUMN_VALUE);
    query.setLong(KEY_COLUMN_VALUE, aColumnValue);
    List<?> list = query.list();
    if (!list.isEmpty()) {
      @SuppressWarnings("unchecked")
      List<T> typedList = (List<T>) list;
      return typedList;
    }
    else {
      return new ArrayList<>();
    }
  }

  /**
   * List all objects of the managed type.
   */
  public List<T> getList(Session session) {
    return castAll(session.createQuery(FROM + getClassName()).list());
  }

  List<T> castAll(final List<?> rawList) {
    List<T> typedList = new ArrayList<>();
    for (Object obj : rawList) {
      typedList.add(getManagedClass().cast(obj));
    }
    return typedList;
  }

  /**
   * Update the referenced object.
   */
  public void update(Session session, final T aPersistedObj) {
    session.update(aPersistedObj);
  }

  /**
   * Delete the referenced object.
   */
  public void delete(Session session, final T aPersistedObj) {
    session.delete(aPersistedObj);
  }

  /**
   * Getter for the class name of the current object.
   *
   * @return The class name value (without package)
   */
  private String getClassName() {
    return getManagedClass().getSimpleName();
  }

  /**
   * Getter for the JAVA bean class managed by this Hibernate manager instance.
   *
   * @return The class value (without package)
   */
  protected abstract Class<T> getManagedClass();
}
