// xlsxdocument.h

#ifndef QXLSX_XLSXDOCUMENT_H
#define QXLSX_XLSXDOCUMENT_H

#include "xlsxformat.h"
#include "xlsxglobal.h"
#include "xlsxworksheet.h"
#include "xlsxreadsax.h"

#include <QIODevice>
#include <QImage>
#include <QObject>
#include <QVariant>

QT_BEGIN_NAMESPACE_XLSX

class Workbook;
class Cell;
class CellRange;
class DataValidation;
class ConditionalFormatting;
class Chart;
class CellReference;
class DocumentPrivate;

class QXLSX_EXPORT Document : public QObject
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(Document) // D-Pointer. Qt classes have a Q_DECLARE_PRIVATE
                                // macro in the public class. The macro reads: qglobal.h
public:
    explicit Document(QObject *parent = nullptr);
    Document(const QString &xlsxName, QObject *parent = nullptr);
    Document(QIODevice *device, QObject *parent = nullptr);
    ~Document();

    bool write(const CellReference &cell, const QVariant &value, const Format &format = Format());
    bool write(int row, int col, const QVariant &value, const Format &format = Format());

    QVariant read(const CellReference &cell) const;
    QVariant read(int row, int col) const;

    int insertImage(int row, int col, const QImage &image);
    bool getImage(int imageIndex, QImage &img);
    bool getImage(int row, int col, QImage &img);
    uint getImageCount();

    Chart *insertChart(int row, int col, const QSize &size);

    bool mergeCells(const CellRange &range, const Format &format = Format());
    bool unmergeCells(const CellRange &range);

    bool setColumnWidth(const CellRange &range, double width);
    bool setColumnFormat(const CellRange &range, const Format &format);
    bool setColumnHidden(const CellRange &range, bool hidden);
    bool setColumnWidth(int column, double width);
    bool setColumnFormat(int column, const Format &format);
    bool setColumnHidden(int column, bool hidden);
    bool setColumnWidth(int colFirst, int colLast, double width);
    bool setColumnFormat(int colFirst, int colLast, const Format &format);
    bool setColumnHidden(int colFirst, int colLast, bool hidden);

    double columnWidth(int column);
    Format columnFormat(int column);
    bool isColumnHidden(int column);

    bool setRowHeight(int row, double height);
    bool setRowFormat(int row, const Format &format);
    bool setRowHidden(int row, bool hidden);
    bool setRowHeight(int rowFirst, int rowLast, double height);
    bool setRowFormat(int rowFirst, int rowLast, const Format &format);
    bool setRowHidden(int rowFirst, int rowLast, bool hidden);

    double rowHeight(int row);
    Format rowFormat(int row);
    bool isRowHidden(int row);

    bool groupRows(int rowFirst, int rowLast, bool collapsed = true);
    bool groupColumns(int colFirst, int colLast, bool collapsed = true);

    bool addDataValidation(const DataValidation &validation);
    bool addConditionalFormatting(const ConditionalFormatting &cf);

    std::shared_ptr<Cell> cellAt(const CellReference &cell) const;
    std::shared_ptr<Cell> cellAt(int row, int col) const;

    bool defineName(const QString &name,
                    const QString &formula,
                    const QString &comment = QString(),
                    const QString &scope   = QString());

    CellRange dimension() const;

    QString documentProperty(const QString &name) const;
    void setDocumentProperty(const QString &name, const QString &property);
    QStringList documentPropertyNames() const;

    QStringList sheetNames() const;
    bool addSheet(const QString &name           = QString(),
                  AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet);
    bool insertSheet(int index,
                     const QString &name           = QString(),
                     AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet);
    bool selectSheet(const QString &name);
    bool selectSheet(int index);
    bool renameSheet(const QString &oldName, const QString &newName);
    bool copySheet(const QString &srcName, const QString &distName = QString());
    bool moveSheet(const QString &srcName, int distIndex);
    bool deleteSheet(const QString &name);

    Workbook *workbook() const;
    AbstractSheet *sheet(const QString &sheetName) const;
    AbstractSheet *currentSheet() const;
    Worksheet *currentWorksheet() const;

    bool save() const;
    bool saveAs(const QString &xlsXname) const;
    bool saveAs(QIODevice *device) const;

    bool saveAsCsv(const QString mainCSVFileName) const;

    // copy style from one xlsx file to other
    static bool copyStyle(const QString &from, const QString &to);

    bool isLoadPackage() const;
    bool load() const; // equals to isLoadPackage()

    bool changeimage(int filenoinmidea, QString newfile); // add by liufeijin20181025

    bool autosizeColumnWidth(const CellRange &range);
    bool autosizeColumnWidth(int column);
    bool autosizeColumnWidth(int colFirst, int colLast);
    bool autosizeColumnWidth();


    /////////////////////////////////
    // New feature: Stream sheet cells with callback "without saving"
    bool read_sheet_sax(const QString& sheet_name,
                        const sax_options& opt,
                        const sax_cell_callback& on_cell);

    bool read_sheet_sax(int sheet_index,
                        const sax_options& opt,
                        const sax_cell_callback& on_cell);

private:
    QMap<int, int> getMaximalColumnWidth(int firstRow = 1, int lastRow = INT_MAX);

private:
    Q_DISABLE_COPY(Document) // Disables the use of copy constructors and
                             // assignment operators for the given Class.
    DocumentPrivate *const d_ptr;
};

QT_END_NAMESPACE_XLSX

#endif // QXLSX_XLSXDOCUMENT_H
