// ************************************************************************************************************
// Author: Marcin Załęczny
// Release Date: 2010-11-08
// Licence: The GNU Lesser General Public License, version 3.0 (LGPLv3)
// ************************************************************************************************************
#include "mzXpsDocument.h"
#include "mzstdxpsGlobals.h"
#include "mzFileUtils.h"
#include "mzXpsResources.h"
#include "mzXpsDefaultFontData.h"

CXpsDocument::CXpsDocument(UINT docNumber)
    : _number(docNumber)
{
    this->setRealClassName(L"CXpsDocument");

    this->_fixedDocumentFdocRel = new CXpsRelationships();
    this->_fixedDocumentFdocRel->addXmlns(L"http://schemas.openxmlformats.org/package/2006/relationships");
    this->_fixedDocumentFdocRel->addRelationship(L"/Metadata/MXDC_Empty_PT.xml", L"R0", "http://schemas.microsoft.com/xps/2005/06/printticket");
    
    this->_fixedDocumentFdoc = new CXpsFixedDocument(CString(L"/Documents/") + docNumber);
    
    this->_metadata = new CXpsMetadata();
    this->_metadata->addPagePT(1, L"A4", L"Portrait", L"600", L"600");
    
    this->_inMemoryResources = new CTypedArrayList(10);
    this->_pages = new CArrayList(10);
}

CXpsDocument::~CXpsDocument() {
    if (this->_fixedDocumentFdocRel) {
        delete this->_fixedDocumentFdocRel;
        this->_fixedDocumentFdocRel = NULL;
    }
    
    if (this->_fixedDocumentFdoc) {
        delete this->_fixedDocumentFdoc;
        this->_fixedDocumentFdoc = NULL;
    }
    
    if (this->_metadata) {
        delete this->_metadata;
        this->_metadata = NULL;
    }
    
    if (this->_inMemoryResources) {
        this->_releaseResources();
    }
    
    if (this->_pages) {
        this->_releasePages();
    }
}

VOID CXpsDocument::_releaseResources() {
    if (this->_inMemoryResources) {
        CTypedArrayListItem* item;
        CXpsBinaryData* resourceItem;
        INT size = this->_inMemoryResources->size();
        LONG* items = this->_inMemoryResources->getItemsBuf();
        
        for (INT i = 0; i < size; i++) {
            item = (CTypedArrayListItem*)items[i];
            resourceItem = (CXpsBinaryData*)item->pointer;
            delete resourceItem;
        }
        
        delete this->_inMemoryResources;
        this->_inMemoryResources = NULL;
    }
}

VOID CXpsDocument::_releasePages() {
    if (this->_pages) {
        CXpsPage* item;
        INT size = this->_pages->size();
        LONG* items = this->_pages->getItemsBuf();
        
        for (INT i = 0; i < size; i++) {
            item = (CXpsPage*)items[i];
            delete item;
        }
        
        delete this->_pages;
        this->_pages = NULL;
    }
}

BOOL CXpsDocument::saveToFiles(CString docDir) {
    AddPathPart(docDir, CString(this->_number));
    CreateDirectory(docDir);
    CreateDirectory(docDir + L"\\_rels");
    CreateDirectory(docDir + L"\\Metadata");
    CreateDirectory(docDir + L"\\Pages");
    CreateDirectory(docDir + L"\\Pages\\_rels");
    CreateDirectory(docDir + L"\\Resources");
    CreateDirectory(docDir + L"\\Resources\\Fonts");
    
    //WriteLogMessage(L"trace.log", CString(__FILE__), __LINE__, ENC_UTF8, L"%o", this->_fixedDocumentFdocRel);
    this->_fixedDocumentFdocRel->saveXmlFile(docDir + L"\\_rels\\FixedDocument.fdoc.rels");
    //WriteLogMessage(L"trace.log", CString(__FILE__), __LINE__, ENC_UTF8, L"%o", this->_fixedDocumentFdoc);
    this->_fixedDocumentFdoc->saveXmlFile(docDir + L"\\FixedDocument.fdoc");
    //WriteLogMessage(L"trace.log", CString(__FILE__), __LINE__, ENC_UTF8, L"%o", this->_metadata);
    this->_metadata->saveToFiles(docDir + L"\\Metadata");
    
    if (this->_inMemoryResources) {
        CTypedArrayListItem* item;
        CXpsBinaryData* resourceItem;
        INT size = this->_inMemoryResources->size();
        LONG* items = this->_inMemoryResources->getItemsBuf();
        
        for (INT i = 0; i < size; i++) {
            item = (CTypedArrayListItem*)items[i];
            //WriteLogMessage(L"trace.log", CString(__FILE__), __LINE__, ENC_UTF8, L"%o", item);
            if (item->type == L"CXpsFontResource") {
                resourceItem = (CXpsBinaryData*)item->pointer;
                //WriteLogMessage(L"trace.log", CString(__FILE__), __LINE__, ENC_UTF8, L"%o", resourceItem);
                resourceItem->save(docDir + L"\\Resources\\Fonts");
            }
        }
    }
    
    if (this->_pages) {
        CXpsPage* item;
        INT size = this->_pages->size();
        LONG* items = this->_pages->getItemsBuf();
        //WriteLogMessage(L"trace.log", CString(__FILE__), __LINE__, ENC_UTF8, L"CXpsDocument::saveToFiles pages count: %d, addresses [%s]", size, (WCHAR*)this->_pages->toString());
        
        for (INT i = 0; i < size; i++) {
            item = (CXpsPage*)items[i];
            //WriteLogMessage(L"trace.log", CString(__FILE__), __LINE__, ENC_UTF8, L"CXpsDocument::saveToFiles: Saving page number: %d, %o", (i+1), item);
            item->saveXmlFile(docDir + L"\\Pages\\" + (i+1) + L".fpage");
        }
    }
    
    return TRUE;
}

VOID CXpsDocument::addPageThumbnail(INT pagenum, BYTE* imageBuffer, DWORD bufferSize) {
    if (this->_metadata) {
        this->_metadata->addInMemoryThumbnailForPage(pagenum, imageBuffer, bufferSize);
    }
}

VOID CXpsDocument::addFontResource(CString fontFilename, BYTE* fontdataBuffer, DWORD bufferSize) {
    CXpsFontResource* fontRes = new CXpsFontResource(fontFilename, fontdataBuffer, bufferSize);
    this->_inMemoryResources->append((LONG)fontRes, L"CXpsFontResource");
}

CString CXpsDocument::addDefFontResource() {
    HANDLE heap = GetProcessHeap();
    DWORD bufferSize;
    BYTE* fontdataBuffer = GetDefaultFontData(&bufferSize);
    CString fontFilename = L"13493494-EFA0-4F63-BA0F-FFBED96980BD.odttf";
    CXpsFontResource* fontRes = new CXpsFontResource(fontFilename, fontdataBuffer, bufferSize);
    this->_inMemoryResources->append((LONG)fontRes, L"CXpsFontResource");
    HeapFree(heap, 0, fontdataBuffer);
    return fontFilename;
}

CString CXpsDocument::getDocumentInternalDirectory() {
    return CString(L"/Documents/") + this->_number;
}

VOID CXpsDocument::addPagePT(INT pagenum, CString PageMediaSize, CString PageOrientation, CString PageResolutionX, CString PageResolutionY) {
    this->_metadata->addPagePT(pagenum, PageMediaSize, PageOrientation, PageResolutionX, PageResolutionY);
}

VOID CXpsDocument::getAvailableFonts(CStringList* lst) {
    if (!lst) {
        return;
    }
    
    lst->clear();
    if (this->_inMemoryResources) {
        CTypedArrayListItem* item;
        CXpsBinaryData* resourceItem;
        INT size = this->_inMemoryResources->size();
        LONG* items = this->_inMemoryResources->getItemsBuf();
        
        for (INT i = 0; i < size; i++) {
            item = (CTypedArrayListItem*)items[i];
            if (item->type == L"CXpsFontResource") {
                resourceItem = (CXpsBinaryData*)item->pointer;
                lst->append(resourceItem->filename);
            }
        }
    }
}

CXpsPage* CXpsDocument::addPage() {
    UINT pagenum = this->_pages->size() + 1;
    CXpsPage* page = new CXpsPage(this, pagenum);
    if (page) {
        this->_pages->append((LONG)page);
        this->_fixedDocumentFdoc->addPageContent(pagenum);
    }
    
    return page;
}

CXpsPage* CXpsDocument::addPage(float width, float height) {
    UINT pagenum = this->_pages->size() + 1;
    CXpsPage* page = new CXpsPage(this, pagenum, XpsFloatToString(width), XpsFloatToString(height));
    if (page) {
        this->_pages->append((LONG)page);
        this->_fixedDocumentFdoc->addPageContent(pagenum);
    }
    
    return page;
}

CXpsPage* CXpsDocument::addPage(CString PageMediaSize, CString PageOrientation, CString PageResolutionX, CString PageResolutionY) {
    UINT pagenum = this->_pages->size() + 1;
    this->addPagePT(pagenum, PageMediaSize, PageOrientation, PageResolutionX, PageResolutionY);
    CXpsPage* page = new CXpsPage(this, pagenum);
    if (page) {
        this->_pages->append((LONG)page);
        this->_fixedDocumentFdoc->addPageContent(pagenum);
    }
    
    return page;
}
