package gov.va.vinci.dart.db.impl;

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

import javax.persistence.NoResultException;
import javax.persistence.Query;

import gov.va.vinci.dart.common.exception.ObjectNotFoundException;
import gov.va.vinci.dart.biz.Person;
import gov.va.vinci.dart.db.PersonDAO;
import gov.va.vinci.dart.db.util.HibernateDAO;

public class PersonDAOImpl extends HibernateDAO implements PersonDAO {

	@Override
	public Person findById(final int personId) throws ObjectNotFoundException {
		Query q = createQuery("from Person where id=:pid");
		q.setParameter("pid", personId);
		try {
			Person result = (Person)q.getSingleResult();
			
			if (result == null) {
				throw new ObjectNotFoundException("No person found with id " + personId);
			}
			
			return result;
		} catch (NoResultException e) {
			throw new ObjectNotFoundException("No person found with id " + personId, e);
		}
	}

	@Override
	public Person findByName(final String name) throws ObjectNotFoundException {
		
		Query query = createQuery("from Person where name like :pname");
		query.setParameter("pname", name);
		try {
			return (Person)query.getSingleResult();
		} catch (NoResultException e) {
			throw new ObjectNotFoundException("No person found with name " + name, e);
		}
	}
	
	@Override
	public Person findByNameCaseInsensitive(final String name) throws ObjectNotFoundException {
		
		Query query = createQuery("from Person where name like :pname");
		query.setParameter("pname", name);
		try {
			return (Person)query.getSingleResult();
		} catch (NoResultException e) {
			throw new ObjectNotFoundException("No person found with name " + name, e);
		}
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public List<Person> listAll() {
		Query query = createQuery("from Person");
		try {
			return (List<Person>)query.getResultList();
		} catch (NoResultException e) {
			return new ArrayList<Person>();
		}
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public List<Person> list(final String term) {
		Query query = createQuery("from Person where name like :term or description like :term or fullName like :term");
		try {
			query.setParameter("term", "%"+term+"%");
			return (List<Person>)query.getResultList();
		} catch (NoResultException e) {
			return new ArrayList<Person>();
		}
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public List<Person> listAllWithRole(final int roleId) {
		Query query = createQuery("select distinct p from Person p inner join p.roles r where r.id=:rid");
		query.setParameter("rid", roleId);
		
		try {
			return (List<Person>)query.getResultList();
		} catch (NoResultException e) {
			return new ArrayList<Person>();
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Person> listByGroup(final int groupId) {
		Query query = createQuery("select distinct p from Person p inner join p.groups g where g.id=:gid");
		query.setParameter("gid", groupId);
		
		try {
			return (List<Person>)query.getResultList();
		} catch (NoResultException e) {
			return new ArrayList<Person>();
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Person> listAllWithRoleAndGroupAndNotifications(final int roleId, final int groupId) {
		Query query = createQuery("select distinct p from Person p inner join p.personGroups pg inner join p.roles r where r.id=:rid and pg.group.id=:gid and pg.notification=true");
		query.setParameter("gid", groupId);
		query.setParameter("rid", roleId);

		try {
			return (List<Person>)query.getResultList();
		} catch (NoResultException e) {
			return new ArrayList<Person>();
		}
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public List<Person> listByGroupAndNotifications(final int groupId) {
		Query query = createQuery("select distinct p from Person p inner join p.personGroups pg where pg.group.id=:gid and pg.notification=true");
		query.setParameter("gid", groupId);
		
		try {
			return (List<Person>)query.getResultList();
		} catch (NoResultException e) {
			return new ArrayList<Person>();
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Person> listAllWithRoleAndGroup(final int roleId, final int groupId) {
		Query query = createQuery("select distinct p from Person p inner join p.groups g inner join p.roles r where r.id=:rid and g.id=:gid");
		query.setParameter("gid", groupId);
		query.setParameter("rid", roleId);
		
		try {
			return (List<Person>)query.getResultList();
		} catch (NoResultException e) {
			return new ArrayList<Person>();
		}
	}
	
	
	@Override
	public void save(final Person person) {
		HibernateDAO.save(person);
	}
}
