/*
 * 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.datasource.structure.IlpChild;
import ilog.cpl.datasource.structure.IlpContainer;
import ilog.cpl.model.IlpObject;
import ilog.cpl.datasource.IlpDefaultDataSource;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

/**
 * JTGO data source explorer sample 2 using a custom IlpClass.
 * See <A href="../../../index.html">index.html</A> for a description of this sample.
 */
public class FileDataSource extends IlpDefaultDataSource {
    Logger log;

    /**
     * Constructor.
     */
    public FileDataSource(Logger log) {
      // call the constructor of IlpDefaultDataSource
      super();
      this.log=log;
      // loads the roots into the data source
      File[] rootdirs = File.listRoots();
      addFiles(rootdirs);
    }

    /**
     * Adds files to the data source.
     * @param files The java.io.Files to be wrapped by FileObject.
     */
    protected synchronized void addFiles(File[] files) {
      // Here we avoid calling IlpDefaultDataSource.addObject, as in this case
      // object would be inserted one by one. It would result in very low
      // performance, as each inserted object will result in one notification,
      // and each notification would result in a redrawing (in the tree for
      // example). So here the IlpObjects are stored in a list before calling
      // the addObjects method which will result in only one notification
      List filesAsIlpObjects = new ArrayList(files.length);
      for (int i = 0; i < files.length; i++) {
        // use the file itself as the object identifier
        File id = files[i];
        try {
          if (id.canRead()) {
            if (getObject(id) == null) {
              IlpObject ilpObject = new FileObject(files[i]);
              filesAsIlpObjects.add(ilpObject);
            }
          }
        } catch (Exception e) {
          // just ignore entry
        }
      }
      if (filesAsIlpObjects.size() != 0)
        addObjects(filesAsIlpObjects);
    }

    /**
     * This method in conjunction with the two previous classes
     * realizes load-on-demand in the data source.
     */
    public synchronized IlpContainer getContainerInterface(Object idOrIlpObject) {
      // retrieve the object from the id or the object
      IlpObject object = idOrIlpObject instanceof IlpObject ? (IlpObject)idOrIlpObject : getObject(idOrIlpObject);
      // if we retrieved the object and it is an instance of FileObject.GetIlpClass()
      if (object != null && FileObject.GetIlpClass().isAssignableFrom(object.getIlpClass()))  {
        // retrieve the file, and test if it is a directory, if not, return null.
        Boolean isDirectory = (Boolean)object.getAttributeValue(FileObject.DIRECTORY);
        if (isDirectory.booleanValue())
          return DIRECTORY_LOADER;
        else
          return null;
      }
      // for all other classes than FileObject.GetIlpClass(), use the regular implementation,
      // So the FileDataSource can behave like an ordinary IlpDefaultDataSource for
      // all other classes.
      return super.getContainerInterface(idOrIlpObject);
    }

    /**
     * Container interface for file objects.
     * This interface uses the listFiles method to get the list of
     * children. It tries to add them to the data source content, doing the
     * loading on demand, and then returns the list of identifiers.
     */
    IlpContainer DIRECTORY_LOADER = new IlpContainer(){
      public Collection getChildren(IlpObject object) {
        // the file is supposed to be a directory
        File directory = (File)object.getIdentifier();
        File[] files = directory.listFiles();
        if (files == null)
          return Collections.EMPTY_LIST;
        List filesIds = new ArrayList(files.length);
        for (int i = 0; i < files.length; i++) {
          // 1st get all the identifiers
          filesIds.add(files[i]);
        }

        // then add the files
        addFiles(files);
        return filesIds;
      }
    };

    /**
     * This method in conjunction with the two previous classes
     * realizes load-on-demand in the data source.
     */
    public synchronized IlpChild getChildInterface(Object idOrIlpObject) {
      // retrieve the object from the id or the object
      IlpObject object = idOrIlpObject instanceof IlpObject ? (IlpObject)idOrIlpObject : getObject(idOrIlpObject);
      // if the object is an instance of FileObject.GetIlpClass()
      if (object != null && FileObject.GetIlpClass().isAssignableFrom(object.getIlpClass()))  {
        // retrieve the file it contains and returns it (see FILE_PARENT below).
        File file = (File)object.getIdentifier();
        File parentFile = file.getParentFile();
        if (parentFile != null) {
          return FILE_PARENT;
        } else {
          return null;
        }
      }
      return super.getChildInterface(idOrIlpObject);
    }

    /**
     * Child interface for file objects.
     * This interface uses the getParentFile method to get the parent.
     */
    IlpChild FILE_PARENT = new IlpChild() {
      public Object getParent(IlpObject object) {
        File file = (File)object.getIdentifier();
        File parentFile = file.getParentFile();
        return parentFile;
      }
    };
}