package kr.co.icontrols.callengine.engine;

import kr.co.icontrols.V40IFCCD.V40IFCCD;
import kr.co.icontrols.wallpadcall.MainActivity;
import kr.co.icontrols.wallpadcall.declare.Global.BOARD_TYPE;
import kr.co.icontrols.wallpadcall.declare.Global.ConfigValues;

import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceView;

import com.util.LogUtil;

import static kr.co.icontrols.wallpadcall.MainActivity.bFFMPEGEnable;

public class VideoJNI {

    String TAG = "VideoJNI";

    V40IFCCD mV40IFCCD;

    int BOARDTYPE = 0;

    boolean SWDecoderStarted = false;

    public VideoJNI() {
        BOARDTYPE = ConfigValues.DEVICE_BOARDTYPE;
        if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
            mV40IFCCD = new V40IFCCD();
        } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
            mV40IFCCD = new V40IFCCD();
        } else {
            Log.w(TAG, "[VideoJNI] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
        }
    }

    public void setCheckIFrame(boolean bSet) {
        try {
            Log.i(TAG, "[setCheckIFrame] bSet [" + bSet + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.setCheckIFrame(bSet);
            } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                mV40IFCCD.setCheckIFrame(bSet);
            } else {
                Log.w(TAG, "[setCheckIFrame] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setCheckIFrame(boolean bSet)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void setCameraSelect() {
        try {
            Log.d(TAG, "[setCameraSelect]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.setCameraSelect();
            } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                mV40IFCCD.setCameraSelect();
            } else {
                Log.w(TAG, "[setCameraSelect] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setCameraSelect()");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void setCameraSurface(Surface CameraSurface, int nWidth, int nHeight, int nBitRate, int nFrameRate) {
        try {
            Log.i(TAG, "[setCameraSurface] nWidth [" + nWidth + "], nHeight [" + nHeight + "], nBitRate [" + nBitRate + "], nFrameRate [" + nFrameRate + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.setCameraSurface(CameraSurface, nWidth, nHeight, nBitRate, nFrameRate);
            } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                mV40IFCCD.setCameraSurface(CameraSurface, nWidth, nHeight, nBitRate, nFrameRate);
            } else {
                Log.w(TAG, "[setCameraSurface] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setCameraSurface(Surface CameraSurface, int nWidth, int nHeight, int nBitRate, int nFrameRate)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void setDecoderInfo_V40(int X, int Y, int W, int H) {
        try {
            if (bFFMPEGEnable) return;
            Log.e(TAG, "[setDecoderInfo_V40] X [" + X + "], Y [" + Y + "], W [" + W + "], H [" + H + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.setDecoderInfo(X, Y, W, H);
            } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                mV40IFCCD.setDecoderInfo(X, Y, W, H);
            } else {
                Log.w(TAG, "[setDecoderInfo_V40] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setDecoderInfo_V40(int X, int Y, int W, int H)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void setPreviewInfo_V40(int X, int Y, int W, int H) {
        try {
            if (bFFMPEGEnable) return;
            Log.i(TAG, "[setPreviewInfo_V40] X [" + X + "], Y [" + Y + "], W [" + W + "], H [" + H + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.setPreviewInfo(X, Y, W, H);
            } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                mV40IFCCD.setPreviewInfo(X, Y, W, H);
            } else {
                Log.w(TAG, "[setPreviewInfo_V40] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setPreviewInfo_V40(int X, int Y, int W, int H)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void encoderStartOperation() {
        try {
            Log.d(TAG, "[encoderStartOperation] BOARDTYPE [" + BOARDTYPE + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.encoderStartOperation();
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.encoderStartOperation();
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                mV40IFCCD.encoderStartOperation();
            }
            else {
                Log.w(TAG, "[encoderStartOperation] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] encoderStartOperation()");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void encoderStopOperation() {
        try {
            Log.d(TAG, "[encoderStopOperation] BOARDTYPE [" + BOARDTYPE + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300) {
                mV40IFCCD.encoderStopOperation();
            }
            else if (BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.encoderStopOperation();
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT) {
                mV40IFCCD.encoderStopOperation();
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                mV40IFCCD.encoderStopOperation();
            }
            else {
                Log.w(TAG, "[encoderStopOperation] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] encoderStopOperation()");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }


    Surface mSurface;
    int nSurfaceWidth = 0;
    int nSurfaceHeight = 0;
    public void setRemoteSurfaceview(Surface surface, int width, int height) {
        try {
            Log.d(TAG, "[setRemoteSurfaceview] surface [" + surface + "], width [" + width + "], height [" + height + "]");
            mSurface = surface;
            nSurfaceWidth = width;
            nSurfaceHeight = height;
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setRemoteSurfaceview(Surface surface, int width, int height)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    boolean bDecoderStarted = false;
    public void decoderStartOperation() {
        try {
            Log.d(TAG, "[decoderStartOperation] BOARDTYPE [" + BOARDTYPE + "], bDecoderStarted [" + bDecoderStarted + "], SWDecoderStarted [" + SWDecoderStarted + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300) {
                if (!bDecoderStarted) {
                    bDecoderStarted = true;
                    mV40IFCCD.decoderStartOperation();
                }
            }
            else if (BOARDTYPE == BOARD_TYPE.V40) {
                if (!bDecoderStarted) {
                    bDecoderStarted = true;
                    mV40IFCCD.decoderStartOperation();
                }
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT) {
                if (!bDecoderStarted) {
                    bDecoderStarted = true;
                    mV40IFCCD.decoderStartOperation();
                }
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                if (!bDecoderStarted) {
                    if (bFFMPEGEnable) {
                        if (bComposite) {
                            // MoIP 영상
                            if (!SWDecoderStarted) {
                                SWDecoderInit(mSurface, nSurfaceWidth, nSurfaceHeight);
                                SWDecoderStarted = true;
                            }
                            mV40IFCCD.decoderStartOperation();
                        }
                        else {
                            // 현관
                            mV40IFCCD.decoderStartOperation();
                        }
                    }
                    else {
                        mV40IFCCD.decoderStartOperation();
                    }
                    bDecoderStarted = true;
                }
            }
            else {
                Log.w(TAG, "[decoderStartOperation] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] decoderStartOperation()");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void decoderStopOperation() {
        try {
            int nTime = 100;
            Log.d(TAG, "[decoderStopOperation] BOARDTYPE [" + BOARDTYPE + "], bDecoderStarted [" + bDecoderStarted + "], SWDecoderStarted [" + SWDecoderStarted + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300) {
                if (bDecoderStarted) {
                    mV40IFCCD.decoderStopOperation();
                    bDecoderStarted = false;
//                    new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
//                        @Override
//                        public void run() {
//
//                        }
//                    }, nTime);
                }
            }
            else if (BOARDTYPE == BOARD_TYPE.V40) {
                if (bDecoderStarted) {
                    mV40IFCCD.decoderStopOperation();
                    bDecoderStarted = false;
                }
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT) {
                if (bDecoderStarted) {
                    mV40IFCCD.decoderStopOperation();
                    bDecoderStarted = false;
                }
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                if (bDecoderStarted) {
                    //bDecoderStarted = false;

                    if (bFFMPEGEnable) {
                        if (SWDecoderStarted) {
                            SWDecoderStarted = false;
                            Log.e(TAG, "[decoderStopOperation] ========== JEFF 1 ========== SWDecoderStarted [" + SWDecoderStarted + "]");
                            SWDecoderClose(1);
                            Log.e(TAG, "[decoderStopOperation] ========== JEFF 2 ========== SWDecoderStarted [" + SWDecoderStarted + "]");
                        }
                        mV40IFCCD.decoderStopOperation();
                        bDecoderStarted = false;
                    }
                    else {
                        mV40IFCCD.decoderStopOperation();
                        bDecoderStarted = false;
                    }
                }
            }
            else {
                Log.w(TAG, "[decoderStopOperation] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] decoderStopOperation()");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void sendDataToDecoder(byte[] hData, int nHeaderLen, int nFrameLen, int nTimeStamp) {
        try {
//            Log.e(TAG, "[sendDataToDecoder] hData.length [" + hData.length + "], nHeaderLen [" + nHeaderLen + "], nFrameLen [" + nFrameLen + "], nTimeStamp [" + nTimeStamp + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300) {
                if (bFFMPEGEnable) {
                    SWSendDataToDecoder(hData, nFrameLen);
                }
                else {
                    if (bDecoderStarted) mV40IFCCD.sendDataToDecoder(hData, nHeaderLen, nFrameLen, nTimeStamp);
                }
            }
            else if (BOARDTYPE == BOARD_TYPE.V40) {
                if (bFFMPEGEnable) {
                    SWSendDataToDecoder(hData, nFrameLen);
                }
                else {
                    if (bDecoderStarted) mV40IFCCD.sendDataToDecoder(hData, nHeaderLen, nFrameLen, nTimeStamp);
                }
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT) {
                if (bFFMPEGEnable) {
                    SWSendDataToDecoder(hData, nFrameLen);
                    if (bDecoderStarted) mV40IFCCD.sendDataToDecoder(hData, nHeaderLen, nFrameLen, nTimeStamp);
                }
                else {
                    if (bDecoderStarted) mV40IFCCD.sendDataToDecoder(hData, nHeaderLen, nFrameLen, nTimeStamp);
                }
            }
            else if (BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                if (bFFMPEGEnable) {
                    SWSendDataToDecoder(hData, nFrameLen);
                    if (bDecoderStarted) mV40IFCCD.sendDataToDecoder(hData, nHeaderLen, nFrameLen, nTimeStamp);
                }
                else {
                    if (bDecoderStarted) mV40IFCCD.sendDataToDecoder(hData, nHeaderLen, nFrameLen, nTimeStamp);
                }
            }
            else {
                Log.w(TAG, "[sendDataToDecoder] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] sendDataToDecoder(byte[] hData, int nHeaderLen, int nFrameLen, int nTimeStamp)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void deallocate() {
        try {
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.deallocate();
            } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                mV40IFCCD.deallocate();
            } else {
                Log.w(TAG, "[deallocate] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] deallocate()");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void stopAllOperation() {
        try {
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.stopAllOperation();
            } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                mV40IFCCD.stopAllOperation();
            } else {
                Log.w(TAG, "[stopAllOperation] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] stopAllOperation()");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    boolean bComposite = false;   // true: 로비, false: 현관
    public void setComposite(boolean bEnable) {
        try {
            bEnable = true; //VIP 경우 현관 아날로그 통화가 없음. 그래서 false 로 들어오더라도 true 로 강제 변환
            Log.d(TAG, "[setComposite] bEnable [" + bEnable + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                mV40IFCCD.composite(1);
                //if (bEnable) mV40IFCCD.composite(1);
                //else mV40IFCCD.composite(0); //VIP 경우 현관 아날로그 통화가 없음.
            } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                // true : 로비통화, false : 현관통화
                bComposite = bEnable;
                mV40IFCCD.composite(1);
                //if (bEnable) mV40IFCCD.composite(1);   // 로비통화
                //else mV40IFCCD.composite(0);   //VIP 경우 현관 아날로그 통화가 없음.
            } else {
                Log.w(TAG, "[setComposite] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setComposite(boolean bEnable)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public Bitmap getMoIPPicture(CallManager.CALLTYPE eCallType) {
        try {
            Log.d(TAG, "[getMoIPPicture] eCallType [" + eCallType + "]");
            if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                if (mV40IFCCD != null) return mV40IFCCD.getDecodedPicture(eCallType);
                else {
                    Log.d(TAG, "[getMoIPPicture] mV40IFCCD is null!!");
                    return null;
                }
            } else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                if (mV40IFCCD != null) return mV40IFCCD.getDecodedPicture(eCallType);
                else {
                    Log.d(TAG, "[getMoIPPicture] mV40IFCCD is null!!");
                    return null;
                }
            } else {
                Log.w(TAG, "[getMoIPPicture] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] getMoIPPicture()");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
        return null;
    }

/* ================================================================================================
 * SW Codec 함수
 ================================================================================================ */

    boolean bSWDecoderRun = false;
    public void SWDecoderInit(Surface surface, int width, int height) {
        try {
            Log.i(TAG, "[SWDecoderInit] bSWDecoderRun [" + bSWDecoderRun + "]");
            if (!bSWDecoderRun) {
                bSWDecoderRun = true;
                mV40IFCCD.SWDecoderInit(surface, width, height);
            }
            else {
                Log.w(TAG, "[SWDecoderInit] SW decoder already run!!");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] SWDecoderInit(Surface surface, int width, int height)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void SWDecoderClose(int nTraceNo) {
        try {
            Log.i(TAG, "[SWDecoderClose] bSWDecoderRun [" + bSWDecoderRun + "], nTraceNo [" + nTraceNo + "]");
            if (bSWDecoderRun) {
                bSWDecoderRun = false;
                mV40IFCCD.SWDecoderClose();
            }
            else {
                Log.w(TAG, "[SWDecoderClose] SW decoder already stop!!");
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] SWDecoderClose(int nTraceNo)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }

    public void SWSendDataToDecoder(byte[] hData, int nFrameLen) {
        try {
            Log.v(TAG, "[SWSendDataToDecoder] SWDecoderStarted [" + SWDecoderStarted + "], hData.length [" + hData.length + "], nFrameLen [" + nFrameLen + "]");
            if (SWDecoderStarted) {
                if (BOARDTYPE == BOARD_TYPE.V40_IGW300 || BOARDTYPE == BOARD_TYPE.V40) {
                    //Log.d(TAG, "[SWSendDataToDecoder] START nFrameLen:" + nFrameLen);
                    mV40IFCCD.SWSendDataToDecoder(hData, nFrameLen);
                }
                else if (BOARDTYPE == BOARD_TYPE.V40_IGW300_NOUGAT || BOARDTYPE == BOARD_TYPE.V40_NOUGAT) {
                    //Log.d(TAG, "[SWSendDataToDecoder] START nFrameLen:" + nFrameLen);
                    mV40IFCCD.SWSendDataToDecoder(hData, nFrameLen);
                }
                else {
                    Log.w(TAG, "[SWSendDataToDecoder] Not supported BOARDTYPE!! [" + BOARDTYPE + "]");
                }
            }
        } catch (RuntimeException re) {
            LogUtil.errorLogInfo("", TAG, re);
        } catch (Exception e) {
            Log.e(TAG, "[Exception] SWSendDataToDecoder(byte[] hData, int nFrameLen)");
            //e.printStackTrace();
            LogUtil.errorLogInfo("", TAG, e);
        }
    }
}