#include "stdafx.h"

#define DEBUG_ME 0

float float_16_to_32(unsigned short value)
{
 const unsigned short s = (value & 0x8000);
 const unsigned short e = (value & 0x7C00) >> 10;
 const unsigned short m = (value & 0x03FF);
 const float sgn = (s ? -1.0f : 1.0f);

 // ok
 if(e == 0) {
    if(m == 0) return sgn*0.0f;
    else return sgn*powf(2, -14.0f)*((float)m/1024.0f);
   } 
 if(e < 32) return sgn*powf(2.0f, (float)e - 15.0f)*(1.0f + ((float)m/1024.0f));

 // ouch!
 if(m == 0) return std::numeric_limits<float>::quiet_NaN();
 return std::numeric_limits<float>::quiet_NaN();
}

bool error(const char* message)
{
 cout << message << endl;
 return false;
}

__int16 LE_read_sint16(ifstream& ifile)
{
 short temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

__int32 LE_read_sint32(ifstream& ifile)
{
 int temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int8 LE_read_uint08(ifstream& ifile)
{
 unsigned char temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int16 LE_read_uint16(ifstream& ifile)
{
 unsigned short temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int32 LE_read_uint32(ifstream& ifile)
{
 unsigned int temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int64 LE_read_uint64(ifstream& ifile)
{
 unsigned __int64 temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int8 BE_read_uint08(ifstream& ifile)
{
 unsigned __int8 temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << (int)temp << endl;
 return temp;
}

unsigned __int16 BE_read_uint16(ifstream& ifile)
{
 unsigned short temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int32 BE_read_uint32(ifstream& ifile)
{
 unsigned __int32 temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int64 BE_read_uint64(ifstream& ifile)
{
 unsigned __int64 temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int8 LE_read_uint08(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 unsigned char temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << (int)temp << endl;
 return temp;
}

unsigned __int16 LE_read_uint16(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 unsigned short temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int32 LE_read_uint32(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 unsigned int temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int64 LE_read_uint64(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 unsigned __int64 temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int8 BE_read_uint08(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 unsigned __int8 temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << (int)temp << endl;
 return temp;
}

unsigned __int16 BE_read_uint16(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 unsigned short temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int32 BE_read_uint32(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 unsigned __int32 temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

unsigned __int64 BE_read_uint64(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 unsigned __int64 temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

signed __int16 BE_read_sint16(ifstream& ifile)
{
 signed __int16 temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

float BE_read_half_float(ifstream& ifile)
{
 unsigned short temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << float_16_to_32(temp) << endl;
 return float_16_to_32(temp);
}

float LE_read_half_float(ifstream& ifile)
{
 unsigned short temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << float_16_to_32(temp) << endl;
 return float_16_to_32(temp);
}

float LE_read_float(ifstream& ifile)
{
 float temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

float BE_read_float(ifstream& ifile)
{
 float temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

double LE_read_double(ifstream& ifile)
{
 double temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

double BE_read_double(ifstream& ifile)
{
 double temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

float LE_read_float(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 float temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

float BE_read_float(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 float temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

double LE_read_double(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 double temp;
 ifile.read((char*)&temp, sizeof(temp));
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

double BE_read_double(ifstream& ifile, unsigned int offset)
{
 ifile.seekg(offset);
 double temp;
 ifile.read((char*)&temp, sizeof(temp));
 reverse_byte_order(&temp);
 if(DEBUG_ME) cout << temp << endl;
 return temp;
}

bool get_models_filename_list(deque<string>& namelist, const char* fext)
{
 // get path of application
 char c_rootname[MAX_PATH];
 GetModuleFileName(0, c_rootname, MAX_PATH);

 // split the pathname
 char c_drive[1024];
 char c_dir[1024];
 _splitpath(c_rootname, c_drive, c_dir, nullptr, nullptr);
 strlwr(c_drive);
 strlwr(c_dir);

 // build pathname
 string s_rootname(c_drive);
 s_rootname += string(c_dir);

 // build directory list
 deque<string> templist;
 templist.insert(templist.end(), s_rootname);

 // transfer directories with EXT files
 deque<string> rootlist;
 for(size_t i = 0; i < templist.size(); i++)
    {
     find_file file;
     bool added = false;
     string path(templist[i]);
     path += "*";
     path += fext;
     if(file.find(path.c_str())) {
        rootlist.insert(rootlist.end(), templist[i]);
        added = true;
       }
    }

 // erase the temporary list
 templist.erase(templist.begin(), templist.end());
 if(rootlist.empty()) return error("No files found in current directory or subdirectories.");

 // build namelist
 namelist.clear();
 for(size_t i = 0; i < rootlist.size(); i++)
    {
     // clear templist
     find_file file;
     templist.erase(templist.begin(), templist.end());

     // add TID files
     string path(rootlist[i]);
     path += "*";
     path += fext;
     if(file.find(path.c_str())) {
        string temp(rootlist[i]);
        temp += file.filename();
        templist.insert(templist.end(), temp);
       }
     while(file.next()) {
        string temp(rootlist[i]);
        temp += file.filename();
        templist.insert(templist.end(), temp);
       }

     // must have something in templist
     file.close();
     if(!templist.size()) return error("No files found in root directory or subdirectories.");

     // sort temporary list and append to the namelist
     sort(templist.begin(), templist.end());
     namelist.insert(namelist.end(), templist.begin(), templist.end());
    }

 // must have something in namelist
 templist.erase(templist.begin(), templist.end());
 if(!namelist.size()) return error("No files found in root directory or subdirectories.");

 return true;
}

bool get_motion_filename_list(deque<string>& namelist, const char* fext)
{
 // get path of application
 char c_rootname[MAX_PATH];
 GetModuleFileName(0, c_rootname, MAX_PATH);

 // split the pathname
 char c_drive[1024];
 char c_dir[1024];
 _splitpath(c_rootname, c_drive, c_dir, nullptr, nullptr);
 strlwr(c_drive);
 strlwr(c_dir);

 // build pathname
 string s_rootname(c_drive);
 s_rootname += string(c_dir);
 s_rootname += "motion\\";

 // build directory list
 deque<string> templist;
 templist.insert(templist.end(), s_rootname);

 size_t i = 0;
 for(;;)
    {
     // get wildcard
     find_file file;
     string path(templist[i]);
     path += "*.*";
     file.find(path.c_str());
     if(!file) return error("Could not build wildcard path.");

     // insert directories
     if(file.is_directory() && !file.is_dots() && !file.is_system()) {
        string path(templist[i]);
        path += string(file.filename());
        path += string("\\");
        templist.insert(templist.end(), path);
       }

     while(file.next()) {
        if(file.is_directory() && !file.is_dots() && !file.is_system()) {
           string path(templist[i]);
           path += string(file.filename());
           path += string("\\");
           templist.insert(templist.end(), path);
          }
       }

     file.close();

     // update index
     if(++i == templist.size())
        break;
    }

 // transfer directories with EXT files
 deque<string> rootlist;
 for(size_t i = 0; i < templist.size(); i++)
    {
     find_file file;
     bool added = false;
     string path(templist[i]);
     path += "*";
     path += fext;
     if(file.find(path.c_str())) {
        rootlist.insert(rootlist.end(), templist[i]);
        added = true;
       }
    }

 // erase the temporary list
 templist.erase(templist.begin(), templist.end());
 if(rootlist.empty()) return error("No files found in current directory or subdirectories.");

 // build namelist
 namelist.clear();
 for(size_t i = 0; i < rootlist.size(); i++)
    {
     // clear templist
     find_file file;
     templist.erase(templist.begin(), templist.end());

     // add TID files
     string path(rootlist[i]);
     path += "*";
     path += fext;
     if(file.find(path.c_str())) {
        string temp(rootlist[i]);
        temp += file.filename();
        templist.insert(templist.end(), temp);
       }
     while(file.next()) {
        string temp(rootlist[i]);
        temp += file.filename();
        templist.insert(templist.end(), temp);
       }

     // must have something in templist
     file.close();
     if(!templist.size()) return error("No files found in root directory or subdirectories.");

     // sort temporary list and append to the namelist
     sort(templist.begin(), templist.end());
     namelist.insert(namelist.end(), templist.begin(), templist.end());
    }

 // must have something in namelist
 templist.erase(templist.begin(), templist.end());
 if(!namelist.size()) return error("No files found in root directory or subdirectories.");

 return true;
}

bool get_filename_list(deque<string>& namelist, const char* fext)
{
 // get path of application
 char c_rootname[MAX_PATH];
 GetModuleFileName(0, c_rootname, MAX_PATH);

 // split the pathname
 char c_drive[1024];
 char c_dir[1024];
 _splitpath(c_rootname, c_drive, c_dir, nullptr, nullptr);
 strlwr(c_drive);
 strlwr(c_dir);

 // build pathname
 string s_rootname(c_drive);
 s_rootname += string(c_dir);

 // build directory list
 deque<string> templist;
 templist.insert(templist.end(), s_rootname);

 size_t i = 0;
 for(;;)
    {
     // get wildcard
     find_file file;
     string path(templist[i]);
     path += "*.*";
     file.find(path.c_str());
     if(!file) return error("Could not build wildcard path.");

     // insert directories
     if(file.is_directory() && !file.is_dots() && !file.is_system()) {
        string path(templist[i]);
        path += string(file.filename());
        path += string("\\");
        templist.insert(templist.end(), path);
       }

     while(file.next()) {
        if(file.is_directory() && !file.is_dots() && !file.is_system()) {
           string path(templist[i]);
           path += string(file.filename());
           path += string("\\");
           templist.insert(templist.end(), path);
          }
       }

     file.close();

     // update index
     if(++i == templist.size())
        break;
    }

 // transfer directories with EXT files
 deque<string> rootlist;
 for(size_t i = 0; i < templist.size(); i++)
    {
     find_file file;
     bool added = false;
     string path(templist[i]);
     path += "*";
     path += fext;
     if(file.find(path.c_str())) {
        rootlist.insert(rootlist.end(), templist[i]);
        added = true;
       }
    }

 // erase the temporary list
 templist.erase(templist.begin(), templist.end());
 if(rootlist.empty()) return error("No files found in current directory or subdirectories.");

 // build namelist
 namelist.clear();
 for(size_t i = 0; i < rootlist.size(); i++)
    {
     // clear templist
     find_file file;
     templist.erase(templist.begin(), templist.end());

     // add TID files
     string path(rootlist[i]);
     path += "*";
     path += fext;
     if(file.find(path.c_str())) {
        string temp(rootlist[i]);
        temp += file.filename();
        templist.insert(templist.end(), temp);
       }
     while(file.next()) {
        string temp(rootlist[i]);
        temp += file.filename();
        templist.insert(templist.end(), temp);
       }

     // must have something in templist
     file.close();
     if(!templist.size()) return error("No files found in root directory or subdirectories.");

     // sort temporary list and append to the namelist
     sort(templist.begin(), templist.end());
     namelist.insert(namelist.end(), templist.begin(), templist.end());
    }

 // must have something in namelist
 templist.erase(templist.begin(), templist.end());
 if(!namelist.size()) return error("No files found in root directory or subdirectories.");

 return true;
}

find_file::find_file() : handle(0)
{
 ZeroMemory(&find32, sizeof(find32));
}

find_file::~find_file()
{
 close();
}

void find_file::close(void)
{
 // must check for valid handle in 
 // VC++ .NET or else exception results
 if(handle) FindClose(handle);
 handle = 0;
 ZeroMemory((void*)&find32, sizeof(find32)); 
}

bool find_file::find(const char* filename)
{
 close();
 handle = FindFirstFile(filename, &find32);
 if(handle == INVALID_HANDLE_VALUE) handle = 0;
 return (handle != 0);
}

bool find_file::next(void)
{
 if(handle == 0) return false;
 return (FindNextFile(handle, &find32) == TRUE);
}

bool find_file::is_dots(void)
{
 return (!strcmp(find32.cFileName, ".") || !strcmp(find32.cFileName, ".."));
}

bool find_file::is_directory(void)
{
 return ((find32.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
}

bool find_file::is_encrypted(void)
{
 return ((find32.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0);
}

bool find_file::is_compressed(void)
{
 return ((find32.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0);
}

bool find_file::is_normal(void)
{
 return ((find32.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) != 0);
}

bool find_file::is_hidden(void)
{
 return ((find32.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
}

bool find_file::is_system(void)
{
 return ((find32.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) != 0);
}

bool find_file::is_archived(void)
{
 return ((find32.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) != 0);
}

bool find_file::is_readonly(void)
{
 return ((find32.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
}

const char* find_file::filename(void)
{
 strlwr(find32.cFileName);
 return (const char*)find32.cFileName;
}

size_t find_file::filesize(void)
{
 return (find32.nFileSizeHigh*(MAXDWORD + 1)) + find32.nFileSizeLow;
}

bool find_file::operator !(void)const
{
 return !handle;
}

// Center Dialog
void CenterDialog(HWND window, bool in_parent)
{
 HWND dialog = window;
 HWND parent = ((in_parent && GetParent(dialog)) ? GetParent(dialog) : GetDesktopWindow());

 RECT rect1; GetWindowRect(dialog, &rect1);
 RECT rect2; GetWindowRect(parent, &rect2);

 int dx1 = rect1.right - rect1.left;
 int dx2 = rect2.right - rect2.left;

 int dy1 = rect1.bottom - rect1.top;
 int dy2 = rect2.bottom - rect2.top;

 int x = (dx2 - dx1)/2 + rect1.left;
 int y = (dy2 - dy1)/2 + rect1.top;

 MoveWindow(dialog, x, y, dx1, dy1, TRUE);
}

// Browse Directory Dialog
int CALLBACK BrowseDirectoryDialogProc(HWND window, UINT message, LPARAM lparam, LPARAM)
{
 char directory[MAX_PATH];
 switch(message) {
   case(BFFM_INITIALIZED) : {
        if(GetCurrentDirectory(sizeof(directory)/sizeof(char), directory))
           SendMessage(window, BFFM_SETSELECTION,  1, (LPARAM)directory);
        break;
       }
   case(BFFM_SELCHANGED) : {
        if(SHGetPathFromIDList((LPITEMIDLIST)lparam ,directory))
           SendMessage(window, BFFM_SETSTATUSTEXT, 0, (LPARAM)directory);
        break;
       }
  }
 return 0;
}

BOOL BrowseDirectoryDialog(HWND parent, const char* caption, char* buffer)
{
 char display_name[MAX_PATH];
 display_name[0] = '\0';

 BROWSEINFO bi = {
  parent,
  0,
  display_name,
  caption,
  BIF_RETURNONLYFSDIRS,
  BrowseDirectoryDialogProc,
  0
 };

 ITEMIDLIST* pIIL = ::SHBrowseForFolder(&bi);

 if(SHGetPathFromIDList(pIIL, buffer)) {
    LPMALLOC pMalloc;
    HRESULT hr = SHGetMalloc(&pMalloc);
    pMalloc->Free(pIIL);
    pMalloc->Release();
    return TRUE;
   }

 return FALSE;
}

// Color Dialog
BOOL ColorDialog(HWND parent, COLORREF& color)
{
 static COLORREF custom[16] = {
  RGB(  0,  0,  0), RGB(255,255,255), RGB(128,128,128), RGB(192,192,192),
  RGB(128,  0,  0), RGB(  0,128,  0), RGB(  0,  0,128), RGB(128,128,  0),
  RGB(128,  0,128), RGB(  0,128,128), RGB(255, 255, 0), RGB(255,  0,255),
  RGB(  0,255,255), RGB(255,  0,  0), RGB(  0,255,  0), RGB(  0,  0,255)
 };
 CHOOSECOLOR data;
 ZeroMemory(&data, sizeof(data));
 data.lStructSize    = sizeof(CHOOSECOLOR);
 data.hwndOwner      = parent;
 data.hInstance      = NULL;
 data.rgbResult      = color;
 data.lpCustColors   = custom;
 data.Flags          = CC_RGBINIT | CC_FULLOPEN;
 data.lCustData      = 0;
 data.lpfnHook       = NULL;
 data.lpTemplateName = NULL;
 if(ChooseColor(&data) == FALSE) return FALSE; 
 else color = data.rgbResult;
 return TRUE;
}

// OpenSave Dialogs
BOOL OpenFileDialog(HWND parent, const char* filter, const char* title, const char* defext, char* filename, char* initdir)
{
 char buffer1[MAX_PATH];
 char buffer2[MAX_PATH];
 buffer1[0] = '\0';
 buffer2[0] = '\0';

 OPENFILENAME ofn;
 ZeroMemory(&ofn, sizeof(ofn));
 ofn.lStructSize     = sizeof(ofn);
 ofn.hwndOwner       = parent;
 ofn.hInstance       = (HINSTANCE)GetModuleHandle(0);
 ofn.lpstrFilter     = filter;
 ofn.lpstrFile       = buffer1;
 ofn.nMaxFile        = MAX_PATH;
 ofn.lpstrFileTitle  = buffer2;
 ofn.nMaxFileTitle   = MAX_PATH;
 ofn.lpstrInitialDir = initdir;
 ofn.lpstrTitle      = title;
 ofn.Flags           = OFN_FILEMUSTEXIST;
 ofn.lpstrDefExt     = defext;

 if(!GetOpenFileName(&ofn)) return FALSE;
 memmove(filename, buffer1, strlen(buffer1) + 1);
 return TRUE;
}

BOOL SaveFileDialog(HWND parent, const char* filter, const char* title, const char* defext, char* filename, char* initdir)
{
 char buffer1[MAX_PATH];
 char buffer2[MAX_PATH];
 buffer1[0] = '\0';
 buffer2[0] = '\0';

 OPENFILENAME ofn;
 ZeroMemory(&ofn, sizeof(ofn));
 ofn.lStructSize     = sizeof(ofn);
 ofn.hwndOwner       = parent;
 ofn.hInstance       = (HINSTANCE)GetModuleHandle(0);
 ofn.lpstrFilter     = filter;
 ofn.lpstrFile       = buffer1;
 ofn.nMaxFile        = MAX_PATH;
 ofn.lpstrFileTitle  = buffer2;
 ofn.nMaxFileTitle   = MAX_PATH;
 ofn.lpstrInitialDir = initdir;
 ofn.lpstrTitle      = title;
 ofn.Flags           = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
 ofn.lpstrDefExt     = defext;

 if(!GetSaveFileName(&ofn)) return FALSE;
 memmove(filename, buffer1, strlen(buffer1) + 1);
 return TRUE;
}