/*
 * Licensed Materials - Property of Rogue Wave Software, Inc. 
 * © Copyright Rogue Wave Software, Inc. 2014, 2015 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */
package datasource.explorer;

import ilog.cpl.model.AttributeValueEvent;
import ilog.cpl.model.AttributeValueListener;
import ilog.cpl.model.IlpAttribute;
import ilog.cpl.model.IlpAttributeGroup;
import ilog.cpl.model.IlpAttributeValueChangeSupport;
import ilog.cpl.model.IlpAttributeValueHolder;
import ilog.cpl.model.IlpClass;
import ilog.cpl.model.IlpDefaultAttribute;
import ilog.cpl.model.IlpDefaultClass;
import ilog.cpl.model.IlpObject;

import java.io.File;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;

/**
 * JTGO data source explorer sample 2 using a custom <code>IlpClass</code>.
 * See <A href="../../../index.html">index.html</A> for a description of this sample.
 *
 * This class implements the <code>IlpObject</code> interface to wrap <code>java.io.File</code>.
 */
public class FileObject implements IlpObject {
  // Create the attributes of the IlpClass
  public static IlpDefaultAttribute EXISTS =
    new IlpDefaultAttribute("exists",Boolean.class, true);
  public static IlpDefaultAttribute NAME =
    new IlpDefaultAttribute("name",String.class, true);
  public static IlpDefaultAttribute PARENT =
    new IlpDefaultAttribute("parent",String.class, true);
  public static IlpDefaultAttribute PATH =
    new IlpDefaultAttribute("path",String.class, true);
  public static IlpDefaultAttribute DIRECTORY =
    new IlpDefaultAttribute("directory",Boolean.class, true);
  public static IlpDefaultAttribute HIDDEN =
    new IlpDefaultAttribute("hidden",Boolean.class, true);
  public static IlpDefaultAttribute LASTMODIFIED =
    new IlpDefaultAttribute("lastModified", Long.class, true);
  public static IlpDefaultAttribute LENGTH =
    new IlpDefaultAttribute("length", Long.class, true);
  public static IlpDefaultAttribute ROOT =
    new IlpDefaultAttribute("root", Boolean.class, true);
  public static IlpDefaultAttribute TYPE =
    new IlpDefaultAttribute("type", String.class, true);

  protected static IlpDefaultClass ILPCLASS;

  // Initialize the IlpClass that corresponds to the FileObject Java class
  static {
    ILPCLASS = new IlpDefaultClass("datasource.explorer.FileObject") {
      /**
       * This method is called when objects are loaded from XML.
       */
       public IlpObject newInstance(IlpClass ilpClass, Object identifier,
        boolean initializeAttributeValues) {
          return new FileObject((File)identifier,ilpClass);
       }
    };
    ILPCLASS.addAttribute(EXISTS);
    ILPCLASS.addAttribute(NAME);
    ILPCLASS.addAttribute(PARENT);
    ILPCLASS.addAttribute(PATH);
    ILPCLASS.addAttribute(DIRECTORY);
    ILPCLASS.addAttribute(HIDDEN);
    ILPCLASS.addAttribute(LASTMODIFIED);
    ILPCLASS.addAttribute(LENGTH);
    ILPCLASS.addAttribute(ROOT);
    ILPCLASS.addAttribute(TYPE);
  }

  // A FileObject wraps a file
  protected File file;
  // A FileObject instanceis by default of the FileObject IlpClass,
  // but it may be of a subclass, so we need to store the ilpClass here.
  protected IlpClass ilpClass;
  // Use an IlpAttributeValueChangeSupport to handle all notification
  // and listeners registration
  protected IlpAttributeValueChangeSupport support = new IlpAttributeValueChangeSupport(this);
  // Use an hashmap to cache some attribute values, as the File class
  // always access the file system each time one its methods is called
  protected Map attributeValueCache = new HashMap();

  /**
   * Creates a <tt>FileObject</tt> from a <tt>java.io.File</tt>
   */
  public FileObject(File file) {
    this.file = file;
    // by default, the IlpClass is the one returned by GetIlpClass()
    this.ilpClass = GetIlpClass();
  }

  /**
   * Creates a <tt>FileObject</tt> from a <tt>java.io.File</tt>.
   * The <tt>IlpClass</tt> parameter permits to support other IlpClasses
   * than the static ILPCLASS defined in the FileObject class.
   */
  public FileObject(File file, IlpClass ilpClass) {
    this.file = file;
    this.ilpClass = ilpClass;
  }

  /***
   * Method GetIlpClass
   * The class managers will recognize this static method and use its result
   * as the <tt>IlpClass</tt> to represent samples.datasource.explorer2.FileObject
   */
  public static IlpClass GetIlpClass() {
    return ILPCLASS;
  }

  // Methods from IlpObject interface

  /**
   * Returns the identifier of the <code>IlpObject</code>.
   * This identifier is an <code>Object</code> that can be used to identify
   * and retrieve this <code>IlpObject</code>. It must be unique.
   */
  public Object getIdentifier() {
    return file;
  }

  /**
   * Retrieves the IlpClass of this object.
   * @return The IlpClass of this object.
   */
  public IlpClass getIlpClass() {
    return ilpClass;
  }

  /**
   * This method initializes the attribute values of the object with the default
   * attribute values, if there are any. There is none here.
   */
  public void initializeDefaultValues() {
    // nothing to do here
  }

  // Methods from IlpAttributeValueHolder interface

  /**
   * Returns the model that defines which attributes are allowed
   * in this instance.
   */
  public IlpAttributeGroup getAttributeGroup () {
    return getIlpClass();
  }

  /**
   * Retrieves the value of an attribute of this object.
   * @param attribute The attribute whose value is to be retrieved.
   * @return The value of the attribute or <CODE>VALUE_NOT_SET</CODE> if no
   * value has been set.
   */
  public Object getAttributeValue (IlpAttribute attribute) {
    if (attributeValueCache.containsKey(attribute)) {
      return attributeValueCache.get(attribute);
    }
    if (attribute == EXISTS) {
      Object result = file.exists()?Boolean.TRUE:Boolean.FALSE;
      attributeValueCache.put(attribute, result);
      return result;
    }
    if (attribute == NAME) {
      String name = file.getName();
      // for the roots the name may be null, so return the path in this case
      Object result = name != null && name.length() != 0 ?name:file.getPath();
      attributeValueCache.put(attribute, result);
      return result;
    }
    if (attribute == PARENT) {
      Object result = file.getParent();
      attributeValueCache.put(attribute, result);
      return result;
    }
    if (attribute == PATH) {
      Object result = file.getPath();
      attributeValueCache.put(attribute, result);
      return result;
    }
    if (attribute == DIRECTORY) {
      Object result = file.isDirectory()?Boolean.TRUE:Boolean.FALSE;
      attributeValueCache.put(attribute, result);
      return result;
    }
    if (attribute == HIDDEN) {
      Object result = file.isHidden()?Boolean.TRUE:Boolean.FALSE;
      attributeValueCache.put(attribute, result);
      return result;
    }
    if (attribute == LASTMODIFIED) {
      Object result = new Long(file.lastModified());
      attributeValueCache.put(attribute, result);
      return result;
    }
    if (attribute == LENGTH) {
      Object result = new Long(file.length());
      attributeValueCache.put(attribute, result);
      return result;
    }
    if (attribute == ROOT) {
      Object result = file.getParent() == null ?Boolean.TRUE:Boolean.FALSE;
      attributeValueCache.put(attribute, result);
      return result;
    }
    if (attribute == TYPE) {
      Object result = URLConnection.getFileNameMap().getContentTypeFor(file.getName());
      attributeValueCache.put(attribute, result);
      return result;
    }
    return null;
  }

  /**
   * Returns <CODE>true</CODE> if the requested attribute is part of the
   * attribute group of this instance and a value has been set for this
   * attribute.
   */
  public boolean hasAttributeValue (IlpAttribute a) {
    return getAttributeGroup().hasAttribute(a);
  }

  /**
   * Sets the value of an attribute of this object. To remove the value of an
   * attribute, you can pass <CODE>VALUE_NOT_SET</CODE> for the <CODE>value
   * </CODE> argument.
   * @param attribute The attribute whose value is set.
   * @param value The new value of the attribute or <CODE>VALUE_NOT_SET</CODE>
   * to remove the value of the attribute.
   * @throws IllegalArgumentException if the attribute cannot have
   * its value modified.
   */
  public void setAttributeValue (IlpAttribute attribute, Object value) {
    if (attribute == LASTMODIFIED) {
      if (value instanceof Number) {
        file.setLastModified(((Number)value).longValue());
        attributeValueCache.remove(LASTMODIFIED);
        fireEvent(new AttributeValueEvent(this, LASTMODIFIED));
      } else
        throw new IllegalArgumentException(value+" is not acceptable as value of attribute "+attribute);
    }
     }

  /**
   * Retrieves the value of an attribute of this object.
   * @param attribute The name of the attribute whose value is to be retrieved.
   * @return The value of the attribute or <CODE>VALUE_NOT_SET</CODE> if no
   * value has been set.
   */
  public Object getAttributeValue (String attribute) {
    IlpAttribute attr = getAttributeGroup().getAttribute(attribute);
    if (attr != null)
      return getAttributeValue(attr);
    return IlpAttributeValueHolder.VALUE_NOT_SET;
  }

  /**
   * Sets the value of an attribute of this object. To remove the value of an
   * attribute, you can pass <CODE>VALUE_NOT_SET</CODE> for the <CODE>value
   * </CODE> argument.
   * @param attribute The name of the attribute whose value is set.
   * @param value The new value of the attribute or <CODE>VALUE_NOT_SET</CODE>
   * to remove the value of the attribute.
   * @throws IllegalArgumentException if the attribute cannot have
   * its value modified.
   */
  public void setAttributeValue (String attribute, Object value) {
    IlpAttribute attr = getAttributeGroup().getAttribute(attribute);
    if (attr != null)
      setAttributeValue(attr, value);
  }

  /**
   * Adds a listener to attribute value changes.
   */
  public void addAttributeValueListener (AttributeValueListener l) {
    support.addAttributeValueListener(l);
  }

  /**
   * Removes the given listener from the attribute value change
   * notifications.
   */
  public void removeAttributeValueListener (AttributeValueListener l) {
    support.removeAttributeValueListener(l);
  }

  /**
   * Fires an event to the listeners.
   */
  public void fireEvent (AttributeValueEvent ev) {
    support.fireEvent(ev);
  }
}