// $Id: DodsDirDatasetSource.java,v 1.6 2004/11/30 22:49:12 edavis Exp $

package thredds.cataloggen.config;

import thredds.catalog.InvDatasetImpl;
import thredds.catalog.InvDataset;

import java.util.List;
import java.util.ArrayList;

import java.net.URI;
import java.net.URISyntaxException;

import org.apache.log4j.Logger;

/**
 * <p>Title: Catalog Generator</p>
 * <p>Description: Tool for generating THREDDS catalogs.</p>
 * <p>Copyright: Copyright (c) 2001</p>
 * <p>Company: UCAR/Unidata</p>
 * @author Ethan Davis
 * @version $Id: DodsDirDatasetSource.java,v 1.6 2004/11/30 22:49:12 edavis Exp $
 */

public class DodsDirDatasetSource extends DatasetSource
{
  private static Logger logger = Logger.getLogger( DodsDirDatasetSource.class.getName());

  private DodsURLExtractor urlExtractor = null;

  public DodsDirDatasetSource()
  {
    this.type = DatasetSourceType.getType( "DodsDir");
    urlExtractor = new DodsURLExtractor();
  }

  public void expandThisType( InvDatasetImpl parent, String givenLocation)
  {
    logger.debug( "expandThisType(): expand the given location (" + givenLocation + ").");

    List possibleDsList = new ArrayList();

    InvDatasetImpl curDs = null; // Current dataset.
    String curDsAbsolutePath = null;     // Current dataset's absolute path.
    String curDsRelativePath = null;     // Current dataset's relative path.
    String accessPointHeader = null;
    String resultContent;
    String verUrlString;

    //-----
    // Check that givenLocation is an OPeNDAP server URL.
    //-----
    verUrlString = givenLocation.endsWith( "/")
                     ? givenLocation + "version"
                     : givenLocation + "/version";
    try
    {
      logger.debug( "expandThisType(): checking that given location" +
              " (" + givenLocation + ") is an OPeNDAP server by checking version.");
      resultContent = urlExtractor.getTextContent( verUrlString);
    }
    catch (java.io.IOException e)
    {
      logger.debug( "expandThisType(): IoException while checking that given location is an OPeNDAP server.");
      InvDatasetImpl tmpDs = null;
      tmpDs = new InvDatasetImpl( null, "Could not expand the DatasetSource \"" + this.getName() +
              "\" at this location \"" + givenLocation + "\". IoException while checking that the" +
              " location references an OPeNDAP server.");
      parent.addDataset( tmpDs);
      return;
    }
    if ( resultContent.indexOf( "DODS") != -1 ||
         resultContent.indexOf( "OPeNDAP") != -1 ||
         resultContent.indexOf( "DAP") != -1)
    {
      logger.debug( "expandThisType(): location is an OPeNDAP server (version info contains" +
              " \"DODS\", \"OPeNDAP\",  or \"DAP\"): " + resultContent);
    }
    else
    {
      logger.warn(  "expandThisType(): location does not reference an OPeNDAP server, bad" +
              " version info (leaving expandThisLevel()):" + resultContent);
      InvDatasetImpl tmpDs = null;
      tmpDs = new InvDatasetImpl( null, "Could not expand the DatasetSource \"" + this.getName() +
              "\" at this location \"" + givenLocation + "\". IoException while checking" +
              " that location references an OPeNDAP server.");
      parent.addDataset( tmpDs);
      return;
    }

    //-----
    // Get list of possible datasets from current URL.
    //-----
    try
    {
      logger.debug( "expandThisType(): getting all URLs at given locatoin.");
      possibleDsList = urlExtractor.extract( givenLocation);
    }
    catch (java.io.IOException e)
    {
      logger.warn(  "expandThisType(): ioexception while expanding given OPeNDAP directory (" +
              givenLocation + ")");
      InvDatasetImpl tmpDs = null;
      tmpDs = new InvDatasetImpl( null, "Could not expand the DatasetSource \"" + this.getName() +
              "\" for this OPeNDAP directory \"" + givenLocation + "\". IoException while expanding" +
              " the location.");
      parent.addDataset( tmpDs);
      return;
    }

    //-----
    // Get the value of ResultService@accessPointHeader. Go through the URI hoopla
    // so that character encoding is handled.
    //-----
    try
    {
      accessPointHeader = new URI( this.getResultService().getAccessPointHeader()).toString();
      logger.debug( "expandThisType(): get and encode access point header (" + accessPointHeader.toString() + ").");
    }
    catch ( URISyntaxException e )
    {
      logger.warn(  "expandThisType(): Could not expand the DatasetSource \"" + this.getName() +
              "\". Creating a URI with accessPointHeader (" + this.getResultService() +
              ") caused a URISyntaxException.");
      InvDatasetImpl tmpDs = null;
      tmpDs = new InvDatasetImpl( null, "Could not expand the DatasetSource \"" + this.getName() +
              "\". Creating a URI with accessPointHeader (" + this.getResultService() +
              ") caused a URISyntaxException.");
      parent.addDataset( tmpDs);
      return;
    }

    // Handle each link in the current access path.
    java.util.Iterator iter = possibleDsList.iterator();
    while ( iter.hasNext())
    {
      curDsAbsolutePath = (String) iter.next();
      logger.debug( "expandThisType(): handle dataset (" + curDsAbsolutePath + ")");

      //-----
      // Remove ".html" extension.
      //-----
      if ( curDsAbsolutePath.endsWith( ".html"))
      {
        curDsAbsolutePath = curDsAbsolutePath.substring( 0, curDsAbsolutePath.length() - 5);
      }
      // Avoid paths that are not OPeNDAP datasets (i.e., do not end with ".html").
      else
      {
        logger.debug( "expandThisType(): current path (" + curDsAbsolutePath + ") is not an OPeNDAP dataset" +
                " because it does not end with \".html\".");
        continue;
      }

      //-----
      // Determine the value of the datasets urlPath, i.e., remove accessPointHeader.
      // @todo Deal with removing the accessPointHeader in DatasetSource.expand() when optimizing service stuff?
      //-----
      if ( curDsAbsolutePath.startsWith( accessPointHeader))
      {
        curDsRelativePath = curDsAbsolutePath.substring( accessPointHeader.length());
      }
      else
      {
        // If the dataset URL doesn't start with the accessPointHeader then it isn't a desired dataset.
        logger.debug( "expandThisType(): current path (" + curDsAbsolutePath + ") not accessible" +
                " from the ResultService (" + this.getResultService().getName() + " - "
                + accessPointHeader +"). THIS SHOULDN'T HAPPEN!");
        continue;
      }

      //-----
      // Avoid links back down the path hierarchy (i.e., parent directory links).
      //-----
      if ( ! curDsAbsolutePath.startsWith( givenLocation))
      {
        logger.debug( "expandThisType(): current path (" + curDsAbsolutePath + ") not child of given" +
                " location (" + givenLocation+ ").");
        continue;
      }

      // Handle directories.
      if ( curDsAbsolutePath.endsWith( "/"))
      {
        logger.debug( "expandThisType(): current dataset is directory.");

        // If building directory tree, add this directory as a new level.
        if ( ! this.isFlatten())
        {
          // Name this level with dataset path.
          curDs = new InvDatasetImpl( null, curDsRelativePath, null, null, null );
          this.expandThisType( curDs, curDsAbsolutePath);
          parent.addDataset( curDs);
        }
        // If building flat structure, add datasets in this directory to parent.
        else
        {
          this.expandThisType( parent, curDsAbsolutePath);
        }
      }
      // If the current file is not a directory.
      else
      {
        logger.debug( "expandThisType(): current dataset is directory.");
        // Set the name to "" and the urlPath with the dataset path.
        curDs = new InvDatasetImpl( null, "", null, null, curDsRelativePath);

        if ( ! this.getDatasetFilterList().isEmpty())
        {
          // Loop through filters in this.datasetFilterList to check that
          // curDs satisfies one of the filters.
          DatasetFilter curFilter = null;
          for ( int j = 0; j < this.getDatasetFilterList().size(); j++)
          {
            curFilter = (DatasetFilter) this.getDatasetFilterList().get( j);
            logger.debug( "expandThisType(): check dataset against filter (" + curFilter.getName() + ").");

            if ( curFilter.accept( curDs))
            {
              logger.debug( "expandThisType(): the current dataset (" + curDs.getUrlPath() + ") was" +
                      " accepted by the filter \"" + curFilter.getName() + "\"");
              parent.addDataset( curDs);
              break;
            }
          } // END - filter loop
        } // END - if there are filters
        else
        {
          parent.addDataset( curDs);
        } // END - if there are no filters
      } // END - if not a directory
    } // END - loop through files in current directory

    return;
  }

  protected InvDataset getTopLevelDataset()
  {
    return null;  //To change body of implemented methods use File | Settings | File Templates.
  }

  protected boolean isCollection( InvDataset dataset )
  {
    return false;  //To change body of implemented methods use File | Settings | File Templates.
  }

  protected List expandThisLevel( InvDataset collectionDataset )
  {
    return null;  //To change body of implemented methods use File | Settings | File Templates.
  }

}
/*
 * $Log: DodsDirDatasetSource.java,v $
 * Revision 1.6  2004/11/30 22:49:12  edavis
 * Start changing DatasetSource into a more usable API.
 *
 * Revision 1.5  2004/06/03 20:27:24  edavis
 * Update for thredds.catalog changes for InvCatalog 1.0.
 *
 * Revision 1.4  2004/05/11 20:38:46  edavis
 * Update for changes to thredds.catalog object model (still InvCat 0.6).
 * Start adding some logging statements.
 *
 * Revision 1.3  2003/09/05 22:05:52  edavis
 * Expand logging.
 *
 */
