package com.brilliance.isc.common.atcmod.service.impl;

import com.brilliance.isc.bo.Atc;
import com.brilliance.isc.common.atcmod.service.AtcmodService;
import com.brilliance.isc.common.atcmod.vo.Atcdia;
import com.brilliance.isc.common.atcmod.vo.Atcdoc;
import com.brilliance.isc.common.atcmod.vo.Atcfee;
import com.brilliance.isc.common.atcmod.vo.AtcmodVo;
import com.brilliance.isc.common.cbsmod.service.XrtmodService;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.util.SettleExceptionUtils;
import com.brilliance.isc.mda.dao.AtcMapper;
import com.brilliance.mda.runtime.mda.IStream;
import com.brilliance.mda.runtime.mda.impl.Argument;
import com.brilliance.mda.runtime.mda.util.Dates;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import com.brilliance.mda.runtime.mda.util.Streams;
import com.brilliance.mda.runtime.mda.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

import static com.brilliance.mda.runtime.mda.Constants.NULLSTR;
import static com.brilliance.mda.runtime.mda.Constants.TAB;


@Service
public class AtcmodServiceImpl implements AtcmodService{

    private static Logger log = LoggerFactory.getLogger(AtcmodServiceImpl.class);

    @Autowired
    private AtcMapper atcMapper;

    @Autowired
    private XrtmodService xrtmodService;

    /**
     *   source:atcmod.0000.script
     */
    public boolean isAtcDefinedForKey(AtcmodVo atcmod, String argCod, String argTyp) {
        //! return TRUE if for passed ArgTrn and ArgCod a defined parameter ATC exits
        String codes = "";
        Argument<String> codesBox = new Argument<String>("",codes);
        getDefinedCodes( atcmod, argTyp, codesBox );
        codes = codesBox.value;
        if( Strings.pos(codes,argCod + TAB) > 0 ) {
            return  true;
        } else {
            return  false;
        }
    }

    /**
     *   source:atcmod.0002.script
     */
    public void getDefinedCodes(AtcmodVo atcmod, String argTyp, Argument<String> argCodes) {
        Atc atc = atcMapper.getAtcByTrnAndTyp(SettleContext.getUserSession().getAtp().getCod(), argTyp);
        if (atc != null) {
            atcmod.setAtc(atc);
            argCodes.value = argCodes.value + atc.getCod() + "_" + atc.getVar()+ TAB;
            switch(atc.getTyp()) {
                case "DIASAV":
                    Atcdia actdia = getDIAContractData(atc);
                    atcmod.setAtcdia(actdia);
                    break;
                case "FEESAV":
                    Atcfee atcfee = getFEEContractData(atc);
                    atcmod.setAtcfee(atcfee);
                    break;
                case "DOC":
                    Atcdoc atcdoc = getDOCContractData(atc);
                    atcmod.setAtcdoc(atcdoc);
                    break;
            }
        }
    }

    public void getNextEntryForDIA(AtcmodVo atcmod, Argument<String> argCodes, Argument<String> argGroup, Argument<String> argDiaTyp, Argument<Date> argDate, Argument<String> argCod, Argument<String> argNam, Argument<String> argFrm, Argument<String> argFlag, Argument<Boolean> argLast) {
        // read ATC entry for each entry in $codes from cache and execute rule
        //    ####    label NextEntry
        NextEntry:
        while(true) {
            int tabpos = Strings.pos(argCodes.value,TAB);
            String actCode = NULLSTR;
            int pos = 0;
            String actVer = NULLSTR;
            String errTxt = NULLSTR;
            if (tabpos > 0) {
                actCode = Strings.mid(argCodes.value, 1, tabpos - 1);
                pos = Strings.pos(actCode, "_");
                actVer = Strings.mid(actCode, pos + 1);
                actCode = Strings.mid(actCode, 1, pos - 1);
                argCodes.value = Strings.mid(argCodes.value, tabpos + 1);
                if (!atcConditionTrue(atcmod.getAtcdia().getIgnflg(), atcmod.getAtcdia().getCnd(), atcmod.getAtcdia().getCndfld1typ(), atcmod.getAtcdia().getCndfld1(), atcmod.getAtcdia().getCndfld2typ(), atcmod.getAtcdia().getCndfld2(), atcmod.getAtcdia().getCndstm())) {
                    continue NextEntry; //   ####   goto NextEntry
                }
                argGroup.value = atcmod.getAtcdia().getGrp();
                switch (atcmod.getAtcdia().getDattyp()) {
                    case "FUNC":
                        switch (Strings.toUpper(atcmod.getAtcdia().getDat())) {
                            case "TODAY":
                                argDate.value = Dates.today();
                                break;
                            default:
                                atcCallSysdumpInfo(atcmod.getAtc(), "ATCDIA\\DAT", atcmod.getAtcdia().getDat(), "Function not defined");
                                continue NextEntry; //   ####   goto NextEntry
                        }
                        break;
                    case "CONST":
                        argDate.value = Strings.parseDate(atcmod.getAtcdia().getDat());
                        /*if( ctx.getErrorCode() > 0 )
                        {
                            errTxt = ctx.getErrorMessage();
                            atcCallSysdumpInfo( "ATCDIA\\DAT", this.getAtcsub().getAtcdia().getDat(), errTxt );
                            continue NextEntry ; //   ####   goto NextEntry
                        }*/
                        break;
                    case "FLD":
                        argDate.value = Strings.parseDate(atcmod.getAtcdia().getDat());
                        break;
                }
                if( ! MdaUtils.isEmpty(atcmod.getAtcdia().getDatnum()) && ! MdaUtils.isEmpty(argDate.value) ) {
                    argDate.value = Dates.dateAddW(argDate.value,atcmod.getAtcdia().getDatnum(),xrtmodService.calendar());
                    /*if( ctx.getErrorCode() > 0 )
                    {
                        errTxt = ctx.getErrorMessage();
                        atcCallSysdumpInfo( "ATCDIA\\DATNUM", MdaUtils.toString(this.getAtcsub().getAtcdia().getDatnum()), errTxt );
                        continue NextEntry ; //   ####   goto NextEntry
                    }*/
                }
                // no creation of diary, if date empty
                if( MdaUtils.isEmpty(argDate.value) ) {
                    continue NextEntry ; //   ####   goto NextEntry
                }
                if( MdaUtils.isEmpty(atcmod.getAtcdia().getAutflg()) ) {
                    argCod.value = atcmod.getAtcdia().getCod();
                } else {
                    argCod.value = atcmod.getAtcdia().getCod() + "$";
                }
                argNam.value = atcmod.getAtcdia().getNam();
                if( MdaUtils.isEmpty(atcmod.getAtcdia().getFrerol()) ) {
                    argFrm.value = atcmod.getAtcdia().getTrn();
                } else {
                    argFrm.value = atcmod.getAtcdia().getTrn() + "@" + atcmod.getAtcdia().getFrerol();
                }
                argFlag.value = atcmod.getAtcdia().getFlg();
                argDiaTyp.value = actCode;
                argLast.value = false;
            } else {
                argLast.value = true;
            }

            break NextEntry;
        }

    }

    /**
     *   source:atcmod.0004.script
     */
    public boolean atcConditionTrue(String argIgnFlg, String argCnd, String argCNDFLD1TYP, String argCNDFLD1, String argCNDFLD2TYP, String argCNDFLD2, IStream argCNDSTM) {
        boolean res = true;
        if( ! MdaUtils.isEmpty(argIgnFlg) ) {
            res = false;
            return res; // ####### 改写 LABEL与GOTO  ####   goto done
        }
        String field1 = "";
        String errTxt = NULLSTR;
        if( MdaUtils.compareTo(argCNDFLD1TYP,"CONST") == 0 ) {
            field1 = argCNDFLD1;
        } else {
            if( MdaUtils.compareTo(argCNDFLD1TYP,"FLD") == 0 ) {
                //TODO field1 = Datas.getContent(this,"\\" + argCNDFLD1);
               /* if( ctx.getErrorCode() > 0 )
                {
                    errTxt = ctx.getErrorMessage();
                    atcCallSysdumpInfo( "ATC\\CNDFLD1", argCNDFLD1, errTxt );
                    res = false;
                    return res; // ####### 改写 LABEL与GOTO  ####   goto done
                }*/
            }
        }
        String field2 = "";
        if( MdaUtils.compareTo(argCNDFLD2TYP,"CONST") == 0 ) {
            field2 = argCNDFLD2;
        } else {
            if( MdaUtils.compareTo(argCNDFLD2TYP,"FLD") == 0 ) {
                //TODO field2 = Datas.getContent(this,"\\" + argCNDFLD2);
                /*if( ctx.getErrorCode() > 0 )
                {
                    errTxt = ctx.getErrorMessage();
                    atcCallSysdumpInfo( "ATC\\CNDFLD2", argCNDFLD2, errTxt );
                    res = false;
                    return res; // ####### 改写 LABEL与GOTO  ####   goto done
                }*/
            }
        }
        String resfld = NULLSTR;
        switch( argCnd ) {
            case "":
            case  "U":
                res = true;
                break;
            case "=":
                if( MdaUtils.compareTo(field1,field2) == 0 ) {
                    res = true;
                } else {
                    res = false;
                }
                break;
            case "<":
                if( MdaUtils.compareTo(field1,field2)<0 ) {
                    res = true;
                } else {
                    res = false;
                }
                break;
            case ">":
                if( MdaUtils.compareTo(field1,field2)>0 ) {
                    res = true;
                } else {
                    res = false;
                }
                break;
            case "<>":
                if( MdaUtils.compareTo(field1,field2) != 0 ) {
                    res = true;
                } else {
                    res = false;
                }
                break;
            case "0":
                if( MdaUtils.isEmpty(field1) ) {
                    res = true;
                } else {
                    res = false;
                }
                break;
            case "9":
                if( ! MdaUtils.isEmpty(field1) ) {
                    res = true;
                } else {
                    res = false;
                }
                break;
            case "F":
                res = false;
                /*this.setRes(NULLSTR);
                resfld = Systems.getAttributeText(this,"res",tdAttrFullName);
                Modules.invokeExpress(this,"if " + MdaUtils.toString(argCNDSTM) + " then " + CR + resfld + " = \"x\"" + CR + "endif",-1); // relative to \\ ?
                if( ! MdaUtils.isEmpty(this.getRes()) )
                {
                    res = true;
                }
                else
                {
                    res = false;
                }*/
                break;
            default:
                SettleExceptionUtils.sysDump("undefined condition in ATC entry");
        }
        // ####### 改写 LABEL与GOTO   ####    label done
        return  res;

    }

    public void atcCallSysdumpInfo(Atc atc, String argField,String argContent,String argErrTxt) {
        log.warn(Strings.formatText("ATC entry for Trn=$1, Cod=$2, Typ=$3 missconfigured.\n$4 ($5) has wrong content $6\nError: $7\nPlease use DBIATC to correct the configuration.",
                atc.getTrn(),
                atc.getCod(),
                atc.getTyp(),
                argField,argField,argContent,argErrTxt));

    }

    /**
     *   source:atcsub.0000.script
     */
    public Atcdoc getDOCContractData(Atc atc) {
        //! copy contract fields into panel fields
        Atcdoc atcdoc = new Atcdoc();
        BeanUtils.copyProperties(atc, atcdoc);
        // type
        atcdoc.setDsctyp( atc.getArg6typ());
        atcdoc.setRoltyp( atc.getArg7typ());
        // values
        atcdoc.setRul( atc.getArg1());
        atcdoc.setApf( atc.getArg2());
        atcdoc.setMdtflg( atc.getArg3());
        atcdoc.setRcv( atc.getArg4());
        atcdoc.setObj( atc.getArg5());
        atcdoc.setDsc( atc.getArg6());
        if( MdaUtils.compareTo(atcdoc.getRoltyp(),"CONST")== 0 ) {
            atcdoc.setRolfix( atc.getArg7());
        } else {
            atcdoc.setRol( atc.getArg7());
        }
        atcdoc.setAdrblk( atc.getArg8());
        return atcdoc;
    }

    /**
     *   source:atcsub.0001.script
     */
    public Atcdia getDIAContractData(Atc atc) {
        //! copy contract fields in panel fields
        Atcdia atcdia = new Atcdia();
        BeanUtils.copyProperties(atc, atcdia);
        // type
        atcdia.setGrptyp( atc.getArg1typ());
        atcdia.setDattyp( atc.getArg2typ());
        atcdia.setCodtyp( atc.getArg3typ());
        atcdia.setNamtyp( atc.getArg4typ());
        atcdia.setTrntyp( atc.getArg5typ());
        atcdia.setFlgtyp( atc.getArg6typ());
        // values
        atcdia.setGrp( atc.getArg1());
        atcdia.setDat( Strings.mid(atc.getArg2(),1,Strings.pos(atc.getArg2(),TAB) - 1));
        atcdia.setDatnum( Strings.parseInt(Strings.mid(atc.getArg2(),Strings.pos(atc.getArg2(),TAB) + 1)));
        atcdia.setCod( atc.getArg3());
        atcdia.setNam( atc.getArg4());
        atcdia.setTrn( atc.getArg5());
        atcdia.setFlg( atc.getArg6());
        return atcdia;
    }

    /**
     *   source:atcsub.0002.script
     */
    public Atcfee getFEEContractData(Atc atc) {
        // copy contract fields in panel fields
        Atcfee atcfee = new Atcfee();
        BeanUtils.copyProperties(atc, atcfee);
        // type
        atcfee.setCodtyp(atc.getArg1typ());
        atcfee.setFlgtyp(atc.getArg2typ());
        atcfee.setUnttyp(atc.getArg3typ());
        atcfee.setDatfrotyp(atc.getArg4typ());
        atcfee.setDattiltyp(atc.getArg5typ());
        // values
        atcfee.setCod(atc.getArg1());
        atcfee.setFlg(atc.getArg2());
        atcfee.setUnt(Strings.parseInt(atc.getArg3()));
        atcfee.setDatfro(atc.getArg4());
        atcfee.setDattil(atc.getArg5());
        return atcfee;
    }

    /**
     * source:atcmod.0001.script
     */
    public void setMandatoryForDocs(IStream argAllIds, IStream argManIds) {
        //! Implements overwriting of mandatory flag by entries in table ATC
        // argAllIds contains list of all Ids, for which ATC should be evaluated for suppression
        // argManIds contains list of all documentids for which 'mandator
        // a line in argManIds contains the document-id followd by tab and respective value of MDTFLG
        Streams.streamClear(argManIds);
        String codes = "";
        Argument<String> codesBox = new Argument<String>("", codes);
        AtcmodVo atcmod = new AtcmodVo();
        atcmod.reset();
        getDefinedCodes(atcmod, "DOC", codesBox);
        codes = codesBox.value;
        if (MdaUtils.isEmpty(codes)) {
            return;
        }
        // list of all codes (i.e. IDs) is read here and filtered below
        // when many ATC for DOC exists performance improvements is possible by maintaining a list per ID
        // multiple ATC records with same COD but different VER may exist (e.g. to implement 'if then
        //    ####    label NextEntry
        NextEntry:
        while (true) {
            int tabpos = Strings.pos(codes, TAB);
            String actCode = NULLSTR;
            int pos = 0;
            String actVar = NULLSTR;
            if (tabpos > 0) {
                actCode = Strings.mid(codes, 1, tabpos - 1);
                pos = Strings.pos(actCode, "_");
                actVar = Strings.mid(actCode, pos + 1);
                actCode = Strings.mid(actCode, 1, pos - 1);
                codes = Strings.mid(codes, tabpos + 1);
                if (Streams.streamSearch(argAllIds, actCode) <= 0) {
                    continue NextEntry; //   ####   goto NextEntry
                }
                if (MdaUtils.isEmpty(atcmod.getAtcdoc().getIgnflg())) {
                    if (atcConditionTrue(atcmod.getAtcdoc().getIgnflg(), atcmod.getAtcdoc().getCnd(), atcmod.getAtcdoc().getCndfld1typ(), atcmod.getAtcdoc().getCndfld1(), atcmod.getAtcdoc().getCndfld2typ(), atcmod.getAtcdoc().getCndfld2(), atcmod.getAtcdoc().getCndstm())) {
                        // add to argManIds
                        Streams.streamInsert(argManIds, 0, actCode + TAB + atcmod.getAtcdoc().getMdtflg());
                    }
                } else {
                    Streams.streamInsert(argManIds, 0, actCode + TAB + "R"); // remove entry
                }
            }
            break NextEntry;
        }
    }

}
