/*
* Copyright 2014 - LAit SpA
*				 Realizzato da Icona Management srl su commessa LAit SpA
* Copyright 2015- LAit SpA
*                                                  Aggiornato da LAit SpA
*
* Concesso in licenza a norma dell'EUPL, versione 1.1 o
* successive dell'EUPL (la "Licenza")– non appena saranno
* approvate dalla Commissione europea;
* Non è possibile utilizzare l'opera salvo nel rispetto della Licenza.
* È possibile ottenere una copia della Licenza al seguente indirizzo:
*
* http://ec.europa.eu/idabc/eupl
*
* Salvo diversamente indicato dalla legge applicabile o
* concordato per iscritto, il software distribuito secondo
* i termini della Licenza è distribuito "TAL QUALE",
* SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO,
* esplicite o implicite.
* Si veda la Licenza per la lingua specifica che disciplina
* le autorizzazioni e le limitazioni secondo i termini della
* Licenza.
*/
/**
 * 
 */
package it.laitspa.cpf.spring.lut;

import it.laitspa.cpf.model.QueryLutOrderBy;
import it.laitspa.cpf.model.QueryResult;
import it.laitspa.cpf.spring.SpringFacade;
import it.laitspa.cpf.util.hibernate.SequenceUtil;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@SuppressWarnings("rawtypes")
@Repository("LUTFacade")
@Transactional
public class LUTFacadeImpl
  extends SpringFacade
  implements LUTFacade
{
  /**
   * 
   */

  public void deleteItem(Class table, Serializable id)
  {
    Session session = this.sessionFactory.getCurrentSession();
    Object item = session.get(table, id);
    session.delete(item);
  }

  public Object getItem(String lut, Object codice)
  {
    Session session = this.sessionFactory.getCurrentSession();

    String hql = "from " + lut + " where codice = :codice";

    Query q = session.createQuery(hql);
    q.setParameter("codice", codice);

    Object result = (Object)q.uniqueResult();
    return result;
  }

  public Object getItemByDescrizione(String lut, String descrizione)
  {
    Session session = this.sessionFactory.getCurrentSession();

    String hql = "from " + lut + " where descrizione = :descrizione";

    Query q = session.createQuery(hql);
    q.setParameter("descrizione", descrizione);

    Object result = (Object)q.uniqueResult();
    return result;
  }

  public Object getItemByDescrizione(String lut, String column, Object filter)
  {
    Session session = this.sessionFactory.getCurrentSession();

    String hql = "from " + lut + " where " + column + " = :descrizione";

    Query q = session.createQuery(hql);
    q.setParameter("descrizione", filter);

    Object result = (Object)q.uniqueResult();
    return result;
  }

  public List retrieve(String lut)
  {
    return retrieveImpl(lut, null, null, null);
  }

  public List retrieve(String lut, String orderColumn)
  {
    return retrieveImpl(lut, orderColumn, null, null);
  }

  public List retrieve(String lut, String orderColumn, String filterColumn, Object filterValue)
  {
    return retrieveImpl(lut, orderColumn, filterColumn, filterValue);
  }

  @SuppressWarnings("unchecked")
  private List
      retrieveImpl(String lut, String orderColumn, String filterColumn, Object filterValue)
  {
    Session session = this.sessionFactory.getCurrentSession();

    String hql = "from " + lut + " lut ";
    if(filterColumn != null)
      hql += " where lut." + filterColumn + " = :filterValue ";
    if(orderColumn != null)
      hql += " order by " + orderColumn;

    Query q = session.createQuery(hql);
    if(filterColumn != null)
      q.setParameter("filterValue", filterValue);

    List result = q.list();
    ArrayList array = new ArrayList();
    for(Object obj : result)
    {
      array.add(obj);
    }
    return array;
  }

  public List retrieveExcludingByCodice(String lut, Integer[] exclude)
  {
    return retrieveExcludingByCodiceImpl(lut, null, null, null, exclude);
  }

  public List retrieveExcludingByCodice(String lut, String orderColumn, Integer[] exclude)
  {
    return retrieveExcludingByCodiceImpl(lut, orderColumn, null, null, exclude);
  }

  public List retrieveExcludingByCodice(String lut, String orderColumn, String filterColumn,
      Object filterValue, Integer[] exclude)
  {
    return retrieveExcludingByCodiceImpl(lut, orderColumn, filterColumn, filterValue, exclude);
  }

  private List retrieveExcludingByCodiceImpl(String lut, String orderColumn, String filterColumn,
      Object filterValue, Integer[] exclude)
  {
    Session session = this.sessionFactory.getCurrentSession();

    String hql = "from " + lut + " lut ";

    boolean firstClause = true;
    if(filterColumn != null)
    {
      if(firstClause)
      {
        hql += "where ";
        firstClause = false;
      }
      hql += "lut." + filterColumn + " = :filterValue ";
    }

    if(exclude != null)
    {
      if(firstClause)
      {
        hql += "where ";
        firstClause = false;
      }
      else
        hql += "and ";

      hql += "lut.codice not in (";
      for(int i = 0; i < exclude.length; ++i)
      {
        hql += exclude[i].toString();
        if(i == (exclude.length - 1))
          hql += ") ";
        else
          hql += ", ";
      }
    }
    if(orderColumn != null)
      hql += " order by lut." + orderColumn;

    Query q = session.createQuery(hql);
    if(filterColumn != null)
      q.setParameter("filterValue", filterValue);

    List result = q.list();
    return result;
  }

  public QueryResult query(String lut, int firstResult, int maxResults)
  {
    return queryImpl(lut, null, firstResult, maxResults);
  }

  public QueryResult query(String lut, String orderColumn, int firstResult, int maxResults)
  {
    return queryImpl(lut, orderColumn, firstResult, maxResults);
  }

  private QueryResult queryImpl(String lut, String orderColumn, int firstResult, int maxResults)
  {
    Session session = this.sessionFactory.getCurrentSession();

    QueryLutOrderBy q = new QueryLutOrderBy(session);

    q.setLut(lut);
    q.setOrderColumn(orderColumn);
    q.setFirstResult(firstResult);
    q.setMaxResults(maxResults);

    return q.query();
  }

  public Object retrieveByCodice(String lut, int codice)
  {
    Session session = this.sessionFactory.getCurrentSession();

    String hql = "from " + lut + " lut where lut.codice = :codice";
    Query q = session.createQuery(hql);
    q.setInteger("codice", codice);
    return q.uniqueResult();
  }

  @Override
  public String buildCode(String sequence, String prefix, int length)
  {
    // Hibernate Session
    //
    Session session = this.sessionFactory.getCurrentSession();

    return SequenceUtil.buildCode(session, sequence, prefix, length);

  }

  @Override
  public List retrieveIncludingByCodice(String lut, Integer[] include)
  {
    return retrieveIncludingByCodiceImpl(lut, null, null, null, include);
  }

  @Override
  public List retrieveIncludingByCodice(String lut, String orderColumn, Integer[] include)
  {
    return retrieveIncludingByCodiceImpl(lut, orderColumn, null, null, include);
  }

  @Override
  public List retrieveIncludingByCodice(String lut, String orderColumn, String filterColumn,
      String filterValue, Integer[] include)
  {
    return retrieveIncludingByCodiceImpl(lut, orderColumn, filterColumn, filterValue, include);
  }

  private List retrieveIncludingByCodiceImpl(String lut, String orderColumn, String filterColumn,
      Object filterValue, Integer[] include)
  {
    Session session = this.sessionFactory.getCurrentSession();

    String hql = "from " + lut + " lut ";

    boolean firstClause = true;
    if(filterColumn != null)
    {
      if(firstClause)
      {
        hql += "where ";
        firstClause = false;
      }
      hql += " lut." + filterColumn + " = :filterValue ";
    }

    if(include != null)
    {
      if(firstClause)
      {
        hql += "where ";
        firstClause = false;
      }
      hql += " lut.codice in (";
      for(int i = 0; i < include.length; ++i)
      {
        hql += include[i].toString();
        if(i == (include.length - 1))
          hql += ") ";
        else
          hql += ", ";
      }
    }
    if(orderColumn != null)
      hql += " order by " + orderColumn;

    Query q = session.createQuery(hql);
    if(filterColumn != null)
      q.setParameter("filterValue", filterValue);

    List result = q.list();
    return result;
  }

  @SuppressWarnings("unchecked")
  private List retrieveAdvanceImpl(String lut, String orderColumn, String filterColumn,
      Object filterValue, String[] joins)
  {
    Session session = this.sessionFactory.getCurrentSession();

    String hql = "select lut from " + lut + " lut ";

    for(String join : joins)
      hql += join + " ";

    if(filterColumn != null)
      hql += " where lut." + filterColumn + " = :filterValue ";
    if(orderColumn != null)
      hql += " order by " + orderColumn;

    Query q = session.createQuery(hql);
    if(filterColumn != null)
      q.setParameter("filterValue", filterValue);

    List result = q.list();
    ArrayList array = new ArrayList();
    for(Object obj : result)
    {
      array.add(obj);
    }
    return array;
  }

  @Override
  public List retrieveAdvance(String lut, String orderColumn, String[] joins)
  {
    return retrieveAdvanceImpl(lut, orderColumn, null, null, joins);
  }

  @Override
  public List retrieveAdvance(String lut, String orderColumn, String filterColumn,
      Object filterValue, String[] joins)
  {
    return retrieveAdvanceImpl(lut, orderColumn, filterColumn, filterValue, joins);
  }

  public LUTFacadeImpl()
  {
  }

}
