/*
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 *
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * The Original Code is jRelationalFramework.
 *
 * The Initial Developer of the Original Code is is.com.
 * Portions created by is.com are Copyright (C) 2000 is.com.
 * All Rights Reserved.
 *
 * Contributor(s): Jonathan Carlson (joncrlsn@users.sf.net)
 * Contributor(s): ____________________________________
 *
 * Alternatively, the contents of this file may be used under the terms of
 * the GNU General Public License (the "GPL") or the GNU Lesser General
 * Public license (the "LGPL"), in which case the provisions of the GPL or
 * LGPL are applicable instead of those above.  If you wish to allow use of
 * your version of this file only under the terms of either the GPL or LGPL
 * and not to allow others to use your version of this file under the MPL,
 * indicate your decision by deleting the provisions above and replace them
 * with the notice and other provisions required by either the GPL or LGPL
 * License.  If you do not delete the provisions above, a recipient may use
 * your version of this file under either the MPL or GPL or LGPL License.
 *
 */
package videoStore;


import com.is.jrf.AbstractDomain;
import com.is.jrf.ColumnSpec;
import com.is.jrf.DatabaseException;
import com.is.jrf.DuplicateRowException;
import com.is.jrf.IntegerColumnSpec;
import com.is.jrf.JoinTable;
import com.is.jrf.LongColumnSpec;
import com.is.jrf.FloatColumnSpec;
import com.is.jrf.MissingAttributeException;
import com.is.jrf.ObjectHasChangedException;
import com.is.jrf.PersistentObject;
import com.is.jrf.SelectSQLBuilder;
import com.is.jrf.StringColumnSpec;
import com.is.jrf.StringJoinColumn;

import com.is.util.sql.JDBCHelper;

import java.sql.SQLException;

import java.util.List;


public class VideoDomain
    extends AbstractDomain
  {

  public VideoDomain()
    {
    super();
    }

  public VideoDomain(int option)
    {
    super(option);
    }

  protected void setup()
    {
    this.setTableName("Video");
    this.setTableAlias("V");
    this.setJDBCHelperPoolName("example");

    this.addColumnSpec(
        new IntegerColumnSpec(
            "ID",     // Column Name
            "getId",
            "setId",
            DEFAULT_TO_NULL,
            SEQUENCED_PRIMARY_KEY));
    this.addColumnSpec(
        new StringColumnSpec(
            "TITLE",    // Column Name
            "getTitle",
            "setTitle",
            DEFAULT_TO_NULL,
            REQUIRED,
            UNIQUE));
    this.addColumnSpec(
        new IntegerColumnSpec(
            "NUM_COPIES",     // Column Name
            "getNumberOfCopies",
            "setNumberOfCopies",
            DEFAULT_TO_ZERO));
    this.addColumnSpec(
        new IntegerColumnSpec(
            "MAX_RENTAL_DAYS",     // Column Name
            "getMaxRentalDays",
            "setMaxRentalDays",
            new Integer(3)));    // Default value
    this.addColumnSpec(
        new IntegerColumnSpec(
            "MEDIA_ID",        // Column Name
            "getMedia.getId", // Getter for saving
            null,             // see the postFind() method
            DEFAULT_TO_NULL));
    this.addColumnSpec(
        new IntegerColumnSpec(
            "GENRE_ID",       // Column Name
            "getGenre.getId", // Getter for saving
            null,             // see the postFind() method
            DEFAULT_TO_NULL));
    this.addColumnSpec(
        new LongColumnSpec(
            "PURCHASE_PRICE",
            "getPurchasePriceInCents",
            "setPurchasePriceInCents",
            DEFAULT_TO_NULL));
    this.addColumnSpec(
        new LongColumnSpec(
            "RENTAL_PRICE",
            "getRentalPriceInCents",
            "setRentalPriceInCents",
            DEFAULT_TO_NULL));
    this.addColumnSpec(
        new FloatColumnSpec(
            "VOLATILITY_PERCENT",
            "getVolatilityPercent",
            "setVolatilityPercent",
            DEFAULT_TO_NULL));

    // This join table sets up an example of how to get better performance
    // by aggregating several objects from one result set.  See the
    // postFind() method.
    JoinTable joinTable =
            new JoinTable(
                "Media M",
                "MEDIA_ID",   // Media column(s)
                "ID");        // Rental column(s)
    joinTable.addJoinColumn(
        new StringJoinColumn(
            "NAME MEDIA_NAME", // column and alias
            null // no setter since this doesn't go into the main obj
            ));
    this.addJoinTable(joinTable);

    } // setup()


  public PersistentObject newPersistentObject()
    {
    return new Video();
    }


  /**
   * Custom SQL for doing a specialized search.
   *
   * @param s a value of type 'String'
   * @return a value of type 'List'
   */
  public List findTitleLike(String s)
    {
    return this.findWhere(
        this.getTableAlias() + ".Title LIKE '%" + s + "%'");
    }


  /**
   * This method finds the Video objects for a given Customer object.  This
   * is a join that is used only for limiting the Videos we return.
   *
   * @param c a value of type 'Customer'
   * @return a value of type 'List'
   */
  public List findForCustomer (Customer c)
    {
    SelectSQLBuilder builder = this.getSelectSQLBuilder();
    // Add a temporary join table
    builder.addJoinTable(
        new JoinTable(
            "Rental R",
            "Id",        // Video column(s)
            "Video_Id,Customer_Id = " + c.getId())); // Rental column(s)
    // Another way to do it:
    // builder.setWhere("R.CustomerId = " + c.getId());
    return this.find(builder);
    }


  /**
   * This method is executed for all found objects.
   *
   * <ol>
   * <li>Uses a CustomerDomain object to add the Customer objects to
   *     this Video.</li>
   * <li>Creates an aggregate Media object using the data in the result set.
   *     This technique is used for efficiency.</li>
   * <li>Sets the Genre object for this video based on the Genre Id</li>
   * </ol>
   *
   * @param aPO a value of type 'PersistentObject'
   * @param aJDBCHelper a value of type 'JDBCHelper' - This should not be
   * used for another query, since it is being used to process the original
   * result set.  A clone of it can do another query, however.
   */
  protected void postFind(PersistentObject aPO, JDBCHelper aJDBCHelper)
    {
    Video video = (Video) aPO;
    List customers = new CustomerDomain(NO_POST_FIND).findForVideo(video);
    video.setCustomers(customers);

    // Attach the appropriate media and genre objects
    Integer mediaId = null;
    Integer genreId = null;
    try
        {
        Media media = new Media(
            aJDBCHelper.getInteger("MEDIA_ID"),
            aJDBCHelper.getString("MEDIA_NAME"));
        video.setMedia(media);
        genreId = aJDBCHelper.getInteger("GENRE_ID");
        }
    catch (SQLException e)
        {
        throw new DatabaseException(e);
        }

    // Note, that the below code would not work if we were to pass in
    // aJDBCHelper to the find() because aJDBCHelper is already involved in
    // iterating through a result set.  The clone of aJDBCHelper does work
    // because it is a different instance (and hence a different connection
    // and transaction).  The downside is that the clone may not (depending
    // on the database) be able to see anything inserted or updated in the
    // current transaction.  This is something to keep in mind in case your
    // find methods don't return what you think should be returned!

    JDBCHelper jdbcHelperClone = null;
    try
        {
        jdbcHelperClone = (JDBCHelper) aJDBCHelper.clone();
        }
    catch (CloneNotSupportedException e)
        {
        }
    Genre genre = (Genre) new GenreDomain().find(genreId, jdbcHelperClone);
    video.setGenre(genre);

    } // postFind(...)


  /**
   * This method is executed before any obect is saved.
   */
  protected void preSave(PersistentObject aPO,
                         JDBCHelper aJDBCHelper)
          throws
          ObjectHasChangedException,
          MissingAttributeException,
          DuplicateRowException
    {
    // This does nothing right now. This is just here to draw attention to
    // the fact that it could be used.
    }


  }