/***********************************************************************************/
void LcfNet::CreateNetLayersFromXML(const char *cnfXMLName, struct CcnnContext *pCtx)
{  
    tinyxml2::XMLDocument doc;
    int res = doc.LoadFile(cnfXMLName);
    if (res != 0) {
        ErrorOutput::ShowErrAndExitIfHappen(XML_CONFIG_CAN_NOT_READ);
    }

    tinyxml2::XMLElement *root = doc.RootElement();
    tinyxml2::XMLElement *userNode = root->FirstChildElement("layer");

    const char *sType;
    int ID;

    pCtx->batchNum = atoi(root->Attribute("batchNum"));
    // when predict, batchNum = 1
    if (pCtx->method == 1) {
        pCtx->batchNum = 1;
    }

    snprintf(LcfFatherLayer::mWeightFileName, sizeof(LcfFatherLayer::mWeightFileName), "%s", root->Attribute("weightFile"));
    snprintf(pCtx->weightFile, sizeof(pCtx->weightFile), "%s", root->Attribute("weightFile"));

    pCtx->maxIterNum = atoi(root->Attribute("maxIterNum"));
    pCtx->saveIterNum = atoi(root->Attribute("saveIterNum"));
    pCtx->minStopError = (float)atof(root->Attribute("minStopError"));

    float lrBase = (float)atof(root->Attribute("lrBase"));
    float lrDecay = (float)atof(root->Attribute("lrDecay"));
    int lrStep = atoi(root->Attribute("lrStep"));

    int tmplayerCount = 0;
    while (userNode != NULL) {
        userNode = userNode->NextSiblingElement("layer");
        tmplayerCount++;
    }
    pCtx->layNum = tmplayerCount;
    
    pCtx->pLcfFatherLayer = new LcfFatherLayer *[tmplayerCount];

    tmplayerCount = 0;
    userNode = root->FirstChildElement("layer");
    while (userNode != NULL) {
   
        sType = userNode->Attribute("Type");
        ID = atoi(userNode->FirstChildElement("ID")->GetText());
        
        int maxSeq = GetIntNode(userNode, "maxSeq", 1);
        if (0 == strcasecmp("INPT", sType)) {            
            int tmpInChannels = GetIntNode(userNode, "channels");
            int tmpInHeight = GetIntNode(userNode, "height");
            int tmpInWidth = GetIntNode(userNode, "width");            
            InputLayer *nInputLayer = new InputLayer(ID, maxSeq, pCtx->batchNum, tmpInChannels, tmpInHeight, tmpInWidth);
            SetInLayersArrayFromXMLNodeCnf(userNode, nInputLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nInputLayer;
                        
        } else if (0 == strcasecmp("CONV", sType) || 0 == strcasecmp("DECONV", sType)) {
            int tmpKerSize = GetIntNode(userNode, "kerSize");
            int tmpKerNum = GetIntNode(userNode, "kerNum");
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);
            int tmpPad = GetIntNode(userNode, "pad", 0);
            int tmpStride = GetIntNode(userNode, "stride", 1);
            int tmpDia = GetIntNode(userNode, "dilate", 1);
            int tmpStdPad = GetIntNode(userNode, "standPad", 0);
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            ConvLayer *nConvLayer = new ConvLayer(ID, maxSeq, sType, tmpPad, tmpStride, tmpDia, tmpStdPad, tmpKerNum, tmpKerSize, \
                                                  tmpLambda, tmpAlpha, learnRate, lrDecay, lrStep);
            SetInLayersArrayFromXMLNodeCnf(userNode, nConvLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nConvLayer;
                        
        } else if (0 == strcasecmp("BN", sType)) {
            float tmpGamma = GetFloatNode(userNode, "gamma", 1.0F);
            float tmpBeta = GetFloatNode(userNode, "beta", 0.0F);
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);
            BatchNormLayer *nBatchNormLayer = new BatchNormLayer(ID, maxSeq, tmpGamma, tmpBeta, tmpLambda, \
                                                                 tmpAlpha, learnRate, lrDecay, lrStep);
            SetInLayersArrayFromXMLNodeCnf(userNode, nBatchNormLayer);      
            pCtx->pLcfFatherLayer[tmplayerCount++] = nBatchNormLayer;
            
        } else if (0 == strcasecmp("LN", sType)) {
            float tmpGamma = GetFloatNode(userNode, "gamma", 1.0F);
            float tmpBeta = GetFloatNode(userNode, "beta", 0.0F);
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            LayerNormLayer *nLayerNormLayer = new LayerNormLayer(ID, maxSeq, tmpGamma, tmpBeta, tmpLambda, \
                                                                 tmpAlpha, learnRate, lrDecay, lrStep);
            SetInLayersArrayFromXMLNodeCnf(userNode, nLayerNormLayer);            
            pCtx->pLcfFatherLayer[tmplayerCount++] = nLayerNormLayer;
            
        } else if (0 == strcasecmp("ACTIVE", sType)) {
            ActiveLayer *nActiveLayer = new ActiveLayer(ID, maxSeq, userNode->FirstChildElement("activeType")->GetText());
            SetInLayersArrayFromXMLNodeCnf(userNode, nActiveLayer);            
            pCtx->pLcfFatherLayer[tmplayerCount++] = nActiveLayer;     
            
        } else if (0 == strcasecmp("AVEPOOL", sType) || 0 == strcasecmp("AVEUS", sType)) {
            int tmpKerSize = GetIntNode(userNode, "kerSize", 2);
            int rtPad = GetIntNode(userNode, "rtPad", 0);
            int rbPad = GetIntNode(userNode, "rbPad", 0);
            int clPad = GetIntNode(userNode, "clPad", 0);
            int crPad = GetIntNode(userNode, "crPad", 0);
             
            AvePoolLayer *nAvePoolLayer = new AvePoolLayer(ID, maxSeq, sType, tmpKerSize, rtPad, rbPad, clPad, crPad);
            SetInLayersArrayFromXMLNodeCnf(userNode, nAvePoolLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nAvePoolLayer; 
            
        } else if (0 == strcasecmp("MAXPOOL", sType)) {
            int tmpKerSize = GetIntNode(userNode, "kerSize", 2);
            int rtPad = GetIntNode(userNode, "rtPad", 0);
            int rbPad = GetIntNode(userNode, "rbPad", 0);
            int clPad = GetIntNode(userNode, "clPad", 0);
            int crPad = GetIntNode(userNode, "crPad", 0);
            
            MaxPoolLayer *nMaxPoolLayer = new MaxPoolLayer(ID, maxSeq, sType, NULL, tmpKerSize, rtPad, rbPad, clPad, crPad);
            SetInLayersArrayFromXMLNodeCnf(userNode, nMaxPoolLayer);            
            pCtx->pLcfFatherLayer[tmplayerCount++] = nMaxPoolLayer; 
            
        } else if (0 == strcasecmp("MAXUS", sType)) {
            int tmpKerSize = GetIntNode(userNode, "kerSize", 2);
            int rtPad = GetIntNode(userNode, "rtPad", 0);
            int rbPad = GetIntNode(userNode, "rbPad", 0);
            int clPad = GetIntNode(userNode, "clPad", 0);
            int crPad = GetIntNode(userNode, "crPad", 0);
            
            int tmpSaveLayerId = GetIntNode(userNode, "saveLayerId", -1);
            LcfFatherLayer *tmpMaxInLayer = GetClassEntityById(pCtx, tmpSaveLayerId);
            if (NULL == tmpMaxInLayer) {
                ErrorOutput::ShowErrAndExitIfHappen(XML_CONFIG_MAX_IN_LAYER_VALID);
            }
            MaxPoolLayer *nMaxPoolLayer = new MaxPoolLayer(ID, maxSeq, sType, (MaxPoolLayer *)tmpMaxInLayer, tmpKerSize, rtPad, rbPad, clPad, crPad);
            SetInLayersArrayFromXMLNodeCnf(userNode, nMaxPoolLayer);            
            pCtx->pLcfFatherLayer[tmplayerCount++] = nMaxPoolLayer; 
                        
        } else if (0 == strcasecmp("BIAS", sType)) {           
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            BiasLayer *nBiasLayer = new BiasLayer(ID, maxSeq, tmpLambda, tmpAlpha, learnRate, lrDecay, lrStep);
            SetInLayersArrayFromXMLNodeCnf(userNode, nBiasLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nBiasLayer; 
            
        } else if (0 == strcasecmp("DROPOUT", sType)) {
            float cnfDropoutP = GetFloatNode(userNode, "keepProb", 0.9F);
            DropoutLayer *nDropoutLayer = new DropoutLayer(ID, maxSeq, cnfDropoutP);
            SetInLayersArrayFromXMLNodeCnf(userNode, nDropoutLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nDropoutLayer; 
            
        } else if (0 == strcasecmp("EXPAND", sType) || 0 == strcasecmp("CROP", sType)) {
            int tmpTc = GetIntNode(userNode, "TC", 0);
            int tmpBc = GetIntNode(userNode, "BC", 0);
            int tmpLc = GetIntNode(userNode, "LC", 0);
            int tmpRc = GetIntNode(userNode, "RC", 0);
  
            ChangeSizeLayer *nChangeSizeLayer = new ChangeSizeLayer(ID, maxSeq, sType, tmpTc, tmpBc, tmpLc, tmpRc);
            SetInLayersArrayFromXMLNodeCnf(userNode, nChangeSizeLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nChangeSizeLayer; 
            
        } else if (0 == strcasecmp("FC", sType)) {
            int tmpOutputNum = GetIntNode(userNode, "outputNum");
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            FCLayer *nFCLayer = new FCLayer(ID, maxSeq, tmpOutputNum, tmpLambda, tmpAlpha, learnRate, lrDecay, lrStep);
            SetInLayersArrayFromXMLNodeCnf(userNode, nFCLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nFCLayer; 
            
        } else if (0 == strcasecmp("SFMIMG", sType)) {
            SoftMaxImgLayer *nSoftMaxImgLayer = NULL;
            if (0 == strcasecmp("SF", userNode->FirstChildElement("LossType")->GetText())) {
                nSoftMaxImgLayer = new SoftMaxImgLayer(ID, maxSeq, SF);
            } else {
                nSoftMaxImgLayer = new SoftMaxImgLayer(ID, maxSeq, FL);
            }
            SetInLayersArrayFromXMLNodeCnf(userNode, nSoftMaxImgLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nSoftMaxImgLayer;   
            
        } else if (0 == strcasecmp("SFMVEC", sType)) {
            SoftMaxVecLayer *nSoftMaxVecLayer = NULL;
            if (0 == strcasecmp("SF", userNode->FirstChildElement("LossType")->GetText())) {
                nSoftMaxVecLayer = new SoftMaxVecLayer(ID, maxSeq, SF);
            }  else {
                nSoftMaxVecLayer = new SoftMaxVecLayer(ID, maxSeq, FL);
            }
            SetInLayersArrayFromXMLNodeCnf(userNode, nSoftMaxVecLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nSoftMaxVecLayer;   
            
        } else if (0 == strcasecmp("L2N", sType)) {
            float tmpScale = GetFloatNode(userNode, "Scale", 0.2F);
            L2NormLayer *nL2NormLayer = new L2NormLayer(ID, maxSeq, tmpScale);
            SetInLayersArrayFromXMLNodeCnf(userNode, nL2NormLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nL2NormLayer;   
            
        } else if (0 == strcasecmp("REGRESS", sType)) {
            int ifNormIn = GetIntNode(userNode, "IfNormIn", 0);
            int ifNormOut = GetIntNode(userNode, "IfNormOut", 0);

            MultiRegressLayer *nMultiRegressLayer = new MultiRegressLayer(ID, maxSeq, userNode->FirstChildElement("LostFun")->GetText(), ifNormIn, ifNormOut);
            SetInLayersArrayFromXMLNodeCnf(userNode, nMultiRegressLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nMultiRegressLayer;   
            
        } else if (0 == strcasecmp("SSD", sType)) {
            int tmpClassNum = GetIntNode(userNode, "classNum");
            int tmpKeepTopMatchNum = GetIntNode(userNode, "keepTopMatchNum", 10);
            SSDLayer *nSSDLayer = NULL;
            if (0 == strcasecmp("SF", userNode->FirstChildElement("LossType")->GetText())) {
                nSSDLayer = new SSDLayer(ID, SSD, maxSeq, SF, tmpClassNum, tmpKeepTopMatchNum);
            } else {
                nSSDLayer = new SSDLayer(ID, SSD, maxSeq, FL, tmpClassNum, tmpKeepTopMatchNum);
            }
            SetInLayersArrayFromXMLNodeCnf(userNode, nSSDLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nSSDLayer;               
            
        } if (0 == strcasecmp("YOLO3", sType)) {
            int tmpClassNum = GetIntNode(userNode, "classNum");
            int tmpKeepTopMatchNum = GetIntNode(userNode, "keepTopMatchNum", 10);
            YOLO3Layer *nYOLO3Layer = NULL;
            if (0 == strcasecmp("SF", userNode->FirstChildElement("LossType")->GetText())) {
                nYOLO3Layer = new YOLO3Layer(ID, YOLO3, maxSeq, SF, tmpClassNum, tmpKeepTopMatchNum);
            } else {
                nYOLO3Layer = new YOLO3Layer(ID, YOLO3, maxSeq, FL, tmpClassNum, tmpKeepTopMatchNum);
            }
            SetInLayersArrayFromXMLNodeCnf(userNode, nYOLO3Layer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nYOLO3Layer;                           
            
        } else if (0 == strcasecmp("MFL", sType)) {        
            MultiFusion *nMultiFusion = new MultiFusion(ID, maxSeq);
            nMultiFusion->SetInputDataFusionMethod(userNode->FirstChildElement("DATA_FUSION")->GetText());  
            SetInLayersArrayFromXMLNodeCnf(userNode, nMultiFusion); 
            pCtx->pLcfFatherLayer[tmplayerCount++] = nMultiFusion;                           
                 
        }  else if (0 == strcasecmp("BTNK1", sType)) {   
            int tmpKerNum = GetIntNode(userNode, "kerNum", 3);            
            float tmpGamma = GetFloatNode(userNode, "gamma", 1.0F);
            float tmpBeta = GetFloatNode(userNode, "beta", 0.0F);
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);                 
            int tmpStride = GetIntNode(userNode, "stride", 1);
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            BTNK1GroupLayer *mBTNK1GroupLayer = new BTNK1GroupLayer(ID, maxSeq, tmpKerNum, tmpStride, tmpLambda, tmpAlpha, \
                                                                    tmpGamma, tmpBeta, learnRate, lrDecay, lrStep, \
                                                                    userNode->FirstChildElement("activeType")->GetText());
            SetInLayersArrayFromXMLNodeCnf(userNode, mBTNK1GroupLayer); 
            pCtx->pLcfFatherLayer[tmplayerCount++] = mBTNK1GroupLayer;                           
            
        } else if (0 == strcasecmp("BTNK2", sType)) {   
            int tmpKerNum = GetIntNode(userNode, "kerNum", 3);            
            float tmpGamma = GetFloatNode(userNode, "gamma", 1.0F);
            float tmpBeta = GetFloatNode(userNode, "beta", 0.0F);
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);      
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            BTNK2GroupLayer *mBTNK2GroupLayer = new BTNK2GroupLayer(ID, maxSeq, tmpKerNum, tmpLambda, tmpAlpha, tmpGamma, tmpBeta, learnRate, \
                                                                    lrDecay, lrStep, userNode->FirstChildElement("activeType")->GetText());
            SetInLayersArrayFromXMLNodeCnf(userNode, mBTNK2GroupLayer); 
            pCtx->pLcfFatherLayer[tmplayerCount++] = mBTNK2GroupLayer;                           
            
        } else if (0 == strcasecmp("FBA", sType)) { 
            int tmpOutputNum = GetIntNode(userNode, "outputNum");
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);     
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            FBAGroupLayer *nFBAGroupLayer = new FBAGroupLayer(ID, maxSeq, tmpOutputNum, tmpLambda, tmpAlpha, learnRate, lrDecay, \
                                                              lrStep, userNode->FirstChildElement("activeType")->GetText());
            SetInLayersArrayFromXMLNodeCnf(userNode, nFBAGroupLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nFBAGroupLayer;                           
            
        } else if (0 == strcasecmp("CBA", sType)) { 
            const char *conType = userNode->FirstChildElement("conv")->GetText();           
            int tmpKerSize = GetIntNode(userNode, "kerSize", 3);
            int tmpKerNum = GetIntNode(userNode, "kerNum", 1);           
            float tmpGamma = GetFloatNode(userNode, "gamma", 1.0F);
            float tmpBeta = GetFloatNode(userNode, "beta", 0.0F);
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);           
            int tmpPad = GetIntNode(userNode, "pad", 0);
            int tmpStride = GetIntNode(userNode, "stride", 1);
            int tmpDia = GetIntNode(userNode, "dilate", 1);
            int tmpStdPad = GetIntNode(userNode, "standPad", 0);        
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            CBAGroupLayer *nCBAGroupLayer = new CBAGroupLayer(ID, maxSeq, conType, tmpPad, tmpStride, tmpDia, tmpStdPad, tmpKerNum, \
                                                              tmpKerSize, tmpGamma, tmpBeta, tmpLambda, tmpAlpha, learnRate, lrDecay, \
                                                              lrStep, userNode->FirstChildElement("activeType")->GetText());                                                
            SetInLayersArrayFromXMLNodeCnf(userNode, nCBAGroupLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nCBAGroupLayer;                           
            
        } else if (0 == strcasecmp("RESU", sType)) { 
            float tmpGamma = GetFloatNode(userNode, "gamma", 1.0F);
            float tmpBeta = GetFloatNode(userNode, "beta", 0.0F);
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);       
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            ResUnitLayer *nResUnitLayer = new ResUnitLayer(ID, maxSeq, tmpGamma, tmpBeta, tmpLambda, tmpAlpha, learnRate, \
                                                           lrDecay, lrStep, userNode->FirstChildElement("activeType")->GetText()); 
            SetInLayersArrayFromXMLNodeCnf(userNode, nResUnitLayer);
            pCtx->pLcfFatherLayer[tmplayerCount++] = nResUnitLayer;                           
             
        } else if (0 == strcasecmp("RESN", sType)) {  
            int resNum = GetIntNode(userNode, "resNum", 1);  
            int tmpKerNum = GetIntNode(userNode, "kerNum", 3);           
            float tmpGamma = GetFloatNode(userNode, "gamma", 1.0F);
            float tmpBeta = GetFloatNode(userNode, "beta", 0.0F);
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F);  
            float learnRate = GetFloatNode(userNode, "learnRate", lrBase);

            ResNLayer *nResNLayer = new ResNLayer(ID, maxSeq, resNum, tmpKerNum, tmpGamma, tmpBeta, tmpLambda, tmpAlpha, \
                                                  learnRate, lrDecay, lrStep, userNode->FirstChildElement("activeType")->GetText());
            SetInLayersArrayFromXMLNodeCnf(userNode, nResNLayer); 
            pCtx->pLcfFatherLayer[tmplayerCount++] = nResNLayer;                           
           
        } else if (0 == strcasecmp("GRU", sType)) {
            float tmpLambda = GetFloatNode(userNode, "lambda", 0.0F);
            float tmpAlpha = GetFloatNode(userNode, "alpha", 0.9F); 
            int iHNum = GetIntNode(userNode, "hiddenLayNum", 0); 
            int iHDim = GetIntNode(userNode, "hiddenDim", 0); 
            int iInDim = GetIntNode(userNode, "inDim", 0); 
            
            GRULayer *nGRULayer = new GRULayer();
            nGRULayer->SetInParaComputerOtherParaAndAllMem(ID, maxSeq, iHNum, iHDim, iInDim, tmpLambda, tmpAlpha, lrBase, lrDecay, lrStep);
            SetInLayersArrayFromXMLNodeCnf(userNode, nGRULayer); 
            pCtx->pLcfFatherLayer[tmplayerCount++] = nGRULayer;                           
        }

        userNode = userNode->NextSiblingElement("layer");

    }
    doc.Clear();
}
