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

/** FtpDir 
  * Implemente la gestion des fichiers (AccessibleDir) 
  * @param Url l'url ou se connecter (Ftp)
  * @version        0.1 Feb 1997
  * @author         Ebele Nicolas, Mallet Frederic
  */

public class FtpDir implements AccessibleDir {
/** le nom de la classe (pour debugger) */
  static final public String ClassName = "FtpDir";
/** le cache (commun a toute les instances de la classe) */ 
  static private DirCache dc = null;
/** la connection au site Ftp */
  Ftp Connect = null;
/** l'adresse de la connection */
  String Url;

/** Renvoie la derniere erreur
  * @param pas de parametres
  * @retrun renvoie la derniere erreur si il y en a eu une, null sinon
  */
public String erreurText()
  {
    if (Connect != null)
      return Connect.erreurText();
    return null;
  }
/** Renvoie la chaine separateur
  * @param pas de parametres
  * @retrun renvoie le separateur de fichier utilise (ici toujours "/") sous forme de string
  */
public String separator()
  {
    return "/";
  }

/** Renvoie le caractere separateur
  * @param pas de parametres
  * @retrun renvoie le separateur de fichier utilise (ici toujours "/") sous forme d'un caractere
  */
public char separatorChar()
  {
    return '/';
  }

/** Initialise le cache
  * @param Url l'url a ajouter en 1er dans le cache
  * @return pas de valeur retournee
  */
private void InitCache(String Url)
  {
    if (dc == null) {
      String param = (String)Init.get(ClassName, "config", "SizeCache");
      int taille = param==null?20:Integer.parseInt(param);
      if (taille == 0)
	taille = 20;
      dc = new DirCache(taille);
    }
    Init.println(ClassName, "Ajout de " + Url);
    if (!dc.isIn(Url)) {
      Init.println(ClassName, "----------------> ok");
      Connect = new Ftp(Url);
      dc.addElement(Url, Connect.GetFullList(),true);
    }
    else {
      // c'est pas beau ca !!! il; faudrait changer ca pour ne pas reouvrir une connection !!!!
      Connect = new Ftp(Url);
      Init.println(ClassName, "-------------> existe deja ...");
    }
  }

 
/** Constructeur
  * @param Url l'url a construire
  * note : on a un cache (static a la classe) on ne se connecte a l'url que si elle ne se trouve pas
  *        dans le cache
  */
  FtpDir(String Url)
  { 
    Init.println(ClassName, "############################CONSTRUCTEUR DE " + Url);
    if (Url.endsWith("/"))
      Url = Url.substring(0,Url.length()-1);
    this.Url = Url;
    InitCache(Url);
  }

/** Constructeur
  * @param Url l'url a construire
  * @param Cache si = vrai on met dans le cache le repertoire
  * note : on a un cache (static a la classe) on ne se connecte a l'url que si elle ne se trouve pas
  *        dans le cache
  */
  FtpDir(String Url, boolean Cache)
  {

    if (Url.endsWith("/"))
      Url = Url.substring(0,Url.length()-1);
    this.Url = Url;

    if (Cache) 
      InitCache(Url);
    else {
      Connect = new Ftp(Url);
      Init.println(ClassName, "Constuction d'urldir sans cache");
    }
  }

/** 
  * @param path le path a comparer
  * @return renvoie vrai si path est un repertoire, faux sinon
  */  
  public boolean isDirectory(String path)
  {

    Init.println(ClassName,"IsDirectory("+path+")");
    if (path != null && path.startsWith("/"))
      path = path.substring(1);

    if (dc.isIn(Url+(path.length()>0? ("/"+path):"")))
      return true;

    String s,t;
    Hashtable ft;
    int i = path.lastIndexOf("/");

    s = path.substring(0,i==-1?0:i);
    if (s.equals("/"))
      s = "";

    t = path.substring(i+1);
    if (s.length() > 0)
      ft = dc.Element(Url+"/"+s);
    else
       ft = dc.Element(Url);

    Init.println(ClassName,"test="+Url+"  s=="+s+" t==" + t);
    if (ft == null ) return false;
    return (((FileType)ft.get(t)).isDirectory());
  }
  
/** Renvoie la liste pour repertoire donne
  * @param path le path ou aller chercher la liste
  * @return renvoie un tableau de string representant le repertoire (on se connecte si on a pas le path
  *         dans le cache)
  */
public String[] list(String path)
  { 
    
    String s;
    
    if (path == null || path.length() == 0)
      s = Url;
    else {
      if (path.startsWith("/"))
	path = path.substring(1);
      s = Url + "/" +path;
    }
    Init.println(ClassName,"list, s==" + s);
    if (!dc.isIn(s)) {
      Init.println(ClassName,"n'est pas deja dans le cache");
      if (path != null)
	dc.addElement(s, Connect.GetFullList(path),true);
      else
	dc.addElement(s, Connect.GetFullList(),true);
    }
    else
      Init.println(ClassName,"est deja dans le cache");
    
    return dc.list(s);
  }

/** Renvoie la liste pour un repertoire donne
  * @param path le path ou aller chercher la liste
  * @param filter le filenamefilter 
  * @return renvoie un tableau de string representant le repertoire (on se connecte si on a pas le path
  *         dans le cache)
  *         la liste est renvoyee par rapport au FileNameFilter
  */ 
public String[] list(String path, FilenameFilter filter) 
  { 
    Init.println(ClassName, "+++++list(filter):"+path);
    String [] tmp = list(path);
    Vector vtmp = new Vector();
         
    for (int i = 0; i<tmp.length; i++) {
      Init.println(ClassName, "Possible choice:"+tmp[i]);
      if (filter.accept(null, path+"/"+tmp[i])) {
        Init.println(ClassName, "Element added:"+tmp[i]);
        vtmp.addElement(tmp[i]);
      }
    }   

    tmp = new String [vtmp.size()];
    for (int i =0; i<vtmp.size(); i++)
      tmp[i] = vtmp.elementAt(i).toString(); 
    
    return tmp;
  }
  
 
/**  Charge le fichier source vers le fichier dest 
  * @param Source le fichier source
  * @param Dest le fichier dest
  * @return renvoie vrai si tout c'est bien passe
  */
public boolean GetFile(String Source, String Dest)
  {
    Init.println(ClassName, "GetFile de " + Source + " vers " + Dest + "Connect=" + Connect);
    if (Dest != null)
      return Connect.GetFile(Source,Dest);
    
    return Connect.GetFile(Source);
  }

/** Met le fichier source vers le fichier dest 
  * @param Source le fichier source
  * @param Dest le fichier dest
  * @return renvoie vrai si tout c'est bien passe
  */
public boolean PutFile(String Source, String Dest)
  {
    Init.println(ClassName, "PutFile de " + Source + " vers " + Dest);
    if (Dest != null)
      return Connect.PutFile(Source,Dest);
    
    return Connect.PutFile(Source);
  }
}



