#ifndef MAINCC3D_H
#define MAINCC3D_H
#include "transaction.h"
#include <string>
#include <qpen.h>
#include <qbrush.h>
#include <map>
#include <vector>

#include <CompuCell3D/Field3D/WatchableField3D.h>
#include <CompuCell3D/Potts3D/Cell.h>
#include <CompuCell3D/Potts3D/EnergyFunction.h>
#include <CompuCell3D/PluginManager.h>

#include "GraphicsData.h"
#include "GraphicsDataFields.h"
#include "Graphics2D.h"


class QMutex;
class QSemaphore;
//template <typename Y> class CompuCell3D::Field3DImpl;
class CompuCell3D::Dim3D;
class CompuCell3D::EnergyFunction;

template <typename Y>
class BasicArray;

class CC3DTransaction : public Transaction
{
public:
    CC3DTransaction(std::string  _filename);
    virtual ~CC3DTransaction();
    QImage apply(const QImage &image);
    void applySimulation();
    QString messageStr(){return QString("DONE");};
    void setPauseMutexPtr(QMutex * mutexPtr){pauseMutexPtr=mutexPtr;};
    void setFieldDrawMutexPtr(QMutex * mutexPtr){fieldDrawMutexPtr=mutexPtr;};
    void setTransactionMutexPtr(QMutex * mutexPtr){mutexTransactionPtr=mutexPtr;};
    void setBufferFreeSem(QSemaphore * _bufferFillFreeSemPtr){bufferFillFreeSemPtr=_bufferFillFreeSemPtr;}
    void setBufferUsedSem(QSemaphore * _bufferFillUsedSemPtr){bufferFillUsedSemPtr=_bufferFillUsedSemPtr;}


    void setGraphicsDataFieldPtr(GraphicsDataFields * _graphFieldsPtr){graphFieldsPtr=_graphFieldsPtr;}
    
private:
    std::string filename;

    unsigned int zPosition;
      

    
    GraphicsDataFields * graphFieldsPtr;
    

    void fillField3D(GraphicsDataFields  &graphFields);
    void createConcentrationFields(GraphicsDataFields  &graphFields, std::map<std::string,
         CompuCell3D::Field3DImpl<float>*> & _fieldMap
         );
   void fillConcentrationFields(GraphicsDataFields  &graphFields, std::map<std::string,CompuCell3D::Field3DImpl<float>*> & _fieldMap);
   
   void createPreasureFields(  GraphicsDataFields  &graphFields,
                                             CompuCell3D::Dim3D fieldDim,
                                             BasicArray<CompuCell3D::EnergyFunction *>  & energyFunctions
                                             );
   void fillPressureFields(GraphicsDataFields  &graphFields);
   
   void fillPressureVolume( GraphicsDataFields  &graphFields,
                                             GraphicsDataFields::floatField3D_t & _floatField3D,
                                             CompuCell3D::EnergyFunction * energyFunctionPtr);
                                             
   void fillPressureVolumeFlex( GraphicsDataFields  &graphFields,
                                             GraphicsDataFields::floatField3D_t & _floatField3D,
                                             CompuCell3D::EnergyFunction * energyFunctionPtr);
   
   void createVectorCellFields(  GraphicsDataFields  &graphFields,
                                             CompuCell3D::Dim3D fieldDim,
                                             BasicArray<CompuCell3D::EnergyFunction *>  & energyFunctions,
                                             CompuCell3D::PluginManager::plugins_t & pluginMap
                                             );
                                             
    void fillVectorCellFields(GraphicsDataFields  &graphFields);
    void fillVelocity( GraphicsDataFields  &graphFields,
                                             GraphicsDataFields::vectorCellFloatField3D_t & _vectorCellFloatField3D,
                                             CompuCell3D::Plugin * plugin
                                             );
                      
    void markBorder(const CompuCell3D::Point3D & _pt , CompuCell3D::CellG *_currentCell, GraphicsData * _pixel);

    
    CompuCell3D::Field3D<CompuCell3D::CellG *> *cellFieldG;
    
    // volume plugin names - we derive pressure using volume plugin data
    std::map<std::string, CompuCell3D::EnergyFunction *> pressureNameEnergyMap;
    std::map<std::string, CompuCell3D::Plugin *> pluginNameMap;
    

    QMutex * pauseMutexPtr;
    QMutex * fieldDrawMutexPtr;
    QMutex * mutexTransactionPtr;
    QSemaphore * bufferFillFreeSemPtr;
    QSemaphore * bufferFillUsedSemPtr;

};


#endif
