package es.dalocar.software.services;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;

import es.dalocar.software.ApplicationManager;
import es.dalocar.software.beans.Factura;
import es.dalocar.software.beans.FacturaId;
import es.dalocar.software.beans.FacturaSearch;
import es.dalocar.software.beans.LineaFactura;
import es.dalocar.software.daos.ClienteDAO;
import es.dalocar.software.daos.FacturaDAO;
import es.dalocar.software.daos.LineaFacturaDAO;

public class FacturaService {
	
	private static final Logger log = Logger.getLogger(FacturaService.class);
	
	private FacturaDAO facturaDAO;
	private LineaFacturaDAO lineaFacturaDAO;
	private ClienteDAO clienteDAO;
	
	private ApplicationManager manager;
	
	
	/**
	 * @param manager
	 */
	public FacturaService(ApplicationManager manager)
	{
		this.manager  = manager;
		this.facturaDAO = manager.getFacturaDAO();
		this.lineaFacturaDAO = manager.getLineaFacturaDAO();	
		this.clienteDAO = manager.getClienteDAO();
	}
	

	/**
	 * Devuelve una Factura rellena con sus diferentes líneas
	 * @param id {@link FacturaId} Identificador de la factura
	 * @return Factura Rellena con sus lineas
	 * @throws ObjectNotFoundException
	 */
	public Factura getFacturaById(FacturaId id) throws ObjectNotFoundException{
		
		Factura factura = this.facturaDAO.findById(id);
		
		if(factura == null)
			throw new ObjectNotFoundException(id, Factura.class.toString());
		
		factura.getLineaFacturas().addAll(this.lineaFacturaDAO.findByFactura(factura));		
		
		return factura;
	}
	
	/**
	 * Devuelve todas las facturas de la base de datos.
	 * @return List
	 */
	public List findAll() {		
		return this.facturaDAO.findAll();
	}
	
	/**
	 * Guarda los cambios 
	 * @param factura
	 */
	public void saveFactura(Factura factura) {		
		this.facturaDAO.saveOrUpdate(factura);
		this.lineaFacturaDAO.saveLineasFactura(factura);	
	}
	
	/**
	 * Realiza una búsqueda de los objetos similares al parámetro search
	 * @param search
	 */
	public List search(FacturaSearch search) {
		
		DetachedCriteria criteria = DetachedCriteria.forClass(Factura.class);
		if (!search.getNumero().equals(""))
			criteria.add(Restrictions.like("id.numero", Integer.valueOf(search.getNumero())));
		if (!search.getAnyo().equals(""))
			criteria.add(Restrictions.eq("id.anyo",  Integer.valueOf(search.getAnyo())));		
		if (!search.getNumCliente().equals(""))
			criteria.add(Restrictions.eq("cliente.identificador",  Integer.valueOf(search.getNumCliente())));

		return this.facturaDAO.getHibernateTemplate().findByCriteria(criteria);
	}
	
	/**
	 * Devuelve el siguiente numero de factura a crear para el año pasado por parámetro
	 * @param year
	 * @return
	 */
	public Integer getNextIdFactura(int year) {
		List lista = this.facturaDAO.getHibernateTemplate().find("select max(id.numero) from Factura where id.anyo=" + year);
		Integer siguiente = (Integer)lista.get(0);
		if(siguiente == null)
			siguiente = new Integer(0);
		if(log.isDebugEnabled())
			log.debug("Siguiente factura: " + siguiente);
		
		return new Integer(siguiente.intValue() + 1);		
	}
	
	/**
	 * Devuelve una Factura rellena con sus diferentes líneas
	 * @param id {@link FacturaId} Identificador de la factura
	 * @return Factura Rellena con sus lineas
	 * @throws ObjectNotFoundException
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 */
	public Factura copyFacturaById(FacturaId id) {
		
		Factura factura = this.facturaDAO.findById(id);
		
		if(factura == null)
			throw new ObjectNotFoundException(id, Factura.class.toString());
		
		factura.getLineaFacturas().addAll(this.lineaFacturaDAO.findByFactura(factura));	
		Factura nuevaFactura = new Factura();
		
		try {
			BeanUtils.copyProperties(nuevaFactura, factura);
		
		Calendar calendar = Calendar.getInstance();
		//Nuevo identificador
		nuevaFactura.getId().setNumero(getNextIdFactura(calendar.get(Calendar.YEAR)));
		nuevaFactura.getId().setAnyo(Integer.valueOf(calendar.get(Calendar.YEAR)));
		//Copiamos las lineas
		Iterator it = factura.getLineaFacturas().iterator();
		nuevaFactura.setLineaFacturas(new ArrayList());
		while(it.hasNext()) {
			LineaFactura lineaNueva = new LineaFactura();
			LineaFactura linea = (LineaFactura)it.next();
			BeanUtils.copyProperties(lineaNueva, linea);
			lineaNueva.getId().setAnyofactura(nuevaFactura.getId().getAnyo());
			lineaNueva.getId().setNumerofactura(nuevaFactura.getId().getNumero());
			lineaNueva.setFactura(nuevaFactura);
			nuevaFactura.getLineaFacturas().add(lineaNueva);			
		}
		facturaDAO.persist(nuevaFactura);
		lineaFacturaDAO.saveLineasFactura(nuevaFactura);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		return nuevaFactura;
	}
	
	//Borra las facturas contenidas en una lista de facturas	
	public boolean deleteListaFacturas(List list) {
		Iterator it = list.iterator();
		while(it.hasNext()) {
			Factura f =(Factura) it.next();		
			//Borramos las lineas
			lineaFacturaDAO.deleteFromFactura(f);
			//Borramos la factura
			facturaDAO.delete(f);			
		}
		
		
		return true;
	}
	
}
