package com.one;

import com.one.file.Connector;
import com.one.file.FileConnection;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Vector;

public class ArchiveConnection implements FileConnection
{
	protected FileConnection base;
	protected ArchiveContainer container;
	protected ArchiveEntry entry;
	protected int mode;

	protected String contname; // имя файла от диска до имени контейнера включительно
	protected String filepath; // путь к файлу внутри контейнера
	protected String filename; // имя файла

	protected boolean isdirectory;

	public ArchiveConnection(FileConnection base, ArchiveContainer container, String file, int mode) throws IOException
	{
		this.base = base;
		this.container = container;
		this.mode = mode;

		contname = base.getPath() + base.getName() + "/";
		int index = file.lastIndexOf('/', file.length() - 2) + 1;
		filepath = file.substring(0, index);
		filename = file.substring(index);

		entry = container.getEntry(file);

		if(entry == null)
		{
			entry = new ArchiveEntry(filepath + filename);
			entry.pureVirtual = true;
		}

		isdirectory = filename.endsWith("/") || filename.length() == 0;
	}

	public void close()
	{
	}

	public long availableSize()
	{
		return base.availableSize();
	}

	public boolean canRead()
	{
		return true;
	}

	public boolean canWrite()
	{
		return !container.isReadOnly();
	}

	public void create() throws IOException
	{
		if(exists() || isdirectory)
		{
			throw new IOException("Entry already exists or is a directory");
		}

		container.virtualizeEntry(entry);
		container.addFile(entry.getName());
	}

	public void delete() throws IOException
	{
		if(!exists())
		{
			throw new IOException("Entry does not exist");
		}

		if(isdirectory && container.listFiles(filepath + filename).hasMoreElements())
		{
			throw new IOException("Directory is not empty");
		}

		if(entry.vfc != null)
		{
			Connector.releaseTempFile(entry.vfc.getPath() + entry.vfc.getName());

			entry.vfc.delete();
			entry.vfc.close();
		}

		if(!container.deleteEntry(entry))
		{
			throw new IOException("Entry not deleted or not found");
		}
	}

	public long directorySize(boolean includeSubDirs) throws IOException
	{
		if(!isdirectory)
		{
			throw new IOException("Entry is a file");
		}

		return container.directorySize(filepath + filename, includeSubDirs);
	}

	public boolean exists()
	{
		return entry.getName().length() > 0 ? container.fileExists(entry.getName()) : true;
	}

	public long fileSize() throws IOException
	{
		if(isdirectory)
		{
			throw new IOException("Entry is a directory");
		}

		if(entry.vfc != null)
		{
			return entry.vfc.fileSize();
		}
		else
		{
			if(entry.getSize() < 0)
			{
				container.virtualizeEntry(entry);
				return entry.vfc.fileSize();
			}
			else
			{
				return entry.getSize();
			}
		}
	}

	public long compressedSize() throws IOException
	{
		if(isdirectory)
		{
			throw new IOException("Entry is a directory");
		}

		return entry.getCompressedSize();
	}

	public String getName()
	{
		return filename;
	}

	public String getPath()
	{
		return contname + filepath;
	}

	public String getURL()
	{
		return "file://" + contname + filepath + filename;
	}

	public boolean isDirectory()
	{
		return isdirectory;
	}

	public boolean isHidden()
	{
		return false;
	}

	public boolean isOpen()
	{
		return entry != null;
	}

	public long lastModified()
	{
		long time = entry.getLastModified();
		return time >= 0 ? time : base.lastModified();
	}

	public Enumeration list() throws IOException
	{
		if(!exists() || !isdirectory)
		{
			throw new IOException("Entry does not exist or is a file");
		}

		return container.listFiles(filepath + filename);
	}

	public Enumeration list(String filter, boolean includeHidden) throws IOException
	{
		Enumeration srcfiles = list();
		Vector dstfiles = new Vector();
		StringPattern pattern = new StringPattern(filter, true);
		String fname;

		while(srcfiles.hasMoreElements())
		{
			fname = (String)srcfiles.nextElement();

			if(pattern.matchesWith(fname))
			{
				dstfiles.addElement(fname);
			}
		}

		return dstfiles.elements();
	}

	public void mkdir() throws IOException
	{
		if(exists() || !isdirectory)
		{
			throw new IOException("Entry already exists or is a file");
		}

		container.addFile(entry.getName());
	}

	public DataInputStream openDataInputStream() throws IOException
	{
		return new DataInputStream(openInputStream());
	}

	public DataOutputStream openDataOutputStream() throws IOException
	{
		return new DataOutputStream(openOutputStream());
	}

	public InputStream openInputStream() throws IOException
	{
		if(!exists() || isdirectory)
		{
			throw new IOException("Entry does not exist or is a directory");
		}

		if(mode != Connector.READ)
		{
			container.virtualizeEntry(entry);
		}

		if(entry.vfc != null)
		{
			return entry.vfc.openInputStream();
		}
		else
		{
			return container.getInputStream(entry);
		}
	}

	public OutputStream openOutputStream() throws IOException
	{
		if(!exists() || isdirectory)
		{
			throw new IOException("Entry does not exist or is a directory");
		}

		container.virtualizeEntry(entry);

		return entry.vfc.openOutputStream();
	}

	public OutputStream openOutputStream(long byteOffset) throws IOException
	{
		if(!exists() || isdirectory)
		{
			throw new IOException("Entry does not exist or is a directory");
		}

		container.virtualizeEntry(entry);

		return entry.vfc.openOutputStream(byteOffset);
	}

	public void rename(String newName) throws IOException
	{
		if(isdirectory)
		{
			container.renameDirectory(entry.getName(), filepath + newName);
		}
		else
		{
			container.renameEntry(entry, filepath + newName);
		}
	}

	public void setFileConnection(String fileName) throws IOException
	{
		throw new IOException("Operation not supported");
	}

	public void setHidden(boolean hidden)
	{
	}

	public void setReadable(boolean readable)
	{
	}

	public void setWritable(boolean writable)
	{
	}

	public long totalSize()
	{
		return base.totalSize();
	}

	public void truncate(long byteOffset) throws IOException
	{
		if(!exists() || isdirectory)
		{
			throw new IOException("Entry does not exist or is a directory");
		}

		container.virtualizeEntry(entry);

		entry.vfc.truncate(byteOffset);
	}

	public long usedSize()
	{
		return base.totalSize();
	}
}
