/* This file is part of the wvWare 2 project
   SPDX-FileCopyrightText: 2003 Werner Trobin <trobin@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02111-1307, USA.
*/

#include "graphics.h"
#include "word97_generated.h"

using namespace wvWare;

Drawings::Drawings(OLEStreamReader *table, const Word97::FIB &fib)
    : m_plcfspaMom(nullptr)
    , m_plcfspaHdr(nullptr)
    , m_plcftxbxTxt(nullptr)
    , m_plcfHdrtxbxTxt(nullptr)
    , m_plcftxbxBkd(nullptr)
    , m_plcfHdrtxbxBkd(nullptr)
{
    table->push();

    // Don't try to read that. It will cause eye-cancer!
    if (fib.lcbPlcspaMom != 0 && table->seek(fib.fcPlcspaMom, WV2_SEEK_SET))
        m_plcfspaMom = new PLCF<Word97::FSPA>(fib.lcbPlcspaMom, table, false);
    if (fib.lcbPlcspaHdr != 0 && table->seek(fib.fcPlcspaHdr, WV2_SEEK_SET))
        m_plcfspaHdr = new PLCF<Word97::FSPA>(fib.lcbPlcspaHdr, table, false);

    if (fib.lcbPlcftxbxTxt != 0 && table->seek(fib.fcPlcftxbxTxt, WV2_SEEK_SET))
        m_plcftxbxTxt = new PLCF<Word97::FTXBXS>(fib.lcbPlcftxbxTxt, table, false);
    if (fib.lcbPlcfHdrtxbxTxt != 0 && table->seek(fib.fcPlcfHdrtxbxTxt, WV2_SEEK_SET))
        m_plcfHdrtxbxTxt = new PLCF<Word97::FTXBXS>(fib.lcbPlcfHdrtxbxTxt, table, false);

    if (fib.lcbPlcftxbxBkd != 0 && table->seek(fib.fcPlcftxbxBkd, WV2_SEEK_SET))
        m_plcftxbxBkd = new PLCF<Word97::BKD>(fib.lcbPlcftxbxBkd, table, false);
    if (fib.lcbPlcftxbxHdrBkd != 0 && table->seek(fib.fcPlcftxbxHdrBkd, WV2_SEEK_SET))
        m_plcfHdrtxbxBkd = new PLCF<Word97::BKD>(fib.lcbPlcftxbxHdrBkd, table, false);

    table->pop();
}

Drawings::~Drawings()
{
    delete m_plcfHdrtxbxBkd;
    delete m_plcftxbxBkd;
    delete m_plcfHdrtxbxTxt;
    delete m_plcftxbxTxt;
    delete m_plcfspaHdr;
    delete m_plcfspaMom;
}

EscherHeader::EscherHeader(OLEStreamReader *stream)
{
    // read first 32 bits
    U32 shifterU32;
    shifterU32 = stream->readU32();
    recVer = shifterU32;
    shifterU32 >>= 4;
    recInstance = shifterU32;
    shifterU32 >>= 12;
    recType = shifterU32;
    // read second 32 bits
    recLen = stream->readU32();
}

EscherHeader::~EscherHeader() = default;

bool EscherHeader::isAtom()
{
    // 0xF in ver means it's a container
    if (recVer == 0xF)
        return false;
    else
        return true;
}

string EscherHeader::getRecordType()
{
    string s;
    switch (recType) {
    case 0xF000:
        s = "msofbtDggContainer";
        break;
    case 0xF001:
        s = "msofbtBstoreContainer";
        break;
    case 0xF002:
        s = "msofbtDgContainer";
        break;
    case 0xF004:
        s = "msofbtSpContainer";
        break;
    case 0xF006:
        s = "msofbtDgg";
        break;
    case 0xF007:
        s = "msofbtBSE";
        break;
    case 0xF008:
        s = "msofbtDg";
        break;
    case 0xF00A:
        s = "msofbtSp";
        break;
    case 0xF00B:
        s = "msofbtOPT"; // OfficeArtFOPT - MS-ODRAW, page 44 of 621
        break;
    case 0xF010:
        s = "msofbtClientAnchor";
        break;
    case 0xF016:
        s = "msofbtCLSID";
        break;
    case 0xF01A:
        s = "EMF";
        break;
    case 0xF01B:
        s = "WMF";
        break;
    case 0xF01C:
        s = "PICT";
        break;
    case 0xF01D:
        s = "JPEG";
        break;
    case 0xF01E:
        s = "PNG";
        break;
    case 0xF01F:
        s = "DIB";
        break;
    case 0xF11A:
        s = "msofbtColorMRU";
        break;
    case 0xF11E:
        s = "msofbtSplitMenuColors";
        break;
    case 0xF118:
        s = "msofbtRegroupItems";
        break;
    case 0xF122:
        s = "msofbtTerOPT"; // OfficeArtTertiaryFOPT - MS-ODRAW, page 46 of 621
        break;
    default:
        s = "unknown";
    }
    return s;
}

// returns size of the record NOT COUNTING the header
int EscherHeader::recordSize()
{
    return static_cast<int>(recLen);
}

// returns the record instance
int EscherHeader::recordInstance()
{
    return recInstance;
}

void EscherHeader::dump()
{
    wvlog << "Dumping Escher header:" << Qt::endl;
    wvlog << " recVer = " << Qt::hex << recVer << Qt::dec << Qt::endl;
    wvlog << " recInstance = " << Qt::hex << recInstance << Qt::dec << Qt::endl;
    wvlog << " recType = " << Qt::hex << recType << Qt::dec << Qt::endl;
    wvlog << " recLen = " << recLen << Qt::endl;
    wvlog << "Finished dumping Escher header." << Qt::endl;
}

FBSE::FBSE(OLEStreamReader *stream)
{
    btWin32 = static_cast<MSOBLIPTYPE>(stream->readU8());
    btMacOS = static_cast<MSOBLIPTYPE>(stream->readU8());
    stream->read(rgbUid, 16);
    tag = stream->readU16();
    size = stream->readU32();
    cRef = stream->readU32();
    foDelay = stream->readU32();
    usage = static_cast<MSOBLIPUSAGE>(stream->readU8());
    cbName = stream->readU8();
    unused2 = stream->readU8();
    unused3 = stream->readU8();
}

FBSE::~FBSE() = default;

void FBSE::dump()
{
    wvlog << "Dumping FBSE:" << Qt::endl;
    wvlog << "\tbtWin32 = " << btWin32 << Qt::endl;
    wvlog << "\tbtMacOS = " << btMacOS << Qt::endl;
    wvlog << "\trgbUid = " << rgbUid << Qt::endl;
    wvlog << "\ttag = " << tag << Qt::endl;
    wvlog << "\tsize = " << size << Qt::endl;
    wvlog << "\tcRef = " << cRef << Qt::endl;
    wvlog << "\tfoDelay = " << foDelay << Qt::endl;
    wvlog << "\tusage = " << static_cast<int>(usage) << Qt::endl;
    wvlog << "\tcbName = " << static_cast<unsigned int>(cbName) << Qt::endl;
    wvlog << "\tunused2 = " << static_cast<unsigned int>(unused2) << Qt::endl;
    wvlog << "\tunused3 = " << static_cast<unsigned int>(unused3) << Qt::endl;
    wvlog << "Finished dumping FBSE." << Qt::endl;
}

int FBSE::recordSize()
{
    // just add up the sizes of btWin32 + btMacOS + rgUid[16] + ...
    return 36;
}

int FBSE::getBlipType()
{
    // cast enum to int
    return static_cast<int>(btWin32);
}

int FBSE::getStreamOffset()
{
    // cast U32 to unsigned int
    return static_cast<unsigned int>(foDelay);
}

int FBSE::getNameLength()
{
    // cast U8 to unsigned int
    return static_cast<unsigned int>(cbName);
}

U8 *FBSE::getRgbUid()
{
    return rgbUid;
}

Blip::Blip(OLEStreamReader *stream, string blipType)
{
    m_size = 0; // just an initial value
    m_blipType = blipType;
    m_isMetafileBlip = false;
    if (blipType.compare("JPEG") == 0 || blipType.compare("PNG") == 0 || blipType.compare("DIB") == 0) {
        stream->read(m_rgbUid, 16); // data UID
        m_bTag = stream->readU8();
        m_size = 17;
        // initialize other variables just to 0
        m_cb = 0;
        m_rcBounds = 0;
        m_ptSize = 0;
        m_cbSave = 0;
        m_fCompression = 255; // test value, so we'll just initialize to this
        m_fFilter = 255; // test value, so we'll just initialize to this
    } else if (blipType.compare("EMF") == 0 || blipType.compare("WMF") == 0 || blipType.compare("PICT") == 0) {
        stream->read(m_rgbUid, 16); // data UID
        stream->read(m_rgbUidPrimary, 16); // primary Uid
        m_cb = stream->readU32(); // cache of metafile size
        m_rcBounds = stream->readU32(); // boundary of metafile drawing commands
        m_ptSize = stream->readU32(); // size of metafile in EMU's
        m_cbSave = stream->readU32(); // cache of saved size (size of m_pvBits)
        m_fCompression = stream->readU8(); // compression
        m_fFilter = stream->readU8(); // always msofilterNone = 254
        m_isMetafileBlip = true;
        m_size = 46;
    }
}

Blip::~Blip() = default;

bool Blip::isMetafileBlip()
{
    return m_isMetafileBlip;
}

bool Blip::isCompressed()
{
    // only metafile blips can be compressed
    // and the flag has to be set
    if (isMetafileBlip() && m_fCompression == 0)
        return true;
    else
        return false;
}

int Blip::recordSize()
{
    return m_size;
}

int Blip::imageSize()
{
    return static_cast<unsigned int>(m_cb);
}

int Blip::compressedImageSize()
{
    return static_cast<unsigned int>(m_cbSave);
}

void Blip::dump()
{
    if (!isCompressed()) {
        wvlog << " bitmap blip:" << Qt::endl;
        wvlog << " m_rgbUid = " << m_rgbUid << Qt::endl;
        wvlog << " m_bTag = " << static_cast<unsigned int>(m_bTag) << Qt::endl;
    } else {
        wvlog << " metafile blip:" << Qt::endl;
        wvlog << " m_rgbUid = " << m_rgbUid << Qt::endl;
        wvlog << " m_cb = " << m_cb << Qt::endl;
        wvlog << " m_rcBounds = " << m_rcBounds << Qt::endl;
        wvlog << " m_ptSize = " << m_ptSize << Qt::endl;
        wvlog << " m_cbSave = " << m_cbSave << Qt::endl;
        wvlog << " m_fCompression = " << static_cast<unsigned int>(m_fCompression) << Qt::endl;
        wvlog << " m_fFilter = " << static_cast<unsigned int>(m_fFilter) << Qt::endl;
    }
}
