#ifndef LCF_CONV_H_
#define LCF_CONV_H_
#include "tensorOperate.h"

class ConvLayer : public TensorOperate
{
    public:
        ConvLayer();
        virtual ~ConvLayer();
        ConvLayer(int ifType, int iID, int iMaxSeqNum, DevicesBatchDisptach *iDevicesBatchDisptach, \
                  const char *cTS, int iPad, int iStd, int iDia, int iStdPad, int kNum, int inKSize, \
                  float iLmd, float iApa, float lb, float ld, int ls);
        void SetConvInfo(int ifType, int iID, int iMaxSeqNum, DevicesBatchDisptach *iDevicesBatchDisptach, \
                         const char *cTS, int iPad, int iStd, int iDia, int iStdPad, int kNum, int inKSize, \
                         float iLmd, float iApa, float lb, float ld, int ls); 
        void CreateParaAndInstance();     
        void SaveLayerWeight(int n);
        void LoadLayerWeight();
        void CompuateOutY(int devID, int seqNum);
        void CompuateOutD(int devID, int seqNum);
        void CompGrad(int devID, int seqNum);
        void ComputerYMemRealease(int devID);
        void ComputerDMemRealease(int devID);
        void UpdateWeightMain(); 
        void ComputeAndCreateOutYInDTensorInfo();
        void GetConvUseParas(int *outIfFill, int *outFillStride, int *outPad, int *outStride, int *outDia);
        int GetKernelSize();
        void ComputeOutHW(int *tOutHeight, int *tOutWidth, int inH, int inW);
        
    private: 
        void GetInvConvUseParas(int *outIfFill, int *outFillStride, int *outPad, int *outStride, int *outDia);
        void GetUpdateConvUseParas(int *outIfFill, int *outFillStride, int *outPad, int *outStride, int *outDia);
        int GetOutStandPadWhenCompD();
        int GetOutStandPadWhenUpdateK();
        void SetYDSaveInfo();
        void RealeaseChildLayerMemory();
        void SetChildLayerMomeryPointInitStatus();
        void ComputerWeightUpdateGrad(int devID, MyVoid *gradSumdkCMem, MyVoid *inD, MyVoid *tmpInY, int seqNum);
        void UpdateWeightEnter(int devID, MyVoid *inWGradCMem);

        ConvType mConvType;
        int kernelSize;
        int pad;                             // the pad of conv
        int stride;                          // the stride of conv
        int dilate;                          // the dilate of conv
        TensorData *mKernel;                 // kernel[inChannels][outChannels][kernelSize][kernelSize]
        TensorData *mMomentumDk;             // Handle for momentumDk
        TensorData *mKernelGrad;             // kernel update grad
        int useBatchNum;
        int mOutStandPad;                    // use for deconv
        
        int inChannels, inHeight, inWidth;
        int outChannels, outHeight, outWidth;
};

#endif
