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

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

/**
 * Abstract parent of the burn command classes.
 *
 * @version 20030807
 * @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"
	;

	protected JDialog activeDialog;
	protected JOptionPane optionPane = null, subPane = null;
	BurnDialog burnDialog;
	int totalKB, oldFreeKB, newFreeKB;
	boolean CDwasClosed = false;
	final String backButton = i18n("MainWin.back");
	final String offlineButton = i18n("burnOffline");
	Object[] options = { i18n("details"), okButton2 };
	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() {
	}

	/**
	 * Get the next dialog of a sequence of user dialogs.
	 */
	protected JDialog nextDialog() {
		if (optionPane == null)
			return null;

		if (subPane != null)
			if (subPane.getValue() == okButton2) {
				try {
					writeCommand("setBurnOffline");
				}
				catch (Exception e) {
				}
				CDcreator.closeMainWin();
				subPane = null;
				return null;
			}
			else {
				subPane = null;
				return activeDialog;
			}

		if (optionPane.getValue() == offlineButton) {
			String[] options = { backButton, okButton2 };
			subPane = new JOptionPane(
				i18n("willNowExit"),
				JOptionPane.INFORMATION_MESSAGE,
				JOptionPane.DEFAULT_OPTION,
				null, options);
			return subPane.createDialog(
				CDcreator.mainWin, i18n("burnOffline"));
		}

		return null;
	}

	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;

		JPanel hp = new JPanel();
		hp.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
		hp.setLayout(new BoxLayout(hp, BoxLayout.X_AXIS));
		hp.add(new JLabel(
			CDcreator.i18n("queue") + " " + rank));
		hp.add(Box.createHorizontalStrut(10));

		JButton button = new JButton(CDcreator.i18n("showStatus"));
		button.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				CDcreator.showServerDocument("");
			}
		});
		hp.add(button);

		optionPane.setMessage(hp);
		activeDialog.pack();
	}

	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();
			JPanel vbox = new JPanel();
			vbox.setLayout(new BoxLayout(vbox, BoxLayout.Y_AXIS));
			vbox.add(Box.createVerticalStrut(10));
			int p0 = 0;
			while (true) {
				int p1 = infoStr.indexOf('\n', p0);
				if (p1 < 0)
					break;
				JLabel l = new JLabel(infoStr.substring(p0, p1));
				l.setAlignmentX(JPanel.LEFT_ALIGNMENT);
				vbox.add(l);
				vbox.add(Box.createVerticalStrut(5));
				p0 = p1 + 1;
			}
			vbox.add(Box.createVerticalStrut(5));
			String[] options = { cancelButton, offlineButton };
			optionPane = new JOptionPane(
				vbox,
				JOptionPane.INFORMATION_MESSAGE,
				JOptionPane.DEFAULT_OPTION,
				null, options);
			activeDialog = optionPane.createDialog(
				CDcreator.mainWin, i18n("titleInsertCD"));
			showDialog(activeDialog);
			infoStr = "";
		}
		else
		if (str.equals(hintCDdetected)) {
			Log.put("Medium 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("BurnDialog.formatting"));
		}
		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);
		}
		else
		if (str.startsWith("Medium ")
				|| str.indexOf("-> eject") >= 0) {
			Log.put(str);
			final Object panel = optionPane.getMessage();
			if (panel instanceof JPanel
					&& Log.getView().getParent() != panel)
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run() {
//							Log.getView().setPreferredSize(
//								new Dimension(160, 100));
							Log.getView().setAlignmentX(
								JPanel.LEFT_ALIGNMENT);
							((JPanel)panel).add(Log.getView());
//							activeDialog.pack();
							Dimension d = activeDialog.getSize();
							d.height += 100;
							activeDialog.setSize(d);
						}
					});
				}
				catch (Exception e) {
				}
		}
	}

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

	public void run() {
		if (activeDialog != null)
			System.out.println("activeDialog != null");
		String[] options = { cancelButton, offlineButton };
		optionPane = new JOptionPane(
			i18n("reserve"),
			JOptionPane.INFORMATION_MESSAGE,
			JOptionPane.DEFAULT_OPTION,
			MainWin.getIcon("burn.png"), options, options[1]);
		activeDialog = optionPane.createDialog(
			CDcreator.mainWin, i18n("titleReserve"));
		showDialog(activeDialog);

		execCommand("resetOptions");
		execOptions();

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

		if (Options.speed > 0)
			execCommand("setSpeed " + Options.speed);

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

		hideDialog();

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

		super.run();
	}

	void showResult() {
		if (cancel)
			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;
		}
	}
}
