package com.microstar.tap3.contact;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.slf4j.LoggerFactory;

import com.microstar.tap3.api.BaseResourceImpl;
import com.microstar.tap3.contact.api.ContactObject;
import com.microstar.tap3.contact.transform.ContactTransformer;
import com.microstar.tap3.db.Address;
import com.microstar.tap3.db.Contact;
import com.microstar.tap3.exceptions.InitializationException;
import com.microstar.tap3.util.RestUtil;

@Path("/contacts")
public class ContactResourceImpl extends BaseResourceImpl implements ContactResource
{
	public ContactResourceImpl() 
	{
		LOG = LoggerFactory.getLogger(ContactResourceImpl.class);
	}
	
	@Override
	public void initSQLLocal() throws InitializationException
	{
	}

	@Override
	public void initDynamoLocal() throws InitializationException 
	{
	}
	
	@Override
	@HEAD
	@Path("/ping")
	public Response ping(@QueryParam("additionalDelay") @DefaultValue("0") int additionalDelay)
	{
		return super.ping(additionalDelay);
	}

	/*
	 * Options method for web app to be able to do the preflight calls and satisfy CORS requirements.
	 * (non-Javadoc)
	 * @see com.microstar.tap3.api.BaseResourceImpl#options()
	 */
	@Override
	@OPTIONS
	public Response options()
	{
		return super.options();
	}

	@Override
	@DELETE
	@Consumes({MediaType.APPLICATION_JSON})
	@Produces({MediaType.APPLICATION_JSON})
	@Path("/{id}")
	public Response deleteContact(@PathParam("id") String id)
	{
		LOG.debug("Entering contacts::DELETE /" + id);

		if ( !SQLinitialized )
		{
			try {
				initSQL();
			} catch (InitializationException e) {
				return Response.serverError()
						.entity(RestUtil.errorMsg("::init:Caught exception:" , e.getMessage()))
						.build();
			}
		}

		try
		{
			// Find the Contact in the DB
			Contact c = session.get(Contact.class, id);

			if ( c == null )
			{
				LOG.debug("Exiting ::deleteContact: NOT_FOUND: " + id);
				session.getTransaction().rollback();
				return Response
						.status(Status.NOT_FOUND)
						.build();
			}

			super.beginTransaction();

			// Mark the Contact as deleted
			c.setDeleted(true);
			getSession().update(c);
			
			super.commitTransaction();

			LOG.debug("Exiting contacts::DELETE /" + id + ": OK");
			return Response
					.ok().build();
		}
		catch ( Exception e )
		{
			abortTransaction();
			e.printStackTrace();
			LOG.debug("Exiting contacts::DELETE /" + id + ": Exception: " + e.getMessage());
			return Response
					.serverError()
					.entity("Caught exception: " + e.getMessage())
					.build();
		}
	}
	
	/* (non-Javadoc)
	 * @see com.microstar.tap3.contact.ContactResource#createContact(com.microstar.tap3.contact.api.ContactObject)
	 */
	@Override
	@POST
	@Consumes({MediaType.APPLICATION_JSON})
	@Produces({MediaType.APPLICATION_JSON})
	public Response createContact(ContactObject co)
	{
		LOG.debug("Entering contacts::POST");
		if ( !SQLinitialized )
		{
			try {
				initSQL();
			} catch (InitializationException e) {
				return Response.serverError()
						.entity(RestUtil.errorMsg("::init:Caught exception:" , e.getMessage()))
						.build();
			}
		}

		try
		{
			super.beginTransaction();
			
			// Setup the new objects
			Contact c = ContactTransformer.transform(co);
			Address a = ContactTransformer.transformAddress(co);
			
			// Persist the objects
			getSession().save(c);
			if ( a != null )
				session.save(a);
			super.commitTransaction();
			
			co.setId(c.getId());
			
			return Response
					.status(Status.CREATED)
					.entity(co)
					.location(RestUtil.makeURI("/contacts/" + c.getId()))
					.build();

		} catch ( Exception e )
		{
			abortTransaction();
			e.printStackTrace();
			return Response
					.serverError()
					.entity(RestUtil.errorMsg("Caught exception: ", e.getMessage()))
					.build();
		}
		finally
		{
			
		}
	}
	
	/* (non-Javadoc)
	 * @see com.microstar.tap3.contact.ContactResource#updateContact(java.lang.String, com.microstar.tap3.contact.api.ContactObject)
	 */
	@Override
	@PUT
	@Path("/{id}")
	@Produces({MediaType.APPLICATION_JSON})
	@Consumes({MediaType.APPLICATION_JSON})
	public Response updateContact(@PathParam("id") String id, ContactObject co)
	{
		LOG.debug("Entering contacts::PUT /" + id);
		if ( !SQLinitialized )
		{
			try {
				initSQL();
			} catch (InitializationException e) {
				return Response.serverError()
						.entity(RestUtil.errorMsg("::init:Caught exception:" , e.getMessage()))
						.build();
			}
		}

		try
		{
			// Find the Contact in the DB
			Contact c = session.get(Contact.class, id);

			if ( c == null )
			{
				session.getTransaction().rollback();
				return Response
						.status(404)
						.build();
			}

			// Update the Contact
			super.beginTransaction();
			c = ContactTransformer.transform(co, c);
			
			// Check to see if there's an address to update as well
			if ( co.getAddress() != null )
			{
				Address a = ContactTransformer.transformAddress(co);
				a = ContactTransformer.transform(co, a);
				session.update(a);
			}
			
			// Update Contact and commit transaction
			session.update(c);
			super.commitTransaction();
			LOG.debug("Updated Contact " + id);
			
			return Response
					.ok()
					.entity(co)
					.location(RestUtil.makeURI("/contacts/" + id))
					.build();

		} catch (Exception e)
		{
			abortTransaction();
			e.printStackTrace();
			return Response
					.serverError()
					.entity(RestUtil.errorMsg("Caught exception: ", e.getMessage()))
					.build();
		}
		finally
		{
			
		}
	}
	
	/* (non-Javadoc)
	 * @see com.microstar.tap3.contact.ContactResource#getByCustId(java.lang.String)
	 */
	@Override
	@GET
	@Produces({MediaType.APPLICATION_JSON})
	public Response getByCustId(@QueryParam("cid") String cid)
	{
		LOG.info("Entering contacts::GET ?cid=" + cid);
		if ( !SQLinitialized )
		{
			try {
				initSQL();
			} catch (InitializationException e) {
				return Response.serverError()
						.entity(RestUtil.errorMsg("::init:Caught exception:" , e.getMessage()))
						.build();
			}
		}

		try
		{

			@SuppressWarnings("deprecation")
			Criteria custCrit = getSession().createCriteria(Contact.class);
			custCrit.add(Restrictions.eq("id", cid));
			@SuppressWarnings("unchecked")
			List<Contact> contacts = (List<Contact>) custCrit.list();
			
			if ( contacts == null )
			{
				return Response
						.status(404)
						.location(RestUtil.makeURI("/contacts?cid=" + cid))
						.build();
			}
			
			return Response.ok()
					.entity(contacts)
					.location(RestUtil.makeURI("/contacts?cid=" + cid))
					.build();
		}
		catch (Exception e)
		{
			abortTransaction();
			e.printStackTrace();
			return Response
					.serverError()
					.entity(RestUtil.errorMsg("Caught exception: ", e.getMessage()))
					.build();
		}
	}
	
	/* (non-Javadoc)
	 * @see com.microstar.tap3.contact.ContactResource#getById(java.lang.String)
	 */
	@Override
	@GET
	@Path("/{id}")
	@Produces({MediaType.APPLICATION_JSON})
	public Response getById(@PathParam("id") String id)
	{
		LOG.info("Entering contacts::GET /" + id);
		if ( !SQLinitialized )
		{
			try {
				initSQL();
			} catch (InitializationException e) {
				return Response.serverError()
						.entity(RestUtil.errorMsg("::init:Caught exception:" , e.getMessage()))
						.build();
			}
		}

		try
		{
			Contact c = (Contact) session.get(Contact.class, id);
			if ( c == null )
			{
				return Response.status(404)
						.location(RestUtil.makeURI("/contacts/" + id))
						.build();
			}

			LOG.info("Got contact: " + c.getFirstName() + " " + c.getLastName());
			ContactObject co = new ContactObject();
			Address a = null;
			
			if ( c.getAddressId() != null )
				a = session.get(Address.class, c.getAddressId());
			
			// Transform Contact and Address into ContactObject
			co = ContactTransformer.transform(c, a, co);
			

			return Response
					.ok()
					.entity(co)
					.location(RestUtil.makeURI("/contacts/" + id))
					.build();
		}
		catch ( Exception ex )
		{
			session.getTransaction().rollback();
			ex.printStackTrace();
			return Response
					.serverError()
					.entity(RestUtil.errorMsg("Caught exception: ", ex.getMessage()))
					.build();
		}
	}

}
