/******************************************************************************
 JXPTPrintSetupDialog.cc

	Clients must call BuildWindow() after constructing the object.
	Derived classes must override BuildWindow() and call SetObjects()
	at the end of their implementation.

	BASE CLASS = JXDialogDirector

	Copyright © 1999 by John Lindal. All rights reserved.

 ******************************************************************************/

#include <JXPTPrintSetupDialog.h>
#include <JXWindow.h>
#include <JXTextButton.h>
#include <JXStaticText.h>
#include <JXIntegerInput.h>
#include <JXTextCheckbox.h>
#include <JXRadioGroup.h>
#include <JXTextRadioButton.h>
#include <JXFileNameDisplay.h>
#include <jXGlobals.h>
#include <JString.h>
#include <jFileUtil.h>
#include <jDirUtil.h>
#include <jAssert.h>

// mappings from dialog window to JPTPrinter options

enum
{
	kPrintToPrinterID = 1,
	kPrintToFileID
};
static const JXPTPrinter::Destination kIndexToDest[] =
{
	JXPTPrinter::kPrintToPrinter,
	JXPTPrinter::kPrintToFile
};
static const JSize kDestCount = sizeof(kIndexToDest)/sizeof(JXPTPrinter::Destination);

/******************************************************************************
 Constructor

 ******************************************************************************/

JXPTPrintSetupDialog::JXPTPrintSetupDialog()
	:
	JXDialogDirector(JXGetApplication(), kTrue)
{
}

/******************************************************************************
 Destructor

 ******************************************************************************/

JXPTPrintSetupDialog::~JXPTPrintSetupDialog()
{
}

/******************************************************************************
 BuildWindow

 ******************************************************************************/

void
JXPTPrintSetupDialog::BuildWindow
	(
	const JXPTPrinter::Destination	dest,
	const JCharacter*				printCmd,
	const JCharacter*				fileName,
	const JBoolean					printLineNumbers
	)
{
// begin JXLayout

    JXWindow* window = new JXWindow(this, 370,220, "");
    assert( window != NULL );
    SetWindow(window);

    itsPrintCmdLabel =
        new JXStaticText("Print command:", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 10,70, 100,19);
    assert( itsPrintCmdLabel != NULL );

    JXTextButton* okButton =
        new JXTextButton("Print", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 219,189, 72,22);
    assert( okButton != NULL );
    okButton->SetShortcuts("^M");

    JXTextButton* cancelButton =
        new JXTextButton("Cancel", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 70,190, 70,20);
    assert( cancelButton != NULL );

    JXStaticText* obj1 =
        new JXStaticText("Destination:", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 50,30, 80,20);
    assert( obj1 != NULL );

    itsDestination =
        new JXRadioGroup(window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 135,20, 139,39);
    assert( itsDestination != NULL );

    JXTextRadioButton* obj2 =
        new JXTextRadioButton(1, "Printer", itsDestination,
                    JXWidget::kHElastic, JXWidget::kVElastic, 5,8, 70,20);
    assert( obj2 != NULL );
    obj2->SetShortcuts("#P");

    JXTextRadioButton* obj3 =
        new JXTextRadioButton(2, "File", itsDestination,
                    JXWidget::kHElastic, JXWidget::kVElastic, 75,8, 50,20);
    assert( obj3 != NULL );
    obj3->SetShortcuts("#F");

    itsPrintCmd =
        new JXInputField(window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 110,70, 240,20);
    assert( itsPrintCmd != NULL );

    itsChooseFileButton =
        new JXTextButton("Choose file", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 30,70, 80,20);
    assert( itsChooseFileButton != NULL );
    itsChooseFileButton->SetShortcuts("#O");

    itsCopyCount =
        new JXIntegerInput(window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 140,110, 40,20);
    assert( itsCopyCount != NULL );

    itsFirstPageIndex =
        new JXIntegerInput(window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 230,150, 40,20);
    assert( itsFirstPageIndex != NULL );

    itsLastPageIndex =
        new JXIntegerInput(window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 290,150, 40,20);
    assert( itsLastPageIndex != NULL );

    itsPrintAllCB =
        new JXTextCheckbox("Print all pages", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 40,150, 120,20);
    assert( itsPrintAllCB != NULL );
    itsPrintAllCB->SetShortcuts("#A");

    itsFirstPageIndexLabel =
        new JXStaticText("Print page", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 163,153, 66,20);
    assert( itsFirstPageIndexLabel != NULL );

    itsLastPageIndexLabel =
        new JXStaticText("to", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 273,153, 16,20);
    assert( itsLastPageIndexLabel != NULL );

    JXStaticText* obj4 =
        new JXStaticText("Number of copies:", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 25,110, 115,20);
    assert( obj4 != NULL );

    itsPrintLineNumbersCB =
        new JXTextCheckbox("Print line numbers", window,
                    JXWidget::kHElastic, JXWidget::kVElastic, 220,110, 130,20);
    assert( itsPrintLineNumbersCB != NULL );
    itsPrintLineNumbersCB->SetShortcuts("#N");

// end JXLayout

	SetObjects(okButton, cancelButton, itsDestination, dest,
			   itsPrintCmdLabel, itsPrintCmd, printCmd,
			   itsChooseFileButton, fileName, itsCopyCount,
			   itsPrintAllCB, itsFirstPageIndexLabel,
			   itsFirstPageIndex, itsLastPageIndexLabel, itsLastPageIndex,
			   itsPrintLineNumbersCB, printLineNumbers);
}

/******************************************************************************
 SetObjects (protected)

 ******************************************************************************/

void
JXPTPrintSetupDialog::SetObjects
	(
	JXTextButton*					okButton,
	JXTextButton*					cancelButton,
	JXRadioGroup*					destinationRG,
	const JXPTPrinter::Destination	dest,
	JXStaticText*					printCmdLabel,
	JXInputField*					printCmdInput,
	const JCharacter*				printCmd,
	JXTextButton*					chooseFileButton,
	const JCharacter*				fileName,
	JXIntegerInput*					copyCount,
	JXTextCheckbox*					printAllCB,
	JXStaticText*					firstPageIndexLabel,
	JXIntegerInput*					firstPageIndex,
	JXStaticText*					lastPageIndexLabel,
	JXIntegerInput*					lastPageIndex,
	JXTextCheckbox*					printLineNumbersCB,
	const JBoolean					printLineNumbers
	)
{
	itsPrintButton         = okButton;
	itsDestination         = destinationRG;
	itsPrintCmdLabel       = printCmdLabel;
	itsPrintCmd            = printCmdInput;
	itsChooseFileButton    = chooseFileButton;
	itsCopyCount           = copyCount;
	itsPrintAllCB          = printAllCB;
	itsFirstPageIndexLabel = firstPageIndexLabel;
	itsFirstPageIndex      = firstPageIndex;
	itsLastPageIndexLabel  = lastPageIndexLabel;
	itsLastPageIndex       = lastPageIndex;
	itsPrintLineNumbersCB  = printLineNumbersCB;

	JXWindow* window = itsDestination->GetWindow();
	window->SetTitle("Print Setup");
	SetButtons(okButton, cancelButton);

	const JRect r = itsPrintCmd->GetFrame();
	itsFileNameDisplay =
		new JXFileNameDisplay(fileName, window,
							  JXWidget::kHElastic, JXWidget::kVElastic,
							  r.left, r.top, r.width(), r.height());
	assert( itsFileNameDisplay != NULL );

	itsPrintCmd->SetText(printCmd);

	ListenTo(itsDestination);
	ListenTo(itsChooseFileButton);
	ListenTo(itsPrintAllCB);

	JBoolean foundDest = kFalse;
	for (JIndex i=1; i<=kDestCount; i++)
		{
		if (kIndexToDest[i-1] == dest)
			{
			SetDestination(i);
			foundDest = kTrue;
			break;
			}
		}
	assert( foundDest );

	itsCopyCount->SetValue(1);
	itsCopyCount->SetLowerLimit(1);

	PrintAllPages(kTrue);

	itsFirstPageIndex->SetLowerLimit(1);
	itsFirstPageIndex->SetIsRequired(kFalse);

	itsLastPageIndex->SetLowerLimit(1);
	itsLastPageIndex->SetIsRequired(kFalse);

	itsPrintLineNumbersCB->SetState(printLineNumbers);
}

/******************************************************************************
 OKToDeactivate (virtual protected)

 ******************************************************************************/

JBoolean
JXPTPrintSetupDialog::OKToDeactivate()
{
	if (!JXDialogDirector::OKToDeactivate())
		{
		return kFalse;
		}
	else if (Cancelled())
		{
		return kTrue;
		}

	if (itsDestination->GetSelectedItem() == kPrintToFileID)
		{
		const JString& fullName = itsFileNameDisplay->GetText();
		if (fullName.IsEmpty())
			{
			(JGetUserNotification())->ReportError(
				"Please specify a destination file.");
			return kFalse;
			}

		JString path, fileName;
		JSplitPathAndName(fullName, &path, &fileName);
		const JBoolean fileExists = JFileExists(fullName);
		if (!JDirectoryExists(path))
			{
			(JGetUserNotification())->ReportError(
				"The specified directory does not exist.");
			return kFalse;
			}
		else if (!fileExists && !JDirectoryWritable(path))
			{
			(JGetUserNotification())->ReportError(
				"The file cannot be created because the you do not have write access "
				"to the specified directory.");
			return kFalse;
			}
		else if (fileExists && !JFileWritable(fullName))
			{
			(JGetUserNotification())->ReportError(
				"You do not have write access to the specified file.");
			return kFalse;
			}
		}

	return kTrue;
}

/******************************************************************************
 Receive (protected)

 ******************************************************************************/

void
JXPTPrintSetupDialog::Receive
	(
	JBroadcaster*	sender,
	const Message&	message
	)
{
	if (sender == itsDestination && message.Is(JXRadioGroup::kSelectionChanged))
		{
		const JXRadioGroup::SelectionChanged* selection =
			dynamic_cast(const JXRadioGroup::SelectionChanged*, &message);
		assert( selection != NULL );
		SetDestination(selection->GetID());
		}

	else if (sender == itsChooseFileButton && message.Is(JXButton::kPushed))
		{
		ChooseDestinationFile();
		}

	else if (sender == itsPrintAllCB && message.Is(JXCheckbox::kPushed))
		{
		PrintAllPages(itsPrintAllCB->IsChecked());
		}

	else
		{
		JXDialogDirector::Receive(sender, message);
		}
}

/******************************************************************************
 SetDestination (private)

 ******************************************************************************/

void
JXPTPrintSetupDialog::SetDestination
	(
	const JIndex id
	)
{
	itsDestination->SelectItem(id);

	if (id == kPrintToPrinterID)
		{
		itsPrintButton->Activate();
		itsPrintCmdLabel->Show();
		itsPrintCmd->Show();
		itsPrintCmd->SetIsRequired(kTrue);
		itsPrintCmd->Focus();
		itsChooseFileButton->Hide();
		itsFileNameDisplay->Hide();
		}
	else
		{
		assert( id == kPrintToFileID );

		itsPrintCmdLabel->Hide();
		itsPrintCmd->Hide();
		itsPrintCmd->SetIsRequired(kFalse);
		itsChooseFileButton->Show();
		itsFileNameDisplay->Show();

		if ((itsFileNameDisplay->GetText()).IsEmpty())
			{
			ChooseDestinationFile();
			}
		}
}

/******************************************************************************
 PrintAllPages (private)

 ******************************************************************************/

void
JXPTPrintSetupDialog::PrintAllPages
	(
	const JBoolean all
	)
{
	itsPrintAllCB->SetState(all);

	if (all)
		{
		if (itsFirstPageIndex->HasFocus() || itsLastPageIndex->HasFocus())
			{
			(GetWindow())->KillFocus();		// values become irrelevant
			(GetWindow())->SwitchFocusToFirstWidget();
			}
		itsFirstPageIndex->Hide();
		itsLastPageIndex->Hide();
		itsFirstPageIndexLabel->Hide();
		itsLastPageIndexLabel->Hide();
		}
	else
		{
		itsFirstPageIndex->Show();
		itsFirstPageIndex->Focus();
		itsLastPageIndex->Show();
		itsFirstPageIndexLabel->Show();
		itsLastPageIndexLabel->Show();
		}
}

/******************************************************************************
 ChooseDestinationFile (private)

 ******************************************************************************/

void
JXPTPrintSetupDialog::ChooseDestinationFile()
{
	JString fileName;
	if ((JGetChooseSaveFile())->SaveFile("Save text file as:", NULL,
										 itsFileNameDisplay->GetText(), &fileName))
		{
		itsFileNameDisplay->SetText(fileName);
		itsPrintButton->Activate();
		}
	else if ((itsFileNameDisplay->GetText()).IsEmpty())
		{
		itsPrintButton->Deactivate();
		}
}

/******************************************************************************
 SetParameters

 ******************************************************************************/

void
JXPTPrintSetupDialog::SetParameters
	(
	JXPTPrinter* p
	)
	const
{
	p->SetDestination(kIndexToDest[ itsDestination->GetSelectedItem()-1 ],
					  itsPrintCmd->GetText(), itsFileNameDisplay->GetText());

	JInteger copyCount;
	const JBoolean ok = itsCopyCount->GetValue(&copyCount);
	assert( ok );
	p->SetCopyCount(copyCount);

	const JBoolean printAll = itsPrintAllCB->IsChecked();
	p->PrintAllPages();

	if (!printAll)
		{
		JInteger p1, p2;
		const JBoolean ok1 = itsFirstPageIndex->GetValue(&p1);
		const JBoolean ok2 = itsLastPageIndex->GetValue(&p2);
		if (ok1 && ok2)
			{
			p->SetFirstPageToPrint(JMin(p1, p2));
			p->SetLastPageToPrint(JMax(p1, p2));
			}
		else
			{
			if (ok1)
				{
				p->SetFirstPageToPrint(p1);
				}
			if (ok2)
				{
				p->SetLastPageToPrint(p2);
				}
			}
		}

	p->ShouldPrintLineNumbers(itsPrintLineNumbersCB->IsChecked());
}
