#include <vcl.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
#include "VolumeManagement.h"
#pragma hdrstop
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
	return 1;
}
//---------------------------------------------------------------------------
bool VolumeManagement::FolderExists(char* file)
{
  DWORD returnvalue;
  returnvalue = GetFileAttributes(file);
  if(returnvalue == ((DWORD)-1))
    return false;
  else
    return true;
}

vector <string> VolumeManagement::GetLogicalDrives_()
{
  vector <string> dyski;
  int drives = GetLogicalDrives();
  int i = 0;
  char tmp;
  string x;
  while(drives)
  {
    i++;
    if(drives & 1)
    {
      tmp = (char)65+i-1;
      x = tmp;
      dyski.push_back(x + ":\\");
    }
    drives >>= 1; // Bitwise right shift assignment
  }
  return dyski;
}
string VolumeManagement::GetDriveType_(string disks)
{
  vector<string> x;
  x.push_back(disks.c_str());
  return GetDriveType_(x);
}
string VolumeManagement::GetDriveType_(vector<string> disks)
{
  ostringstream output;
  for (unsigned int i=0; i<disks.size(); i++)
  {
    switch(GetDriveType(disks[i].c_str()))
    {
      case DRIVE_NO_ROOT_DIR:
        output << ("Wrong path!"); //Moze nie byc zamontowany
        break;
      case DRIVE_REMOVABLE:
        output << ("Volume is FDD or USB pendrive");
        break;
      case DRIVE_FIXED:
        output << ("Volume is HDD");
        break;
      case DRIVE_REMOTE:
        output << ("Volume is Remote");
        break;
      case DRIVE_CDROM:
        output << ("Volume is DVD-rom or similar");
        break;
      case DRIVE_RAMDISK:
        output << ("Volume is RAM disk");
        break;
      case DRIVE_UNKNOWN:
        output << ("Volume type is Unknown");
        break;
    }
  }
  return output.str();
}

vector<string> VolumeManagement::GetLogicalDriveStrings_()
{
  vector<string> output;
  char sBuffer[1024];
  GetLogicalDriveStrings(1024, sBuffer);
  char *p = sBuffer;
  while(*p)
  {
    output.push_back(p);
    p = &p[strlen(p) + 1];
  }
  return output;
}

string VolumeManagement::FormatFileSystemFlags(DWORD flags, LPCTSTR sep)
{
  if (flags==0)
  return _T("[none]");

  const struct
  {
    long flag;
    LPCTSTR name;
  }
  FlagNames[] = {
		{ FILE_NAMED_STREAMS, _T("FILE_NAMED_STREAMS") },
		{ FILE_READ_ONLY_VOLUME, _T("FILE_READ_ONLY_VOLUME") },
		{ FILE_SUPPORTS_OBJECT_IDS, _T("FILE_SUPPORTS_OBJECT_IDS") },
		{ FILE_SUPPORTS_REPARSE_POINTS, _T("FILE_SUPPORTS_REPARSE_POINTS") },
		{ FILE_SUPPORTS_SPARSE_FILES, _T("FILE_SUPPORTS_SPARSE_FILES") },
		{ FILE_VOLUME_QUOTAS, _T("FILE_VOLUME_QUOTAS") },
		{ FS_CASE_IS_PRESERVED, _T("FS_CASE_IS_PRESERVED") },
		{ FS_CASE_SENSITIVE, _T("FS_CASE_SENSITIVE") },
		{ FS_FILE_COMPRESSION, _T("FS_FILE_COMPRESSION") },
		{ FS_FILE_ENCRYPTION, _T("FS_FILE_ENCRYPTION") },
		{ FS_PERSISTENT_ACLS, _T("FS_PERSISTENT_ACLS") },
		{ FS_UNICODE_STORED_ON_DISK, _T("FS_UNICODE_STORED_ON_DISK") },
		{ FS_VOL_IS_COMPRESSED, _T("FS_VOL_IS_COMPRESSED") },
		{ 0,NULL }};
  string str;
  for (int i=0; FlagNames[i].name; i++)
  {
    if (flags & FlagNames[i].flag)
      str += "1";
    else
      str += "0";
  }
  return str;
}

string VolumeManagement::GetVolumeInformation_(const char* drive)
{
  unsigned char FileSystem[MAX_PATH],
                VolumeName[MAX_PATH];
  unsigned long Serial,
                MaxFileLength,
                SystemFlags;
  ostringstream output;
  bool check = GetVolumeInformation(drive,
                          (LPTSTR)VolumeName,
                          MAX_PATH,
                          &Serial,
                          &MaxFileLength,
                          &SystemFlags,
                          (LPTSTR)FileSystem,
                          MAX_PATH);
  if(check)
  {
    output << "Vol " << drive << " has been found\r\n";
    if(VolumeName[0] == NULL)
        output << "Volume Name not present\r\n";
    else
        output << "Volume Name is " << VolumeName << "\r\n";
    output << "Volume Serial is " << Serial << "\r\n";
    output << "Max Filelength is " << MaxFileLength << "\r\n";
    output << "The file system flags are " << "\r\n\t";
    output << FormatFileSystemFlags(SystemFlags, "\r\n\t") << "\r\n";
    output << "Filesystem is " << FileSystem << "\r\n";

    return output.str();
  }
  return "";
}

bool VolumeManagement::SetVolumeMointPoint_(const char* device, const char* target)
{
  if(!FolderExists((char*)target))
    if(!CreateDirectory(target, NULL))
      throw "Folder doesn't exists and wasn't able to create it, maybe wrong path?";
  char Buffer[MAX_PATH];
  if(GetVolumeNameForVolumeMountPoint(device, Buffer, MAX_PATH))
    if(SetVolumeMountPoint(target, Buffer))
      return true;
  return false;
}

bool VolumeManagement::DeleteVolumeMountPoint_(const char* target)
{
  if(DeleteVolumeMountPoint(target))
  {
    if(RemoveDirectory(target))
      return true;
    throw "Drive was unmounted but folder wasn't deleted";
  }
  return false;
}

//----------------------------------------
string VolumeManagement::GetVolumePathName_(const char* target)
{
  char Buffer[1024];
  if(GetVolumePathName(target, Buffer, MAX_PATH))
    return (string)Buffer;
  return "";
}

string VolumeManagement::GetVolumeNameForVolumeMountPoint_(const char* target)
{
  char Buffer[MAX_PATH];
  if(GetVolumeNameForVolumeMountPoint(target, Buffer, MAX_PATH))
    return (string)Buffer;
  return "";
}

string VolumeManagement::FindFirstVolume_()
{
  char Buffer[MAX_PATH];
  this->drivehandle = FindFirstVolume(Buffer, MAX_PATH);
  if(this->drivehandle == INVALID_HANDLE_VALUE)
    return "";
  return (string)Buffer;
}

string VolumeManagement::FindNextVolume_()
{
  char Buffer[MAX_PATH];
  if(this->drivehandle == NULL)
    return "1";
  if(FindNextVolume(this->drivehandle, Buffer, MAX_PATH))
    return (string)Buffer;
  return "";
}

string VolumeManagement::GetVolumePathNamesForVolumeName_(const char* Buf)
{
  char Buffer[MAX_PATH];
  PDWORD tmp;
  if(GetVolumePathNamesForVolumeName(Buf, Buffer, MAX_PATH, NULL)) /* \\?\Volume{GUID}\ */
    return (string)Buffer;
  return "";
}
string VolumeManagement::QueryDosDevice_(const char* name)
{
  char Buffer[MAX_PATH];
  if(QueryDosDevice(name, Buffer, MAX_PATH))
    return (string)Buffer;
  return "";
}