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

import java.io.*;
import java.text.*;
import javax.swing.*;

/**
 * Abstract parent of the burn command classes.
 *
 * @version 20030303
 * @author Jörg P. M. Haeger
 */
abstract public class Burn extends Command {
	final static String
	hintBlankingTOC = "blanking TOC",
	hintCDdetected = "CD detected",
	hintCDrecordStarted = "cdrecord started",
	hintCDwasClosed = "CD was closed",
	hintDVDFormatStarted = "dvd-format started",
	hintFixating = "fixating",
	hintGrowisofsStarted = "growisofs started",
	hintImageReady = "image ready",
	hintMakingImage = "making image",
	hintPercentDone = "percentDone",
	hintVerifying = "verifying",
	hintWriterReserved = "writer reserved"
	;

	QueueDialog queueDialog;
	JOptionPane optionPane;
	BurnDialog burnDialog;
	int totalKB, oldFreeKB, newFreeKB;
	boolean CDwasClosed = false;
	Object[] options = { i18n("details"), "OK" };
	String burnSessionResult;
	boolean burnSessionResultOK;

	Burn() {
		burnDialog = new BurnDialog();
	}

	void cancelCommand() {
		try {
			writeCommand("noop");
		}
		catch (java.io.IOException e) {
			System.out.println("cancelCommand: IOException");
		}
	}

	private JDialog createErrorDialog() {
		optionPane = new JOptionPane(
			burnSessionResult,
			JOptionPane.ERROR_MESSAGE,
			JOptionPane.DEFAULT_OPTION,
			null, options);
		return optionPane.createDialog(
			CDcreator.mainWin, i18n("error"));
	}

	private JDialog createSuccessDialog() {
		MessageFormat formatter = new MessageFormat("");
		formatter.setLocale(CDcreator.locale);
		if (CDwasClosed)
			formatter.applyPattern(
				i18n("burnSuccessCDwasClosed"));
		else
			formatter.applyPattern(i18n("burnSuccess"));

		int writtenKB = oldFreeKB - newFreeKB;
		if (totalKB < 1024 * 1024) {
			// is a CD-R(W)
			writtenKB -= 2 * (4500 + 2250);
			if (oldFreeKB == totalKB)
				// lead out of the first session
				writtenKB -= 2 * 4500;
			if (writtenKB < 0)
				writtenKB = 0;
		}

		Object[] args = {
			new Integer(writtenKB / 1024),
			new Integer(newFreeKB / 1024),
			new Integer(totalKB / 1024) };

		optionPane = new JOptionPane(
			formatter.format(args),
			JOptionPane.INFORMATION_MESSAGE,
			JOptionPane.DEFAULT_OPTION,
			null, options);
		return optionPane.createDialog(
			CDcreator.mainWin, i18n("titleBurnResult"));
	}

	abstract protected void execBurnCommand();

	protected void execOptions() {
	}

	void parseCapacityHint(String lineStr) throws IOException {
		StreamTokenizer tokenizer
			= new StreamTokenizer(
				new StringReader(lineStr));

		tokenizer.nextToken();
		if (!tokenizer.sval.equals("capacity"))
			return;

		if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
			return;
		totalKB = (int)tokenizer.nval;

		if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
			return;
		oldFreeKB = (int)tokenizer.nval;

		if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
			return;
		newFreeKB = (int)tokenizer.nval;
	}

	void parseCDrecordLine(String lineStr) throws IOException {
		StreamTokenizer tokenizer
			= new StreamTokenizer(
				new StringReader(lineStr));
		tokenizer.wordChars(':', ':');

		tokenizer.nextToken();
		if (!tokenizer.sval.equals("Track"))
			return;

		if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
			return;
		int track = (int)tokenizer.nval;

		if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
			return;
		if (!tokenizer.sval.equals(":"))
			return;

		if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
			return;
		int n = (int)tokenizer.nval;

		if (tokenizer.nextToken() != StreamTokenizer.TT_WORD)
			return;
		if (!tokenizer.sval.equals("of"))
			return;

		if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
			return;
		int N = (int)tokenizer.nval;

		burnDialog.setRange(0, N);
		burnDialog.setProgress(n);

		if (oldFreeKB == 0)
			oldFreeKB = 1024 * N;
	}

	void parsePercentDoneHint(String lineStr) throws IOException {
		StreamTokenizer tokenizer
			= new StreamTokenizer(
				new StringReader(lineStr));

		tokenizer.nextToken();
		if (!tokenizer.sval.equals(hintPercentDone))
			return;

		if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
			return;
		burnDialog.setProgress((int)tokenizer.nval);
	}

	void parseRankHint(String lineStr) throws IOException {
		StreamTokenizer tokenizer
			= new StreamTokenizer(
				new StringReader(lineStr));

		tokenizer.nextToken();
		if (!tokenizer.sval.equals("rank"))
			return;

		if (tokenizer.nextToken() != StreamTokenizer.TT_NUMBER)
			return;
		int rank = (int)tokenizer.nval;
		queueDialog.setRank(rank);
	}

	void processHint(String str) {
//		System.out.println("processHint " + str);
		try {
			if (str.startsWith("rank"))
				parseRankHint(str);
			else
			if (str.startsWith("Track"))
				parseCDrecordLine(str);
			else
			if (str.startsWith("capacity"))
				parseCapacityHint(str);
			else
			if (str.startsWith(hintPercentDone))
				parsePercentDoneHint(str);
		}
		catch (IOException e) {
		}

		if (str.equals(hintWriterReserved)) {
			hideDialog();
			optionPane = new JOptionPane(
				infoStr,
				JOptionPane.INFORMATION_MESSAGE,
				JOptionPane.DEFAULT_OPTION,
				null, cancelButton);
			JDialog dialog = optionPane.createDialog(
				CDcreator.mainWin, i18n("titleInsertCD"));
			showDialog(dialog);
			infoStr = "";
		}
		else
		if (str.equals(hintCDdetected)) {
			Log.put("CD detected");
			burnDialog = new BurnDialog();
			burnDialog.setTitle(i18n("titleBurnSessionControl"));
			burnDialog.setRange(0, 100);
			replaceDialog(burnDialog);
		}
		else
		if (str.equals(hintBlankingTOC)) {
			Log.put("");
			Log.put("cdrecord blank=fast started ==>");
			burnDialog.setMessage(i18n("blankingTOC"));
		}
		else
		if (str.equals(hintDVDFormatStarted)) {
			Log.put("");
			Log.put("dvd+rw-format started ==>");
			burnDialog.setMessage(i18n("formating"));
		}
		else
		if (str.equals(hintMakingImage)) {
			Log.put("");
			Log.put("mkisofs started ==>");
			burnDialog.setTitle(i18n("titleCreateImage"));
			burnDialog.setMessage(i18n("createImage"));
		}
		else
		if (str.equals(hintCDrecordStarted)) {
			Log.put("");
			Log.put("cdrecord started ==>");
//			hideDialog();
			burnDialog.setTitle(i18n("titleBurn"));
			burnDialog.setMessage(i18n("burn"));
			burnDialog.setProgress(0);
//			showDialog(burnDialog);
		}
		else
		if (str.equals(hintGrowisofsStarted)) {
			Log.put("");
			Log.put("growisofs started ==>");
			burnDialog.setTitle(i18n("titleBurn"));
			burnDialog.setMessage(i18n("burn"));
			burnDialog.setProgress(0);
		}
		else
		if (str.equals(hintFixating)) {
			burnDialog.setMessage(i18n("fixating"));
			burnDialog.setProgress(0);
			burnDialog.setRange(0, 100);
		}
		else
		if (str.equals(hintCDwasClosed)) {
			CDwasClosed = true;
		}
		else
		if (str.equals(hintVerifying)) {
			Log.put("");
			Log.put("CDWverify started ==>");
			burnDialog.setTitle(i18n("titleVerifying"));
			burnDialog.setMessage(i18n("verifying"));
			burnDialog.setProgress(0);
			burnDialog.setRange(0, 100);
		}
	}

	void processInfo(String str) {
		super.processInfo(str);
		if (optionPane != null)
			optionPane.setMessage(infoStr);
	}

	public void run() {
		queueDialog = new QueueDialog(
			CDcreator.mainWin, i18n("titleReserve"),
			i18n("reserve"));
		showDialog(queueDialog);

		execCommand("resetOptions");
		execOptions();

		if (Options.format)
			execCommand("setFormat");

		execCommand("setSpeed " + Options.speed);

		if (Options.offline)
			execCommand("setBurnOffline");

		execBurnCommand();
		burnSessionResult = lastResult;
		burnSessionResultOK = lastResultOK();

		hideDialog();

		if (Options.offline) {
			JOptionPane pane = new JOptionPane(
				infoStr + "\n"
				+ Version.product + " "
				+ i18n("willNowExit"),
				JOptionPane.INFORMATION_MESSAGE,
				JOptionPane.DEFAULT_OPTION,
				null, okButton);
			JDialog dialog = pane.createDialog(
				CDcreator.mainWin, i18n("titleInsertCD"));
			showInfoWin(dialog);
			super.run();
			return;
		}

		try {
			if (cancel)
				readResult();
		}
		catch (java.io.IOException e) {
			System.out.println("BurnSession: IOException");
		}

		super.run();
	}

	void showResult() {
		if (cancel || Options.offline)
			return;

		JDialog dialog;
		if (burnSessionResultOK)
			dialog = createSuccessDialog();
		else
			dialog = createErrorDialog();

		while (true) {
			optionPane.setInitialValue(options[1]);
			optionPane.setValue(
				JOptionPane.UNINITIALIZED_VALUE);
			dialog.show();
			if (optionPane.getValue() == options[0])
				new LogWin().show();
			else
				break;
		}
	}
}
