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

  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 "vtkVVMD5FileAuthenticator.h"

#include "vtkObjectFactory.h"
#include "vtkVVFileInstance.h"
#include "vtkKWDataTransfer.h"
#include "vtkKWCacheManager.h"
#include "vtkKWRemoteIOManager.h"
#include "vtkVVApplication.h"
#include "vtkKWMessageDialog.h"
#include "vtkKWInternationalization.h"

#include <vtksys/ios/sstream>

#include "vtkKWWidgetsProConfigure.h" // Needed for KWWidgetsPro_USE_LICENSE
#ifdef KWWidgetsPro_USE_LICENSE
#include "vtkKWRSA.h"
#include "vtkKWRegistrationWizard.h"
#endif

//---------------------------------------------------------------------------
vtkStandardNewMacro(vtkVVMD5FileAuthenticator);
vtkCxxRevisionMacro(vtkVVMD5FileAuthenticator, "$Revision: 1.10 $");

//----------------------------------------------------------------------------
vtkVVMD5FileAuthenticator::vtkVVMD5FileAuthenticator()
{
}

//----------------------------------------------------------------------------
vtkVVMD5FileAuthenticator::~vtkVVMD5FileAuthenticator()
{
}

//----------------------------------------------------------------------------
int vtkVVMD5FileAuthenticator::AuthenticateFile( const char * f )
{
#ifdef KWWidgetsPro_USE_LICENSE
  vtkVVApplication * vvapp 
    = vtkVVApplication::SafeDownCast(this->GetApplication());
  vtkKWRegistrationWizard *registration = vvapp->GetRegistrationWizard();

  // The Authentication check is enfored only in Limited edition mode.
  // In Trial mode, let the user load any file. 
  // In Full mode, he paid us :). Let him load everything.
  
  if (registration->GetSupportLimitedEditionMode() &&
      registration->InLimitedEditionMode())
    {

    // If the Application is in 
    vtkstd::string key, line;
    vtksys_stl::string msg;

    // Sanity check. Make sure the file exists.
    if ( !vtksys::SystemTools::FileExists( f ))
      {
      return 0;
      }

    // Look for a license file in the path now.
    // The license file must be found in the same directory.
    vtkstd::string licenseFile = 
      vtksys::SystemTools::GetFilenamePath(f) + "/.midas.key";

    // Sanity check. Make sure the license file exists.
    if ( !vtksys::SystemTools::FileExists( licenseFile.c_str() ))
      {
      char msgs[1024];
      sprintf( msgs, 
               k_("This application is running in %s mode. In this mode, you can only load datasets from the %s data server. You must purchase and register a full edition to avail of this functionality. You can do so by going to the Help->Register dialog."), vvapp->GetLimitedEditionModeName(), vvapp->GetName());
      msg += msgs;
      msg += "\n\n";
      msg += k_("The following license file was not found. Authentication failed.");
      msg += "\n";
      msg += licenseFile;
      this->SetReasonString(msg.c_str());

      vtkKWMessageDialog::PopupMessage(
        this->GetApplication(), NULL, "Authentication Error", msg.c_str(),
        vtkKWMessageDialog::ErrorIcon);

      return 0;
      }

    vtksys_ios::ostringstream os;

    // A typical key file looks like this:
    // CTNeck.vti:JPqqY4PrCzuWLYqI1BY8VimbwXtTS+v+RTtg3bvbaCUWX/PmfCdgxxR83v/PpvRn5bmYCVGYzV0DvXVrsQYw2hCGMAu39BF3C0qrJDAEJpfEKChSOP37ZG09WoqRmRhvIkAr0ZDczaa+DCNn7PL5NcQAas1IYvpR98GOkiL+DIU=
    // CTNeck.vti.vvi:SY4A+OtEc/sNUVOPbxm3zovbdIFzk8dk31ozuy5PJhT43OkxnN/JksEQeW1XH2pS4s3KydKh1RasIeiOyJplTq1oxg731/TweDEL0hbHDbGVhTSqUKqYTuCZfF7/0OxHoy8IusO5kloeq5baOjeI4/UQUhULxnAju7kAn6TLg6g=
    // Case002.osa:UxBurvjhC8nywqfarNOyIQKd1s8JwEiVBxzkhv3Iw44LVuqRo7zPhgemzG2XnRypwY0/6eH3aqW4WsI5Elv1hytTrtPB52zDdmte4ui3cRYL30lZ3bKJw/puf8C1N5nukjg/FsFBwzZkvhStBszilzt2STY0i5yI1UB4C5FGNGg=
    //
    // We need to parse each line, check if the first part is the filename
    // "f" and if so, get that key. Then we will decrypt it with the public 
    // key and check if the MD5 of the file matches it.
    
    vtkstd::string filename = vtksys::SystemTools::GetFilenameName(f);

    std::ifstream licenseFileStream(licenseFile.c_str());
    if (licenseFileStream.is_open())
      {
      vtkstd::string searchstring = filename + ":";
      while (!licenseFileStream.eof())
        {
        // Get each line in the license stream. One of these lines contains
        // the key for this file.
        getline(licenseFileStream, line);

        if (line.length())
          {
          // If the search string is found right at the beginning.
          if (line.find(searchstring) == 0)
            {
            // We found the key. 
            key = line.substr(searchstring.length());

#ifdef KWWidgetsPro_USE_LICENSE
            if (vtkKWRSA::VerifyMD5OfFile( f, key, this->GetPublicKey() ))
              {
              return 1;
              }
            else
#endif
              {
              os << "Failed to authenticate " << filename 
                 << ". The key file appears to be corrupt" << std::ends;
              this->SetReasonString(os.str().c_str());

              vtkKWMessageDialog::PopupMessage(
                this->GetApplication(), NULL, "Authentication Error", os.str().c_str(),
                vtkKWMessageDialog::ErrorIcon);

              return 0;
              }
            }
          }
        }
      }

    os << "Authentication of " << filename 
       << " failed. Could not find corresponding key in " 
       << licenseFile << std::ends;
    this->SetReasonString(os.str().c_str());

    vtkKWMessageDialog::PopupMessage(
      this->GetApplication(), NULL, "Authentication Error", os.str().c_str(),
      vtkKWMessageDialog::ErrorIcon);
    return 0;
    }
#endif

  return 1;
}

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

