/**
 * Copyright © 2009-2010, Res Interactive, LLC. All Rights Reserved.
 */

package com.tootsville;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Random;

import javax.mail.MessagingException;

import org.starhope.appius.except.NotFoundException;
import org.starhope.appius.game.AppiusClaudiusCaecus;
import org.starhope.appius.mb.UserEnrolment;
import org.starhope.appius.messaging.Mail;
import org.starhope.appius.sql.SQLPeerDatum;
import org.starhope.appius.user.AbstractPerson;
import org.starhope.appius.util.AppiusConfig;

/**
 * TODO: The documentation for this type (Coupon) is incomplete.
 * (twheys@gmail.com, Nov 3, 2009) XXX: I have no idea what this used to
 * do and I'm removing it for now. XXX: Find out what this does and fix
 * it.
 * 
 * @author twheys@gmail.com
 */
public class Coupon extends SQLPeerDatum {
	
	/**
	 * WRITEME: document this field (twheys@gmail.com, Oct 28, 2009)
	 * serialVersionUID (long)
	 */
	private static final long serialVersionUID = -910537582879371680L;
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Sep 29, 2009)
	 * 
	 * @return WRITEME
	 */
	private static String generateRandomCode () {
		final StringBuilder eCode = new StringBuilder ();
		boolean found = false;
		final Random rnd = new Random ();

		PreparedStatement checkExists = null;
		try {
			checkExists = AppiusConfig
			.getStoreDatabaseConnection ()
			.prepareStatement (
			"SELECT COUNT(*) FROM zen_coupons WHERE coupon_code=?");
			do {
				// generate 12 random characters from the given
				for (int i = 0; i < 12; ++i) {
					eCode
					.append (UserEnrolment.getOrderCodeChars() [(int) (rnd
							.nextDouble () * UserEnrolment.getOrderCodeChars().length)]);
				}
				checkExists.setString (1, eCode.toString ());
				if (checkExists.execute ()) {
					final ResultSet exists = checkExists
					.getResultSet ();
					exists.next ();
					if (exists.getInt (1) == 0) {
						found = true;
					}
				}
			} while (!found);
			checkExists.close ();
		} catch (final SQLException e) {
			throw AppiusClaudiusCaecus.fatalBug (e);
		} finally {
			if (null != checkExists) {
				try {
					checkExists.close ();
				} catch (final SQLException e) {
					AppiusClaudiusCaecus.reportBug ("finally", e);
				}
			}
		}

		return eCode.toString ();
	}
	
	/**
	 * WRITEME: document this field (twheys@gmail.com, Nov 3, 2009)
	 * couponAmount (Coupon)
	 */
	private BigDecimal couponAmount = new BigDecimal (14.95);
	
	/**
	 * WRITEME: document this field (twheys@gmail.com, Nov 3, 2009)
	 * couponCode (Coupon)
	 */
	private String couponCode;

	/**
	 * WRITEME FIXME: getText
	 */
	private String couponDescription = "Free Plush Toot order code for V.I.T. membership.  Thank you!  Redeem for Toots Account: ";

	/**
	 * The coupon's unique ID value
	 */
	private int couponID;

	/**
	 * The minimum amount for the coupon to WTF? WRITEME
	 */
	private BigDecimal couponMinAmount = new BigDecimal (0);

	/**
	 * The label for this coupon
	 */
	private String couponName = "Free Plush Toot";

	/**
	 * The expiry date of this coupon.
	 */
	private Date endDate =
		Date.valueOf (AppiusConfig.getConfigOrDefault (
				"com.tootsville.coupons.plushToot.expiry",
					"2010-1-1"));

	/**
	 * The date at which this coupon becomes effective
	 */
	private Date startDate = new Date (System.currentTimeMillis ());

	/**
	 * The number of times for which this coupon may be used
	 */
	private int usesPerCoupon = 1;

	/**
	 * The number of times for which one user may use this coupon
	 */
	private int usesPerUser = 1;

	/**
	 * @param userName The debug name (user name plus user ID number) of
	 *        the user for whom the coupon is being created
	 */
	public Coupon (final String userName) {
		// FIXME: LibMisc.getText
		couponDescription =
			"Free Plush Toot™ coupon code for V.I.T. membership.  Thank you!  Redeem for Toots Account: "
			+ userName;
		couponCode = Coupon.generateRandomCode ();

		insertCoupon ();
		insertCouponDescription ();
	}

	/**
	 * This is an overriding method.
	 *
	 * @see org.starhope.appius.sql.SQLPeerDatum#flush()
	 */
	@Override
	public void flush () {
		// do nothing
	}

	/**
	 * This is an overriding method.
	 *
	 * @see org.starhope.appius.sql.SQLPeerDatum#getCacheUniqueID()
	 */
	@Override
	protected String getCacheUniqueID () {
		return "Coupon/" + getCouponID ();
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public BigDecimal getCouponAmount () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return couponAmount;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public String getCouponCode () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return couponCode;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public String getCouponDescription () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return couponDescription;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public int getCouponID () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return couponID;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public BigDecimal getCouponMinAmount () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return couponMinAmount;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public String getCouponName () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return couponName;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public Date getEndDate () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return endDate;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public Date getStartDate () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return startDate;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public int getUsesPerCoupon () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return usesPerCoupon;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @return TODO
	 */
	public int getUsesPerUser () {
		// default getter (twheys@gmail.com, Oct 28, 2009)
		return usesPerUser;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 */
	private void insertCoupon () {

		PreparedStatement insert = null;
		Connection storeCon = null;
		try {
			storeCon = AppiusConfig.getStoreDatabaseConnection ();
			insert = storeCon
			.prepareStatement (
					"INSERT INTO zen_coupons "
					+ "(coupon_code, coupon_amount, coupon_minimum_order, "
					+ "coupon_start_date, coupon_expire_date, uses_per_coupon, "
					+ "uses_per_user, date_created) "
					+ "VALUES (?,?,?,?,?,?,?,NOW())");

			insert.setString (1, couponCode);
			insert.setBigDecimal (2, couponAmount);
			insert.setBigDecimal (3, couponMinAmount);
			insert.setDate (4, startDate);
			insert.setDate (5, endDate);
			insert.setInt (6, usesPerCoupon);
			insert.setInt (7, usesPerUser);

			if (insert.executeUpdate () != 1) {
				throw new SQLException ("adding new user failed with "
						+ insert.getUpdateCount () + " updates");
			}
			final ResultSet keys = insert.getGeneratedKeys ();
			if (keys.next ()) {
				couponID = keys.getInt (1);
				System.out.println ("New Coupon ID: " + couponID);
			} else {
				throw new SQLException ("Can't get coupon ID");
			}
		} catch (final SQLException e) {
			AppiusClaudiusCaecus.fatalBug (e);
		} finally {
			if (null != insert) {
				try {
					insert.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
			if (null != storeCon) {
				try { storeCon.close (); } catch (final SQLException e) { /* No Op */ }
			}
		}
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 */
	private void insertCouponDescription () {
		PreparedStatement insert = null;
		Connection storeCon = null;
		try {
			storeCon = AppiusConfig.getStoreDatabaseConnection ();
			insert = storeCon
			.prepareStatement (
					"INSERT INTO zen_coupons_description "
					+ "(coupon_id, language_id, coupon_name, coupon_description ) "
					+ "VALUES (?,?,?,?)");

			insert.setInt (1, couponID);
			insert.setInt (2, 1);
			insert.setString (3, couponName);
			insert.setString (4, couponDescription);
			insert.execute ();
		} catch (final SQLException e) {
			AppiusClaudiusCaecus.fatalBug (e);
		} finally {
			if (null != insert) {
				try {
					insert.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
			if (null != storeCon) {
				try { storeCon.close (); } catch (final SQLException e) { /* No Op */ }
			}
		}
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param user TODO
	 */
	public void sendCouponCode (final AbstractPerson user) {
		try {
			// user.setCouponCode (getCouponCode ());
			Mail
			.sendTemplateMail (
					user,
					AppiusConfig
					.getConfigOrNull ("com.tootsville.coupon.templates.freeplush"),
					false,
					AppiusConfig
					.getConfigOrNull ("com.tootsville.coupon.templates.freeplush.subject"));
		} catch (final FileNotFoundException e) {
			// Default catch action, report bug (twheys@gmail.com, Oct 28, 2009)
			AppiusClaudiusCaecus.reportBug (
					"Template not found for coupon", e);
		} catch (final IOException e) {
			// Default catch action, report bug (twheys@gmail.com, Oct 28, 2009)
			AppiusClaudiusCaecus.reportBug (
					"File unable to be loaded for coupon template", e);
		} catch (final NotFoundException e) {
			// Default catch action, report bug (twheys@gmail.com, Oct 28, 2009)
			AppiusClaudiusCaecus.reportBug (
					"Template not found for coupon", e);
		} catch (final MessagingException e) {
			// Default catch action, report bug (twheys@gmail.com, Oct 28, 2009)
			AppiusClaudiusCaecus.reportBug (
					"Unable to send mail for coupon", e);
		}

	}

	/**
	 * This is an overriding method.
	 *
	 * @see org.starhope.appius.sql.SQLPeerDatum#set(java.sql.ResultSet)
	 */
	@Override
	protected void set (final ResultSet rs) throws SQLException {
		// TODO Auto-generated method stub (twheys@gmail.com, Oct 28, 2009)
		throw AppiusClaudiusCaecus.fatalBug ("Unimplemented method");
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param newCouponAmount TODO
	 */
	public void setCouponAmount (final BigDecimal newCouponAmount) {
		// default setter (twheys@gmail.com, Oct 28, 2009)
		couponAmount = newCouponAmount;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param newCouponCode TODO
	 */
	public void setCouponCode (final String newCouponCode) {
		// default setter (twheys@gmail.com, Oct 28, 2009)
		couponCode = newCouponCode;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param newCouponID TODO
	 */
	public void setCouponID (final int newCouponID) {
		// default setter (twheys@gmail.com, Oct 28, 2009)
		couponID = newCouponID;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param newCouponMinAmount TODO
	 */
	public void setCouponMinAmount (final BigDecimal newCouponMinAmount) {
		// default setter (twheys@gmail.com, Oct 28, 2009)
		couponMinAmount = newCouponMinAmount;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param newCouponName TODO
	 */
	public void setCouponName (final String newCouponName) {
		// default setter (twheys@gmail.com, Oct 28, 2009)
		couponName = newCouponName;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param newEndDate TODO
	 */
	public void setEndDate (final Date newEndDate) {
		// default setter (twheys@gmail.com, Oct 28, 2009)
		endDate = newEndDate;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param newStartDate TODO
	 */
	public void setStartDate (final Date newStartDate) {
		// default setter (twheys@gmail.com, Oct 28, 2009)
		startDate = newStartDate;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param newUsesPerCoupon TODO
	 */
	public void setUsesPerCoupon (final int newUsesPerCoupon) {
		// default setter (twheys@gmail.com, Oct 28, 2009)
		usesPerCoupon = newUsesPerCoupon;
	}
	
	/**
	 * WRITEME: document this method (twheys@gmail.com, Nov 3, 2009)
	 * 
	 * @param newUsesPerUser TODO
	 */
	public void setUsesPerUser (final int newUsesPerUser) {
		// default setter (twheys@gmail.com, Oct 28, 2009)
		usesPerUser = newUsesPerUser;
	}

	/**
	 * This is an overriding method.
	 *
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString () {return getCouponName ()
		+ ": "
		+ getCouponCode ();
	}

}
