/* The copyright in this software is being made available under the BSD
 * License, included below. This software may be subject to other third party
 * and contributor rights, including patent rights, and no such rights are
 * granted under this license.
 *
 * Copyright (c) 2010-2020, ITU/ISO/IEC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
 *    be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

/** \file     CrossCompPrediction.cpp
    \brief    cross component prediction class
*/

#include "CrossCompPrediction.h"

#include "Unit.h"
#include "CommonDef.h"
#include "CodingStructure.h"
#include "Slice.h"

//! \ingroup CommonLib
//! \{

int8_t CrossComponentPrediction::xCalcCrossComponentPredictionAlpha( TransformUnit &tu, const ComponentID &compID, bool useRecoResidual )
{
  const CPelBuf pResiL = useRecoResidual ? tu.cs->getResiBuf( tu.Y() ) : tu.cs->getOrgResiBuf( tu.Y() );
  const CPelBuf pResiC = tu.cs->getResiBuf( tu.blocks[compID] );

  const int diffBitDepth = tu.cs->sps->getDifferentialLumaChromaBitDepth();

  int8_t alpha = 0;
  int SSxy = 0;
  int SSxx = 0;

  for( uint32_t uiY = 0; uiY < pResiL.height; uiY++ )
  {
    for( uint32_t uiX = 0; uiX < pResiL.width; uiX++ )
    {
      const Pel scaledResiL = rightShift( pResiL.at( uiX, uiY ), diffBitDepth );
      SSxy += ( scaledResiL * pResiC.at( uiX, uiY ) );
      SSxx += ( scaledResiL * scaledResiL );
    }
  }

  if( SSxx != 0 )
  {
    double dAlpha = SSxy / double( SSxx );
    alpha = int8_t( Clip3<int>( -16, 16, ( int ) ( dAlpha * 16 ) ) );

    static const int8_t alphaQuant[17] = { 0, 1, 1, 2, 2, 2, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8 };

    alpha = ( alpha < 0 ) ? -alphaQuant[int( -alpha )] : alphaQuant[int( alpha )];
  }

  tu.compAlpha[compID] = alpha;

  return alpha;
}


void CrossComponentPrediction::crossComponentPrediction(        TransformUnit &tu,
                                                          const ComponentID   &compID,
                                                          const CPelBuf       &piResiL,
                                                          const CPelBuf       &piResiC,
                                                                PelBuf        &piResiT,
                                                          const bool          &reverse )
{
  const int alpha = tu.compAlpha[compID];
  const int diffBitDepth = tu.cs->sps->getDifferentialLumaChromaBitDepth();

#if !RExt__HIGH_BIT_DEPTH_SUPPORT
  ClpRng clpRng; //not limited by adaptive clipping
  clpRng.min = std::numeric_limits<Pel>::min();
  clpRng.max = std::numeric_limits<Pel>::max();
#endif

  for( int y = 0; y < piResiT.height; y++ )
  {
    if( reverse )
    {
      // A constraint is to be added to the HEVC Standard to limit the size of pResiL and pResiC at this point.
      // The likely form of the constraint is to either restrict the values to CoeffMin to CoeffMax,
      // or to be representable in a bitDepthY+4 or bitDepthC+4 signed integer.
      //  The result of the constraint is that for 8/10/12bit profiles, the input values
      //  can be represented within a 16-bit Pel-type.
#if RExt__HIGH_BIT_DEPTH_SUPPORT
      for( int x = 0; x < piResiT.width; x++ )
      {
        piResiT.at( x, y ) = piResiC.at( x, y ) + ( ( alpha * rightShift( piResiL.at( x, y ), diffBitDepth ) ) >> 3 );
      }
#else
      for( int x = 0; x < piResiT.width; x++ )
      {
        piResiT.at( x, y ) = ClipPel<int>( piResiC.at( x, y ) + ( ( alpha * rightShift<int>( int( piResiL.at( x, y ) ), diffBitDepth ) ) >> 3 ), clpRng );
      }
#endif
    }
    else
    {
      // Forward does not need clipping. Pel type should always be big enough.
      for( int x = 0; x < piResiT.width; x++ )
      {
        piResiT.at( x, y ) = piResiC.at( x, y ) - ( ( alpha * rightShift<int>( int( piResiL.at( x, y ) ), diffBitDepth ) ) >> 3 );
      }
    }
  }
}
