import com.webobjects.eocontrol.*;
import com.webobjects.eoaccess.*;
import com.webobjects.foundation.*;

/*
 * On any complex WebObjects project, it is very helpful to have a custom abstract EO
 * superclass, as there are many possible hooks that can be used to affect all
 * your EOs all at once.  This file is an example of some of the methods you might
 * want to have in such a class.  The EOGJavaSource template provides an example of
 * how to alter the templates to insert your own superclass instead of EOGenericRecord.
 * There is no reason this class has to be present in the EOModel itself.
 */


public class MyGenericRecord extends EOGenericRecord
{

    /**
     * Returns the EOEntity instance associated with the receiver's class.
     */
    public EOEntity eoEntity()
    {
        EOClassDescription classDesc = classDescription();
 
        if (classDesc instanceof EOEntityClassDescription)
            return ((EOEntityClassDescription)classDesc).entity();
        return null;
    }

    /**
     * Returns the receiver's EOGlobalID.
     */
    public EOGlobalID globalID()
    {
        EOEditingContext myContext = editingContext();
        return (myContext == null) ? null : myContext.globalIDForObject(this);
    }

    /**
     * Returns the receiver's primary key.
     */
    public NSDictionary primaryKey()
    {
        return EOUtilities.primaryKeyForObject(editingContext(), this);
    }

    /**
     * Returns true if this EO has never been saved to the database, i.e.
     * represents a new record that needs to be inserted.
     */
    public boolean isNewObject()
    {
        EOGlobalID myID = globalID();
        return (myID == null || myID.isTemporary());
    }

    /**
     * Returns the current database snapshot() for the receiver.  Differs from
     * snapshot() in that non-class-property foreign keys etc. are present, but
     * relationship values are not.
     */
    public NSDictionary databaseSnapshot()
    {
        EOGlobalID myID = globalID();

        if (myID == null) return null;

        EOObjectStoreCoordinator rootStore = (EOObjectStoreCoordinator)editingContext().rootObjectStore();
        EODatabaseContext dbContext = (EODatabaseContext)rootStore.objectStoreForGlobalID(myID);
        return (dbContext == null)? null : dbContext.snapshotForGlobalID(myID);
    }


    public boolean shouldUppercaseAttributeNamed(String name)
    {
        /*
         * Alternatively, a list of keys could be kept in the EOEntity's userInfo, or
         * subclasses could override this method to do checks in code.
         */
        NSDictionary info = this.eoEntity().attributeNamed(name).userInfo();
        if (info == null) return false;
        return Boolean.valueOf((String)info.objectForKey("ShouldUppercase")).booleanValue();
    }

    /**
     * Overrides to do some generic processing on String values.  This method typically
     * gets called before any value is stored in the EO, and also before saving as
     * part of EOF's validation scheme.
     */
    public Object validateValueForKey(Object value, String key) throws NSValidation.ValidationException
    {
        if ( value != null && value instanceof String )
        {
            EOAttribute attrib = this.eoEntity().attributeNamed(key);

            /* the attribute may be null for derived keys; must check for that */
            if (attrib != null && "java.lang.String".equals(attrib.className()))
            {
                if ( this.shouldUppercaseAttributeNamed(key) )
                    value = ((String)value).toUpperCase();
                if ( attrib.width() > 0 && ((String)value).length() > attrib.width() )
                    value = ((String)value).substring(0, attrib.width());
            }

            /* Null out blank strings... the adapter sometimes does this anyways, in which case
               EOF null-value validations are bypassed and the SQL statement will fail.
               If we null out here, then EOF's validation will catch it. */
            if (value != null && ((String)value).length() == 0)
                value = null;
        }

        return super.validateValueForKey(value, key);
    }

    // Methods from Jonathan Rentzsch. Helpers for creating scalar cover methods
    // for generated getter/setter that have Number as their value. For example,
    // if there is a Number key "isActiveElement", you could do:
    // 
    //   public boolean isActive() { return toBoolean(isActiveElement()); }
    //   public void setIsActive(boolean val) { setIsActiveElement(toNumber(val)); }

    protected static boolean toBoolean(Number aValue) {
        boolean result = false;
        if( aValue != null )
            result = aValue.intValue() == 0 ? false : true;
        return result;
    }
    
    protected static int toInt(Number aValue) {
        int result = 0;
        if( aValue != null )
            result = aValue.intValue();
        return result;
    }
    
    protected static double toDouble(Number aValue) {
        double result = 0;
        if( aValue != null )
            result = aValue.doubleValue();
        return result;
    }
    
    protected static float toFloat(Number aValue) {
        float result = 0;
        if( aValue != null )
            result = aValue.floatValue();
        return result;
    }
    
    protected static Number toNumber(boolean aValue) {
        return new Integer(aValue? 1 : 0);
    }
    
    protected static Number toNumber(int aValue) {
        return new Integer(aValue);
    }
    
    protected static Number toNumber(double aValue) {
        return new Double(aValue);
    }
    
    protected static Number toNumber(float aValue) {
        return new Float(aValue);
    }
}