/*
 * ScanManagerConfig.java
 *
 * Created on July 13, 2006, 3:42 PM
 *
 * %W% %E%
 *
 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Oracle or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */

package com.sun.jmx.examples.scandir.config;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;


/**
 * The <code>ScanManagerConfig</code> Java Bean is used to model
 * the configuration of the {@link 
 * com.sun.jmx.examples.scandir.ScanManagerMXBean ScanManagerMXBean}.
 *  
 * The {@link 
 * com.sun.jmx.examples.scandir.ScanManagerMXBean ScanManagerMXBean} will 
 * use this configuration to initialize the {@link 
 * com.sun.jmx.examples.scandir.ResultLogManagerMXBean ResultLogManagerMXBean} 
 * and create the {@link 
 * com.sun.jmx.examples.scandir.DirectoryScannerMXBean DirectoryScannerMXBeans}
 * <p>
 * This class is annotated for XML binding.
 * </p> 
 * 
 * @author Sun Microsystems, 2006 - All rights reserved.
 **/
@XmlRootElement(name="ScanManager",
        namespace="jmx:com.sun.jmx.examples.scandir.config")
public class ScanManagerConfig {
    
    // A logger for this class
    //
    // private static final Logger LOG =
    //        Logger.getLogger(ScanManagerConfig.class.getName());
    
    /**
     * A set of DirectoryScannerConfig objects indexed by their names.
     **/
    private final Map<String, DirectoryScannerConfig> directoryScanners;
    
    /**
     * The initial Result Log configuration.
     */
    private ResultLogConfig initialResultLogConfig;

    /**
     * Holds value of property name. The name of the configuration 
     *       usually corresponds to
     *       the value of the {@code name=} key of the {@code ObjectName}
     *       of the {@link 
     *       com.sun.jmx.examples.scandir.ScanDirConfigMXBean 
     *       ScanDirConfigMXBean} which owns this configuration.
     **/
    private String name;

    /**
     * Creates a new instance of ScanManagerConfig. 
     * <p>You should not use this constructor directly, but use 
     *    {@link #ScanManagerConfig(String)} instead.
     * </p>
     * <p>This constructor is tagged deprecated so that the compiler 
     *    will generate a warning if it is used by mistake.
     * </p>
     * @deprecated Use {@link #ScanManagerConfig(String)} instead. This 
     *             constructor is used through reflection by the XML
     *             binding framework.
     */
    public ScanManagerConfig() {
        this(null,true);
    }

    /**
     * Creates a new instance of ScanManagerConfig. 
     * @param name The name of the configuration which usually corresponds to
     *       the value of the {@code name=} key of the {@code ObjectName}
     *       of the {@link 
     *       com.sun.jmx.examples.scandir.ScanDirConfigMXBean 
     *       ScanDirConfigMXBean} which owns this configuration.
     **/
    public ScanManagerConfig(String name) {
        this(name,false);
    }
    
    // Our private constructor...
    private ScanManagerConfig(String name, boolean allowsNull) {
        if (name == null && allowsNull==false)
            throw new IllegalArgumentException("name=null");
        this.name = name;
        directoryScanners = new LinkedHashMap<String,DirectoryScannerConfig>();
        this.initialResultLogConfig = new ResultLogConfig();
        this.initialResultLogConfig.setMemoryMaxRecords(1024);        
    }
    
    // Creates an array for deep equality.
    private Object[] toArray() {
        final Object[] thisconfig = {
            name,directoryScanners,initialResultLogConfig
        };
        return thisconfig;
    }
    
    // equals
    @Override
    public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof ScanManagerConfig)) return false;
        final ScanManagerConfig other = (ScanManagerConfig)o;
        if (this.directoryScanners.size() != other.directoryScanners.size()) 
            return false;
        return Arrays.deepEquals(toArray(),other.toArray());
    }
    
    @Override
    public int hashCode() {
        final String key = name;
        if (key == null) return 0;
        else return key.hashCode();
    }

    /**
     * Gets the name of this configuration. The name of the configuration 
     *       usually corresponds to
     *       the value of the {@code name=} key of the {@code ObjectName}
     *       of the {@link 
     *       com.sun.jmx.examples.scandir.ScanDirConfigMXBean 
     *       ScanDirConfigMXBean} which owns this configuration.
     * @return The name of this configuration.
     */
    @XmlAttribute(name="name",required=true)
    public String getName() {
        return this.name;
    }

    /**
     * Sets the name of this configuration. The name of the configuration 
     *       usually corresponds to
     *       the value of the {@code name=} key of the {@code ObjectName}
     *       of the {@link 
     *       com.sun.jmx.examples.scandir.ScanDirConfigMXBean 
     *       ScanDirConfigMXBean} which owns this configuration.
     *       <p>Once set this value cannot change.</p>
     * @param name The name of this configuration.
     */
    public void setName(String name) {
        if (this.name == null)
            this.name = name;
        else if (name == null)
            throw new IllegalArgumentException("name=null");
        else if (!name.equals(this.name))
            throw new IllegalArgumentException("name="+name);
    }

   /**
    * Gets the list of Directory Scanner configured by this 
    * configuration. From each element in this list, the 
    * {@link com.sun.jmx.examples.scandir.ScanManagerMXBean ScanManagerMXBean}
    * will create, initialize, and register a {@link 
    * com.sun.jmx.examples.scandir.DirectoryScannerMXBean}.
    * @return The list of Directory Scanner configured by this configuration.
    */
    @XmlElementWrapper(name="DirectoryScannerList", 
            namespace=XmlConfigUtils.NAMESPACE)
    @XmlElementRef
    public DirectoryScannerConfig[] getScanList() {
        return directoryScanners.values().toArray(new DirectoryScannerConfig[0]);
    }

   /**
    * Sets the list of Directory Scanner configured by this 
    * configuration. From each element in this list, the 
    * {@link com.sun.jmx.examples.scandir.ScanManagerMXBean ScanManagerMXBean}
    * will create, initialize, and register a {@link 
    * com.sun.jmx.examples.scandir.DirectoryScannerMXBean}.
    * @param scans The list of Directory Scanner configured by this configuration.
    */
    public void setScanList(DirectoryScannerConfig[] scans) {
        directoryScanners.clear();
        for (DirectoryScannerConfig scan : scans)
            directoryScanners.put(scan.getName(),scan);
    }

    /**
     * Get a directory scanner by its name.
     * 
     * @param name The name of the directory scanner. This is the
     *             value returned by {@link 
     *             DirectoryScannerConfig#getName()}.
     * @return The named {@code DirectoryScannerConfig}
     */
    public DirectoryScannerConfig getScan(String name) {
        return directoryScanners.get(name);
    }

    /**
     * Adds a directory scanner to the list. 
     * <p>If a directory scanner
     * configuration by that name already exists in the list, it will
     * be replaced by the given <var>scan</var>.
     * </p>
     * @param scan The {@code DirectoryScannerConfig} to add to the list.
     * @return The replaced {@code DirectoryScannerConfig}, or {@code null}
     *         if there was no {@code DirectoryScannerConfig} by that name 
     *         in the list.
     */
    public DirectoryScannerConfig putScan(DirectoryScannerConfig scan) {
        return this.directoryScanners.put(scan.getName(),scan);
    }
    
    // XML value of  this object.
    public String toString() {
        return XmlConfigUtils.toString(this);
    }

    /**
     * Removes the named directory scanner from the list.
     * 
     * @param name The name of the directory scanner. This is the
     *             value returned by {@link 
     *             DirectoryScannerConfig#getName()}.
     * @return The removed {@code DirectoryScannerConfig}, or {@code null}
     *         if there was no directory scanner by that name in the list.
     */
    public DirectoryScannerConfig removeScan(String name) {
       return this.directoryScanners.remove(name);
    }

    /**
     * Gets the initial Result Log Configuration.
     * @return The initial Result Log Configuration.
     */
    @XmlElement(name="InitialResultLogConfig",namespace=XmlConfigUtils.NAMESPACE)
    public ResultLogConfig getInitialResultLogConfig() {
        return this.initialResultLogConfig;
    }

    /**
     * Sets the initial Result Log Configuration.
     * @param initialLogConfig The initial Result Log Configuration.
     */
    public void setInitialResultLogConfig(ResultLogConfig initialLogConfig) {
        this.initialResultLogConfig = initialLogConfig;
    }

    /**
     * Creates a copy of this object, with the specified name.
     * @param newname the name of the copy.
     * @return A copy of this object.
     **/
    public ScanManagerConfig copy(String newname) {
        return copy(newname,this);
    }
    
    // Copy by XML cloning, then change the name.
    //
    private static ScanManagerConfig 
            copy(String newname, ScanManagerConfig other) {
        ScanManagerConfig newbean = XmlConfigUtils.xmlClone(other);
        newbean.name = newname;
        return newbean;
    }
}
