/***************************************************************************
 *   Copyright (C) 2020 by S. MANKOWSKI / G. DE BURE support@mankowski.fr  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program. If not, see <https://www.gnu.org/licenses/>  *
 ***************************************************************************/
#ifndef SKGTRANSACTIONMNG_H
#define SKGTRANSACTIONMNG_H
/** @file
 * This file defines classes SKGTransactionMng and a macro.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgdefine.h"
#include "skgtraces.h"
#include <qstring.h>

/**
 * @def SKGBEGINTRANSACTION(Document, Name, Error)
 * Macro to start a new transaction
 * Example of usage:
 * @code
 * { // BEGIN OF THE TRANSACTION SCOPE
 *  // Error management of the scope
 *  SKGError err;
 *
 *  // Begin transaction
 *   SKGBEGINTRANSACTION(Your_SKGDocument, QStringLiteral("The_Name_Of_The_Transaction"), err)
 *
 *  // Check the error
 *  if(!err)
 *  {
 *   // You code here
 *   // At the end the err variable must contain the result of your operation
 *  }
 *
 *  // A commit or rollback is done here because the scope is close
 * } // END OF THE TRANSACTION
 * @endcode
 */
#define SKGBEGINTRANSACTION(Document, Name, Error) \
    SKGTransactionMng TOKENPASTE2(transaction_, __LINE__)(&(Document), Name, &(Error));

/**
 * @def SKGBEGINLIGHTTRANSACTION(Document, Name, Error)
 * Macro to start a new light transaction (without views computation)
 */
#define SKGBEGINLIGHTTRANSACTION(Document, Name, Error) \
    SKGTransactionMng transactionlight_(&(Document), Name, &(Error), 1, false);
/**
 * @def SKGBEGINPROGRESSTRANSACTION(Document, Name, Error)
 * Macro to start a new transaction
 * Example of usage:
 * @code
 * { // BEGIN OF THE TRANSACTION SCOPE
 *  // Error management of the scope
 *  SKGError err;
 *
 *  // Begin transaction
 *   SKGBEGINPROGRESSTRANSACTION(Your_SKGDocument, "The_Name_Of_The_Transaction", err, 5)
 *
 *  // Check the error
 *  if(!err)
 *  {
 *   // You code here
 *   // At the end the err variable must contain the result of your operation
 *  Your_SKGDocument.stepForward(1);
 *  ...
 *  Your_SKGDocument.stepForward(2);
 *  ...
 *  Your_SKGDocument.stepForward(3);
 *  ...
 *  }
 *
 *  // A commit or rollback is done here because the scope is close
 * } // END OF THE TRANSACTION
 * @endcode
 */
#define SKGBEGINPROGRESSTRANSACTION(Document, Name, Error, Nb) \
    SKGTransactionMng TOKENPASTE2(transaction_, __LINE__)(&(Document), Name, &(Error), Nb);

/**
 * @def SKGBEGINLIGHTPROGRESSTRANSACTION(Document, Name, Error)
 * Macro to start a new light transaction (without views computation)
 */
#define SKGBEGINLIGHTPROGRESSTRANSACTION(Document, Name, Error, Nb) \
    SKGTransactionMng TOKENPASTE2(transactionlight_, __LINE__)(&(Document), Name, &(Error), Nb, false);

/**
 * @def SKGENDTRANSACTION(Document,  Error)
 * End correctly a transaction
 */
#define SKGENDTRANSACTION(Document,  Error) \
    if (!(Error)) {(Error) = (Document)->endTransaction(true);} \
    else {(Document)->endTransaction(false);}

class SKGError;
class SKGDocument;

/**
* Facilitate the transaction management
*/
class SKGBASEMODELER_EXPORT SKGTransactionMng
{
public:
    /**
     * Constructor.
     * This class must be used with the macro
     * @see SKGBEGINTRANSACTION
     * @param iDocument The parent document of the transaction
     * @param iName The message of the transaction
     * @param iError A pointer of the error object of the calling scope
     * @param iNbStep the number of step in this transaction.
     * @param iRefreshViews at the end of the transaction, computed views will be recomputed.
     * It is used to call the progress callback.
     * @see The SKGError
     */
    explicit SKGTransactionMng(SKGDocument* iDocument, const QString& iName, SKGError* iError, int iNbStep = 1, bool iRefreshViews = true);

    /**
     * Destructor
     */
    virtual ~SKGTransactionMng();

private:
    Q_DISABLE_COPY(SKGTransactionMng)

    SKGError* m_error;
    SKGDocument* m_parentDocument;
    bool m_errorInBeginTransaction;
};

#endif
