package com.wesabe.api.accounts.resources;

import java.util.Locale;

import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.hibernate.validator.InvalidStateException;

import com.google.inject.Inject;
import com.wesabe.api.accounts.dao.AccountDAO;
import com.wesabe.api.accounts.entities.Account;
import com.wesabe.api.accounts.entities.AccountStatus;
import com.wesabe.api.accounts.entities.InvestmentAccount;
import com.wesabe.api.accounts.params.BooleanParam;
import com.wesabe.api.accounts.params.CurrencyParam;
import com.wesabe.api.accounts.params.IntegerParam;
import com.wesabe.api.accounts.presenters.AccountPresenter;
import com.wesabe.api.accounts.presenters.InvalidStateExceptionPresenter;
import com.wesabe.api.accounts.presenters.InvestmentAccountPresenter;
import com.wesabe.api.util.auth.WesabeUser;
import com.wesabe.xmlson.XmlsonObject;

/**
 * Return account details for a single account
 * 
 * @author brad
 */
@Path("/v2/accounts/accounts/{accountId}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public class AccountResource {
	private final AccountDAO accountDAO;
	private final AccountPresenter accountPresenter;
	private final InvestmentAccountPresenter investmentAccountPresenter;
	
	@Inject
	public AccountResource(AccountDAO accountDAO, AccountPresenter accountPresenter, 
			InvestmentAccountPresenter investmentAccountPresenter) {
		this.accountDAO = accountDAO;
		this.accountPresenter = accountPresenter;
		this.investmentAccountPresenter = investmentAccountPresenter;
	}
	
	@GET
	public XmlsonObject show(@Context WesabeUser user,
			@Context Locale locale,
			@PathParam("accountId") IntegerParam accountId) {
		
		final Account account = accountDAO.findAccount(user.getAccountKey(), accountId.getValue());
		if (account == null) {
			throw new WebApplicationException(Status.NOT_FOUND);
		}
		
		return present(account, locale);
	}
	
	@PUT
	public XmlsonObject update(@Context WesabeUser user,
			@Context Locale locale,
			@PathParam("accountId") IntegerParam accountId,
			@FormParam("name") String name,
			@FormParam("currency") CurrencyParam currency,
			@FormParam("archived") BooleanParam archived) {
		
		final Account account = accountDAO.findAccount(user.getAccountKey(), accountId.getValue());
		boolean shouldUpdate = false;
		
		if (account == null) {
			throw new WebApplicationException(Status.NOT_FOUND);
		}
		
		if (name != null) {
			account.setName(name);
			shouldUpdate = true;
		}
		
		if (currency != null) {
			account.setCurrency(currency.getValue());
			shouldUpdate = true;
		}
		
		if (archived != null) {
			shouldUpdate = true;
			if ((archived.getValue() && account.isArchived()) || (!archived.getValue() && account.isActive())) {
				// already in the target state
				shouldUpdate = false;
			} else if (archived.getValue() && account.isActive()) {
				account.setStatus(AccountStatus.ARCHIVED);
			} else if (!archived.getValue() && account.isArchived()) {
				account.setStatus(AccountStatus.ACTIVE);
			} else {
				throw new WebApplicationException(
						Response
							.status(Status.BAD_REQUEST)
							.entity("Cannot change archived status of an account with status of " + account.getStatus())
							.build()
				);
			}
		}
		
		if (shouldUpdate) {
			try {
				accountDAO.update(account);
			} catch (InvalidStateException ex) {
				throw new WebApplicationException(
						Response
							.status(Status.BAD_REQUEST)
							.entity(new InvalidStateExceptionPresenter().present(ex))
							.build()
				);
			}
		}
		
		return present(account, locale);
	}
	
	private XmlsonObject present(Account account, Locale locale) {
		if (account instanceof InvestmentAccount) {
			return investmentAccountPresenter.present(account, locale);
		} else {
			return accountPresenter.present(account, locale);
		}
	}
}

@@ -2897,32 +2897,8 @@
 ) %7B%0A
-%09%09%09shouldUpdate = true;%0A
 %09%09%09i
@@ -2993,24 +2993,24 @@
 ctive())) %7B%0A
+
 %09%09%09%09// alrea
@@ -3036,34 +3036,8 @@
 ate%0A
-%09%09%09%09shouldUpdate = false;%0A
 %09%09%09%7D
@@ -3138,16 +3138,41 @@
 HIVED);%0A
+%09%09%09%09shouldUpdate = true;%0A
 %09%09%09%7D els
@@ -3221,24 +3221,24 @@
 chived()) %7B%0A
-
 %09%09%09%09account.
@@ -3270,16 +3270,41 @@
 CTIVE);%0A
+%09%09%09%09shouldUpdate = true;%0A
 %09%09%09%7D els

Allow updating archival state and name/currency at the same time.