// SimpleResourceSaver.java
// $Id: SimpleResourceSaver.java,v 1.2 1997/07/30 14:09:50 ylafon Exp $  
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.tools.resources.simple;

import java.net.*;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;

import w3c.util.*;
import w3c.tools.resources.*;
import w3c.tools.resources.event.*;
import w3c.tools.resources.impl.*;
import w3c.tools.resources.PersistentReference;

public class SimpleResourceSaver implements ResourceSaver {

  /**
   * Our ResourceSpace.
   */
  protected ResourceSpaceImpl space = null;

  /**
   * protected File rootDir = null;
   */
  protected File rootDir = null;

  public synchronized void save (Resource r) {
    ResourceImpl pr = (ResourceImpl) r;
    ResourceReference rr = null;
    try {
      rr = pr.getContainer();
      // rr == null if it's the root resource.
      if (rr != null) {
	ResourceContainerImpl c = (ResourceContainerImpl)rr.lock();
	File out = c.getStore().getResourceFile(r.getName());
	ObjectOutputStream oo = 
	  new ObjectOutputStream (new BufferedOutputStream
				  (new FileOutputStream
				   (out)));
	save(pr,oo);
      }
    } catch (IOException ex) {
      System.out.println(ex.getMessage());
      ex.printStackTrace();
    } finally {
      if (rr != null) rr.unlock();
    }
  }


  /**
   * Save the given resource in a object file located in the
   * container directory.
   * @param r The Resource to save
   * @param c The resource container
   */
  public synchronized void save(ResourceImpl r, 
				ObjectOutputStream oo) 
    throws RuntimeException
  {
    try {
      // write resource itself
      oo.writeObject(r);

      // write delegatee
      ResourceReference delegatees [] = r.getDelegatees();
      oo.writeInt(delegatees.length);
      int i = 0;
      while (i < delegatees.length) {
	try {
	  oo.writeObject(delegatees[i].lock());
	} finally {
	  delegatees[i++].unlock();
	}
      }
    } catch (IOException ex) {
      System.out.println(ex.getMessage());
      ex.printStackTrace();
      throw new RuntimeException("Unable to save resource : "+r.getName());
    } finally {
      if (oo != null) {
	try { oo.close(); } catch (Exception ex) {}
      }
    }
  }


  public synchronized Resource revalidate (PersistentReference pr,
					   ResourceReference container)
    throws ClassNotFoundException
  {
    Resource sr                    = null;
    ResourceImpl deleg             = null;
    ResourceContainerImpl rcont    = null;
    PersistentReference prd        = null;
    ResourceReference rrd          = null;
    ResourceReference rr           = null;
    ResourceContext context = null;
    try {
      ResourceContainerImpl cont = (ResourceContainerImpl)container.lock();
      context = (cont.getContext()).getClone();
      context.setContainer(container);
    } catch (Exception e) {
      System.out.println(e.getMessage());
      e.printStackTrace();
    } finally {
      container.unlock();
    }
    PersistentReferenceImpl prImpl = (PersistentReferenceImpl) pr;
    File file = new File(rootDir, prImpl.containerPath+"/"+
			 prImpl.resourceName+
			 ".s");
    //    File file = new File(prImpl.containerPath,prImpl.resourceName+".s");
    if (! file.exists()) return null;
    ObjectInputStream oi = null;
    try {
      oi = new ObjectInputStream(new BufferedInputStream
				 (new FileInputStream
				  (file)));
      sr = (Resource) oi.readObject();
      rr = space.getCache().getReference(pr,sr);
      context.setResourceReference(rr);
      // Probably here
      sr.init(context);
      int delegNb = oi.readInt();
      try {
	rcont = (ResourceContainerImpl)container.lock();
	while (-- delegNb >= 0) {
	  try {
	    deleg = (ResourceImpl) oi.readObject();
	    ResourceContext ctxt = null;
	    try {
	      ResourceContainerImpl cont = 
		(ResourceContainerImpl)container.lock();
	      ctxt = (cont.getContext()).getClone();
	      ctxt.setContainer(container);
	    } catch (Exception e) {
	      System.out.println(e.getMessage());
	      e.printStackTrace();
	    } finally {
	      container.unlock();
	    }
	    deleg.init(ctxt);
	    prd = new PersistentReferenceImpl(rcont.getUrlPath(),
					      deleg.getName());
	    //prd = rcont.getStore().getPersistentReference(deleg.getName());
	    rrd = space.getCache().getReference(prd,deleg);
	    ctxt.setResourceReference(rrd);
	    deleg.init(ctxt);
	    sr.addDelegatee(space.getCache().getReference(prd,deleg));
	  } catch (Exception ex) {
	    System.out.println(ex.getMessage());
	    ex.printStackTrace();
	  }
	}
      } finally {
	container.unlock();
      }
    } catch (ResourceInitException ex) {
      ex.printStackTrace();
    } catch (StreamCorruptedException ex) {
      ex.printStackTrace();
    } catch (FileNotFoundException ex) {
      ex.printStackTrace();
    } catch (IOException ex) {
      ex.printStackTrace();
    } finally {
      if ( oi != null ) {
	try { oi.close() ; } catch (Exception ex) {}
      }
    }
    return sr;
  }

  public synchronized ResourceReference load (PersistentReference pr,
					      ResourceReference container) 
    throws ClassNotFoundException
  {
    Resource sr = revalidate(pr,container);
    return space.getCache().getReference(pr,sr);
  }

  public synchronized void delete (Resource r) {
    ResourceReference rcont = ((ResourceImpl)r).getContainer();
    try {
      ResourceContainerImpl cont = (ResourceContainerImpl)rcont.lock();
      File file = cont.getStore().getResourceFile(r.getName());
      if (file.exists()) file.delete();
    } finally {
      rcont.unlock();
    }
  }

  public synchronized void delete (String name, 
				   ResourceReference container) 
  {
    ResourceContainerImpl cont = null;
    try {
      cont = (ResourceContainerImpl)container.lock();
      File file = cont.getStore().getResourceFile(name);
      if (file.exists()) file.delete();
    } finally {
      container.unlock();
    }
  }

  public void init(ResourceSpace space, Properties P) 
    throws ResourceSaverInitException    
  {
    
    this.space = (ResourceSpaceImpl)space;

    String root = (String)P.get(ResourceSpaceImpl.ROOTDIR_P);
    if (root == null)
      throw new ResourceSaverInitException("no "+
					   ResourceSpaceImpl.ROOTDIR_P+
					   " prop.");    
    this.rootDir = new File(root);
  }

  public PropertyHolder getPropertyHolder(Runner run, Resource r) {
    return new PropertyHolderImpl(run,r);
  }

  public SimpleResourceSaver() {}

  public SimpleResourceSaver (ResourceSpace space, String defaultClass)  {
    this.space = (ResourceSpaceImpl)space;
  }

}
