//--------------------------------------------------------------------------------------------------
/// 
//--------------------------------------------------------------------------------------------------
RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator(
    RimEclipseCellColors* cellResultColors, 
    RimTernaryLegendConfig* ternaryLegendConfig,
    size_t timeStepIndex, 
    size_t gridIndex, 
    const cvf::StructGridQuadToCellFaceMapper* quadMapper)
{
    CVF_ASSERT(quadMapper);
    m_quadMapper = quadMapper;

    RigEclipseCaseData* eclipseCase = cellResultColors->reservoirView()->eclipseCase()->eclipseCaseData();

    size_t resTimeStepIdx = timeStepIndex;

    if (cellResultColors->hasStaticResult()) resTimeStepIdx = 0;

    RiaDefines::PorosityModelType porosityModel = cellResultColors->porosityModel();

    cvf::ref<RigResultAccessor> soil = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, RigEclipseResultAddress("SOIL"));
    cvf::ref<RigResultAccessor> sgas = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, RigEclipseResultAddress("SGAS"));
    cvf::ref<RigResultAccessor> swat = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, RigEclipseResultAddress("SWAT"));

    m_resultAccessor = new RigTernaryResultAccessor();
    m_resultAccessor->setTernaryResultAccessors(soil.p(), sgas.p(), swat.p());

    cvf::ref<RigPipeInCellEvaluator> pipeInCellEval = 
        new RigPipeInCellEvaluator(cellResultColors->reservoirView()->wellCollection()->resultWellGeometryVisibilities(timeStepIndex),
                                   eclipseCase->gridCellToResultWellIndex(gridIndex));

    const RivTernaryScalarMapper* mapper = ternaryLegendConfig->scalarMapper();

    m_texMapper = new RivTernaryResultToTextureMapper(mapper, pipeInCellEval.p());
    CVF_ASSERT(m_texMapper.notNull());
}
//--------------------------------------------------------------------------------------------------
/// 
//--------------------------------------------------------------------------------------------------
void RivCellEdgeGeometryUtils::addCellEdgeResultsToDrawableGeo(
    size_t timeStepIndex,
    RimEclipseCellColors* cellResultColors,
    RimCellEdgeColors* cellEdgeResultColors,
    const cvf::StructGridQuadToCellFaceMapper* quadToCellFaceMapper,
    cvf::DrawableGeo* geo,
    size_t gridIndex,
    bool useDefaultValueForHugeVals,
    float opacityLevel)
{
    RigEclipseCaseData* eclipseCase = cellResultColors->reservoirView()->eclipseCase()->eclipseCaseData();
    CVF_ASSERT(eclipseCase != nullptr);

    // Create result access objects

    cvf::ref<RigResultAccessor> cellCenterDataAccessObject = createCellCenterResultAccessor(cellResultColors, timeStepIndex, eclipseCase, eclipseCase->grid(gridIndex));
    cvf::ref<RigResultAccessor> cellEdgeResultAccessor = createCellEdgeResultAccessor(cellResultColors, cellEdgeResultColors, timeStepIndex, eclipseCase, eclipseCase->grid(gridIndex));

    size_t vertexCount = geo->vertexArray()->size();
    size_t quadCount = vertexCount / 4;

    cvf::ref<cvf::Vec2fArray> localCoords = new cvf::Vec2fArray;
    localCoords->resize(vertexCount);

    cvf::ref<cvf::IntArray> faceIndexArray = new cvf::IntArray;
    faceIndexArray->resize(vertexCount);

    cvf::ref<cvf::FloatArray> cellColorTextureCoordArray = new cvf::FloatArray;
    cellColorTextureCoordArray->resize(vertexCount);

    // Build six cell face color arrays
    cvf::Collection<cvf::FloatArray> cellEdgeColorTextureCoordsArrays;
    size_t idx;
    for (idx = 0; idx < 6; idx++)
    {
        cvf::ref<cvf::FloatArray> colorArray = new cvf::FloatArray;
        colorArray->resize(vertexCount);
        cellEdgeColorTextureCoordsArrays.push_back(colorArray.p());
    }

    cvf::ScalarMapper* cellResultScalarMapper = cellResultColors->legendConfig()->scalarMapper();
    cvf::ScalarMapper* edgeResultScalarMapper = cellEdgeResultColors->legendConfig()->scalarMapper();

    double ignoredScalarValue = cellEdgeResultColors->ignoredScalarValue();

    const std::vector<cvf::ubyte>* isWellPipeVisible = nullptr;
    cvf::cref<cvf::UIntArray>      gridCellToWellindexMap;

    if (opacityLevel < 1.0f)
    {
        isWellPipeVisible = &(cellResultColors->reservoirView()->wellCollection()->resultWellGeometryVisibilities(timeStepIndex));
        gridCellToWellindexMap = eclipseCase->gridCellToResultWellIndex(gridIndex);
    }

#pragma omp parallel for
    for (int quadIdx = 0; quadIdx < static_cast<int>(quadCount); quadIdx++)
    {
        localCoords->set(quadIdx * 4 + 0, cvf::Vec2f(0, 0));
        localCoords->set(quadIdx * 4 + 1, cvf::Vec2f(1, 0));
        localCoords->set(quadIdx * 4 + 2, cvf::Vec2f(1, 1));
        localCoords->set(quadIdx * 4 + 3, cvf::Vec2f(0, 1));

        faceIndexArray->set(quadIdx * 4 + 0, quadToCellFaceMapper->cellFace(quadIdx));
        faceIndexArray->set(quadIdx * 4 + 1, quadToCellFaceMapper->cellFace(quadIdx));
        faceIndexArray->set(quadIdx * 4 + 2, quadToCellFaceMapper->cellFace(quadIdx));
        faceIndexArray->set(quadIdx * 4 + 3, quadToCellFaceMapper->cellFace(quadIdx));

        size_t cellIndex = quadToCellFaceMapper->cellIndex(quadIdx);
        {
            cvf::StructGridInterface::FaceType cellFace = quadToCellFaceMapper->cellFace(quadIdx);
            double scalarValue = cellCenterDataAccessObject->cellFaceScalar(cellIndex, cellFace);

            {
                float cellColorTextureCoord = 0.5f; // If no results exists, the texture will have a special color
                if (useDefaultValueForHugeVals || scalarValue != HUGE_VAL)
                {
                    if (scalarValue != HUGE_VAL)
                    {
                        cellColorTextureCoord = cellResultScalarMapper->mapToTextureCoord(scalarValue)[0];
                    }

                    // If we are dealing with wellcells, the default is transparent.
                    // we need to make cells opaque if there are no wellpipe through them.
                    if (opacityLevel < 1.0f)
                    {
                        cvf::uint wellIndex = gridCellToWellindexMap->get(cellIndex);
                        if (wellIndex != cvf::UNDEFINED_UINT)
                        {
                            if (!(*isWellPipeVisible)[wellIndex])
                            {
                                cellColorTextureCoord += 2.0f; // The shader must interpret values in the range 2-3 as "opaque"
                            }
                        }
                    }
                }
                else
                {
                    cellColorTextureCoord = -1.0f; // Undefined texture coord. Shader handles this.
                }

                cellColorTextureCoordArray->set(quadIdx * 4 + 0, cellColorTextureCoord);
                cellColorTextureCoordArray->set(quadIdx * 4 + 1, cellColorTextureCoord);
                cellColorTextureCoordArray->set(quadIdx * 4 + 2, cellColorTextureCoord);
                cellColorTextureCoordArray->set(quadIdx * 4 + 3, cellColorTextureCoord);
            }
        }


        for (size_t cubeFaceIdx = 0; cubeFaceIdx < 6; cubeFaceIdx++)
        {
            float edgeColor = -1.0f; // Undefined texture coord. Shader handles this.

            double scalarValue = cellEdgeResultAccessor->cellFaceScalar(cellIndex, static_cast<cvf::StructGridInterface::FaceType>(cubeFaceIdx));

            if (!hideScalarValue(scalarValue, ignoredScalarValue, 1e-2))
            {
                edgeColor = edgeResultScalarMapper->mapToTextureCoord(scalarValue)[0];
            }

            cvf::FloatArray* colArr = cellEdgeColorTextureCoordsArrays.at(cubeFaceIdx);

            colArr->set(quadIdx * 4 + 0, edgeColor);
            colArr->set(quadIdx * 4 + 1, edgeColor);
            colArr->set(quadIdx * 4 + 2, edgeColor);
            colArr->set(quadIdx * 4 + 3, edgeColor);
        }
    }

    geo->setVertexAttribute(new cvf::Vec2fVertexAttribute("a_localCoord", localCoords.p()));
    geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorCell", cellColorTextureCoordArray.p()));

    cvf::ref<cvf::IntVertexAttributeDirect> faceIntAttribute = new cvf::IntVertexAttributeDirect("a_face", faceIndexArray.p());
    geo->setVertexAttribute(faceIntAttribute.p());

    geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorPosI", cellEdgeColorTextureCoordsArrays.at(0)));
    geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorNegI", cellEdgeColorTextureCoordsArrays.at(1)));
    geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorPosJ", cellEdgeColorTextureCoordsArrays.at(2)));
    geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorNegJ", cellEdgeColorTextureCoordsArrays.at(3)));
    geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorPosK", cellEdgeColorTextureCoordsArrays.at(4)));
    geo->setVertexAttribute(new cvf::FloatVertexAttribute("a_colorNegK", cellEdgeColorTextureCoordsArrays.at(5)));
}