// ThinDir.cpp : ThinApp SDK sample program to illustrate the use of the file objects
//
// Usage: ThinDir <PhysicalPackageName> [<VirtualTarget>]
// So you have the package name as visible in the physical file system optionally followed 
// a path to either a file or folder in the virtual file system inside the package.

#include "stdafx.h"

// Using #import creates some wrapper classes which allow you to concentrate on
// the logic instead of getting drowned in error handling
#import "progid:ThinApp.Management"
using namespace ThinAppSDK;

/*
 * Print information line for a single folder
 */
static void PrintFolderInfo(const IThinApp_VFolderPtr &Folder)
{
   DATE LastModifiedDate = Folder->DateLastModified;
   SYSTEMTIME LastModifiedSysTime;
   if (VariantTimeToSystemTime(LastModifiedDate, &LastModifiedSysTime))
      // Feel free to format using the users locale instead....
      printf("%04u/%02u/%02u %02u:%02u", LastModifiedSysTime.wYear, LastModifiedSysTime.wMonth, LastModifiedSysTime.wDay,
               LastModifiedSysTime.wHour, LastModifiedSysTime.wMinute);
   else
      printf("                ");

   printf("   <DIR> %10I64d %ls\n", Folder->Size, (LPCWSTR) Folder->Name);
}

/*
 * Print information line for a single file
 */
static void PrintFileInfo(const IThinApp_VFilePtr &File)
{
   DATE LastModifiedDate = File->DateLastModified;
   SYSTEMTIME LastModifiedSysTime;
   if (VariantTimeToSystemTime(LastModifiedDate, &LastModifiedSysTime))
      // Feel free to format using the users locale instead....
      printf("%04u/%02u/%02u %02u:%02u", LastModifiedSysTime.wYear, LastModifiedSysTime.wMonth, LastModifiedSysTime.wDay,
               LastModifiedSysTime.wHour, LastModifiedSysTime.wMinute);
   else
      printf("                ");

   printf("         %10I64d %ls\n", File->Size, (LPCWSTR) File->Name);
}

/*
 * Display a simple directory listing for Target inside PackageName
 */
static void ThinDir(LPCWSTR PackageName, LPCWSTR Target)
{
   // Everything starts with the ThinApp.Management object, create it
   IThinApp_ManagementPtr Management;
   HRESULT Hr =  Management.CreateInstance(__uuidof(CThinApp_Management));
   if (FAILED(Hr)) 
   {
      fprintf(stderr, "Failed to create ThinApp.Management object, perhaps ThinApp SDK is not registered?\n");
      exit(1);
   }

   // Follow the chain from ThinApp.Management to ThinApp.Package to ThinApp.VFileSystemObject
   IThinApp_PackagePtr Package = Management->OpenPackage(PackageName);
   IThinApp_VFileSystemObjectPtr VFS = Package->GetVFileSystemObject(0);

   long SubFoldersCount= 0;
   long FilesCount = 0;
   __int64 TotalFilesSize = 0;

   if (VFS->FolderExists(Target))
   {
      // User specified a directory in the package
      IThinApp_VFolderPtr Folder = VFS->GetFolder(Target);
      printf("\n Directory of %ls|%ls\n\n", PackageName, Target);

      // First handle the subfolders
      IThinApp_VFoldersPtr SubFolders = Folder->SubFolders;
      // You could also use the IEnumVARIANT interface here, but looping is easier in C++
      SubFoldersCount = SubFolders->Count;
      // COM collections start with index 1
      for (long SubFolderIndex = 1; SubFolderIndex <= SubFoldersCount; SubFolderIndex++)
      {
         IThinApp_VFolderPtr SubFolder = SubFolders->Item[SubFolderIndex];
         PrintFolderInfo(SubFolder);
      }

      // Now the files
      IThinApp_VFilesPtr Files = Folder->Files;
      FilesCount = Files->Count;
      for (long FileIndex = 1; FileIndex <= FilesCount; FileIndex++)
      {
         IThinApp_VFilePtr File = Files->Item[FileIndex];
         PrintFileInfo(File);
         TotalFilesSize += File->Size;
      }
   }
   else if (VFS->FileExists(Target))
   {
      // User specified a file in the package
      IThinApp_VFilePtr File = VFS->GetFile(Target);
      printf("\n Directory of %ls|%ls\n\n", PackageName, (LPCWSTR) File->Path);

      FilesCount = 1;
      PrintFileInfo(File);
      TotalFilesSize = File->Size;
   }
   else
   {
      // Don't know what the user is talking about
      printf("\n Directory of %ls\n\nFile Not Found\n", PackageName);
   }

   // And finally the statistics
   printf("%10ld File(s) %10I64d bytes\n", FilesCount, TotalFilesSize);
   printf("%10ld Dir(s)\n", SubFoldersCount);
}

/*
 * Main program. Parse arguments and then call ThinDir to do the real work.
 */
int wmain(int argc, WCHAR *argv[])
{
#ifdef _DEBUG
   // Dump memory leaks on exit
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
#endif

   CoInitialize(NULL);

   // The smart pointer classes will throw _com_error on failures, handle these
   int ExitCode;
   try
   {
      LPCWSTR Target;
      if (argc == 2)
         Target = L"\\";
      else if (argc == 3)
         Target = argv[2];
      else
      {
         fprintf(stderr, "Usage: ThinDir <PhysicalPackageName> [<VirtualTarget>]\n");
         exit(1);
      }

      // Produce the directory listing
      ThinDir(argv[1], Target);

      ExitCode = 0;
   }
   catch(_com_error e)
   {
      fprintf(stderr, "Error: %ls\n", (LPCWSTR) e.Description());
      ExitCode = 1;
   }

   CoUninitialize();

   return ExitCode;
}

