/*
 * @(#)CDNode.java
 *
 * This file is part of webCDwriter - Network CD Writing.
 *
 * Copyright (C) 2001-2004 Jörg P. M. Haeger
 *
 * webCDwriter is free software. See CDcreator.java for details.
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import javax.swing.tree.DefaultTreeModel;

/**
 * CDNode
 *
 * @version 20040211
 * @author Jörg P. M. Haeger
 */
class CDNode extends DirTreeNode {
	public CDNode(String aName) {
		super(aName);
	}

	public CDNode(File aFile) {
		super(aFile);
	}

	public void clearCache() {
		clear = true;
	}

	protected DirTreeNode createNode(File file) {
		return new CDNode(file);
	}

	protected void expand() {
		if (expanded)
			return;

		super.expand();
//		recount();
//		CDTreeModel.reload();

		String lsPath = "/bin/ls";
		boolean lsAvailable = false;
		try {
			lsAvailable = new SecFile(lsPath).canRead();
		}
		catch (Exception e) {
		}

		// get the executable bit of UNIX files
		// by running a "ls -l" child process
		if (!(file instanceof ServerFile)
				&& lsAvailable
				&& !CDcreator.isNetscapeVM())
		try {
//			netscape.security.PrivilegeManager.enablePrivilege(
//				"UniversalExecAccess");
			int count = 0;
			Version.debug("ls -l", "Running <"
				+ lsPath + " -l " + file.getPath() + ">");
			Process ls = Runtime.getRuntime().exec(
				lsPath + " -l " + file.getPath());
			BufferedReader in = new BufferedReader(
				new InputStreamReader(
					ls.getInputStream()));
			while (true) {
				if (CDcreator.isNetscapeVM()) {
					// workaround since Netscape 4 hangs at the
					// end of the input from the child process
//					if (!in.ready() && count > 0)
					if (count == childs.getNumOfNodes()) {
//						ls.getInputStream().close();
//						ls.getOutputStream().close();
						ls.destroy();
						break;
					}
				}
				String line = in.readLine();
				if (line == null)
					break;
				StringTokenizer tokenizer = new StringTokenizer(
					line, "\t ");

				int mode = 0;
				String modeStr = tokenizer.nextToken();
				if (modeStr.charAt(0) != '-'
					&& modeStr.charAt(0) != 'd'
					&& modeStr.charAt(0) != 'l')
					continue;

				count++;

				if (modeStr.charAt(0) == 'd')
					continue;

				for (int i = 1; i <= 9; i++) {
					mode *= 2;
					if (modeStr.charAt(i) != '-')
						mode += 1;
				}

				tokenizer.nextToken();
				tokenizer.nextToken();
				tokenizer.nextToken();
				long size = Long.parseLong(tokenizer.nextToken());
				tokenizer.nextToken();
				tokenizer.nextToken();
				tokenizer.nextToken();
				String name = tokenizer.nextToken();
				if (count < 3 || count > childs.getNumOfNodes() - 3)
					Version.debug("ls -l",
						count + " of " + childs.getNumOfNodes()
						+ " <" + name + "> "
						+ Integer.toOctalString(mode) + " " + size);

				if ((mode & 0111) > 0)
				for (int i = 0; i < childs.getNumOfNodes(); i++) {
					DirTreeNode node = (DirTreeNode)childs.getNode(i);
					if (node.file.getName().equals(name)) {
						node.isExe = true;
						break;
					}
				}
			}
		}
		catch (Exception e) {
		}
	}

	public int getNumOfFiles() {
		return numOfFiles;
	}

	public long getSize() {
		return size;
	}

	public void recount() {
		if (isLeaf()) {
			numOfFiles = 1;
			if (Mode.audioCD())
				if (file instanceof ServerFile)
					size = ((ServerFile)file).getSeconds();
				else
				try {
					size = new Wave(file).getSeconds();
				} catch (Exception e) {
					try {
						if (file.getName().toLowerCase().endsWith(".mp3"))
							size = new MP3(file).getSeconds();
						else
							size = new Ogg(file).getSeconds();
					}
					catch (Exception e2) {
						size = 0;
					}
				}
			else
				size = roundTo2048Blocks(file.length());
			Project.numOfFiles++;
			Project.size += size;
			if (!(file instanceof ServerFile))
				Project.transferSize += size;
		}
		else
		if (expanded) {
			numOfFiles = 0;
			size = 0;
			for (int i = 0; i < childs.numOfNodes; i++) {
				if (State.stopRecount || Project.isTooBig())
					return;
				CDNode child = (CDNode)childs.getNode(i);
				if (clear)
					child.clearCache();
				child.recount();
				numOfFiles += child.getNumOfFiles();
				size += child.getSize();
			}
		}
		else {
			if (clear || numOfFiles == 0) {
				numOfFiles = 0;
				size = 0;
				recount(file);
			}
			else {
				Project.numOfFiles += numOfFiles;
				Project.size += size;
				if (!(file instanceof ServerFile))
					Project.transferSize += size;
			}
		}
		clear = false;
	}

	private void recount(File file) {
		if (!file.isDirectory()) {
			numOfFiles++;
			long cluster = roundTo2048Blocks(file.length());
			size += cluster;
			Project.numOfFiles++;
			Project.size += cluster;
			if (!(file instanceof ServerFile))
				Project.transferSize += cluster;
			return;
		}

		if (file instanceof ServerFile) {
			Stat stat = new Stat();
			stat.run(file.getPath());
			long n = stat.seconds / 1000 / 1000 / 1000;
			long s = stat.seconds - 1000 * 1000 * 1000 * n;
			n /= 10;
			numOfFiles += n;
			size += 1024 * s;
			Project.numOfFiles += n;
			Project.size += 1024 * s;
			return;
		}

		File files[] = ((File2)file).listFiles();
		if (files != null)
			for (int i = 0; i < files.length; i++) {
				if (State.stopRecount || Project.isTooBig()) {
					numOfFiles = 0;
					return;
				}
				recount(files[i]);
			}

		Thread.yield();
	}

	private long roundTo2048Blocks(long n) {
		if (n <= 0)
			return 0;
		else
			return 2048 * (((n - 1) / 2048) + 1);
	}

//	static DefaultTreeModel CDTreeModel;
	/** cache the size of the subtrees */
	private boolean clear = true;
	private int numOfFiles = 0;
	private long size = 0;
}
