package org.apache.commons.jcs3.engine;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;

/**
 * The CompositeCacheAttributes defines the general cache region settings. If a region is not
 * explicitly defined in the cache.ccf then it inherits the cache default settings.
 * <p>
 * If all the default attributes are not defined in the default region definition in the cache.ccf,
 * the hard coded defaults will be used.
 */
public class CompositeCacheAttributes
    implements ICompositeCacheAttributes
{
    /** Don't change */
    private static final long serialVersionUID = 6754049978134196787L;

    /** default lateral switch */
    private static final boolean DEFAULT_USE_LATERAL = true;

    /** default remote switch */
    private static final boolean DEFAULT_USE_REMOTE = true;

    /** default disk switch */
    private static final boolean DEFAULT_USE_DISK = true;

    /** default shrinker setting */
    private static final boolean DEFAULT_USE_SHRINKER = false;

    /** default max objects value */
    private static final int DEFAULT_MAX_OBJECTS = 100;

    /** default */
    private static final int DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS = 60 * 120;

    /** default interval to run the shrinker */
    private static final int DEFAULT_SHRINKER_INTERVAL_SECONDS = 30;

    /** default */
    private static final int DEFAULT_MAX_SPOOL_PER_RUN = -1;

    /** default */
    private static final String DEFAULT_MEMORY_CACHE_NAME = "org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache";

    /** Default number to send to disk at a time when memory fills. */
    private static final int DEFAULT_CHUNK_SIZE = 2;

    /** allow lateral caches */
    private boolean useLateral = DEFAULT_USE_LATERAL;

    /** allow remote caches */
    private boolean useRemote = DEFAULT_USE_REMOTE;

    /** Whether we should use a disk cache if it is configured. */
    private boolean useDisk = DEFAULT_USE_DISK;

    /** Whether or not we should run the memory shrinker thread. */
    private boolean useMemoryShrinker = DEFAULT_USE_SHRINKER;

    /** The maximum objects that the memory cache will be allowed to hold. */
    private int maxObjs = DEFAULT_MAX_OBJECTS;

    /** maxMemoryIdleTimeSeconds */
    private long maxMemoryIdleTimeSeconds = DEFAULT_MAX_MEMORY_IDLE_TIME_SECONDS;

    /** shrinkerIntervalSeconds */
    private long shrinkerIntervalSeconds = DEFAULT_SHRINKER_INTERVAL_SECONDS;

    /** The maximum number the shrinker will spool to disk per run. */
    private int maxSpoolPerRun = DEFAULT_MAX_SPOOL_PER_RUN;

    /** The name of this cache region. */
    private String cacheName;

    /** The name of the memory cache implementation class. */
    private String memoryCacheName;

    /** Set via DISK_USAGE_PATTERN_NAME */
    private DiskUsagePattern diskUsagePattern = DiskUsagePattern.SWAP;

    /** How many to spool to disk at a time. */
    private int spoolChunkSize = DEFAULT_CHUNK_SIZE;

    /**
     * Constructor for the CompositeCacheAttributes object
     */
    public CompositeCacheAttributes()
    {
        // set this as the default so the configuration is a bit simpler
        memoryCacheName = DEFAULT_MEMORY_CACHE_NAME;
    }

    /**
     * Sets the maxObjects attribute of the CompositeCacheAttributes object
     * <p>
     * @param maxObjs The new maxObjects value
     */
    @Override
    public void setMaxObjects( final int maxObjs )
    {
        this.maxObjs = maxObjs;
    }

    /**
     * Gets the maxObjects attribute of the CompositeCacheAttributes object
     * <p>
     * @return The maxObjects value
     */
    @Override
    public int getMaxObjects()
    {
        return this.maxObjs;
    }

    /**
     * Sets the useDisk attribute of the CompositeCacheAttributes object
     * <p>
     * @param useDisk The new useDisk value
     */
    @Override
    public void setUseDisk( final boolean useDisk )
    {
        this.useDisk = useDisk;
    }

    /**
     * Gets the useDisk attribute of the CompositeCacheAttributes object
     * <p>
     * @return The useDisk value
     */
    @Override
    public boolean isUseDisk()
    {
        return useDisk;
    }

    /**
     * Sets the useLateral attribute of the CompositeCacheAttributes object
     * <p>
     * @param b The new useLateral value
     */
    @Override
    public void setUseLateral( final boolean b )
    {
        this.useLateral = b;
    }

    /**
     * Gets the useLateral attribute of the CompositeCacheAttributes object
     * <p>
     * @return The useLateral value
     */
    @Override
    public boolean isUseLateral()
    {
        return this.useLateral;
    }

    /**
     * Sets the useRemote attribute of the CompositeCacheAttributes object
     * <p>
     * @param useRemote The new useRemote value
     */
    @Override
    public void setUseRemote( final boolean useRemote )
    {
        this.useRemote = useRemote;
    }

    /**
     * Gets the useRemote attribute of the CompositeCacheAttributes object
     * <p>
     * @return The useRemote value
     */
    @Override
    public boolean isUseRemote()
    {
        return this.useRemote;
    }

    /**
     * Sets the cacheName attribute of the CompositeCacheAttributes object
     * <p>
     * @param s The new cacheName value
     */
    @Override
    public void setCacheName( final String s )
    {
        this.cacheName = s;
    }

    /**
     * Gets the cacheName attribute of the CompositeCacheAttributes object
     * <p>
     * @return The cacheName value
     */
    @Override
    public String getCacheName()
    {
        return this.cacheName;
    }

    /**
     * Sets the memoryCacheName attribute of the CompositeCacheAttributes object
     * <p>
     * @param s The new memoryCacheName value
     */
    @Override
    public void setMemoryCacheName( final String s )
    {
        this.memoryCacheName = s;
    }

    /**
     * Gets the memoryCacheName attribute of the CompositeCacheAttributes object
     * <p>
     * @return The memoryCacheName value
     */
    @Override
    public String getMemoryCacheName()
    {
        return this.memoryCacheName;
    }

    /**
     * Whether the memory cache should perform background memory shrinkage.
     * <p>
     * @param useShrinker The new UseMemoryShrinker value
     */
    @Override
    public void setUseMemoryShrinker( final boolean useShrinker )
    {
        this.useMemoryShrinker = useShrinker;
    }

    /**
     * Whether the memory cache should perform background memory shrinkage.
     * <p>
     * @return The UseMemoryShrinker value
     */
    @Override
    public boolean isUseMemoryShrinker()
    {
        return this.useMemoryShrinker;
    }

    /**
     * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
     * <p>
     * @param seconds The new MaxMemoryIdleTimeSeconds value
     */
    @Override
    public void setMaxMemoryIdleTimeSeconds( final long seconds )
    {
        this.maxMemoryIdleTimeSeconds = seconds;
    }

    /**
     * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
     * <p>
     * @return The MaxMemoryIdleTimeSeconds value
     */
    @Override
    public long getMaxMemoryIdleTimeSeconds()
    {
        return this.maxMemoryIdleTimeSeconds;
    }

    /**
     * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
     * This sets the shrinker interval.
     * <p>
     * @param seconds The new ShrinkerIntervalSeconds value
     */
    @Override
    public void setShrinkerIntervalSeconds( final long seconds )
    {
        this.shrinkerIntervalSeconds = seconds;
    }

    /**
     * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
     * This gets the shrinker interval.
     * <p>
     * @return The ShrinkerIntervalSeconds value
     */
    @Override
    public long getShrinkerIntervalSeconds()
    {
        return this.shrinkerIntervalSeconds;
    }

    /**
     * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
     * This sets the maximum number of items to spool per run.
     * <p>
     * If the value is -1, then there is no limit to the number of items to be spooled.
     * <p>
     * @param maxSpoolPerRun The new maxSpoolPerRun value
     */
    @Override
    public void setMaxSpoolPerRun( final int maxSpoolPerRun )
    {
        this.maxSpoolPerRun = maxSpoolPerRun;
    }

    /**
     * If UseMemoryShrinker is true the memory cache should auto-expire elements to reclaim space.
     * This gets the maximum number of items to spool per run.
     * <p>
     * @return The maxSpoolPerRun value
     */
    @Override
    public int getMaxSpoolPerRun()
    {
        return this.maxSpoolPerRun;
    }

    /**
     * By default this is SWAP_ONLY.
     * <p>
     * @param diskUsagePattern The diskUsagePattern to set.
     */
    @Override
    public void setDiskUsagePattern( final DiskUsagePattern diskUsagePattern )
    {
        this.diskUsagePattern = diskUsagePattern;
    }

    /**
     * Translates the name to the disk usage pattern short value.
     * <p>
     * The allowed values are SWAP and UPDATE.
     * <p>
     * @param diskUsagePatternName The diskUsagePattern to set.
     */
    @Override
    public void setDiskUsagePatternName( final String diskUsagePatternName )
    {
        if ( diskUsagePatternName != null )
        {
            final String name = diskUsagePatternName.toUpperCase().trim();
            if ( name.startsWith( "SWAP" ) )
            {
                this.setDiskUsagePattern( DiskUsagePattern.SWAP );
            }
            else if ( name.startsWith( "UPDATE" ) )
            {
                this.setDiskUsagePattern( DiskUsagePattern.UPDATE );
            }
        }
    }

    /**
     * Number to send to disk at the time when memory is full.
     * <p>
     * @return int
     */
    @Override
    public int getSpoolChunkSize()
    {
        return spoolChunkSize;
    }

    /**
     * Number to send to disk at a time.
     * <p>
     * @param spoolChunkSize
     */
    @Override
    public void setSpoolChunkSize( final int spoolChunkSize )
    {
        this.spoolChunkSize = spoolChunkSize;
    }

    /**
     * @return Returns the diskUsagePattern.
     */
    @Override
    public DiskUsagePattern getDiskUsagePattern()
    {
        return diskUsagePattern;
    }

    /**
     * Dumps the core attributes.
     * <p>
     * @return For debugging.
     */
    @Override
    public String toString()
    {
        final StringBuilder dump = new StringBuilder();

        dump.append( "[ " );
        dump.append( "useLateral = " ).append( useLateral );
        dump.append( ", useRemote = " ).append( useRemote );
        dump.append( ", useDisk = " ).append( useDisk );
        dump.append( ", maxObjs = " ).append( maxObjs );
        dump.append( ", maxSpoolPerRun = " ).append( maxSpoolPerRun );
        dump.append( ", diskUsagePattern = " ).append( diskUsagePattern );
        dump.append( ", spoolChunkSize = " ).append( spoolChunkSize );
        dump.append( " ]" );

        return dump.toString();
    }

    /**
     * @see Object#clone()
     */
    @Override
    public ICompositeCacheAttributes clone()
    {
        try
        {
            return (ICompositeCacheAttributes)super.clone();
        }
        catch (final CloneNotSupportedException e)
        {
            throw new RuntimeException("Clone not supported. This should never happen.", e);
        }
    }
}
