/*=========================================================================

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkKWRegistrationWizard.h"

#include "vtkKWApplicationPro.h"
#include "vtkKWComputerID.h"
#include "vtkKWEntry.h"
#include "vtkKWFrame.h"
#include "vtkKWIcon.h"
#include "vtkKWInternationalization.h"
#include "vtkKWLabel.h"
#include "vtkKWEntryWithLabel.h"
#include "vtkKWLabelWithLabel.h"
#include "vtkKWLoadSaveButtonWithLabel.h"
#include "vtkKWRadioButtonSetWithLabel.h"
#include "vtkKWLoadSaveButton.h"
#include "vtkKWLoadSaveDialog.h"
#include "vtkKWMessageDialog.h"
#include "vtkKWPushButton.h"
#include "vtkKWRadioButton.h"
#include "vtkKWRadioButtonSet.h"
#include "vtkObjectFactory.h"
#include "vtkKWWindow.h"
#include "vtkKWTkUtilities.h"
#include "vtkKWText.h"

#include <vtksys/SystemTools.hxx>

#include <time.h>

#define VTK_KW_RW_KEY_SIZE 2048

#define VTK_KW_RW_REG_TYPE_TRIAL_ID           0
#define VTK_KW_RW_REG_TYPE_FULL_ID            1
#define VTK_KW_RW_REG_TYPE_LIMITED_EDITION_ID 2

#define VTK_KW_RW_MAX_NB_DAYS 365

//----------------------------------------------------------------------------
vtkStandardNewMacro( vtkKWRegistrationWizard );
vtkCxxRevisionMacro(vtkKWRegistrationWizard, "$Revision: 1.57 $");

//----------------------------------------------------------------------------
vtkKWRegistrationWizard::vtkKWRegistrationWizard()
{
  this->ComputerID                  = vtkKWComputerID::New();

  this->PublicEncryptionKey         = NULL;
  this->PrivateEncryptionKey        = NULL;

  this->LicenseKeyRegistrySubKey   = NULL;
  this->LicenseKeyRegistryKey      = NULL;

  this->FullModeName                = NULL;

  this->SetFullModeName(ks_("Registration Wizard|Full Mode Name|full"));

  this->ExpectedLicenseKeyFileName          = NULL;
  this->RegistrationURL             = NULL;

  this->SetLicenseKeyRegistrySubKey("Setup");
  this->SetLicenseKeyRegistryKey("LicenseKey");

  this->LimitedEditionModeRegistrySubKey = NULL;
  this->LimitedEditionModeRegistryKey    = NULL;

  this->SetLimitedEditionModeRegistrySubKey("Setup");
  this->SetLimitedEditionModeRegistryKey("LimitedEditionMode");

  this->Invoked                     = 0;

  this->SupportTrialMode            = 1;
  this->SupportLimitedEditionMode   = 1;

  this->RegistrationChoice          = vtkKWRegistrationWizard::INVALID_MODE;
  this->LicenseKey                  = NULL;

  // Registration type

  this->RegistrationTypeFrame       = NULL;
  this->RegistrationTypeInfoLabel   = NULL;
  this->RegistrationTypeChoice      = NULL;

  // Purchase

  this->PurchaseApplicationParametersFrame = NULL;
  this->PurchaseApplicationTextArea        = NULL;

  // Internet connection

  this->InternetConnectionFrame       = NULL;
  this->InternetConnectionChoice      = NULL;

  // Trial Mode

  this->OnlineRegistrationParametersFrame    = NULL;
  this->OnlineRegistrationEmailEntry         = NULL;

  this->OnlineRegistrationConfirmationFrame  = NULL;
  this->OnlineRegistrationConfirmationLabel  = NULL;

  // Full Mode

  this->OfflineRegistrationParametersFrame     = NULL;
  this->OfflineRegistrationTextArea            = NULL;
  this->OfflineRegistrationLicenseFileButton   = NULL;
  this->OfflineRegistrationErrorLabel          = NULL;

  this->OfflineRegistrationConfirmationFrame   = NULL;
  this->OfflineRegistrationConfirmationLabel   = NULL;

  // Build Date

  this->MostRecentDate = 0;
}

//----------------------------------------------------------------------------
vtkKWRegistrationWizard::~vtkKWRegistrationWizard()
{
  this->SetFullModeName(NULL);

  this->SetExpectedLicenseKeyFileName(NULL);

  this->SetPublicEncryptionKey(NULL);
  this->SetPrivateEncryptionKey(NULL);

  this->SetLicenseKeyRegistrySubKey(NULL);
  this->SetLicenseKeyRegistryKey(NULL);

  this->SetLimitedEditionModeRegistrySubKey(NULL);
  this->SetLimitedEditionModeRegistryKey(NULL);

  this->SetLicenseKey(NULL);

  if (this->ComputerID)
    {
    this->ComputerID->Delete();
    this->ComputerID = NULL;
    }

  // Registration type

  if (this->RegistrationTypeFrame)
    {
    this->RegistrationTypeFrame->Delete();
    this->RegistrationTypeFrame = NULL;
    }

  if (this->RegistrationTypeInfoLabel)
    {
    this->RegistrationTypeInfoLabel->Delete();
    this->RegistrationTypeInfoLabel = NULL;
    }

  if (this->RegistrationTypeChoice)
    {
    this->RegistrationTypeChoice->Delete();
    this->RegistrationTypeChoice = NULL;
    }

  if (this->OfflineRegistrationTextArea)
    {
    this->OfflineRegistrationTextArea->Delete();
    this->OfflineRegistrationTextArea = NULL;
    }

  // Purchase

  if (this->PurchaseApplicationParametersFrame)
    {
    this->PurchaseApplicationParametersFrame->Delete();
    this->PurchaseApplicationParametersFrame = NULL;
    }

  if (this->PurchaseApplicationTextArea)
    {
    this->PurchaseApplicationTextArea->Delete();
    this->PurchaseApplicationTextArea = NULL;
    }

  // Internet connection

  if (this->InternetConnectionFrame)
    {
    this->InternetConnectionFrame->Delete();
    this->InternetConnectionFrame = NULL;
    }

  if (this->InternetConnectionChoice)
    {
    this->InternetConnectionChoice->Delete();
    this->InternetConnectionChoice = NULL;
    }

  // Trial Mode

  if (this->OnlineRegistrationParametersFrame)
    {
    this->OnlineRegistrationParametersFrame->Delete();
    this->OnlineRegistrationParametersFrame = NULL;
    }

  if (this->OnlineRegistrationEmailEntry)
    {
    this->OnlineRegistrationEmailEntry->Delete();
    this->OnlineRegistrationEmailEntry = NULL;
    }

  if (this->OnlineRegistrationConfirmationFrame)
    {
    this->OnlineRegistrationConfirmationFrame->Delete();
    this->OnlineRegistrationConfirmationFrame = NULL;
    }

  if (this->OnlineRegistrationConfirmationLabel)
    {
    this->OnlineRegistrationConfirmationLabel->Delete();
    this->OnlineRegistrationConfirmationLabel = NULL;
    }

  // Full Mode

  if (this->OfflineRegistrationParametersFrame)
    {
    this->OfflineRegistrationParametersFrame->Delete();
    this->OfflineRegistrationParametersFrame = NULL;
    }

  if (this->OfflineRegistrationLicenseFileButton)
    {
    this->OfflineRegistrationLicenseFileButton->Delete();
    this->OfflineRegistrationLicenseFileButton = NULL;
    }

  if (this->OfflineRegistrationErrorLabel)
    {
    this->OfflineRegistrationErrorLabel->Delete();
    this->OfflineRegistrationErrorLabel = NULL;
    }

  if (this->OfflineRegistrationConfirmationFrame)
    {
    this->OfflineRegistrationConfirmationFrame->Delete();
    this->OfflineRegistrationConfirmationFrame = NULL;
    }

  if (this->OfflineRegistrationConfirmationLabel)
    {
    this->OfflineRegistrationConfirmationLabel->Delete();
    this->OfflineRegistrationConfirmationLabel = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::CreateWidget()
{
  // Set the application

  if (this->IsCreated())
    {
    vtkErrorMacro("Wizard already created");
    return;
    }

  this->Superclass::CreateWidget();

  // Set title

  this->TitleLabel->SetText(
    ks_("Registration Wizard|Title|Registration Wizard"));

  // Configure the computer ID

  this->ComputerID->SetApplicationName(
    this->GetApplication()->GetName());
  this->ComputerID->SetVersion(
    this->GetApplication()->GetMajorVersion(), 
    this->GetApplication()->GetMinorVersion());
}

//----------------------------------------------------------------------------
const char* vtkKWRegistrationWizard::GetLimitedEditionModeName()
{
  vtkKWApplication *app = this->GetApplication();
  if (app && app->GetLimitedEditionModeName())
    {
    return app->GetLimitedEditionModeName();
    }
  return "Limited Edition";
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::ConfigureComputerID()
{
  if (!this->ComputerID || !this->GetApplication())
    {
    return 0;
    }

  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);

  this->ComputerID->SetApplicationName(app->GetName());
  this->ComputerID->SetVersion(app->GetMajorVersion(), app->GetMinorVersion());
  if (app_pro)
    {
    this->ComputerID->SetRegisterURL(app_pro->GetRegistrationURL());
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::CheckLicenseFramework()
{
  int res = 1;

  ostrstream *error = NULL;

  // Configure the computer ID

  if (!this->ConfigureComputerID())
    {
    if (!error)
      {
      error = new ostrstream;
      }
    *error << "The ComputerID ivar has not been configured properly. "
           << "Do not forget to call Create() on the license wizard."
           << endl;
    res = 0;
    }

  if (!this->PrivateEncryptionKey)
    {
    if (!error)
      {
      error = new ostrstream;
      }
    *error << "The private encryption key is empty." << endl;
    res = 0;
    }

  if (!this->PublicEncryptionKey)
    {
    if (!error)
      {
      error = new ostrstream;
      }
    *error << "The public encryption key is empty." << endl;
    res = 0;
    }

  if (!res && this->IsCreated() && error)
    {
    *error << ends;
    vtkKWMessageDialog::PopupMessage(
      this->GetApplication(), 0, 
      ks_("Registration Wizard|Dialog|Registration Error!"), 
      error->str(),
      vtkKWMessageDialog::ErrorIcon);
    error->rdbuf()->freeze(0);
    delete error;
    }

  return res;
}

//----------------------------------------------------------------------------
const char* vtkKWRegistrationWizard::GetComputerId()
{
  if (!this->CheckLicenseFramework())
    {
    return 0;
    }

  return this->ComputerID->GetComputerId(this->PublicEncryptionKey);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::VerifyLicenseKey(const char *license_key)
{
  if (!license_key || !this->CheckLicenseFramework())
    {
    return 0;
    }

  char *cleaned_key = vtksys::SystemTools::RemoveCharsButUpperHex(license_key);
  int res = this->ComputerID->VerifyLicense(
    this->PrivateEncryptionKey, cleaned_key);
  delete [] cleaned_key;
  return res;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::GetLicenseKeyFromFile(
  const char *fname, char *buffer)
{
  if (!fname || !buffer)
    {
    return 0;
    }

  // Open the file

  ifstream ifs(fname);
  if (!ifs)
    {
    vtkErrorMacro("Cannot open registration file: " << fname);
    return 0;
    }

  // Dump contents to string

  ostrstream str;
  str << ifs.rdbuf();
  str << ends;
  vtkstd::string license = str.str();

  // Search for License tag

  const char* stag = "<License>";
  const char* etag = "</License>";
  vtkstd::string::size_type spos, epos;
  spos = license.find(stag);
  epos = license.find(etag);

  // Retrieve license key

  int res = 0;
  if (spos != vtkstd::string::npos && epos != vtkstd::string::npos)
    {
    spos += strlen(stag);
    license = license.substr(spos, epos - spos);
    sprintf(buffer, "%s", license.c_str());
    res = 1;
    }

  str.rdbuf()->freeze(0);
  return res;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::StoreLicenseKeyInRegistry(
  const char *license_key)
{
  if (!license_key || 
      !this->GetApplication() || 
      !this->LicenseKeyRegistrySubKey || 
      !this->LicenseKeyRegistryKey)
    {
    return 0;
    }

  char *cleaned_key = vtksys::SystemTools::RemoveCharsButUpperHex(license_key);
  int res = this->GetApplication()->SetRegistryValue(
    0, 
    this->LicenseKeyRegistrySubKey, 
    this->LicenseKeyRegistryKey, 
    cleaned_key);
  delete [] cleaned_key;

  return res;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::RetrieveLicenseKeyFromRegistry(char *buffer)
{
  if (!this->GetApplication() || 
      !this->LicenseKeyRegistrySubKey || 
      !this->LicenseKeyRegistryKey)
    {
    return 0;
    }

  return this->GetApplication()->GetRegistryValue(
    0, 
    this->LicenseKeyRegistrySubKey, 
    this->LicenseKeyRegistryKey, 
    buffer);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::RemoveLicenseKeyFromRegistry()
{
  if (!this->GetApplication() || 
      !this->LicenseKeyRegistrySubKey || 
      !this->LicenseKeyRegistryKey)
    {
    return 0;
    }

  return this->GetApplication()->DeleteRegistryValue(
    0, 
    this->LicenseKeyRegistrySubKey, 
    this->LicenseKeyRegistryKey);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::VerifyLicenseKeyInRegistry()
{
  char license_key[VTK_KW_RW_KEY_SIZE];
  return (this->RetrieveLicenseKeyFromRegistry(license_key) &&
          this->VerifyLicenseKey(license_key));
}

//----------------------------------------------------------------------------
time_t vtkKWRegistrationWizard::GetLicenseKeyExpirationDate(
  const char *license_key)
{
  // Need to call VerifyLicense() to have an expiration date
  // We do not care if it's valid or not

  if (!license_key || !this->CheckLicenseFramework())
    {
    return 0;
    }
  this->VerifyLicenseKey(license_key);

  const char *exp_date = this->ComputerID->GetExpirationDate();
  if (!exp_date)
    {
    return 0;
    }

  int year = 0, month = 0, day = 0;
  if (sscanf(exp_date, "%d/%d/%d", &year, &month, &day) != 3)
    {
    return 0;
    }

  struct tm time;
  time.tm_hour = 0;
  time.tm_isdst = -1;
  time.tm_mday = day;
  time.tm_min = 0;
  time.tm_mon = month - 1;
  time.tm_sec = 0;
  time.tm_year = year - 1900;

  return mktime(&time);
}
  
//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::GetLicenseKeyOnline(char *buffer, 
                                                 const char *email)
{

  if (!buffer || !this->CheckLicenseFramework())
    {
    return 0;
    }

  const char *res = this->ComputerID->RegisterOnLine(
    this->GetComputerId(), 
    email, 
    this->PrivateEncryptionKey);

  if (res)
    {
    sprintf(buffer, "%s", res);
    return 1;
    }

  return 0;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::InTrialMode()
{
  // The license (trial or full) should be valid

  char license_key[VTK_KW_RW_KEY_SIZE];
  if (!this->RetrieveLicenseKeyFromRegistry(license_key) ||
      !this->VerifyLicenseKey(license_key))
    {
    return 0;
    }

  // Get the expiration date in seconds

  time_t exp = this->GetLicenseKeyExpirationDate(license_key);
  if (!exp)
    {
    return 0;
    }

  // Has to be > current date, and <= current date + max trial mode days

  time_t now = time(NULL);
  time_t now_and_trial = now + VTK_KW_RW_MAX_NB_DAYS * (24 * 60 * 60);

  return (exp > now && exp <= now_and_trial);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::HasTrialModeExpired()
{
  // The license (trial or full) should be invalid

  char license_key[VTK_KW_RW_KEY_SIZE];
  if (!this->RetrieveLicenseKeyFromRegistry(license_key) ||
      this->VerifyLicenseKey(license_key))
    {
    return 0;
    }

  // Get the expiration date in seconds

  time_t exp = this->GetLicenseKeyExpirationDate(license_key);
  if (!exp)
    {
    return 0;
    }

  // Has to be <= current date

  return (exp <= time(NULL));
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::IsLicenseKeyInFullMode(const char *license_key)
{
  // The license (trial or full) should be valid

  if (!this->VerifyLicenseKey(license_key))
    {
    return 0;
    }

  // Get the expiration date in seconds

  time_t exp = this->GetLicenseKeyExpirationDate(license_key);
  if (!exp)
    {
    return 0;
    }

  // Has to be > current date + max trial mode days 
  // Typically it will be large (like 10 years)

  time_t now_and_trial = time(NULL) + VTK_KW_RW_MAX_NB_DAYS * (24 * 60 * 60);

  return (exp > now_and_trial);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::InFullMode()
{
  // Get the registry license

  char license_key[VTK_KW_RW_KEY_SIZE];
  if (!this->RetrieveLicenseKeyFromRegistry(license_key))
    {
    return 0;
    }

  return this->IsLicenseKeyInFullMode(license_key);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::InLimitedEditionMode()
{
  int le_mode;
  return (this->RetrieveLimitedEditionModeFromRegistry(&le_mode) && le_mode);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::StoreLimitedEditionModeInRegistry(int mode)
{
  if (!this->GetApplication() || 
      !this->LimitedEditionModeRegistrySubKey || 
      !this->LimitedEditionModeRegistryKey)
    {
    return 0;
    }

  return this->GetApplication()->SetRegistryValue(
    0, 
    this->LimitedEditionModeRegistrySubKey, 
    this->LimitedEditionModeRegistryKey, 
    "%d", mode);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::RetrieveLimitedEditionModeFromRegistry(int *mode)
{
  if (!this->GetApplication() || 
      !this->LimitedEditionModeRegistrySubKey || 
      !this->LimitedEditionModeRegistryKey)
    {
    return 0;
    }

  char buffer[VTK_KW_RW_KEY_SIZE];
  int res = this->GetApplication()->GetRegistryValue(
    0, 
    this->LimitedEditionModeRegistrySubKey, 
    this->LimitedEditionModeRegistryKey,
    buffer);

  if (res)
    {
    *mode = atoi(buffer);
    }
  
  return res;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::RemoveLimitedEditionModeFromRegistry()
{
  if (!this->GetApplication() || 
      !this->LimitedEditionModeRegistrySubKey || 
      !this->LimitedEditionModeRegistryKey)
    {
    return 0;
    }

  return this->GetApplication()->DeleteRegistryValue(
    0, 
    this->LimitedEditionModeRegistrySubKey, 
    this->LimitedEditionModeRegistryKey);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::IsApplicationAllowedToRun()
{
  return (!this->IsCurrentDateBeforeMostRecentDate() &&
          (this->InLimitedEditionMode() || 
           this->VerifyLicenseKeyInRegistry()));
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::IsCurrentDateBeforeMostRecentDate()
{
  return (this->MostRecentDate > 0 && (time(NULL) < this->MostRecentDate));
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::Invoke()
{
  if (!this->IsCreated())
    {
    return 1;
    }

  // Special case: if the title has been set to NULL, set the dialog title
  // to use the current application name (do not modify the title Ivar
  // though, so that it works if the application name is changed dynamically)

  if (!this->GetTitle())
    {
    ostrstream title;
    title << this->GetApplication()->GetPrettyName() 
          << " : " << ks_("Registration Wizard|Title|Registration Wizard")
          << ends;
    this->SetTitle(title.str());
    title.rdbuf()->freeze(0);
    }

  this->Invoked = 0;

  return this->PromptRegistrationType();
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::Cancel()
{
  this->Superclass::Cancel();

  this->RegistrationChoice = vtkKWRegistrationWizard::INVALID_MODE;
  this->SetLicenseKey(NULL);
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::OK()
{
  this->Superclass::OK();

  // Save the registration settings

  switch (this->GetRegistrationChoice())
    {
    case vtkKWRegistrationWizard::TRIAL_MODE:
    case vtkKWRegistrationWizard::FULL_MODE:
      if (this->VerifyLicenseKey(this->GetLicenseKey()) &&
          this->StoreLicenseKeyInRegistry(this->GetLicenseKey()))
        {
        this->RemoveLimitedEditionModeFromRegistry();
        if (this->GetApplication())
          {
          this->GetApplication()->LimitedEditionModeOff();
          }
        }
      break;
    case vtkKWRegistrationWizard::LIMITED_EDITION_MODE:
      this->StoreLimitedEditionModeInRegistry(1);
      if (this->GetApplication())
        {
        this->GetApplication()->LimitedEditionModeOn();
        }
      break;
    }
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::GetSubTitleLabelGivenRegistrationChoice(
  int choice, ostream &os)
{
  if (!this->GetApplication())
    {
    return;
    }

  const char *fullm_name = this->FullModeName;
  const char *lem_name = this->GetLimitedEditionModeName();

  char buffer[500];

  switch (choice)
    {
    case vtkKWRegistrationWizard::TRIAL_MODE:
      os << k_("Get or extend a trial license.") 
         << ends;
      break;

    case vtkKWRegistrationWizard::FULL_MODE:
      sprintf(
        buffer, k_("Purchase and register the '%s' version."), fullm_name);
      os << buffer << ends;
      break;

    case vtkKWRegistrationWizard::LIMITED_EDITION_MODE:
      sprintf(
        buffer, k_("Run the application in '%s' mode."), lem_name);
      os << buffer << ends;
      break;
      
    default:
      os << k_("Unknown registration choice !") << ends;
    }
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::GetCurrentLicenseStatusAsString(ostream &os)
{
  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);

  const char *app_name = app->GetName();
  const char *fullm_name = this->FullModeName;
  const char *lem_name = this->GetLimitedEditionModeName();

  char buffer[500];

  if (this->HasTrialModeExpired() ||
      ((this->InTrialMode() || this->InFullMode()) &&
       !this->InLimitedEditionMode()))
    {
    if (this->InTrialMode() && !this->InLimitedEditionMode())
      {
      sprintf(buffer, 
              k_("You are running %s in '%s' mode with a trial license."),
              app_name, fullm_name);
      os << buffer;

      char license_key[VTK_KW_RW_KEY_SIZE];
      if (this->RetrieveLicenseKeyFromRegistry(license_key))
        {
        time_t exp = this->GetLicenseKeyExpirationDate(license_key);
        if (exp)
          {
          time_t diff = exp - time(NULL);
          int days = (int)((double)diff / (double)(24 * 60* 60));
          sprintf(buffer, k_("You have %d day(s) remaining."), days);
          os << " " << buffer;
          }
        }
      os << " ";
      }
    else if (this->HasTrialModeExpired())
      {
      sprintf(buffer, k_("Your %s trial license has expired."),app_name);
      os << buffer;
      }
    }

  if (this->InLimitedEditionMode())
    {
    sprintf(buffer, 
            k_("You are running %s in '%s' mode."), 
            app_name, lem_name);
    os << buffer;
    }
  else if (this->InFullMode())
    {
    sprintf(buffer, 
            k_("You are running %s in '%s' mode."), 
            app_name, fullm_name);
    os << buffer;
    }
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::CreateRegistrationTypePage()
{
  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);

  const char *app_name = app->GetName();
  const char *fullm_name = this->FullModeName;
  const char *lem_name = this->GetLimitedEditionModeName();
  const char *comp_name = app_pro ? app_pro->GetCompanyName() : NULL;
  const char *comp_support_contact = 
    app_pro ? app_pro->GetCompanySupportContact() : NULL;

  // Let the user know what is up
  
  char buffer[500];
  sprintf(buffer, k_("Welcome to %s !"), app_name);
  this->SubTitleLabel->SetText(buffer); 

  strstream pre_str;

  if (this->SupportLimitedEditionMode)
    {
    sprintf(buffer, 
            k_("%s can be run in either '%s' or '%s' mode. The '%s' mode is "
               "free for unlimited use but lacks some of the features of the " 
               "'%s' mode."),
            app_name, fullm_name, lem_name, lem_name, fullm_name);
    pre_str << buffer << " ";
    }

  if (this->SupportTrialMode && !this->HasTrialModeExpired())
    {
    if (this->SupportLimitedEditionMode)
      {
      sprintf(buffer, 
              k_("You can try out %s in '%s' mode for free after which you "
                 "can purchase a license or use it in '%s' mode."), 
              app_name, fullm_name, lem_name);
      }
    else
      {
      sprintf(buffer, 
              k_("You can try out %s in '%s' mode for free after which you "
                 "can purchase a license."), 
              app_name, fullm_name);
      }
    pre_str << buffer;
    }

  pre_str << ends;
  this->SetPreText(pre_str.str());
  pre_str.rdbuf()->freeze(0);

  // Frame container

  if (!this->RegistrationTypeFrame)
    {
    this->RegistrationTypeFrame = vtkKWFrame::New();
    this->RegistrationTypeFrame->SetParent(this->ClientArea);
    this->RegistrationTypeFrame->Create();
    }

  // Label that will optionally display in which mode we are already in

  if (!this->RegistrationTypeInfoLabel)
    {
    this->RegistrationTypeInfoLabel = vtkKWLabelWithLabel::New();
    this->RegistrationTypeInfoLabel->SetParent(this->RegistrationTypeFrame);
    this->RegistrationTypeInfoLabel->Create();
    this->RegistrationTypeInfoLabel->GetLabel()->SetImageToPredefinedIcon(
      vtkKWIcon::IconSilkInformation);
    }

  // The registration choices

  vtkKWRadioButtonSet *rbs = NULL;
  vtkKWRadioButton *rb = NULL;

  if (!this->RegistrationTypeChoice)
    {
    this->RegistrationTypeChoice = vtkKWRadioButtonSetWithLabel::New();
    this->RegistrationTypeChoice->SetParent(this->RegistrationTypeFrame);
    this->RegistrationTypeChoice->Create();
    this->RegistrationTypeChoice->GetLabel()->SetText(
      k_("Choose your registration method:"));
    this->RegistrationTypeChoice->SetLabelPositionToTop();

    rbs = this->RegistrationTypeChoice->GetWidget();

    rb = rbs->AddWidget(VTK_KW_RW_REG_TYPE_TRIAL_ID);
    rb->SetValueAsInt(VTK_KW_RW_REG_TYPE_TRIAL_ID);

    rb = rbs->AddWidget(VTK_KW_RW_REG_TYPE_FULL_ID);
    rb->SetValueAsInt(VTK_KW_RW_REG_TYPE_FULL_ID);

    rb = rbs->AddWidget(VTK_KW_RW_REG_TYPE_LIMITED_EDITION_ID);
    rb->SetValueAsInt(VTK_KW_RW_REG_TYPE_LIMITED_EDITION_ID);

    this->Script("pack %s -side top -fill both", 
                 this->RegistrationTypeChoice->GetWidgetName());
    }

  this->SetRegistrationTypeInfoLabel(0);

  rbs = this->RegistrationTypeChoice->GetWidget();

  // Hide the Trial Mode button if :
  // - Trial Mode is not supported, 
  // - A valid License was found, and we are not in Limited Mode already

  rbs->SetWidgetVisibility(
    VTK_KW_RW_REG_TYPE_TRIAL_ID, this->SupportTrialMode);
  if (this->InFullMode() && !this->InLimitedEditionMode())
    {
    rbs->SetWidgetVisibility(VTK_KW_RW_REG_TYPE_TRIAL_ID, 0);
    }

  // Create the Trial Mode button label

  if (this->SupportTrialMode)
    {
    vtkKWRadioButton *trialb = rbs->GetWidget(VTK_KW_RW_REG_TYPE_TRIAL_ID);
    if (trialb)
      {
      ostrstream trialb_str;
      this->GetSubTitleLabelGivenRegistrationChoice(
        vtkKWRegistrationWizard::TRIAL_MODE, trialb_str);
      trialb->SetText(trialb_str.str());
      trialb_str.rdbuf()->freeze(0);
      }
    }

  // Hide the Full Mode button if :
  // - A valid License was found, and we are not in Limited Mode already

  rbs->SetWidgetVisibility(VTK_KW_RW_REG_TYPE_FULL_ID, 1);
  if (this->InFullMode() && !this->InLimitedEditionMode())
    {
    rbs->SetWidgetVisibility(VTK_KW_RW_REG_TYPE_FULL_ID, 0);
    }

  // Create the Full Mode button label

  vtkKWRadioButton *fullb = rbs->GetWidget(VTK_KW_RW_REG_TYPE_FULL_ID);
  if (fullb)
    {
    ostrstream fullb_str;
    this->GetSubTitleLabelGivenRegistrationChoice(
      vtkKWRegistrationWizard::FULL_MODE, fullb_str);
    fullb->SetText(fullb_str.str());
    fullb_str.rdbuf()->freeze(0);
    }

  // Hide the Limited Mode button if :
  // - Limited Mode is not supported, 
  // - We are not in Limited Mode already

  rbs->SetWidgetVisibility(
    VTK_KW_RW_REG_TYPE_LIMITED_EDITION_ID, this->SupportLimitedEditionMode);
  if (this->InLimitedEditionMode())
    {
    rbs->SetWidgetVisibility(VTK_KW_RW_REG_TYPE_LIMITED_EDITION_ID, 0);
    }

  // Create the limited edition button label

  if (this->SupportLimitedEditionMode)
    {
    vtkKWRadioButton *leb = 
      rbs->GetWidget(VTK_KW_RW_REG_TYPE_LIMITED_EDITION_ID);
    if (leb)
      {
      ostrstream leb_str;
      this->GetSubTitleLabelGivenRegistrationChoice(
        vtkKWRegistrationWizard::LIMITED_EDITION_MODE, leb_str);
      leb->SetText(leb_str.str());
      leb_str.rdbuf()->freeze(0);
      }
    }

  // If nothing visible is selected, select something

  int nb_widgets = rbs->GetNumberOfWidgets();
  int visible_widget_is_selected = 0;
  int first_visible_widget = -1;
  for (int rank =  0; rank < nb_widgets; rank++)
    {
    int id = rbs->GetIdOfNthWidget(rank);
    if (rbs->GetWidgetVisibility(id))
      {
      if (first_visible_widget < 0)
        {
        first_visible_widget = id;
        }
      if (rbs->GetWidget(id)->GetSelectedState())
        {
        visible_widget_is_selected = 1;
        break;
        }
      }
    }

  if (!visible_widget_is_selected)
    {
    rb = rbs->GetWidget(first_visible_widget);
    if (rb)
      {
      rb->SelectedStateOn();
      }
    }

  // Nothing is visible, hide the set altogether

  this->RegistrationTypeChoice->SetLabelVisibility(
    rbs->GetNumberOfVisibleWidgets() ? 1 : 0);

  // If the clock is skewed, mention it and disable all choices
  
  if (this->IsCurrentDateBeforeMostRecentDate())
    {
    this->SetRegistrationTypeInfoLabel(
      k_("It seems your system clock has been altered in a way that\n"
         "prevents registration to be carried on properly."));
    if (comp_support_contact)
      {
      sprintf(buffer, 
              k_("If you continue to have a problem please contact %s at %s."),
              comp_name, comp_support_contact);
      this->SetPostText(buffer);
      }
    this->RegistrationTypeChoice->SetEnabled(0);
    }
  else
    {
    ostrstream reg_info_str;
    this->GetCurrentLicenseStatusAsString(reg_info_str);
    reg_info_str << ends;
    if (*reg_info_str.str())
      {
      this->SetRegistrationTypeInfoLabel(reg_info_str.str());
      }
    this->RegistrationTypeChoice->SetEnabled(this->GetEnabled());
    reg_info_str.rdbuf()->freeze(0);
    }
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::SetRegistrationTypeInfoLabel(const char *str)
{
  this->RegistrationTypeInfoLabel->GetWidget()->SetText(str);

  if (this->IsCreated())
    {
    if (str && *str)
      {
      this->Script("pack %s -side top -fill both -before %s -pady 3", 
                   this->RegistrationTypeInfoLabel->GetWidgetName(),
                   this->RegistrationTypeChoice->GetWidgetName());
      }
    else
      {
      this->Script("pack forget %s", 
                   this->RegistrationTypeInfoLabel->GetWidgetName());
      }
    }
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::PromptRegistrationType()
{
  this->RegistrationChoice = vtkKWRegistrationWizard::INVALID_MODE;
  this->SetLicenseKey(NULL);

  // Clear any other page

  this->ClearPage();

  // Create/update/bring up the widgets

  this->CreateRegistrationTypePage();

  this->Script("pack %s -side top", 
               this->RegistrationTypeFrame->GetWidgetName());

  // Next ? Only if the clock is not skewed (cheat) or choices were available

  if (this->IsCurrentDateBeforeMostRecentDate() ||
      !this->RegistrationTypeChoice->GetWidget()->GetNumberOfVisibleWidgets())
    {
    this->NoNextStep();
    }
  else
    {
    this->PropagateEnableState(this->NextButton);
    this->NextButton->SetCommand(this, "ProcessRegistrationType");
    }

  if (!this->Invoked)
    {
    this->Invoked = 1;
    return this->vtkKWWizard::Invoke();
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::ProcessRegistrationType()
{
  // Set the back button 

  this->AddBackButtonCommand("PromptRegistrationType");

  // Given the registration choices, branch

  vtkKWRadioButtonSet *rbs = this->RegistrationTypeChoice->GetWidget();

  if (rbs->GetWidget(VTK_KW_RW_REG_TYPE_TRIAL_ID)->GetSelectedState())
    {
    this->RegistrationChoice = vtkKWRegistrationWizard::TRIAL_MODE;
    return this->PromptInternetConnection();
    }

  if (rbs->GetWidget(VTK_KW_RW_REG_TYPE_FULL_ID)->GetSelectedState())
    {
    this->RegistrationChoice = vtkKWRegistrationWizard::FULL_MODE;
    return this->PromptPurchaseApplication();
    }

  if (rbs->GetWidget(VTK_KW_RW_REG_TYPE_LIMITED_EDITION_ID)->GetSelectedState())
    {
    this->RegistrationChoice = vtkKWRegistrationWizard::LIMITED_EDITION_MODE;
    return this->PromptLimitedEditionModeConfirmation();
    }

  return 1;
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::CreatePurchaseApplicationPage()
{
  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);

  const char *app_name = app->GetName();
  const char *fullm_name = this->FullModeName;
  const char *comp_name = app_pro ? app_pro->GetCompanyName() : NULL;
  const char *comp_sales_contact = 
    app_pro ? app_pro->GetCompanySalesContact() : NULL;

  // Let the user know what is up

  strstream subtitle_str;
  this->GetSubTitleLabelGivenRegistrationChoice(
    this->RegistrationChoice, subtitle_str);
  this->SubTitleLabel->SetText(subtitle_str.str()); 
  subtitle_str.rdbuf()->freeze(0);

  strstream pre_str;
  char buffer[500];

  const char *url = app_pro ? app_pro->GetPurchaseURL() : NULL;
  const char *prefix = "http://";
  if (url && !strncmp(prefix, url, strlen(prefix)))
    {
    url += strlen(prefix);
    }
  if (comp_sales_contact || url)
    {
    if (url && comp_sales_contact)
      {
      sprintf(
        buffer, 
        k_("You can purchase a '%s' license for %s online by going to the "
           "website %s or by contacting %s at %s."),
        fullm_name, app_name, url, comp_name, comp_sales_contact);
      }
    else if (url)
      {
      sprintf(
        buffer, 
        k_("You can purchase a '%s' license for %s online by going to the "
           "website %s."),
        fullm_name, app_name, url);
      }
    else if (comp_sales_contact)
      {
      sprintf(
        buffer, 
        k_("You can purchase a '%s' license for %s by contacting %s at %s."),
        fullm_name, app_name, comp_name, comp_sales_contact);
      }
    pre_str << buffer;

    if (this->CheckLicenseFramework())
      {
      pre_str << " " << k_("You will need to provide your computer ID:") 
              << " **" << this->GetComputerId() << "**. ";
      }
    }
  
  sprintf(
    buffer, 
    k_("Once you have received the email confirming your '%s' license "
       "purchase you can register your license by pressing the 'Next' button "
       "below."),
    fullm_name);
  pre_str << endl << endl << buffer;

  // Container frame

  if (!this->PurchaseApplicationParametersFrame)
    {
    this->PurchaseApplicationParametersFrame = vtkKWFrame::New();
    this->PurchaseApplicationParametersFrame->SetParent(this->ClientArea);
    this->PurchaseApplicationParametersFrame->Create();
    }

  // Text area that can be used to copy/paste

  if (!this->PurchaseApplicationTextArea)
    {
    this->PurchaseApplicationTextArea = vtkKWText::New();
    this->PurchaseApplicationTextArea->SetParent(
      this->PurchaseApplicationParametersFrame);
    this->PurchaseApplicationTextArea->Create();
    this->PurchaseApplicationTextArea->ReadOnlyOn();
    this->PurchaseApplicationTextArea->SetReliefToFlat();
    this->PurchaseApplicationTextArea->QuickFormattingOn();
    this->PurchaseApplicationTextArea->SetHeight(9);
    this->PurchaseApplicationTextArea->SetBackgroundColor(
      this->PurchaseApplicationParametersFrame->GetBackgroundColor());

    this->Script("pack %s -side top -anchor nw -expand n -fill x", 
                 this->PurchaseApplicationTextArea->GetWidgetName());
    }

  pre_str << ends;
  this->PurchaseApplicationTextArea->SetText(pre_str.str());
  pre_str.rdbuf()->freeze(0);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::PromptPurchaseApplication()
{
  if (this->RegistrationChoice == vtkKWRegistrationWizard::INVALID_MODE)
    {
    return this->PromptRegistrationType();
    }

  // Clear any other page

  this->ClearPage();

  // Create/update/bring up the widgets

  this->CreatePurchaseApplicationPage();

  this->Script("pack %s -side top -fill x",
               this->PurchaseApplicationParametersFrame->GetWidgetName());

  // Next ?

  this->PropagateEnableState(this->NextButton);
  this->NextButton->SetCommand(this, "ProcessPurchaseApplication");

  if (!this->Invoked)
    {
    this->Invoked = 1;
    return this->vtkKWWizard::Invoke();
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::ProcessPurchaseApplication()
{
  // Set the back button 

  this->AddBackButtonCommand("PromptPurchaseApplication");

  return this->PromptInternetConnection();
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::CreateInternetConnectionPage()
{
  // Let the user know what is up

  strstream subtitle_str;
  this->GetSubTitleLabelGivenRegistrationChoice(
    this->RegistrationChoice, subtitle_str);
  this->SubTitleLabel->SetText(subtitle_str.str()); 
  subtitle_str.rdbuf()->freeze(0);

  strstream pre_str;

  this->SetPreText(
    k_("This application can automatically retrieve and install your "
       "license if your computer is connected to the Internet.")); 

  // Frame container

  if (!this->InternetConnectionFrame)
    {
    this->InternetConnectionFrame = vtkKWFrame::New();
    this->InternetConnectionFrame->SetParent(this->ClientArea);
    this->InternetConnectionFrame->Create();
    }

  // Internet connection yes/no ?

  vtkKWRadioButtonSet *rbs = NULL;
  vtkKWRadioButton *rb = NULL;

  if (!this->InternetConnectionChoice)
    {
    this->InternetConnectionChoice = vtkKWRadioButtonSetWithLabel::New();
    this->InternetConnectionChoice->SetParent(this->InternetConnectionFrame);
    this->InternetConnectionChoice->Create();
    this->InternetConnectionChoice->GetLabel()->SetText(
      k_("Is your computer connected to the Internet ?"));
    this->InternetConnectionChoice->SetLabelPositionToTop();

    rbs = this->InternetConnectionChoice->GetWidget();

    rb = rbs->AddWidget(1);
    rb->SetValueAsInt(1);
    rb->SetText(k_("Yes"));

    rb = rbs->AddWidget(0);
    rb->SetValueAsInt(0);
    rb->SetText(k_("No"));

    this->Script("pack %s -side top -fill both", 
                 this->InternetConnectionChoice->GetWidgetName());
    }

  rbs = this->InternetConnectionChoice->GetWidget();

  // If nothing visible is selected, select something

  int nb_widgets = rbs->GetNumberOfWidgets();
  int visible_widget_is_selected = 0;
  int first_visible_widget = -1;
  for (int rank =  0; rank < nb_widgets; rank++)
    {
    int id = rbs->GetIdOfNthWidget(rank);
    if (rbs->GetWidgetVisibility(id))
      {
      if (first_visible_widget < 0)
        {
        first_visible_widget = id;
        }
      if (rbs->GetWidget(id)->GetSelectedState())
        {
        visible_widget_is_selected = 1;
        break;
        }
      }
    }
  if (!visible_widget_is_selected)
    {
    rb = rbs->GetWidget(first_visible_widget);
    if (rb)
      {
      rb->SelectedStateOn();
      }
    }
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::PromptInternetConnection()
{
  if (this->RegistrationChoice == vtkKWRegistrationWizard::INVALID_MODE)
    {
    return this->PromptRegistrationType();
    }

  // Clear any other page

  this->ClearPage();

  // Create/update/bring up the widgets

  this->CreateInternetConnectionPage();

  this->Script("pack %s -side top", 
               this->InternetConnectionFrame->GetWidgetName());

  // Next ?

  this->PropagateEnableState(this->NextButton);
  this->NextButton->SetCommand(this, "ProcessInternetConnection");

  if (!this->Invoked)
    {
    this->Invoked = 1;
    return this->vtkKWWizard::Invoke();
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::ProcessInternetConnection()
{
  // Set the back button 

  this->AddBackButtonCommand("PromptInternetConnection");

  // Given the internet connection, branch

  vtkKWRadioButtonSet *rbs = 
    this->InternetConnectionChoice->GetWidget();

  if (rbs->GetWidget(1)->GetSelectedState())
    {
    // If we are in Full Mode, we do not need any additional parameters

    if (this->RegistrationChoice == vtkKWRegistrationWizard::FULL_MODE)
      {
      return this->PromptOnlineRegistrationConfirmation();
      }
    else
      {
      return this->PromptOnlineRegistrationParameters();
      }
    }

  return this->PromptOfflineRegistrationParameters();
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::CreateOnlineRegistrationParametersPage()
{
  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);

  const char *app_name = app->GetName();
  const char *comp_name = app_pro ? app_pro->GetCompanyName() : NULL;

  // Let the user know what is up

  strstream subtitle_str;
  this->GetSubTitleLabelGivenRegistrationChoice(
    this->RegistrationChoice, subtitle_str);
  this->SubTitleLabel->SetText(subtitle_str.str()); 
  subtitle_str.rdbuf()->freeze(0);

  char buffer[500];
  sprintf(buffer, 
          k_("If you would like to receive information and offers regarding "
             "%s from %s please provide your email. Your email is optional "
             "and is not required to obtain a license. It will not be shared "
             "with any third parties."), app_name,  comp_name);

  this->SetPreText(buffer);

  // Frame container

  if (!this->OnlineRegistrationParametersFrame)
    {
    this->OnlineRegistrationParametersFrame = vtkKWFrame::New();
    this->OnlineRegistrationParametersFrame->SetParent(this->ClientArea);
    this->OnlineRegistrationParametersFrame->Create();
    }

  // Optional email

  if (!this->OnlineRegistrationEmailEntry)
    {
    this->OnlineRegistrationEmailEntry = vtkKWEntryWithLabel::New();
    this->OnlineRegistrationEmailEntry->SetParent(
      this->OnlineRegistrationParametersFrame);
    this->OnlineRegistrationEmailEntry->Create();
    this->OnlineRegistrationEmailEntry->GetWidget()->SetWidth(30);
    this->OnlineRegistrationEmailEntry->GetLabel()->SetText(
      ks_("Registration Wizard|Email:"));
    }

  if (this->RegistrationChoice == vtkKWRegistrationWizard::FULL_MODE)
    {
    this->Script("pack forget %s", 
                 this->OnlineRegistrationEmailEntry->GetWidgetName());
    }
  else
    {
    this->Script("pack %s -side top", 
                 this->OnlineRegistrationEmailEntry->GetWidgetName());
    }
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::PromptOnlineRegistrationParameters()
{
  if (this->RegistrationChoice == vtkKWRegistrationWizard::INVALID_MODE)
    {
    return this->PromptRegistrationType();
    }

  // Clear any other page

  this->ClearPage();

  // Create/update/bring up the widgets

  this->CreateOnlineRegistrationParametersPage();

  this->Script("pack %s -side top", 
               this->OnlineRegistrationParametersFrame->GetWidgetName());

  // Next ?

  this->PropagateEnableState(this->NextButton);
  this->NextButton->SetCommand(this, "ProcessOnlineRegistrationParameters");

  if (!this->Invoked)
    {
    this->Invoked = 1;
    return this->vtkKWWizard::Invoke();
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::ProcessOnlineRegistrationParameters()
{
  // Set the back button 

  this->AddBackButtonCommand("PromptOnlineRegistrationParameters");

  return this->PromptOnlineRegistrationConfirmation();
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::CreateOnlineRegistrationConfirmationPage()
{
  const char *fullm_name = this->FullModeName;

  // Let the user know what is up

  strstream subtitle_str;
  this->GetSubTitleLabelGivenRegistrationChoice(
    this->RegistrationChoice, subtitle_str);
  this->SubTitleLabel->SetText(subtitle_str.str()); 
  subtitle_str.rdbuf()->freeze(0);

  char buffer[500];

  if (this->RegistrationChoice == vtkKWRegistrationWizard::TRIAL_MODE)
    {
    this->SetPreText(
      k_("This application will now try to get your trial license online and "
         "install it."));
    }
  else if (this->RegistrationChoice == vtkKWRegistrationWizard::FULL_MODE)
    {
    sprintf(
      buffer, 
      k_("This application will now try to get your '%s' license online and "
         "install it."), fullm_name);
    this->SetPreText(buffer);
    }
  else
    {
    this->SetPreText(
      k_("This application will now try to get your license online and "
         "install it."));
    }

  // Container frame

  if (!this->OnlineRegistrationConfirmationFrame)
    {
    this->OnlineRegistrationConfirmationFrame = vtkKWFrame::New();
    this->OnlineRegistrationConfirmationFrame->SetParent(this->ClientArea);
    this->OnlineRegistrationConfirmationFrame->Create();
    }

  // Confirmation label

  if (!this->OnlineRegistrationConfirmationLabel)
    {
    this->OnlineRegistrationConfirmationLabel = vtkKWLabelWithLabel::New();
    this->OnlineRegistrationConfirmationLabel->SetParent(
      this->OnlineRegistrationConfirmationFrame);
    this->OnlineRegistrationConfirmationLabel->Create();

    this->Script("pack %s -side top", 
                 this->OnlineRegistrationConfirmationLabel->GetWidgetName());
    }
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::PromptOnlineRegistrationConfirmation()
{
  if (this->RegistrationChoice == vtkKWRegistrationWizard::INVALID_MODE)
    {
    return this->PromptRegistrationType();
    }

  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);

  const char *comp_name = app_pro ? app_pro->GetCompanyName() : NULL;
  const char *comp_support_contact = 
    app_pro ? app_pro->GetCompanySupportContact() : NULL;

  // Clear any other page

  this->ClearPage();

  // Create/update/bring up the widgets

  this->CreateOnlineRegistrationConfirmationPage();

  this->Script("pack %s -side top", 
               this->OnlineRegistrationConfirmationFrame->GetWidgetName());

  // Get the key online

  this->OnlineRegistrationConfirmationLabel->GetLabel()->SetImageToPredefinedIcon(
    vtkKWIcon::IconConnection);
  this->OnlineRegistrationConfirmationLabel->GetWidget()->SetText(
    k_("Getting license online... This may take up to a minute."));

  this->SetEnabledButtons(0);
  vtkKWTkUtilities::SetTopLevelMouseCursor(this, "watch");
  this->Script("update");
  
  const char *email = NULL;
  if (this->RegistrationChoice == vtkKWRegistrationWizard::TRIAL_MODE &&
      this->OnlineRegistrationEmailEntry)
    {
    email = this->OnlineRegistrationEmailEntry->GetWidget()->GetValue();
    }

  char license_key[VTK_KW_RW_KEY_SIZE];
  int res = this->GetLicenseKeyOnline(license_key, email);

  this->SetEnabledButtons(this->GetEnabled());
  vtkKWTkUtilities::SetTopLevelMouseCursor(this, NULL);

  // Check the key
  // Has to be verified, and if in Full Mode, really a full license

  if (res &&
      this->VerifyLicenseKey(license_key) &&
      (this->RegistrationChoice != vtkKWRegistrationWizard::FULL_MODE ||
       this->IsLicenseKeyInFullMode(license_key)))
    {
    this->OnlineRegistrationConfirmationLabel->GetLabel()->SetImageToPredefinedIcon(
      vtkKWIcon::IconSilkInformation);
    this->OnlineRegistrationConfirmationLabel->GetWidget()->SetText(
      k_("Your license was retrieved successfully !"));
    this->SetLicenseKey(license_key);
    this->LastStep();
    }
  else
    {
    this->OnlineRegistrationConfirmationLabel->GetLabel()->SetImageToPredefinedIcon(
      vtkKWIcon::IconSilkExclamation);
    this->OnlineRegistrationConfirmationLabel->GetWidget()->SetText(
      k_("Sorry, your license could not be retrieved sucessfully !"));

    char buffer[500];

    ostrstream posttext_str;

    if (this->RegistrationChoice == vtkKWRegistrationWizard::FULL_MODE)
      {
      posttext_str << 
        k_("It could simply be that the license has not been added to our "
           "database yet. This usually takes one to two business days. "
           "Please try again later.") << endl << endl;
      }
    posttext_str <<
      k_("It could be that this application was unable to reach the license "
         "server from this computer. This may occur if your computer is not "
         "connected to the network, or if you are connected using a proxy "
         "server or VPN. For instructions on how to manually obtain and "
         "install a license file, please press the 'Back' button until you "
         "reach 'Is your computer connected to the Internet ?' then select "
         "'No', and press 'Next'.");

    if (comp_support_contact)
      {
      sprintf(buffer, 
              k_("If you continue to have a problem please contact %s at %s."),
              comp_name, comp_support_contact);
      posttext_str << endl << endl << buffer;
      }

    posttext_str << ends;
    this->SetPostText(posttext_str.str());
    posttext_str.rdbuf()->freeze(0);
    this->NoNextStep(); 
    }

  // Next ?

  if (!this->Invoked)
    {
    this->Invoked = 1;
    return this->vtkKWWizard::Invoke();
    }
  return 1;
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::CreateOfflineRegistrationParametersPage()
{
  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);

  const char *app_name = app->GetName();
  const char *comp_name = app_pro ? app_pro->GetCompanyName() : NULL;
  const char *comp_sales_contact = 
    app_pro ? app_pro->GetCompanySalesContact() : NULL;

  // Let the user know what is up

  strstream subtitle_str;
  this->GetSubTitleLabelGivenRegistrationChoice(
    this->RegistrationChoice, subtitle_str);
  this->SubTitleLabel->SetText(subtitle_str.str()); 
  subtitle_str.rdbuf()->freeze(0);

  ostrstream pre_str;

  // If in Trial Mode, give some instruction on how to get the license
  // We do not need that in Full Mode, since those instructions were given
  // in PromptPurchaseApplication().

  char buffer[500];

  if (this->RegistrationChoice == vtkKWRegistrationWizard::TRIAL_MODE)
    {
    const char *url = app_pro ? app_pro->GetRegistrationURL() : NULL;
    const char *prefix = "http://";
    if (url && !strncmp(prefix, url, strlen(prefix)))
      {
      url += strlen(prefix);
      }

    if (comp_sales_contact || url)
      {

      if (url && comp_sales_contact)
        {
        sprintf(
          buffer, 
          k_("You can retrieve a trial license for %s online by going to the "
             "website %s or by contacting %s at %s."),
          app_name, url, comp_name, comp_sales_contact);
        }
      else if (url)
        {
        sprintf(
          buffer, 
          k_("You can retrieve a trial license for %s online by going to the "
             "website %s."), app_name, url);
        }
      else if (comp_sales_contact)
        {
        sprintf(
          buffer, 
          k_("You can retrieve a trial license for %s by contacting %s at %s."),
          app_name, comp_name, comp_sales_contact);
        }
      pre_str << buffer;

      if (this->CheckLicenseFramework())
        {
        pre_str << " " << k_("You will need to provide your computer ID:") 
                << " **" << this->GetComputerId() << "**. ";
        }
      }

    if (this->ExpectedLicenseKeyFileName)
      {
      sprintf(
        buffer, 
        k_("You will receive a confirmation email with a license file "
           "attached (%s)."), this->ExpectedLicenseKeyFileName);
      pre_str << endl << endl << buffer;
      }
    else
      {
      pre_str << endl << endl <<
        k_("You will receive a confirmation email with a license file.");
      }
    }

  // Otherwise just imply that we have received the email already

  else
    {
    if (this->ExpectedLicenseKeyFileName)
      {
      sprintf(
        buffer, 
        k_("You have received a confirmation email with a license file "
           "attached (%s)."), this->ExpectedLicenseKeyFileName);
      pre_str << buffer;
      }
    else
      {
      pre_str << 
        k_("You have received a confirmation email with a license file.");
      }
    }

  pre_str << " " << 
    k_("Please specify the location of this license file using the button " 
       "below.");

  // Container frame

  if (!this->OfflineRegistrationParametersFrame)
    {
    this->OfflineRegistrationParametersFrame = vtkKWFrame::New();
    this->OfflineRegistrationParametersFrame->SetParent(this->ClientArea);
    this->OfflineRegistrationParametersFrame->Create();
    }

  // Text area that can be used to copy/paste

  if (!this->OfflineRegistrationTextArea)
    {
    this->OfflineRegistrationTextArea = vtkKWText::New();
    this->OfflineRegistrationTextArea->SetParent(
      this->OfflineRegistrationParametersFrame);
    this->OfflineRegistrationTextArea->Create();
    this->OfflineRegistrationTextArea->ReadOnlyOn();
    this->OfflineRegistrationTextArea->SetReliefToFlat();
    this->OfflineRegistrationTextArea->QuickFormattingOn();
    this->OfflineRegistrationTextArea->SetHeight(7);
    this->OfflineRegistrationTextArea->SetBackgroundColor(
      this->OfflineRegistrationParametersFrame->GetBackgroundColor());

    this->Script("pack %s -side top -anchor nw -expand n -fill x", 
                 this->OfflineRegistrationTextArea->GetWidgetName());
    }

  pre_str << ends;
  this->OfflineRegistrationTextArea->SetText(pre_str.str());
  pre_str.rdbuf()->freeze(0);

  // License file load button

  if (!this->OfflineRegistrationLicenseFileButton)
    {
    this->OfflineRegistrationLicenseFileButton = 
      vtkKWLoadSaveButtonWithLabel::New();
    vtkKWLoadSaveButton *lsb = 
      this->OfflineRegistrationLicenseFileButton->GetWidget();
    vtkKWLoadSaveDialog *dlg = lsb->GetLoadSaveDialog();

    this->OfflineRegistrationLicenseFileButton->SetParent(
      this->OfflineRegistrationParametersFrame);
    dlg->SetParent(this->MasterWindow);
    this->OfflineRegistrationLicenseFileButton->Create();
    this->OfflineRegistrationLicenseFileButton->GetLabel()->SetText(
      ks_("Registration Wizard|License file:"));

    lsb->SetCommand(this, "ValidateOfflineRegistrationParameters");
    dlg->SetTitle(ks_("Registration Wizard|Select License File"));

    this->Script("pack %s -side top", 
                 this->OfflineRegistrationLicenseFileButton->GetWidgetName());
    }

  // Error message

  if (!this->OfflineRegistrationErrorLabel)
    {
    this->OfflineRegistrationErrorLabel = vtkKWLabelWithLabel::New();
    this->OfflineRegistrationErrorLabel->SetParent(
      this->OfflineRegistrationParametersFrame);
    this->OfflineRegistrationErrorLabel->Create();
    this->OfflineRegistrationErrorLabel->GetLabel()->SetImageToPredefinedIcon(
      vtkKWIcon::IconSilkExclamation);

    this->Script("pack %s -side top", 
                 this->OfflineRegistrationErrorLabel->GetWidgetName());
    }

  this->SetOfflineRegistrationErrorLabel(0);

  // Set the load dialog (use the license file name, if any)

  vtkKWLoadSaveDialog *dlg = 
    this->OfflineRegistrationLicenseFileButton->GetWidget()
    ->GetLoadSaveDialog();

  ostrstream file_types;
  if (this->ExpectedLicenseKeyFileName)
    {
    char *ext = strrchr(this->ExpectedLicenseKeyFileName, '.');
    if (ext && ext[1])
      {
      file_types << "{{" << this->GetApplication()->GetName() 
                 << " " << ks_("Registration Wizard|License File") 
                 << " (" << this->ExpectedLicenseKeyFileName
                 << ")} {" << ext << "}} ";
      }
    dlg->SetInitialFileName(this->ExpectedLicenseKeyFileName);
    }
  else
    {
    file_types << " {{" << ks_("Registration Wizard|License File") 
               << "} {.dat}}";
    }
  file_types << ends;
  dlg->SetFileTypes(file_types.str());
  file_types.rdbuf()->freeze(0);
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::SetOfflineRegistrationErrorLabel(const char *str)
{
  this->OfflineRegistrationErrorLabel->GetWidget()->SetText(str);

  if (this->IsCreated())
    {
    if (str && *str)
      {
      this->Script(
        "pack %s -side top -after %s -pady 3", 
        this->OfflineRegistrationErrorLabel->GetWidgetName(),
        this->OfflineRegistrationLicenseFileButton->GetWidgetName());
      }
    else
      {
      this->Script("pack forget %s", 
                   this->OfflineRegistrationErrorLabel->GetWidgetName());
      }
    }
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::PromptOfflineRegistrationParameters()
{
  if (this->RegistrationChoice == vtkKWRegistrationWizard::INVALID_MODE)
    {
    return this->PromptRegistrationType();
    }

  // Clear any other page

  this->ClearPage();

  // Create/update/bring up the widgets

  this->CreateOfflineRegistrationParametersPage();

  this->Script("pack %s -side top -fill x",
               this->OfflineRegistrationParametersFrame->GetWidgetName());

  // Next ? Not until the parameters are valid

  this->ValidateOfflineRegistrationParameters();

  if (!this->Invoked)
    {
    this->Invoked = 1;
    return this->vtkKWWizard::Invoke();
    }

  return 1;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::ValidateOfflineRegistrationParameters()
{
  int valid = 1;

  if (!this->OfflineRegistrationLicenseFileButton)
    {
    valid = 0;
    }
  else
    {
    const char *fname = 
      this->OfflineRegistrationLicenseFileButton->GetWidget()->GetFileName();
    if (!fname || !*fname)
      {
      valid = 0;
      }
    else
      {
      char license_key[VTK_KW_RW_KEY_SIZE];
      if (!this->GetLicenseKeyFromFile(fname, license_key))
        {
        valid = 0;
        this->SetOfflineRegistrationErrorLabel(
          k_("The license key could not be retrieved from the file !"));
        }
      else
        {
        int valid_license = this->VerifyLicenseKey(license_key);
        int valid_license_but_not_full = 
          (valid_license && 
           this->RegistrationChoice == vtkKWRegistrationWizard::FULL_MODE &&
           !this->IsLicenseKeyInFullMode(license_key));
        
        if (!valid_license || valid_license_but_not_full)
          {
          valid = 0;
          const char *msg = 0;
          if (valid_license_but_not_full)
            {
            msg = k_("The license is invalid, expired or a trial license !");
            }
          else
            {
            msg = k_("The license is invalid or expired !");
            }
          this->SetOfflineRegistrationErrorLabel(msg);
          }
        }
      }
    }

  if (!valid)
    {
    this->NoNextStep();
    }
  else
    {
    this->SetOfflineRegistrationErrorLabel(NULL);
    this->PropagateEnableState(this->NextButton);
    this->NextButton->SetCommand(this, "ProcessOfflineRegistrationParameters");
    }

  return valid;
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::ProcessOfflineRegistrationParameters()
{
  // Set the back button 

  this->AddBackButtonCommand("PromptOfflineRegistrationParameters");

  return this->PromptOfflineRegistrationConfirmation();
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::CreateOfflineRegistrationConfirmationPage()
{
  const char *fullm_name = this->FullModeName;

  // Let the user know what is up

  strstream subtitle_str;
  this->GetSubTitleLabelGivenRegistrationChoice(
    this->RegistrationChoice, subtitle_str);
  this->SubTitleLabel->SetText(subtitle_str.str()); 
  subtitle_str.rdbuf()->freeze(0);

  char buffer[500];

  if (this->RegistrationChoice == vtkKWRegistrationWizard::TRIAL_MODE)
    {
    this->SetPreText(
      k_("This application will now validate and install your trial license "
         "online and install it."));
    }
  else if (this->RegistrationChoice == vtkKWRegistrationWizard::FULL_MODE)
    {
    sprintf(
      buffer, 
      k_("This application will now validate and install your '%s' license " 
         "online and install it."), fullm_name);
    this->SetPreText(buffer);
    }
  else
    {
    this->SetPreText(
      k_("This application will now validate and install your license online "
         "and install it."));
    }

  // Container frame
  
  if (!this->OfflineRegistrationConfirmationFrame)
    {
    this->OfflineRegistrationConfirmationFrame = vtkKWFrame::New();
    this->OfflineRegistrationConfirmationFrame->SetParent(this->ClientArea);
    this->OfflineRegistrationConfirmationFrame->Create();
    }

  // Confirmation label

  if (!this->OfflineRegistrationConfirmationLabel)
    {
    this->OfflineRegistrationConfirmationLabel = vtkKWLabelWithLabel::New();
    this->OfflineRegistrationConfirmationLabel->SetParent(
      this->OfflineRegistrationConfirmationFrame);
    this->OfflineRegistrationConfirmationLabel->Create();

    this->Script("pack %s -side top", 
                 this->OfflineRegistrationConfirmationLabel->GetWidgetName());
    }
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::PromptOfflineRegistrationConfirmation()
{
  if (this->RegistrationChoice == vtkKWRegistrationWizard::INVALID_MODE)
    {
    return this->PromptRegistrationType();
    }

  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);

  const char *comp_name = app_pro ? app_pro->GetCompanyName() : NULL;
  const char *comp_support_contact = 
    app_pro ? app_pro->GetCompanySupportContact() : NULL;

  // Clear any other page

  this->ClearPage();

  // Create/update/bring up the widgets

  this->CreateOfflineRegistrationConfirmationPage();

  this->Script("pack %s -side top", 
               this->OfflineRegistrationConfirmationFrame->GetWidgetName());

  // Check the key

  char buffer[500];

  char license_key[VTK_KW_RW_KEY_SIZE];
  if (this->GetLicenseKeyFromFile(
       this->OfflineRegistrationLicenseFileButton->GetWidget()->GetFileName(),
        license_key) && 
      this->VerifyLicenseKey(license_key))
    {
    this->OfflineRegistrationConfirmationLabel->GetLabel()->SetImageToPredefinedIcon(
      vtkKWIcon::IconSilkInformation);

    this->OfflineRegistrationConfirmationLabel->GetWidget()->SetText(
      k_("Your license was validated and installed sucessfully !"));
    this->SetLicenseKey(license_key);
    this->LastStep();
    }
  else
    {
    this->OfflineRegistrationConfirmationLabel->GetLabel()->SetImageToPredefinedIcon(
      vtkKWIcon::IconSilkExclamation);
    this->OfflineRegistrationConfirmationLabel->GetWidget()->SetText(
     k_("Sorry, there was a problem validating or installing your license !"));

    ostrstream posttext_str;
    posttext_str << 
      k_("Please make sure you have specified the correct license file.");
    if (comp_support_contact)
      {
      sprintf(buffer, 
              k_("If you continue to have a problem please contact %s at %s."),
              comp_name, comp_support_contact);
      posttext_str << " " << buffer;
      }
    posttext_str << ends;
    this->SetPostText(posttext_str.str());
    posttext_str.rdbuf()->freeze(0);
    this->NoNextStep();
    }

  // Next ?

  if (!this->Invoked)
    {
    this->Invoked = 1;
    return this->vtkKWWizard::Invoke();
    }

  return 1;
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::CreateLimitedEditionModeConfirmationPage()
{
  vtkKWApplication *app = this->GetApplication();
  vtkKWApplicationPro *app_pro = vtkKWApplicationPro::SafeDownCast(app);

  const char *app_name = app->GetName();
  const char *fullm_name = this->FullModeName;
  const char *lem_name = this->GetLimitedEditionModeName();
  const char *comp_support_contact = 
    app_pro ? app_pro->GetCompanySupportContact() : NULL;

  // Let the user know what is up

  strstream subtitle_str;
  this->GetSubTitleLabelGivenRegistrationChoice(
    this->RegistrationChoice, subtitle_str);
  this->SubTitleLabel->SetText(subtitle_str.str()); 
  subtitle_str.rdbuf()->freeze(0);

  char buffer[500];

  strstream pre_str;

  if (this->SupportTrialMode && !this->HasTrialModeExpired())
    {
    sprintf(
      buffer,
      k_("You are now setup to run %s in '%s' mode. Should you later decide "
         "to purchase a '%s' license or try the '%s' mode just select "
         "'Register' from the 'Help' menu and follow the instructions."),
      app_name, lem_name, fullm_name, fullm_name);

    }
  else
    {
    sprintf(
      buffer,
      k_("You are now setup to run %s in '%s' mode. Should you later decide "
         "to purchase a '%s' license just select 'Register' from the 'Help' "
         "menu and follow the instructions."),
      app_name, lem_name, fullm_name);
    }

  pre_str << buffer << " " << k_("We hope you find this application useful.");

  if (comp_support_contact)
    {
    sprintf(buffer, 
            k_("We welcome feedback at %s."), comp_support_contact);
    pre_str << " " << buffer;
    }
  pre_str << ends;
  this->SetPreText(pre_str.str());
  pre_str.rdbuf()->freeze(0);
}

//----------------------------------------------------------------------------
int vtkKWRegistrationWizard::PromptLimitedEditionModeConfirmation()
{
  if (this->RegistrationChoice == vtkKWRegistrationWizard::INVALID_MODE)
    {
    return this->PromptRegistrationType();
    }

  // Clear any other page

  this->ClearPage();

  // Create/update/bring up the widgets

  this->CreateLimitedEditionModeConfirmationPage();

  // Next ?

  this->LastStep();
  if (!this->Invoked)
    {
    this->Invoked = 1;
    return this->vtkKWWizard::Invoke();
    }
  return 1;
}

//----------------------------------------------------------------------------
void vtkKWRegistrationWizard::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "ComputerID: " << this->ComputerID << endl;
  os << indent << "SupportTrialMode: " 
     << (this->SupportTrialMode ? "On" : "Off") << endl;
  os << indent << "SupportLimitedEditionMode: " 
     << (this->SupportLimitedEditionMode ? "On" : "Off") << endl;
  os << indent << "LicenseKey: " 
     << (this->LicenseKey ? this->LicenseKey : "None") << endl;
  os << indent << "RegistrationChoice: " << this->RegistrationChoice << endl;
  os << indent << "PublicEncryptionKey: " 
     << (this->PublicEncryptionKey ? this->PublicEncryptionKey : "None") 
     << endl;
  os << indent << "PrivateEncryptionKey: " 
     << (this->PrivateEncryptionKey  ? this->PrivateEncryptionKey : "None") 
     << endl;
  os << indent << "ExpectedLicenseKeyFileName: " 
     << (this->ExpectedLicenseKeyFileName ? this->ExpectedLicenseKeyFileName : "None") << endl;
  os << indent << "RegistrationURL: " 
     << (this->RegistrationURL ? this->RegistrationURL : "None") << endl;
  os << indent << "LimitedEditionModeRegistrySubKey: " 
     << (this->LimitedEditionModeRegistrySubKey 
         ? this->LimitedEditionModeRegistrySubKey : "None") << endl;
  os << indent << "LimitedEditionModeRegistryKey: " 
     << (this->LimitedEditionModeRegistryKey 
         ? this->LimitedEditionModeRegistryKey : "None") << endl;
  os << indent << "LicenseKeyRegistrySubKey: " 
     << (this->LicenseKeyRegistrySubKey 
         ? this->LicenseKeyRegistrySubKey : "None") << endl;
  os << indent << "LicenseKeyRegistryKey: " 
     << (this->LicenseKeyRegistryKey 
         ? this->LicenseKeyRegistryKey : "None") << endl;
  os << indent << "FullModeName: " 
     << (this->FullModeName ? this->FullModeName : "None") << endl;
  os << indent << "MostRecentDate: " << this->MostRecentDate << endl;
}
