/***************************************************************************
    Copyright          : (C) 2002 by Neoworks Limited. All rights reserved
    URL                : http://www.neoworks.com
 ***************************************************************************/
/***************************************************************************
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

/*
 * JukeXAttributeValue.java
 *
 * Created on 10 April 2002, 12:52
 */

package com.neoworks.jukex.sqlimpl;

import java.sql.*;
import com.neoworks.jukex.*;

import org.apache.log4j.Category;

import com.neoworks.connectionpool.PoolManager;

/**
 * A JukeX AttributeValue, holding the value of an Attribute.
 *
 * @author Nick Vincent <a href="mailto:nick@neoworks.com">nick@neoworks.com</a>
 */
public class JukeXAttributeValue implements AttributeValue, DatabaseObject
{
	private static final Category log = Category.getInstance(JukeXAttributeValue.class.getName());
	private static final boolean logDebugEnabled = log.isDebugEnabled();
	private static final boolean logInfoEnabled = log.isInfoEnabled();
	
	private long _attrenumid = -1;
	private String _stringValue = null;
	private int _value = -1;
	private Attribute _attribute = null;
	
	/**
	 * Do NOT use this method if you wish an AttributeValue to be stored in the
	 * database.  This call will <b>not</b> store an attribute in the database.
	 */
	public JukeXAttributeValue( long id , Attribute attr , String s )
	{
		this._attrenumid = id;
		this._attribute = attr;
		this._stringValue = s;
	}
	
	/** 
	 * Do NOT use this method if you wish an AttributeValue to be stored in the
	 * database.  This call will <b>not</b> store an attribute in the database.
	 */
	public JukeXAttributeValue ( Attribute attr , int value )
	{
		this._attribute = attr;
		this._value = value;
	}
	
	/** Creates a new instance of JukeXAttributeValue */
	JukeXAttributeValue( Attribute attr , String s )
	{
		if ( s != null )
		{
			this._stringValue = s;
			this._attribute = attr;

			// To get a string first we need to go to the database and see if it's
			// already present in the enumeration for the given Attribute
			Connection conn = null;
			long attributeID = ((DatabaseObject)attr).getId();

			try
			{
				conn = PoolManager.getInstance().getConnection( JukeXTrackStore.DB_NAME );
				PreparedStatement findValue = conn.prepareStatement( "SELECT id FROM AttributeEnum "+
					"WHERE attributeid=? AND value=?" );
				findValue.setLong( 1 , attributeID );
				findValue.setString( 2 , s );

				ResultSet existingEntries = findValue.executeQuery();
				if ( existingEntries.next() )
				{
					this._attrenumid = existingEntries.getLong( 1 );
				}
				else
				{
					// Did not find an entry corresponding to this, so add a new one
					PreparedStatement insertNewRecord = conn.prepareStatement( "INSERT INTO AttributeEnum (attributeid,value) " +
						"VALUES ( ? , ? )" );
					insertNewRecord.setLong( 1 , attributeID );
					insertNewRecord.setString( 2 , s );
					insertNewRecord.executeUpdate();

					// Now find the generated id of the entry we added (this 
					// shouldn't be necessary when the JDK1.4 SQL Extensions are 
					// implemented in the MySQL driver)
					ResultSet newEntryId = findValue.executeQuery( "SELECT LAST_INSERT_ID()" );
					if ( !newEntryId.next() )
					{
						log.error("Something awful happened.  An INSERT somehow failed to appear in the database");
					}
					else
					{
						this._attrenumid = newEntryId.getLong( 1 );
					}
				}
			}
			catch ( Exception e )
			{
				log.error( "Encountered an exception whilst trying to create a String AttributeValue" , e );
			}
			finally
			{
				try { conn.close(); } catch ( SQLException ignore ) {}
			}
		}
	}
	
	public long getId()
	{
		return this._attrenumid;
	}
 	
	public int getInt()
	{
		if ( this._attribute.getType() != Attribute.TYPE_INT )
		{
			throw new RuntimeException( "Cannot return type 'int' from an AttributeValue of a different type" );
		}
		
		return _value;
	}
	
	public String getString()
	{
		if ( this._attribute.getType() != Attribute.TYPE_STRING )
		{
			throw new RuntimeException( "Cannot return type 'String' from an AttributeValue of a different type" );
		} 
		
		return this._stringValue;
	}
	
	public int getType()
	{
		return this._attribute.getType();
	}
	
	/** 
	 * Changes the value of the current AttributeValue.  Every other object
	 * which uses this attribute value will reflect this change.  If the
	 * required behaviour is to change the value *without* affecting other
	 * Tracks using this attribute then create a new value, and use this
	 * instead.
	 */
	public void setString(String newval)
	{
		if ( this._attribute.getType() != Attribute.TYPE_STRING )
		{
			throw new RuntimeException( "Cannot complete setString() on an AttributeValue of a different type" );
		}
		
		Connection conn = null;
		
		try
		{
			conn = PoolManager.getInstance().getConnection( JukeXTrackStore.DB_NAME );
			PreparedStatement updateStatement = conn.prepareStatement( "UPDATE AttributeEnum SET value = ? WHERE id = ?" );
			updateStatement.setString( 1 , newval );
			updateStatement.setLong( 2 , this._attrenumid );
			
			updateStatement.executeUpdate();
			this._stringValue = newval;
		}
		catch ( Exception e )
		{
			log.error("Encountered an exception attempting to change an AttributeValue string value");
		}
		finally
		{
			try { conn.close(); } catch ( SQLException ignore ) {}
		}
	}
	
	public String toString()
	{
		if ( this._attribute.getType() == Attribute.TYPE_STRING )
		{
			return this._stringValue;
		}
		else if ( this._attribute.getType() == Attribute.TYPE_INT )
		{
			return String.valueOf( this._value );
		}
		return " UNKNOWN TYPE!!!";
	}
}
