/*
 * 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.test.simpleclient;

import java.io.File;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.util.jar.JarFile;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.vamsas.client.simpleclient.Lock;
import uk.ac.vamsas.client.simpleclient.SessionFile;
import uk.ac.vamsas.client.simpleclient.SimpleDocument;
import uk.ac.vamsas.client.simpleclient.VamsasArchiveReader;
import uk.ac.vamsas.client.simpleclient.VamsasFile;
import uk.ac.vamsas.objects.core.ApplicationData;
import uk.ac.vamsas.objects.core.User;
import uk.ac.vamsas.objects.core.VAMSAS;
import uk.ac.vamsas.objects.core.VamsasDocument;
import uk.ac.vamsas.test.objects.Core;

public class VamsasArchive {
  /**
   * test the org.vamsas.simpleclient.vamsasArchive class
   */
  static Log log = LogFactory.getLog(VamsasArchive.class);

  public static ApplicationData makeDemoAppdata(
      uk.ac.vamsas.client.simpleclient.VamsasArchive va, String apname,
      String userName, String userOrg) {
    if (va == null)
      return null;
    VamsasArchiveReader vread = null;
    try {
      vread = va.getOriginalArchiveReader();
    } catch (Exception e) {
      log.error("Failed to get original archive reader!", e);
      return null;
    }
    ApplicationData appdata = new ApplicationData();
    appdata.setName("uk.ac.vamsas.test.simpleclient.VamsasArchive");
    appdata.setData(new String("this is some test data.").getBytes());
    User apuser = new User();
    apuser.setFullname(userName);
    apuser.setOrganization(userOrg);
    String appdata_ref = "vamsas:" + apname + "/" + apuser.getOrganization()
        + "/" + apuser.getFullname();
    SimpleDocument sdoc = new SimpleDocument("test.simpleclient.VamsasArchive");
    if (vread != null) {
      VamsasDocument orignalnew;
      try {
        orignalnew = sdoc.getVamsasDocument(vread);
        log.info("*** Dump follows ***");

        ArchiveReports.reportDocument(orignalnew, vread, false, System.out);
        log.info("*** Dump precedes ***");
      } catch (Exception e) {
        log.info("makeDemoAppdata: Problems accessing original document");
      }

      log.info("Reading (and avoiding references to) original data");
      if (vread.getAppdataStream(appdata_ref) != null) {
        // transfer over
        try {
          va.transferAppDataEntry(appdata_ref);
        } catch (Exception e) {
          log.warn("Exception when transferring appdata reference : "
              + appdata_ref, e);
        }
        int i = 0;
        while (vread
            .getAppdataStream(appdata_ref + "/" + Integer.toString(++i)) != null) {
          try {
            // copy over another duplicate.
            va.transferAppDataEntry(appdata_ref + "/" + Integer.toString(i));
          } catch (Exception e) {
            log.warn("Exception when transferring appdata reference : "
                + appdata_ref, e);
          }
        }
        // this one must be unique!
        appdata_ref += "/" + Integer.toString(i);
      }
    }

    log.info("Adding new data stuff.");
    log.info("Writing an apdata reference using AppDataStream interface.");
    apuser.setDataReference(appdata_ref);
    appdata.addUser(apuser);
    appdata.setVersion("noggin");
    // TODO: write instance appdata appdata.setUrn("program:/the.nog/");
    try {
      ObjectOutputStream ost = new ObjectOutputStream(va
          .getAppDataStream(appdata_ref));
      ost.writeObject(appdata);
      ost.close();
    } catch (Exception e) {
      log.warn("Couldn't write appdata reference " + appdata_ref);
    }
    return appdata;
  }

  public static void main(String args[]) {

    try {
      File av;
      if (args.length > 0)
        av = new File(args[0]);
      else
        av = new File("test/vamsas.zip");
      try {
        RandomAccessFile raf = new RandomAccessFile(av, "r");
        raf.readByte();
        raf.close();
      } catch (Exception f) {
        log.info("Couldn't random access file archive " + av, f);
      }
      try {
        JarFile jf = new JarFile(av, true, JarFile.OPEN_READ);
        if (jf.getEntry("vamsasDocument.xml") != null) {
          log.info("Valid archive (sun) " + av);
        }
        jf.close();
      } catch (Exception f) {
        log.warn("Couldn't access jar archive with sun jartools: " + av, f);
      }
      try {
        org.apache.tools.zip.ZipFile jf = new org.apache.tools.zip.ZipFile(av);
        if (jf.getEntry("vamsasDocument.xml") != null) {
          log.info("Valid archive (apache) " + av);
        }
        jf.close();
      } catch (Exception f) {
        log.warn("Couldn't access jar archive with apache ziptool: " + av, f);
      }

      log.info("Opening archive " + av);
      uk.ac.vamsas.client.simpleclient.VamsasArchive varchive = new uk.ac.vamsas.client.simpleclient.VamsasArchive(
          av, true);

      VAMSAS[] roots = (VAMSAS[]) varchive.getOriginalRoots();

      if (roots != null) {
        log.info("Report on Original roots in archive:");
        ArchiveReports.rootReport(roots, true, System.out);
      }
      log.info("Getting current vamsas document.");
      VamsasDocument doc = varchive.getVamsasDocument();
      ArchiveReports.reportDocument(doc, varchive.getOriginalArchiveReader(),
          true, System.out); // not modified document so references will still
                             // be valid
      // do some stuff
      log.info("Retrieving backup");
      File backup = varchive.backupFile();
      if (backup == null)
        log.info(av + " is a New Archive.");
      else
        log.info(av + " has been backed up as " + backup);
      File newf = new File(av.getAbsolutePath() + "_new.zip");
      VamsasFile sfile = new VamsasFile(newf);
      /*
       * if (newf.exists()) { int q=1; do { newf=new
       * File(av.getAbsolutePath()+"_"+q+++"_new.zip"); } while (newf.exists());
       * }
       */
      if (newf.exists()) {
        log.info("Removing existing " + newf);
        newf.delete();
      }

      log.info("Now writing new Archive into " + newf.getAbsolutePath());
      uk.ac.vamsas.client.simpleclient.VamsasArchive va = null;
      { // hold lock over deletion and write of new archive.
        // Lock wlock = sfile.getLock();
        // newf.delete(); // clear out old file.
        sfile.getLock();
        va = new uk.ac.vamsas.client.simpleclient.VamsasArchive(newf, true,
            true, sfile);
        // open another and...
        ApplicationData appdata = makeDemoAppdata(va,
            "uk.ac.vamsas.test.simpleclient.VamsasArchive",
            "arnold Bugger esq", "disOrganised");
        log.info("Preparing to write new document.");
        doc.addApplicationData(appdata);
        doc.addVAMSAS(Core.getDemoVamsas());
        va.putVamsasDocument(doc); // gets stream and puts it.
        va.closeArchive();
        sfile.unLock();
      }
      log.info("Dump of new vamsas document :");
      log.info("Testing update: ");
      {
        Lock lock = sfile.getLock();
        if (lock == null)
          while ((lock = sfile.getLock()) == null) {
            log.info("Waiting for lock.");
            Thread.sleep(100);
          }
        VamsasArchiveReader vreader = new VamsasArchiveReader(sfile
            .getVamsasFile());// lock); // cannot do new JarFile on a locked
                              // file. // newf);
        SimpleDocument sdoc = new SimpleDocument("testing new vamsas write");
        ArchiveReports.reportDocument(sdoc.getVamsasDocument(vreader), vreader,
            true, System.out);
        sfile.unLock();
      }
      // backup.delete(); // tidy up

      log.info("Now Cancelling write to original archive " + av);
      if (varchive.cancelArchive())
        log.info("Successfully cancelled.");
      else
        log.info("Didn't cancel.");
      long t = System.currentTimeMillis() + 200;
      while (t > System.currentTimeMillis())
        ;
      log.info("Now testing archive update.");
      va = new uk.ac.vamsas.client.simpleclient.VamsasArchive(newf, false,
          true, sfile);
      doc = va.getVamsasDocument();
      doc.addVAMSAS(Core.getDemoVamsas());
      doc.addApplicationData(makeDemoAppdata(va,
          "uk.ac.vamsas.test.simpleclient.VamsasArchive",
          "another old Bugger esq", "rescinded"));
      if (va.transferRemainingAppDatas())
        log.info("Remain appdatas were transferred.");
      else
        log.warn("No appdatas were transferred. This is wrong.");
      va.putVamsasDocument(doc);
      va.closeArchive();
      sfile.unLock();
      log.info("Testing update: ");
      {
        Lock lock = sfile.getLock();
        if (lock == null)
          while ((lock = sfile.getLock()) == null)
            log.info("Waiting for lock.");
        // VamsasArchiveReader vreader = new VamsasArchiveReader(lock);
        VamsasArchiveReader vreader = new VamsasArchiveReader(newf);

        SimpleDocument sdoc = new SimpleDocument("testing vamsas update");
        VamsasDocument finaldoc = sdoc.getVamsasDocument(vreader);
        if (finaldoc != null)
          ArchiveReports.reportDocument(finaldoc, vreader, true, System.out);
        else
          log.error("Null Document Read from " + newf);
      }
    } catch (Exception e) {
      e.printStackTrace(System.err);
    }
  }
}
