// $Id: DIFWriter.java,v 1.3 2004/09/24 03:26:28 caron Exp $
/*
 * Copyright 1997-2004 Unidata Program Center/University Corporation for
 * Atmospheric Research, P.O. Box 3000, Boulder, CO 80307,
 * support@unidata.ucar.edu.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package thredds.catalog.dl;

import thredds.catalog.*;
import thredds.datatype.DateType;

import org.jdom.*;
import org.jdom.output.*;

import java.io.*;
import java.util.*;

public class DIFWriter {
  private static final Namespace defNS = Namespace.getNamespace("http://gcmd.gsfc.nasa.gov/DIF/");
  private static final Namespace xsiNS = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
  private static final String schemaLocation = defNS.getURI() + " http://www.unidata.ucar.edu/schemas/other/gcmd/dif.xsd";
  private static final String schemaLocationLocal = defNS.getURI() + " file://P:/schemas/other/gcmd/dif.xsd";
  private static String threddsServerURL = "http://localhost:8080/thredds/subset.html";

  // private InvCatalog cat;
  public DIFWriter() {
  }

  public void writeDatasetEntries( InvCatalog cat, String fileDir, StringBuffer mess) {
    File dir = new File(fileDir);
    if (!dir.exists())
      dir.mkdirs();

    List datasets = cat.getDatasets();
    for (int i=0; i<datasets.size(); i++) {
      InvDataset elem = (InvDataset) datasets.get(i);
      doDataset( elem, fileDir, mess);
    }
  }

  private void doDataset( InvDataset ds, String fileDir, StringBuffer mess) {
    if (!ds.isHarvest()) {
      mess.append( "Dataset "+ ds.getName()+ " id = "+ds.getID()+" has harvest = false\n");

    } else if (isDatasetUseable( ds, mess)) {
      String fileOutName = fileDir+"/"+ds.getID()+".dif.xml";
      try {
        OutputStream out = new BufferedOutputStream(new FileOutputStream( fileOutName));
        writeOneEntry(ds, System.out);
        writeOneEntry(ds, out);
        out.close();
        return;
      } catch (IOException ioe) {
        ioe.printStackTrace();
      }
    }

    List datasets = ds.getDatasets();
    for (int i=0; i<datasets.size(); i++) {
      InvDataset nested = (InvDataset) datasets.get(i);
      doDataset( nested, fileDir, mess);
    }
  }

  public boolean isDatasetUseable(InvDataset ds, StringBuffer sbuff) {
    boolean ok = true;
    sbuff.append("Dataset "+ ds.getName()+ " id = "+ds.getID()+": ");

    if (ds.getName() == null) {
      ok = false;
      sbuff.append(" missing Name field\n");
    }

    if (ds.getUniqueID() == null) {
      ok = false;
      sbuff.append(" missing ID field\n");
    }

    ThreddsMetadata.Variables vs = ds.getVariables("DIF");
    if ((vs == null) || (vs.getVariableList().size() == 0)) {
      ok = false;
      sbuff.append(" missing Variables with DIF vocabulary\n");
    }

    List list = ds.getPublishers();
    if ((list == null) || (list.size() == 0)) {
      ok = false;
      sbuff.append(" must have publisher element that defines the data center\n");
    }

    String summary = ds.getDocumentation("summary");
    if (summary == null) {
      ok = false;
      sbuff.append(" must have documentation element of type summary\n");
    }

    sbuff.append(" useable= "+ok+"\n");
    return ok;
  }

  private void writeOneEntry( InvDataset ds, OutputStream out) throws IOException {
    Element rootElem = new Element("DIF", defNS);
    Document doc = new Document(rootElem);
    writeDataset( ds, rootElem);
    rootElem.addNamespaceDeclaration(xsiNS);
    rootElem.setAttribute("schemaLocation", schemaLocation, xsiNS);

    // Output the document, use standard formatter
    XMLOutputter fmt = new XMLOutputter("  ", true);
    fmt.output( doc, out);
  }

  public void writeDataset(InvDataset ds, Element rootElem) {

    rootElem.addContent( new Element("Entry_ID", defNS).addContent(ds.getUniqueID()));
    rootElem.addContent( new Element("Entry_Title", defNS).addContent(ds.getName()));

    // parameters
    ThreddsMetadata.Variables vs = ds.getVariables("DIF");
    if (vs != null) {
      List vlist = vs.getVariableList();
      for (int j = 0; j < vlist.size(); j++) {
        ThreddsMetadata.Variable v = (ThreddsMetadata.Variable) vlist.get(j);
        writeVariable( rootElem, v);
      }
    }

    // keywords
    List list = ds.getKeywords();
    if (list.size() > 0) {
      for (int i=0; i<list.size(); i++) {
        ThreddsMetadata.Vocab k = (ThreddsMetadata.Vocab) list.get(i);
        rootElem.addContent( new Element("Keyword", defNS).addContent( k.getText()));
      }
    }

    //temporal
    ThreddsMetadata.TimeCoverage tm = ds.getTimeCoverage();
    if (tm != null) {
      Element tmElem = new Element("Temporal_Coverage", defNS);
      rootElem.addContent(tmElem);

      tmElem.addContent(new Element("Start_Date",
                        defNS).addContent(tm.getStart().toDateString()));
      tmElem.addContent(new Element("Stop_Date",
                        defNS).addContent(tm.getEnd().toDateString()));
    }

    //geospatial
    ThreddsMetadata.GeospatialCoverage geo = ds.getGeospatialCoverage();
    if (geo != null) {
      Element geoElem = new Element("Spatial_Coverage", defNS);
      rootElem.addContent(geoElem);

      geoElem.addContent(new Element("Southernmost_Latitude",
                         defNS).addContent(Double.toString(geo.getLatSouth())));
      geoElem.addContent(new Element("Northernmost_Latitude",
                         defNS).addContent(Double.toString(geo.getLatNorth())));
      geoElem.addContent(new Element("Westernmost_Longitude",
                         defNS).addContent(Double.toString(geo.getLonWest())));
      geoElem.addContent(new Element("Easternmost_Longitude",
                         defNS).addContent(Double.toString(geo.getLonEast())));
    }

    String rights = ds.getDocumentation("rights");
    if (rights != null)
      rootElem.addContent( new Element("Use_Constraints", defNS).addContent(rights));

    // data center
    list = ds.getPublishers();
    if (list.size() > 0) {
      for (int i=0; i<list.size(); i++) {
        ThreddsMetadata.Source p = (ThreddsMetadata.Source) list.get(i);
        Element dataCenter = new Element("Data_Center", defNS);
        rootElem.addContent( dataCenter);
        writeDataCenter(p, dataCenter);
      }
    }

    String summary = ds.getDocumentation("summary");
    if (summary != null)
      rootElem.addContent( new Element("Summary", defNS).addContent(summary));

    Element primaryURLelem = new Element("Related_URL", defNS);
    rootElem.addContent( primaryURLelem);

    String primaryURL = threddsServerURL +
        "?catalog="+((InvCatalogImpl)ds.getParentCatalog()).getBaseURI().toString() +
        "&dataset="+ds.getID();
    primaryURLelem.addContent( new Element("URL_Content_Type", defNS).addContent("THREDDS access page"));
    primaryURLelem.addContent( new Element("URL", defNS).addContent(primaryURL));

    DateType today = new DateType(false, new Date());
    rootElem.addContent(new Element("DIF_Creation_Date", defNS).addContent(today.toDateString()));

  }

  protected void writeDataCenter(ThreddsMetadata.Source p, Element dataCenter) {
    Element name = new Element("Data_Center_Name", defNS);
    dataCenter.addContent( name);
    // dorky
    StringTokenizer stoker = new StringTokenizer(p.getName(), ">");
    int n = stoker.countTokens();
    if (n == 2) {
      name.addContent( new Element("Short_Name", defNS).addContent(stoker.nextToken().trim()));
      name.addContent( new Element("Long_Name", defNS).addContent(stoker.nextToken().trim()));
    } else {
      name.addContent( new Element("Short_Name", defNS).addContent(p.getName()));
    }

    if ((p.getUrl() != null) && p.getUrl().length() > 0)
      dataCenter.addContent( new Element("Data_Center_URL", defNS).addContent(p.getUrl()));

    Element person = new Element("Personnel", defNS);
    dataCenter.addContent( person);
    person.addContent( new Element("Role", defNS).addContent("DATA CENTER CONTACT"));
    person.addContent( new Element("Email", defNS).addContent(p.getEmail()));
  }

  private void writeVariable( Element rootElem, ThreddsMetadata.Variable v) {
    String vname = v.getVocabularyName();
    StringTokenizer stoker = new StringTokenizer(vname,">");
    int n = stoker.countTokens();
    if (n < 3) return; // gottta have the first 3

    Element param = new Element("Parameters", defNS);
    rootElem.addContent(param);

    if (stoker.hasMoreTokens())
      param.addContent( new Element("Category", defNS).addContent(stoker.nextToken().trim()));
    if (stoker.hasMoreTokens())
      param.addContent( new Element("Topic", defNS).addContent(stoker.nextToken().trim()));
    if (stoker.hasMoreTokens())
      param.addContent( new Element("Term", defNS).addContent(stoker.nextToken().trim()));
    if (stoker.hasMoreTokens())
      param.addContent( new Element("Variable", defNS).addContent(stoker.nextToken().trim()));
    if (stoker.hasMoreTokens())
      param.addContent( new Element("Detailed_Variable", defNS).addContent(stoker.nextToken().trim()));
  }

  // test
  private static void doOne( InvCatalogFactory fac, String url) {
    System.out.println("***read "+url);
    try {
      InvCatalogImpl cat = (InvCatalogImpl) fac.readXML(url);
      StringBuffer buff = new StringBuffer();
      boolean isValid = cat.check( buff, false);
      System.out.println("catalog <" + cat.getName()+ "> "+ (isValid ? "is" : "is not") + " valid");
      System.out.println(" validation output=\n" + buff);
      // System.out.println(" catalog=\n" + fac.writeXML(cat));

      DIFWriter w = new DIFWriter();
      StringBuffer sbuff = new StringBuffer();
      w.writeDatasetEntries( cat, "C:/temp/dif", sbuff);
      System.out.println(" messages=\n"+sbuff);
    } catch (Exception e) {
      e.printStackTrace();
    }

  }

   /** testing */
  public static void main (String[] args) throws Exception {
    InvCatalogFactory catFactory = InvCatalogFactory.getDefaultFactory(true);

    doOne(catFactory, "file:///C:/dev/thredds/catalog/test/data/TestHarvest.xml");
    //doOne(catFactory, "file:///C:/dev/thredds/catalog/test/data/Example1.0rc7.xml");
  }

}

/* Change History:
   $Log: DIFWriter.java,v $
   Revision 1.3  2004/09/24 03:26:28  caron
   merge nj22

   Revision 1.2  2004/06/09 00:27:26  caron
   version 2.0a release; cleanup javadoc

 */