/*******************************************************************************
**
** SPDX-FileCopyrightText: Copyright 2023 Open Mobile Platform LLC <community@omp.ru>
** SPDX-License-Identifier: BSD-3-Clause
** This file is part of the OfficeViewer project.
**
** Redistribution and use in source and binary forms,
** with or without modification, are permitted provided
** that the following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice,
**   this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice,
**   this list of conditions and the following disclaimer
**   in the documentation and/or other materials provided with the distribution.
** * Neither the name of the copyright holder nor the names of its contributors
**   may be used to endorse or promote products derived from this software
**   without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
** FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
** OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS;
** OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
*******************************************************************************/


#include <QDataStream>
#include <QDebug>

#include "loevent.h"

namespace LoEvent {

    QDataStream &operator<<(QDataStream &os, const LoEvent::Header &msg)
    {
        os.writeRawData(msg.signature, LoEvent::EVENT_ID_LENGTH);
        os << static_cast<quint8>(msg.commandType);
        os << msg.sizePayload;

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::Header &msg)
    {
        is.readRawData(msg.signature, LoEvent::EVENT_ID_LENGTH);
        is >> reinterpret_cast<quint8 &>(msg.commandType);
        is >> msg.sizePayload;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::Message &msg)
    {
        LoEvent::Header header = msg.header;
        header.sizePayload = msg.payload.size();
        os << header;
        os.writeRawData(msg.payload.data(), msg.payload.size());

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::Message &msg)
    {
        is >> msg.header;
        msg.payload.resize(msg.header.sizePayload);
        is.readRawData(msg.payload.data(), msg.header.sizePayload);

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadPageSize &msg)
    {
        os << msg.pageIndex;
        os << msg.size;

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadPageSize &msg)
    {
        is >> msg.pageIndex;
        is >> msg.size;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadPageName &msg)
    {
        os << msg.pageIndex;
        os << msg.name;

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadPageName &msg)
    {
        is >> msg.pageIndex;
        is >> msg.name;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadNewPage &msg)
    {
        os << msg.pageIndex;
        os << msg.size;
        os << msg.zoom;
        os << msg.renderRequest;
        os << msg.sharedMemKey;

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadNewPage &msg)
    {
        is >> msg.pageIndex;
        is >> msg.size;
        is >> msg.zoom;
        is >> msg.renderRequest;
        is >> msg.sharedMemKey;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadNewTile &msg)
    {
        os << msg.pageIndex;
        os << msg.rect;
        os << msg.canvasSize;
        os << msg.zoom;
        os << msg.renderRequest;
        os << msg.sharedMemKey;

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadNewTile &msg)
    {
        is >> msg.pageIndex;
        is >> msg.rect;
        is >> msg.canvasSize;
        is >> msg.zoom;
        is >> msg.renderRequest;
        is >> msg.sharedMemKey;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadMakePage &msg)
    {
        os << msg.pageIndex;
        os << msg.rect;
        os << msg.canvasSize;
        os << msg.zoom;
        os << msg.renderRequest;

        return os;
    }
    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadMakePage &msg)
    {
        is >> msg.pageIndex;
        is >> msg.rect;
        is >> msg.canvasSize;
        is >> msg.zoom;
        is >> msg.renderRequest;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadKeyEvent &msg)
    {
        os << msg.type;
        os << msg.charCode;
        os << msg.keyCode;

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadKeyEvent &msg)
    {
        is >> msg.type;
        is >> msg.charCode;
        is >> msg.keyCode;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadMouseEvent &msg)
    {
        os << static_cast<qint8>(msg.type);
        os << msg.x;
        os << msg.y;
        os << msg.count;
        os << msg.buttons;
        os << msg.modifier;
        os << msg.pageIndex;

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadMouseEvent &msg)
    {
        quint8 type = 0;
        is >> type;
        msg.type = static_cast<LibreOfficeKitMouseEventType>(type);
        is >> msg.x;
        is >> msg.y;
        is >> msg.count;
        is >> msg.buttons;
        is >> msg.modifier;
        is >> msg.pageIndex;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadSelectEvent &msg)
    {
        os << static_cast<quint8>(msg.type);
        os << msg.x;
        os << msg.y;

        return os;
    }
    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadSelectEvent &msg)
    {
        quint8 type = 0;
        is >> type;
        msg.type = static_cast<LibreOfficeKitSetTextSelectionType>(type);
        is >> msg.x;
        is >> msg.y;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadCallbackEvent &msg)
    {
        os << static_cast<qint8>(msg.type);
        os << msg.payload;

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadCallbackEvent &msg)
    {
        qint8 value;
        is >> value;
        msg.type = static_cast<LibreOfficeKitCallbackType>(value);
        is >> msg.payload;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadUnoEvent &msg)
    {
        os << msg.command;
        os << msg.arguments;
        os << msg.notifyWhenFinished;

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadUnoEvent &msg)
    {
        is >> msg.command;
        is >> msg.arguments;
        is >> msg.notifyWhenFinished;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::RenderRequestFlags &flags)
    {
        os << static_cast<int>(flags);

        return os;
    }

    QDataStream &operator>>(QDataStream &is, LoEvent::RenderRequestFlags &flags)
    {
        int value;
        is >> value;
        flags = static_cast<RenderRequestFlags>(value);

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadSaveAs &msg)
    {
        os << msg.path;
        os << msg.format;
        os << msg.filterOptions;

        return os;
    }
    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadSaveAs &msg)
    {
        is >> msg.path;
        is >> msg.format;
        is >> msg.filterOptions;

        return is;
    }

    QDataStream &operator<<(QDataStream &os, const LoEvent::PayloadSaveAsStatus &msg)
    {
        os << msg.path;
        os << msg.format;
        os << msg.status;

        return os;
    }
    QDataStream &operator>>(QDataStream &is, LoEvent::PayloadSaveAsStatus &msg)
    {
        is >> msg.path;
        is >> msg.format;
        is >> msg.status;

        return is;
    }

    QDebug operator<<(QDebug debug, const CommandType &cmdType)
    {
        QDebugStateSaver saver(debug);
        switch (cmdType) {
        case UnknownCommand:
            return debug.space() << "UnknownCommand";
        case OfficeReady:
            return debug.space() << "OfficeReady";
        case LoadStatus:
            return debug.space() << "LoadStatus";
        case LoadProgress:
            return debug.space() << "LoadProgress";
        case DocumentType:
            return debug.space() << "DocumentType";
        case PageRectangles:
            return debug.space() << "PageRectangles";
        case PageCount:
            return debug.space() << "PageCount";
        case PageSize:
            return debug.space() << "PageSize";
        case PageName:
            return debug.space() << "PageName";
        case Error:
            return debug.space() << "Error";
        case NewPage:
            return debug.space() << "NewPage";
        case NewTile:
            return debug.space() << "NewTail";
        case MakePage:
            return debug.space() << "MakePage";
        case MakeTile:
            return debug.space() << "MakeTail";
        case ClearTasks:
            return debug.space() << "ClearTasks";
        case StopRender:
            return debug.space() << "StopRender";
        case RemoveSharedMem:
            return debug.space() << "RemoveSharedMem";
        case PostUnoCommand:
            return debug.space() << "UnoCommand";
        case SetPart:
            return debug.space() << "SetPart";
        case Debug:
            return debug.space() << "Debug";
        default:
            return debug.space() << QString("Type(%1)").arg(static_cast<int>(cmdType));
        }
    }

    QDebug operator<<(QDebug debug, const Message &msg)
    {
        QDebugStateSaver saver(debug);
        debug.space() << "Signature: " << QByteArray(msg.header.signature, EVENT_ID_LENGTH);
        debug.space() << "Command type: " << msg.header.commandType;
        debug.space() << "Size payload:" << msg.header.sizePayload;

        return debug;
    }

    QDebug operator<<(QDebug debug, const LibreOfficeKitCallbackType &type)
    {
        QDebugStateSaver saver(debug);
        debug.space() << lokCallbackTypeToString(type);
        return debug;
    }

    RenderRequestFlags operator|(RenderRequestFlags lhs, RenderRequestFlags rhs) {
        return static_cast<RenderRequestFlags>(
            static_cast<std::underlying_type_t<RenderRequestFlags>>(lhs) |
            static_cast<std::underlying_type_t<RenderRequestFlags>>(rhs)
            );
    }

    RenderRequestFlags operator&(RenderRequestFlags lhs, RenderRequestFlags rhs) {
        return static_cast<RenderRequestFlags>(
            static_cast<std::underlying_type_t<RenderRequestFlags>>(lhs) &
            static_cast<std::underlying_type_t<RenderRequestFlags>>(rhs)
            );
    }

    } // namespace LoEvent
