#include "AVM.h"
#include "CELLMath.h"
#include "Common.h"
#include "Car.h"
#include "Bowl.h"
#include "Calibration.h"
#include "Avm_3DRender.h"
#include "PlanView.h"
#include "Line.h"

#define MODULE_NAME "AVM_Render"
#define AVM_INFO_SWITCH         1
#define AVM_DEBUG_SWITCH        0
#define AVM_LOCATION_SWITCH     1
#include "Avm_log.h"


#define CALIBRATION
#define AUTOMOVE_DEBUG          0

#define NUM_WINDOWS    2

#ifdef CALIBRATION
#define QUARDI_START_X    10
#define QUARDI_START_Y    10
#define QUARDI_WIDTH      1280
#define QUARDI_HEIGHT     720
Coord g_stOfflineCorner[4][23];
#endif

static OVSBasicInfo g_stOVSBasicInfo;
float verQuadri[32] = {
    //top-left
    -1.0,  1.0,
    -1.0,  0.0,
     0.0,  1.0,
     0.0,  0.0,

    //top-right
     0.0,  1.0,
     0.0,  0.0,
     1.0,  1.0,
     1.0,  0.0,

    //bottom-left
    -1.0,  0.0,
    -1.0, -1.0,
     0.0,  0.0,
     0.0, -1.0,

    //bottom-right
     0.0,  0.0,
     0.0, -1.0,
     1.0,  0.0,
     1.0, -1.0
};

float verPic[8] = {
    -1.0,  1.0,
    -1.0, -1.0,
     1.0,  1.0,
     1.0, -1.0
};
float texPic[8] = {
    0.0, 1.0,
    0.0, 0.0,
    1.0, 1.0,
    1.0, 0.0
};


/*****************functions Lev 2**********************************/


/*输入的摄像头视频[0-3]:前-后-左-右
*输出的图像纹理ID[0-3]:左-右-前-后，函数内部做了顺序的调整*/
bool funLoadVideo(void **videoBuffer, int width, int height, GLuint *videoTexID)
{
    bool ret = FALSE;
    UInt retCount = 0;
    int i=0;
    int tmpA, tmpB;

    do
    {
        for (i=0; i<4; i++)
        {
            if (FALSE == loadTexture(&videoTexID[i], videoBuffer[i], width, height, 1))
            {
                retCount++;
                AVM_ERROR("failed to load video texture[%d]\n", i);
            }
        }

        //swap: (0-front/1-rear/2-left/3-right) ---> (0-left/1-right/2-front/3-rear)
        tmpA = videoTexID[0];
        tmpB = videoTexID[1];
        videoTexID[0] = videoTexID[2];
        videoTexID[1] = videoTexID[3];
        videoTexID[2] = tmpA;
        videoTexID[3] = tmpB;

        ret = (0 == retCount) ? TRUE : FALSE;
    } while(0);

    return ret;
}


/*
*绘制前后左右原图
*/
void funRenderOrignalView( avmViewState avmWhitchView, GLuint *texid_Ori )
{
    static GLuint renderTexID[4] = {0, 0, 0, 0};
    int i = 0;

    renderTexID[0] = texid_Ori[2];      //front
    renderTexID[1] = texid_Ori[3];      //rear
    renderTexID[2] = texid_Ori[0];      //left
    renderTexID[3] = texid_Ori[1];      //right

    switch (avmWhitchView)
    {
        case AVM_DISPLAY_STATE_QUADRI_GRID:
            for (i=0; i<4; i++)
            {
                PlaneOriginalRender(renderTexID[i], 4, &verQuadri[i*8], texPic, 0);

                lineOfflineCorner(g_stOfflineCorner);
                LineOrigViewMOD(i);
            }
            break;
        case AVM_DISPLAY_STATE_ORIGNAL_FRONT:
            PlaneOriginalRender(renderTexID[0], 4, verPic, texPic, 0);
            LineSaleCaliCorner(0);
            break;
        case AVM_DISPLAY_STATE_ORIGNAL_REAR:
            PlaneOriginalRender(renderTexID[1], 4, verPic, texPic, 0);
            LineSaleCaliCorner(1);
            break;
        case AVM_DISPLAY_STATE_ORIGNAL_LEFT:
            PlaneOriginalRender(renderTexID[2], 4, verPic, texPic, 0);
            LineSaleCaliCorner(2);
            break;
        case AVM_DISPLAY_STATE_ORIGNAL_RIGHT:
            PlaneOriginalRender(renderTexID[3], 4, verPic, texPic, 0);
            LineSaleCaliCorner(3);
            break;
        default:
            PlaneOriginalRender(renderTexID[0], 4, verPic, texPic, 0);
            LineSaleCaliCorner(0);
            break;
    }
}


void funTracksRender ( OVSBasicInfo *pOVSBasicInfo, avmViewState WhitchView, VehicleSignal* pstVehicleSignal, int line_on )
{
    enumTracks trackType = TRACKS_NONE;

    if (line_on)
    {
        trackType = SetPlaneTracksType(WhitchView);
        if (100 != trackType)
        {
            LineTracksRender(pOVSBasicInfo, trackType, pstVehicleSignal);
        }
    }
}

/*根据输入信号进行逻辑处理，确定应该绘制哪些提示图标*/
void fun2DPicRender ( )
{
    /*1: 控制逻辑，确定绘制哪些提示图标*/
    /* .logic.. */

    /*2: 调用绘图函数进行绘制*/
    PlanePicRender();

}

/*根据输入信号进行逻辑处理，确定应该绘制哪些MOD框 */
void fun2DMODRender ( )
{
    /*1: 逻辑处理*/
    /* ... */

    /*2: 调用MOD框绘制函数进行绘制*/

}

void funRenderUndistView ( avmViewState avmWhitchView, GLuint *texid_Uds, OVSBasicInfo *pOVSBasicInfo, VehicleSignal* pstVehicleSignal, int line_on )
{
    PlaneUndistView(avmWhitchView, texid_Uds);

    funTracksRender(pOVSBasicInfo, avmWhitchView, pstVehicleSignal, line_on);

    fun2DPicRender();

    fun2DMODRender();

}


void fun3DMove ( avmViewState preView, avmViewState curView )
{
    if ((1 == ((preView>>BIT_3D_MOVE)&0x01)) && (1 == ((curView>>BIT_3D_MOVE)&0x01)))
    {
        Set3DMove(1);
    }
    else
    {
        Set3DMove(0);
    }
}


avmViewState autochangeview()
{
    static int tCount = 0;
    static int i = -1;
    static avmViewState arryView[28] =
    {

        AVM_DISPLAY_STATE_QUADRI_GRID,
        AVM_DISPLAY_STATE_ORIGNAL_FRONT,
        AVM_DISPLAY_STATE_ORIGNAL_REAR,
        AVM_DISPLAY_STATE_ORIGNAL_LEFT,
        AVM_DISPLAY_STATE_ORIGNAL_RIGHT,

            AVM_DISPLAY_STATE_3D_TOP,
        AVM_DISPLAY_STATE_3D_FRONT,
        AVM_DISPLAY_STATE_3D_LEFT_FRONT,
        AVM_DISPLAY_STATE_3D_LEFT,
        AVM_DISPLAY_STATE_3D_LEFT_REAR,

        AVM_DISPLAY_STATE_CORRECT_FRONT,
        AVM_DISPLAY_STATE_CORRECT_REAR,
        AVM_DISPLAY_STATE_CORRECT_LEFT,
        AVM_DISPLAY_STATE_CORRECT_RIGHT,
        AVM_DISPLAY_STATE_CORRECT_LR_FRONT,
        AVM_DISPLAY_STATE_CORRECT_LR_REAR,
        AVM_DISPLAY_STATE_CORRECT_180_FRONT,
        AVM_DISPLAY_STATE_CORRECT_180_REAR,
        /*3D View*/

        AVM_DISPLAY_STATE_3D_REAR,
        AVM_DISPLAY_STATE_3D_RIGHT_REAR,
        AVM_DISPLAY_STATE_3D_RIGHT,
        AVM_DISPLAY_STATE_3D_RIGHT_FRONT,
        AVM_DISPLAY_STATE_3D_TOP_FRONT,
        AVM_DISPLAY_STATE_3D_TOP_REAR,
        AVM_DISPLAY_STATE_3D_LOOKDOWN_FRONT,
        AVM_DISPLAY_STATE_3D_LOOKDOWN_REAR,
        AVM_DISPLAY_STATE_3D_ANYVIEW,
        AVM_DISPLAY_STATE_3D_CRUISE_VIEW,
    };

    if (0 == (tCount%25))
    {
        i = (i+1) % 28;
    }
    tCount++;

    return arryView[i];
}


/*****************functions Lev 1**********************************/
/*
* 1. OpenGL ES create program
* 2. Load files(luts/pictures/carmodel)
* 3. Set default params(algorithm)
*/
#define HUNDREDS_PLACE      1
#define TENS_PLACE          1
#define ONES_PLACE          1
bool avmInit(ConfigFile stConfigFile)
{
    bool ret = FALSE;
    UInt retCount = 0;
    UChar Avm_Version[3];

    do
    {
        {/* set Version*/
            Avm_Version[0] = HUNDREDS_PLACE;
            Avm_Version[1] = TENS_PLACE;
            Avm_Version[2] = ONES_PLACE;
            AVM_INFO("AVM Version:\033[1;32m %d.%d.%d \033[0m\n", Avm_Version[0], Avm_Version[1], Avm_Version[2]);
        }

        Init_OES_State();
        AlgParamInit(stConfigFile.lutsPath, &g_stOVSBasicInfo);

        tmpTexBufMalloc();

        if (FALSE == bowlInit(stConfigFile.lutsPath, g_stOVSBasicInfo))
        {
            retCount++;
            AVM_ERROR("func:bowlInit return failed\n");
        }
        if (FALSE ==carInit(stConfigFile.carModelPath, stConfigFile.picturePath))
        {
            retCount++;
            AVM_ERROR("func:carInit return failed\n");
        }
        if (FALSE == PlanInit(stConfigFile, g_stOVSBasicInfo))
        {
            retCount++;
            AVM_ERROR("func:PlanInit return failed\n");
        }
        LineInit();


        tmpTexBufFree();

        ret = (0 == retCount) ? TRUE : FALSE;
    } while(0);

    return ret;
}

avmViewState *avmRenderer(WindowPos *stWindowPos[], VideoList *stVideoList, CtrlSignal *stCtrlSignal, VehicleSignal *stVehicleSignal, unsigned int *texidYUV)
{
    static avmViewState avmWhitchView = AVM_DISPLAY_STATE_ORIGNAL_FRONT;
    static avmViewState ackViewState[NUM_WINDOWS]  = {AVM_DISPLAY_STATE_NONE, AVM_DISPLAY_STATE_NONE};
    double wbFactor[] = {1.0, 1.0,1.0, 1.0};
    static GLuint CamTex[] = {0, 0, 0, 0};      // 左-右-前-后

#ifndef STANDALONE
    CamTex[0] = texidYUV[0];
    CamTex[1] = texidYUV[1];
    CamTex[2] = texidYUV[2];
    CamTex[3] = texidYUV[3];
#else
    if (FALSE == funLoadVideo(stVideoList->videoBuffer, stVideoList->width, stVideoList->height, CamTex))
    {
        AVM_ERROR("func:funLoadVideo return failed\n");
    }
#endif

    glClearColor(1.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#if AUTOMOVE_DEBUG
    stWindowPos[1]->whitchView = autochangeview();
#endif
    for (int i=0; i<NUM_WINDOWS; i++)
    {
        /* check stWindowPos signal*/
        if ((0 == stWindowPos[i]->valid) || (AVM_DISPLAY_STATE_NONE == stWindowPos[i]->whitchView))
        {
            continue;
        }

        avmWhitchView = stWindowPos[i]->whitchView;
#if AUTOMOVE_DEBUG
        if (stWindowPos[1]->whitchView != ackViewState[1])
        {
            AVM_DEBUG("avmWhitchView=3D[%d]-View[%d]\n", (avmWhitchView>>31)&0x01, (avmWhitchView & 0x0F));
        }
#endif
        /* do White Balance if in 3D View */
        if (1 == ((avmWhitchView >> BIT_2D_3D)&0x01))     //is 3D view ?
        {
            funWBCalculate((UChar**)stVideoList->videoBuffer, stVideoList->camState, wbFactor);
        }

        fun3DMove(ackViewState[i], avmWhitchView);
        /*AVM Render Start*/
        glViewport(stWindowPos[i]->startX, stWindowPos[i]->startY, stWindowPos[i]->width, stWindowPos[i]->height);
        if(0 == ((avmWhitchView>>BIT_2D_3D) & 0x01))
        {
            /*Render 2D View*/
            if (0 == ((avmWhitchView>>BIT_ORI_UND)&0x01))    // is 2D orignal view ?
            {
                funRenderOrignalView(avmWhitchView, CamTex);
            }
            else
            {
                funRenderUndistView(avmWhitchView, CamTex, &g_stOVSBasicInfo, stVehicleSignal, stCtrlSignal->lineOn);
            }
        }
        else
        {
            /*Render 3D View*/
//            PerspectInit(stWindowPos);
            fun3DRender(CamTex, stWindowPos, &g_stOVSBasicInfo, avmWhitchView, stVehicleSignal, stCtrlSignal, wbFactor);
        }

        {
            /*Render Spliters*/
//            SpliterRender();
        }
        ackViewState[i] = avmWhitchView;
        AVM_GL_CHECK("After Render One Window");
    }

    return ackViewState;
}


#ifdef CALIBRATION
/*****************calibration**********************************/
void RenderQuadriView(VideoList *stVideoList)
{
    static GLuint CamTex[4] = {0, 0, 0, 0};      // 左-右-前-后
    static GLuint CamTexOrder[4] = {0, 0, 0, 0};
    int i = 0;

    if (FALSE == funLoadVideo(stVideoList->videoBuffer, stVideoList->width, stVideoList->height, CamTex))
    {
        AVM_ERROR("Load Video error\n");
    }
    CamTexOrder[0] = CamTex[2];
    CamTexOrder[1] = CamTex[3];
    CamTexOrder[2] = CamTex[0];
    CamTexOrder[3] = CamTex[1];

    /*AVM Render start*/
    glClearColor(0.2, 0.4, 0.4, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glViewport(QUARDI_START_X, QUARDI_START_Y, QUARDI_WIDTH, QUARDI_HEIGHT);

    for (i=0; i<4; i++)
    {
        PlaneOriginalRender(CamTexOrder[i], 4, &verQuadri[i*8], texPic, 0);
        lineOfflineCorner(g_stOfflineCorner);
    }
}


bool avmOfflineCalibration(VideoList *stVideoList)
{
    bool ret = FALSE;
    UInt retCount = 0;

    do
    {
        ApicaliInit();
        ApiOfflineCali(stVideoList, g_stOfflineCorner);  //获取角点坐标及内外参
        ApiGenerateLuts();

        if (FALSE == updateLuts())   // 将生成的表格等数据保存到内存和文件中
        {
            AVM_ERROR("failed to update luts\n");
            retCount++;
        }
        RenderQuadriView(stVideoList);     //函数内部死循环，绘制四分格图像 + 绘制识别到的角点

        ret = (0 == retCount) ? TRUE : FALSE;
    } while(0);

    return ret;
}


bool avmSaleCalibration(Corner *pCorner)
{
    bool ret = FALSE;
    UInt retCount = 0;

    do
    {
        ApiSaleCali(pCorner);
        ApiGenerateLuts();
        if (FALSE == updateLuts())   // 将生成的表格等数据保存到内存和文件中
        {
            AVM_ERROR("failed to update luts\n");
            retCount++;
        }

        ret = (0 == retCount) ? TRUE : FALSE;

    } while(0);

    return ret;
}
#endif

