/**
 * <p>
 * Copyright © 2009-2010, Bruce-Robert Pocock
 * </p>
 * <p>
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * </p>
 * <p>
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * </p>
 * <p>
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * </p>
 * 
 * @author brpocock
 */

package org.starhope.appius.mb;

import java.math.BigDecimal;
import java.sql.*;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.LinkedList;

import org.starhope.appius.except.NotFoundException;
import org.starhope.appius.game.AppiusClaudiusCaecus;
import org.starhope.appius.sql.SQLPeerDatum;
import org.starhope.appius.util.AppiusConfig;

/**
 * <p>
 * An Enrolment object represents a <i>potential type</i> of enrolment
 * or subscription into which an User can be subscribed. This does
 * <i>not</i> represent an actual commitment by the user to a particular
 * subscription, only that one is potentially possible.
 * </p>
 * 
 * @see UserEnrolment UserEnrolment for actual
 *      subscriptions/registrations
 * 
 * @author brpocock
 * 
 */
public class Enrolment extends SQLPeerDatum {
	/**
	 * TODO: document this field (theys, Oct 5, 2009)
	 * 
	 * serialVersionUID (long)
	 */
	private static final long serialVersionUID = 7040272239205566945L;

	/**
	 * Returns all products in the products table that are flagged as
	 * Available AND Visible
	 * 
	 * @return all products in the products table that are flagged as
	 *         Available AND Visible
	 */
	public static Enrolment [] getAvailableEnrolments () {
		final LinkedList <Enrolment> products = new LinkedList <Enrolment> ();
		Connection con = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		try {
			con = AppiusConfig.getDatabaseConnection ();
			st = con
			.prepareStatement ("SELECT * FROM products WHERE available='Y' AND visible='Y'");
			if (st.execute ()) {
				rs = st.getResultSet ();
				while (rs.next ()) {
					Enrolment enrolment = null;
					try {
						enrolment = new Enrolment (rs);
					} catch (final NotFoundException e) {
						// Default catch action, report bug (theys, Oct
						// 30,
						// 2009)
						AppiusClaudiusCaecus.reportBug (e);
					}
					if (null != enrolment) {
						products.add (enrolment);
					}
				}
			}
		} catch (final SQLException e) {
			return new Enrolment [] {};
		} finally {
			if (null != rs) {
				try {
					rs.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
			if (null != st) {
				try {
					st.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
			if (null != con) {
				try {
					con.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}

		}
		return products.toArray (new Enrolment [products.size ()]);
	}

	/**
	 * TODO: document this method (brpocock, Sep 23, 2009)
	 * 
	 * @param id WRITEME
	 * @return WRITEME
	 * @throws NotFoundException WRITEME
	 */
	public static Enrolment getByID (final int id)
	throws NotFoundException {
		Connection con = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		try {
			con = AppiusConfig.getDatabaseConnection ();
			st = con
			.prepareStatement ("SELECT * FROM products WHERE id=?");
			st.setInt (1, id);
			st.execute ();
			rs = st.getResultSet ();
			rs.next ();
			final Enrolment e = new Enrolment (rs);
			return e;
		} catch (final SQLException e) {
			AppiusClaudiusCaecus.reportBug (e);
			throw new NotFoundException ("Product with id (" + id
					+ ") does not exist.");
		} finally {
			if (null != rs) {
				try {
					rs.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
			if (null != st) {
				try {
					st.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
			if (null != con) {
				try {
					con.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}

		}
	}

	/**
	 * @param id the database ID of the Enrolment
	 * @return Enrolment object
	 * @throws NotFoundException if the ID doesn't point to a valid
	 *         enrolment
	 */
	public static Enrolment getByProductCode (final String id)
	throws NotFoundException {
		Connection con = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		try {
			con = AppiusConfig.getDatabaseConnection ();
			st = con
			.prepareStatement ("SELECT * FROM products WHERE productCode=?");
			st.setString (1, id);
			st.execute ();
			rs = st.getResultSet ();
			rs.next ();
			final Enrolment e = new Enrolment (rs);
			return e;
		} catch (final SQLException e) {
			AppiusClaudiusCaecus.reportBug (e);
			throw new NotFoundException ("Product with id (" + id
					+ ") does not exist.");
		} finally {
			if (null != rs) {
				try {
					rs.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
			if (null != st) {
				try {
					st.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
			if (null != con) {
				try {
					con.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}

		}
	}

	/**
	 * WRITEME
	 */
	private boolean autoRenew;
	/**
	 * WRITEME
	 */
	private boolean available;
	/**
	 * WRITEME
	 */
	private int id;
	/**
	 * WRITEME
	 */
	private BigDecimal price;
	/**
	 * WRITEME
	 */
	private String productCode;
	/**
	 * WRITEME
	 */
	private long renewDays;
	/**
	 * WRITEME
	 */
	private int renewMonths;

	/**
	 * WRITEME
	 */
	private String title;

	/**
	 * @param d WRITEME
	 */
	public Enrolment (final BigDecimal d) {
		setPrice (d);
	}

	/**
	 * WRITEME
	 * 
	 * @param resultSet WRITEME
	 * @throws NotFoundException WRITEME
	 */
	protected Enrolment (final ResultSet resultSet)
	throws NotFoundException {
		try {
			set (resultSet);
		} catch (final SQLException e) {
			throw new NotFoundException (e.toString ());
		}
	}

	/**
	 * 
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.sql.SQLPeerDatum#flush()
	 */
	@Override
	public void flush () {
		// This should never be called, report bug if it is
		try {
			throw new Exception ();
		} catch (final Exception e) {
			AppiusClaudiusCaecus.reportBug (
					"Something is calling flush on Enrolments.", e);
		}
	}

	/**
	 * 
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.sql.SQLPeerDatum#getCacheUniqueID()
	 */
	@Override
	protected String getCacheUniqueID () {
		// TODO Auto-generated method stub (theys, Oct 5, 2009)
		return null;
	}

	/**
	 * @return WRITEME
	 */
	public Currency getCurrency () {
		return Currency.get_USD ();
	}

	/**
	 * @param begins WRITEME
	 * @return WRITEME
	 */
	public Date getExpiryFor (final Date begins) {
		final Calendar expiry = new GregorianCalendar ();
		expiry.setTimeInMillis (begins.getTime ());
		if (0 != renewMonths) {
			expiry.add (Calendar.MONTH, renewMonths);
		} else {
			expiry.add (Calendar.DATE, (int) renewDays);
		}
		return new Date (expiry.getTimeInMillis ());
	}

	/**
	 * WRITEME TODO: document this method (brpocock, Oct 13, 2009)
	 * 
	 * @return WRITEME
	 */
	public int getId () {
		// default getter (theys, Oct 5, 2009)
		return id;
	}

	/**
	 * 
	 * TODO: document this method (brpocock, Oct 13, 2009)
	 * 
	 * @return WRITEME
	 */
	public BigDecimal getPrice () {
		return price;
	}

	/**
	 * @return WRITEME
	 */
	public long getPrivilegeDays () {
		return renewDays;
	}

	/**
	 * @return WRITEME
	 */
	public int getPrivilegeMonths () {
		return renewMonths;
	}

	/**
	 * 
	 * TODO: document this method (brpocock, Oct 13, 2009)
	 * 
	 * @return WRITEME
	 */
	public String getProductCode () {
		// default getter (theys, Oct 5, 2009)
		return productCode;
	}

	/**
	 * @return WRITEME
	 */
	public int getProductID () {
		return id;
	}

	/**
	 * WRITEME TODO: document this method (brpocock, Oct 13, 2009)
	 * 
	 * @return WRITEME
	 */
	public int getRenewMonths () {
		// default getter (theys, Oct 5, 2009)
		return renewMonths;
	}

	/**
	 * @return WRITEME
	 */
	public String getTitle () {
		return title;
	}

	/**
	 * 
	 * TODO: document this method (brpocock, Oct 13, 2009)
	 * 
	 * @return WRITEME
	 */
	public boolean isAutoRenew () {
		// default getter (theys, Oct 5, 2009)
		return autoRenew;
	}

	/**
	 * @return WRITEME
	 */
	public boolean isAvailable () {
		return available;
	}

	/**
	 * 
	 * This is an overriding method.
	 * 
	 * @see org.starhope.appius.sql.SQLPeerDatum#set(java.sql.ResultSet)
	 */
	@Override
	protected void set (final ResultSet rs) throws SQLException {
		id = rs.getInt ("id");
		productCode = rs.getString ("productCode");
		price = rs.getBigDecimal ("price");
		renewMonths = rs.getInt ("renewMonths");
		renewDays = rs.getLong ("days");
		autoRenew = "Y".equals (rs.getString ("autoRenew"));
		available = "Y".equals (rs.getString ("available"));
		title = rs.getString ("title");
	}

	/**
	 * 
	 * TODO: document this method (brpocock, Sep 23, 2009)
	 * 
	 * @param price1 WRITEME
	 */
	public void setPrice (final BigDecimal price1) {
		price = price1;
	}

}
