/*---------------------------------------------------------------------------*/
/* httpfiles_unzip.cpp                                                       */
/* copyright (c) innovaphone 2018                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#include <platform.h>

#include "sdk/common/interface/file.h"
#include "sdk/common/interface/httpfile.h"
#include "sdk/common/interface/process.h"
#include "sdk/common/interface/guuid.h"

#include "../lib/httpfiles_unzip.h"

#define MAX_PATH_LENGTH 512

Httpfiles_unzipItem::Httpfiles_unzipItem(char * filePath, byte * fileData, size_t fileLength)
{
    this->path = _strdup(filePath);
    // patch backward slashes to forward slashes (Windows powershell bug when creating ZIP files)
    char * p = this->path;
    while (*p) {
        if (*p == '\\') *p = '/';
        ++p;
    }
    this->data = new byte[fileLength];
    memcpy(this->data, fileData, fileLength);
    this->file = new class httpfile(this->path, 0, 0, this->data, fileLength);
}

Httpfiles_unzipItem::~Httpfiles_unzipItem()
{
    delete this->file; this->file = 0;
    free(this->path); this->path = 0;
    delete [] this->data; this->data = 0;
    
}

Httpfiles_unzip::Httpfiles_unzip(class IInstanceLog * log, const char * httpFileZip)
{
    this->log = log;
    //char initialPathbuffer[MAX_PATH_LENGTH];
    //char absoluteFilePathbuffer[MAX_PATH_LENGTH];
    ////char * pbuffer = buffer;
    //char initialPath[MAX_PATH_LENGTH] = "/tmp";
    //char appTmpPath[MAX_PATH_LENGTH] = { 0 };
    //_snprintf(appTmpPath, MAX_PATH_LENGTH, "%s/%s", initialPath, appName);
    //
    //char absoluteFilePath[MAX_PATH_LENGTH] = "/tmp";
    //_snprintf(&absoluteFilePath[strlen(absoluteFilePath)], MAX_PATH_LENGTH, "/%s", appName);
    //


    

    // It may happen, that two executables have the same file name. 

    char guid[GUID_SIZE + 1] = { 0 };
    char filePath[MAX_PATH_LENGTH] = { 0 };
    char appTmpPath[MAX_PATH_LENGTH] = { 0 };
    
    IGuuid::GenerateUUID(guid);

    _snprintf(appTmpPath, sizeof(appTmpPath), "/tmp/%s", guid);

    //char httpfilesPath[MAX_PATH_LENGTH] = "/apps";
    //_snprintf(&httpfilesPath[strlen(httpfilesPath)], MAX_PATH_LENGTH, "/%s/%s", appName, "httpfiles.zip");
    
    /*if (!FileSystem::FileExists(initialPath, this->log)){
        if (FileSystem::CreateDirectory(initialPath, 0700, this->log)){
        }
        else {
            if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::Httpfiles_unzip Directory %s cannot be created", this, initialPath);
            return;
        }
    }*/
    
    if (FileSystem::FileExists(appTmpPath, log) && !FileSystem::RemoveDirectory(appTmpPath, this->log)){
        if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::Httpfiles_unzip Directory %s cannot be removed", this, appTmpPath);
    }
    
    if (FileSystem::CreateDirectory(appTmpPath, 0700, this->log)){
        if (IProcess::System(log, "unzip %s -d %s/", httpFileZip, appTmpPath) == 0) {
            IDirectory * dir = FileSystem::OpenDirectory(appTmpPath, this->log);
            if (dir)
                this->ScanFiles(dir, appTmpPath, filePath);
            else {
                if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::Httpfiles_unzip Directory %s cannot be opened", this, appTmpPath);
            }
            if (dir) delete dir;
        }
        else {
            if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::Httpfiles_unzip Directory %s cannot be unzipped", this, appTmpPath);
        }

        if (!FileSystem::RemoveDirectory(appTmpPath, this->log)){
            if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::Httpfiles_unzip Directory %s cannot be removed", this, appTmpPath);
        }
    }
    else{
        if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::Httpfiles_unzip Directory %s cannot be created", this, appTmpPath);
        
    }
}

Httpfiles_unzip::~Httpfiles_unzip()
{
    while (!listItems.empty())
    {
        class Httpfiles_unzipItem* item = this->listItems.front();
        item->remove();
        delete item;
    }
}

void Httpfiles_unzip::ScanFiles(class IDirectory * dir, const char * absoluteFilePath, char * filePath)
{
    if (dir->IsOpen()) {
        class IDirectoryEntry * dirEntry = dir->ReadNext();
        unsigned int len = (unsigned int)strlen(filePath);
        while (dirEntry) {
            const char * name = dirEntry->GetName();
            char buffer[MAX_PATH_LENGTH];
            char * pbuffer = buffer;
            _snprintf(buffer, MAX_PATH_LENGTH, "%s/%s", absoluteFilePath, name);
            
            if (len != 0){
                if (len < MAX_PATH_LENGTH)
                    _snprintf(&filePath[len], MAX_PATH_LENGTH, filePath[0] != 0 ? "/%s" : "%s", name);
                else
                    continue;
            }
			else {
				_snprintf(filePath, MAX_PATH_LENGTH, "%s", name);
			}
            
            if (dirEntry->IsFile()){
                this->ReadFile(pbuffer, filePath);
            }
            else {
                IDirectory * dir = FileSystem::OpenDirectory(buffer, this->log);
                if (dir) {
                    this->ScanFiles(dir, pbuffer, filePath);
                    delete dir;
                }
                else {
                    if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::ScanFiles Directory %s cannot be opened", this, buffer);
                }
            }
            delete dirEntry;
            dirEntry = dir->ReadNext();
        }
        dir->Close();
    }
    else {
        if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::ScanFiles Directory %s is not opened", this, absoluteFilePath);
    }
}

void Httpfiles_unzip::ReadFile(char * absolutePath, char * name)
{
    unsigned long int fileLength = FileSystem::GetFileSize(absolutePath, this->log);
    if (fileLength) {
        IFileRead * fileRead = FileSystem::OpenReadFile(absolutePath, this->log);
        if (fileRead && fileRead->IsOpen()){
            byte * buffer = new byte[fileLength];
            size_t len = fileRead->Read(buffer, fileLength);
            if (len == fileLength) {
                this->listItems.push_back(new class Httpfiles_unzipItem(name, buffer, len));
            }
            else {
                if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::ReadFile File length and read length are not the same", this);
            }
            delete [] buffer;
        }
        else {
            if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::ReadFile File cannot be opened", this);
        }
        fileRead->Close();
        delete fileRead;
    }
    else {
        if (this->log) this->log->Log(LOG_HTTP_FILE, "Httpfiles_unzip(%08x)::ReadFile No file length ", this);
    }
}

