/*
 * This file is part of the Vamsas Client version 0.2. 
 * Copyright 2010 by Jim Procter, Iain Milne, Pierre Marguerite, 
 *  Andrew Waterhouse and Dominik Lindner.
 * 
 * Earlier versions have also been incorporated into Jalview version 2.4 
 * since 2008, and TOPALi version 2 since 2007.
 * 
 * The Vamsas Client 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 3 of the License, or
 * (at your option) any later version.
 *  
 * The Vamsas Client 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 the Vamsas Client.  If not, see <http://www.gnu.org/licenses/>.
 */
package uk.ac.vamsas.client.simpleclient;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.vamsas.client.Vobject;
import uk.ac.vamsas.client.VorbaIdFactory;
import uk.ac.vamsas.client.VorbaXmlBinder;
import uk.ac.vamsas.objects.core.VAMSAS;
import uk.ac.vamsas.objects.core.VamsasDocument;
import uk.ac.vamsas.objects.utils.AppDataReference;
import uk.ac.vamsas.objects.utils.DocumentStuff;
import uk.ac.vamsas.objects.utils.ProvenanceStuff;
import uk.ac.vamsas.objects.utils.document.VersionEntries;

/**
 * Base class for SimpleClient Vamsas Document Object Manipulation holds static
 * vamsasDocument from XML routines and state objects for a particular
 * unmarshalled Document instance.
 * 
 * @author jimp
 */

public class SimpleDocBinding {

  protected VorbaIdFactory vorba;

  protected static Log log = LogFactory.getLog(SimpleDocBinding.class);

  /**
   * @return Returns the vorba.
   */
  public VorbaIdFactory getVorba() {
    return vorba;
  }

  /**
   * @param vorba
   *          The vorba to set.
   */
  public void setVorba(VorbaIdFactory vorba) {
    this.vorba = vorba;
  }

  /**
   * Uses VorbaXmlBinder to retrieve the VamsasDocument from the given stream
   */
  public VamsasDocument getVamsasDocument(VamsasArchiveReader oReader)
      throws IOException, org.exolab.castor.xml.MarshalException,
      org.exolab.castor.xml.ValidationException {
    if (oReader != null) {
      // check the factory
      if (vorba == null) {
        log
            .error("Invalid SimpleDocument construction - no VorbaIdFactory defined!");
        return null;
      }

      if (oReader.isValid()) {
        // Read vamsasDocument.xsd instance
        InputStreamReader vdoc = new InputStreamReader(oReader
            .getVamsasDocumentStream());
        Object unmarsh[] = VorbaXmlBinder.getVamsasObjects(vdoc, vorba,
            new VamsasDocument());
        if (unmarsh == null)
          log.fatal("Couldn't unmarshall document!");

        Vobject vobjs = (Vobject) unmarsh[0];
        if (vobjs != null) {
          VamsasDocument doc = (VamsasDocument) vobjs;
          if (doc != null)
            return doc;
        }
        log
            .debug("Found no VamsasDocument object in properly formatted Vamsas Archive.");
      } else {
        // deprecated data handler (vamsas.xsd instance)
        InputStream vxmlis = oReader.getVamsasXmlStream();
        if (vxmlis != null) { // Might be an old vamsas file.
          BufferedInputStream ixml = new BufferedInputStream(oReader
              .getVamsasXmlStream());
          InputStreamReader vxml = new InputStreamReader(ixml);
          Object unmarsh[] = VorbaXmlBinder.getVamsasObjects(vxml, vorba,
              new VAMSAS());

          if (unmarsh == null)
            log.fatal("Couldn't unmarshall document!");

          VAMSAS root[] = new VAMSAS[] { null };
          root[0] = (VAMSAS) unmarsh[0];

          if (root[0] == null) {
            log.debug("Found no VAMSAS object in VamsasXML stream.");
          } else {
            log.debug("Making new VamsasDocument from VamsasXML stream.");
            VamsasDocument doc = DocumentStuff.newVamsasDocument(root,
                ProvenanceStuff.newProvenance(vorba.getUserHandle()
                    .getFullName(),
                    "Vamsas Document constructed from vamsas.xml"),
                VersionEntries.ALPHA_VERSION);
            // VAMSAS: decide on 'system' operations provenance form
            // LATER: implement classes for translating Vorba properties into
            // provenance user fields.
            // VAMSAS: decide on machine readable info embedding in provenance
            // should be done
            root[0] = null;
            root = null;
            return doc;
          }
        }
      }
    }
    // otherwise - there was no valid original document to read.
    return null;
  }

  /**
   * Extract all jarEntries in an archive referenced by the vamsas document
   * LATER: a family of methods for finding extraneous jarEntries , and invalid
   * appDataReferences
   * 
   * @param doc
   * @param oReader
   * @return array of the subset of JarEntry names that are referenced in doc
   */
  public Vector getReferencedEntries(VamsasDocument doc,
      VamsasArchiveReader oReader) {
    if (oReader == null)
      return null;
    if (doc == null) {
      try {
        doc = getVamsasDocument(oReader);
      } catch (Exception e) {
        log.warn("Failed to get document from " + oReader.jfileName);
      }
      ;
    }
    Vector docrefs = AppDataReference.getAppDataReferences(doc);
    if (docrefs == null)
      return null;
    Vector entries = oReader.getExtraEntries();
    if (entries != null && entries.size() > 0 && docrefs.size() > 0) {
      int i = 0, j = entries.size();
      do {
        if (!docrefs.contains(entries.get(i))) {
          entries.remove(i);
          j--;
        } else
          i++;
      } while (i < j);
    }
    return entries;
  }
}
