/* ======================================================
                  Ricardo Martin Manso
                     PFC - UOC 2010
======================================================= */

package backup;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

// =======================================================
// Utilizado par almacenar datos de directorio
// =======================================================
public class Directorio {

    final static int TIPO_DIR=0;
    final static int TIPO_ARCH=1;

    private String nombre;
    private long ptr;
    private int tipo;
    private long lastMod;
    private List<Directorio> contenido;

    private boolean existe;

    public Directorio()
    {
        contenido=new ArrayList<Directorio>();
        ptr=0;
        nombre="";
        existe=true;
    }

    public Directorio(String nombre)
    {
        contenido=new ArrayList<Directorio>();
        ptr=0;
        tipo=TIPO_DIR;
        this.nombre=nombre;
        existe=true;
    }

    /**
     * @return the nombre
     */
    public String getNombre() {
        return nombre;
    }

    /**
     * @param nombre the nombre to set
     */
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    /**
     * @return the ptr
     */
    public long getPtr() {
        return ptr;
    }

    /**
     * @param ptr the ptr to set
     */
    public void setPtr(long ptr) {
        this.ptr = ptr;
    }

   // public void updatePtr(long ptr)
   // {
   //     setPtr(ptr);
   //     existe=true;
   // }

    /**
     * @return the tipo
     */
    public int getTipo() {
        return tipo;
    }

    /**
     * @param tipo the tipo to set
     */
    public void setTipo(int tipo) {
        this.tipo = tipo;
    }

    /**
     * @return the contenido
     */
    public List<Directorio> getContenido() {
        return contenido;
    }

    /**
     * @param contenido the contenido to set
     */
    public void setContenido(List<Directorio> contenido) {
        this.contenido = contenido;
    }


    public Directorio getDirectorio(String path) 
    {
        Directorio nodo=findNodo(path);
        if (nodo==null) return null;
        if (nodo.getTipo()==TIPO_DIR) 
            return nodo;
        else
            return null;
    }

    public Directorio mkdir(String nombre)
    {
        Directorio nuevo=new Directorio(nombre);
        contenido.add(nuevo);
        //System.out.println("CREANDO DIRECTORIO: "+nombre+" EN "+this.nombre);
        return nuevo;
    }

    public Directorio cd(String nombre) 
    {
        //System.out.println("buscado:["+nombre+"]");
        String dirs[]=nombre.split("['\\\\']");
        int i;
        //System.out.println(dirs.length);
        Directorio nodo=this;
        for(i=0;i<dirs.length;i++) 
        {
            nodo=nodo.getDirectorio(dirs[i]);
            if (nodo==null) return null;
        }
        return nodo;
    }

    public Directorio create(String fichero,long lastMod,long ptr)
    {
        Directorio nuevo=new Directorio();
        nuevo.setNombre(fichero);
        nuevo.setTipo(TIPO_ARCH);
        nuevo.setPtr(ptr);
        nuevo.setLastMod(lastMod);
        contenido.add(nuevo);
        //System.out.println("CREANDO ARCHIVO: "+fichero+" EN "+nombre);
        return nuevo;
    }

    public void delete(Directorio nodo)
    {
        contenido.remove(nodo);
    }

    public void print(String padre)
    {
        if (tipo==TIPO_ARCH)
        {
            System.out.println("[ARCH] "+padre+nombre);
        }
        else
        {
            System.out.println("[DIRE] " +padre+ nombre);
            int i;
            for(i=0;i<contenido.size();i++) contenido.get(i).print(padre+nombre+"\\");
        }
    }
    
    public void print(String padre,Job trabajo)
    {
        if (tipo==TIPO_ARCH)
        {
            if (trabajo.testFiltro(nombre))
                System.out.println("[ARCH] "+padre+nombre);
        }
        else
        {
            if (trabajo.testFiltro(nombre))
                System.out.println("[DIRE] " +padre+ nombre);
            if (trabajo.isRecursivo())
            {
                int i;
                for(i=0;i<contenido.size();i++)
                {
                     contenido.get(i).print(padre + nombre + "\\",trabajo);
                }
            }
        }
    }

    public void purge()
    {
        int i;
        Directorio nodo;
        for(i=contenido.size()-1;i>=0;i--)
        {
            nodo=contenido.get(i);
            if (!nodo.existe)
            {
                //System.out.println("Purgando..."+nodo.getNombre());
                contenido.remove(i);
            }
            else
                if (nodo.tipo==TIPO_DIR) nodo.purge();
        }   
    }

    private long getTamDir()
    {
        int i;
        long t=0;
        t=4;
        for(i=0;i<contenido.size();i++)
        {
            //t+=4+4+contenido.get(i).getNombre().length()*2+8;
            t+=4+4+contenido.get(i).getNombre().length()*2+8+8;
        }
        return t;
    }

    public long findArchivo(String nombre)
    {
        int i;
        for(i=0;i<contenido.size();i++)
        {
            if (contenido.get(i).getNombre().equals(nombre)) return contenido.get(i).getPtr();
        }
        return -1;
    }


    public Directorio findNodo(String nombre)
    {
        int i;
        for(i=0;i<contenido.size();i++)
        {
            if (contenido.get(i).getNombre().equals(nombre)) return contenido.get(i);
        }
        return null;
    }

    public long write(RandomAccessFile fich,long destino) throws IOException
    {
        //System.out.println("Escribiendo DIR:"+nombre+" en:"+destino);
        long t=getTamDir();
        long tt=0;
        long tmp=destino+t;
        int n=contenido.size();
        int i;
        for(i=0;i<n;i++)
        {
            if (contenido.get(i).getTipo()==TIPO_DIR)
            {
                tt=contenido.get(i).write(fich,tmp);
                contenido.get(i).setPtr(tmp);
                tmp+=tt;
            }
        }

        fich.seek(destino);
        fich.writeInt(n);

        ptr=destino;
        for(i=0;i<n;i++)
        {
           fich.writeInt(contenido.get(i).getTipo());
           fich.writeInt(contenido.get(i).getNombre().length());
           fich.writeChars(contenido.get(i).getNombre());
           fich.writeLong(contenido.get(i).getPtr());
           fich.writeLong(contenido.get(i).getLastMod());
        }

        return tmp-destino;
    }

    public void read(RandomAccessFile fich,long destino) throws IOException
    {

        //System.out.println("Leyendo directorio:"+destino);

        long t=getTamDir();
        long tt=0;
        long tmp=destino+t;
        int n=contenido.size();
        int i;

        fich.seek(destino);
        n=fich.readInt();
        
        //System.out.println("NEntradas:"+n);
        
        int z;
        //System.out.println("Nombre:"+nombre+" Posicion:"+destino+" Entradas:"+n);

        for(i=0;i<n;i++)
        {
            Directorio nodo=new Directorio();
            nodo.setExiste(false);
            nodo.setTipo(fich.readInt());
            z=fich.readInt();
            StringWriter buf=new StringWriter(z);
            int k;
            for(k=0;k<z;k++) buf.write(fich.readChar());
            nodo.setNombre(buf.toString());
            //System.out.println("Contenido:"+nodo.getNombre());
            nodo.setPtr(fich.readLong());
            nodo.setLastMod(fich.readLong());
            contenido.add(nodo);
        }

        for(i=0;i<n;i++)
        {
            if (contenido.get(i).getTipo()==TIPO_DIR) contenido.get(i).read(fich,contenido.get(i).getPtr());
        }
    }

    /**
     * @return the lastMod
     */
    public long getLastMod() {
        return lastMod;
    }

    /**
     * @param lastMod the lastMod to set
     */
    public void setLastMod(long lastMod) {
        this.lastMod = lastMod;
    }

    /**
     * @return the existe
     */
    public boolean isExiste() {
        return existe;
    }

    /**
     * @param existe the existe to set
     */
    public void setExiste(boolean existe) {
        this.existe = existe;
    }

}
