/* 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-2017, 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     dtrace_blockstatistics.h
 *  \brief    DTrace block statistcis support for next software
 */

#ifndef _DTRACE_BLOCKSTATISTICS_H_
#define _DTRACE_BLOCKSTATISTICS_H_

#include <map>
#include "CommonLib/CommonDef.h"
#include "CommonLib/Unit.h"

#if ENABLE_BLOCK_STATS
#define DTRACE_HEADER(ctx,...) ctx->dtrace_header( __VA_ARGS__ )
#define DTRACE_BLOCK_SCALAR(ctx,channel,cs_cu_pu,stat_type,val)      ctx->dtrace_block_scalar( channel, cs_cu_pu, stat_type, val )
#define DTRACE_BLOCK_VECTOR(ctx,channel,cu_pu,stat_type,v_x,v_y)  ctx->dtrace_block_vector( channel, cu_pu, stat_type, v_x, v_y )
#define DTRACE_BLOCK_AFFINETF(ctx,channel,pu,stat_type,v_x0,v_y0,v_x1,v_y1,v_x2,v_y2)  ctx->dtrace_block_affinetf( channel, pu, stat_type, v_x0, v_y0, v_x1, v_y1, v_x2, v_y2 )

enum class BlockStatistic {
  PredMode,
  MergeFlag,
  MVL0,
  MVL1,
  IPCM,
  Y_IntraMode,
  Cb_IntraMode,
  Cr_IntraMode,
  SkipFlag,
  PartSize,
  Depth,
  QT_Depth,
  BT_Depth,
  MT_Depth,
  ChromaQPAdj,
  QP,
  SplitSeries,
  RootCBF,
  TransQuantBypassFlag,
  MergeIdx,
  InterDir,
  MergeType,
  MVPIdxL0,
  MVPNumL0,
  MVDL0,
  RefIdxL0,
  MVPIdxL1,
  MVPNumL1,
  MVDL1,
  RefIdxL1,
#if JEM_TOOLS
  IMVFlag,
  FrucMrgMode,
  AffineFlag,
  AffineMVL0,
  AffineMVL1,
  EMTFlag, // this is called flag, though the type is UChar ?!
  LICFlag,
  OBMCFlag,
  MVRefineFlag,
  PDPCFlag,
  NSSTIdx,
#endif
  NumBlockStatistics,
};

enum class BlockStatisticType {
  Flag,
  Vector,
  Integer,
  AffineTFVectors,
};

static const std::map<BlockStatistic, std::tuple<std::string, BlockStatisticType, std::string>> blockstatistic2description =
{
  // Statistics enum                                                                                Statistics name string         Statistic Type                              Type specific information:
  //                                                                                                                                                                           Value range, vector scale
  { BlockStatistic::PredMode,               std::tuple<std::string, BlockStatisticType, std::string>{"PredMode",                    BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::MergeFlag,              std::tuple<std::string, BlockStatisticType, std::string>{"MergeFlag",                   BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::MVL0,                   std::tuple<std::string, BlockStatisticType, std::string>{"MVL0",                        BlockStatisticType::Vector,                 "Scale: 4"}}, // todo: what about high precision. can this be automatic
  { BlockStatistic::MVL1,                   std::tuple<std::string, BlockStatisticType, std::string>{"MVL1",                        BlockStatisticType::Vector,                 "Scale: 4"}}, // todo: what about high precision. can this be automatic
  { BlockStatistic::IPCM,                   std::tuple<std::string, BlockStatisticType, std::string>{"IPCM",                        BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::Y_IntraMode,            std::tuple<std::string, BlockStatisticType, std::string>{"Y_IntraMode",                 BlockStatisticType::Integer,                "[0, " + std::to_string(NUM_INTRA_MODE) + "]"}},
  { BlockStatistic::Cb_IntraMode,           std::tuple<std::string, BlockStatisticType, std::string>{"Cb_IntraMode",                BlockStatisticType::Integer,                "[0, " + std::to_string(NUM_INTRA_MODE) + "]"}},
  { BlockStatistic::Cr_IntraMode,           std::tuple<std::string, BlockStatisticType, std::string>{"Cr_IntraMode",                BlockStatisticType::Integer,                "[0, " + std::to_string(NUM_INTRA_MODE) + "]"}},
  { BlockStatistic::SkipFlag,               std::tuple<std::string, BlockStatisticType, std::string>{"SkipFlag",                    BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::PartSize,               std::tuple<std::string, BlockStatisticType, std::string>{"PartSize",                    BlockStatisticType::Integer,                "[0, " + std::to_string(NUMBER_OF_PART_SIZES) + "]"}},
  { BlockStatistic::Depth,                  std::tuple<std::string, BlockStatisticType, std::string>{"Depth",                       BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::QT_Depth,               std::tuple<std::string, BlockStatisticType, std::string>{"QT_Depth",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::BT_Depth,               std::tuple<std::string, BlockStatisticType, std::string>{"BT_Depth",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::MT_Depth,               std::tuple<std::string, BlockStatisticType, std::string>{"MT_Depth",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::ChromaQPAdj,            std::tuple<std::string, BlockStatisticType, std::string>{"ChromaQPAdj",                 BlockStatisticType::Integer,                "[-10, 10]"}}, // todo: actual limits?
  { BlockStatistic::QP,                     std::tuple<std::string, BlockStatisticType, std::string>{"QP",                          BlockStatisticType::Integer,                "[0, 51]"}},
  { BlockStatistic::SplitSeries,            std::tuple<std::string, BlockStatisticType, std::string>{"SplitSeries",                 BlockStatisticType::Integer,                "[0, " + std::to_string(std::numeric_limits<SplitSeries>::max()) + "]"}},
  { BlockStatistic::RootCBF,                std::tuple<std::string, BlockStatisticType, std::string>{"RootCBF",                     BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::TransQuantBypassFlag,   std::tuple<std::string, BlockStatisticType, std::string>{"TransQuantBypassFlag",        BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::MergeIdx,               std::tuple<std::string, BlockStatisticType, std::string>{"MergeIdx",                    BlockStatisticType::Integer,                "[0, " + std::to_string(MAX_UCHAR) + "]"}},
  { BlockStatistic::InterDir,               std::tuple<std::string, BlockStatisticType, std::string>{"InterDir",                    BlockStatisticType::Integer,                "[0, " + std::to_string(MAX_UCHAR) + "]"}},
  { BlockStatistic::MergeType,              std::tuple<std::string, BlockStatisticType, std::string>{"MergeType",                   BlockStatisticType::Integer,                "[0, " + std::to_string(NUM_MRG_TYPE) + "]"}},
  { BlockStatistic::MVPIdxL0,               std::tuple<std::string, BlockStatisticType, std::string>{"MVPIdxL0",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::MVPNumL0,               std::tuple<std::string, BlockStatisticType, std::string>{"MVPNumL0",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::MVDL0,                  std::tuple<std::string, BlockStatisticType, std::string>{"MVDL0",                       BlockStatisticType::Vector,                 "Scale: 4"}}, // todo: what about high precision. can this be automatic
  { BlockStatistic::RefIdxL0,               std::tuple<std::string, BlockStatisticType, std::string>{"RefIdxL0",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::MVPIdxL1,               std::tuple<std::string, BlockStatisticType, std::string>{"MVPIdxL1",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::MVPNumL1,               std::tuple<std::string, BlockStatisticType, std::string>{"MVPNumL1",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::MVDL1,                  std::tuple<std::string, BlockStatisticType, std::string>{"MVDL1",                       BlockStatisticType::Vector,                 "Scale: 4"}}, // todo: what about high precision. can this be automatic
  { BlockStatistic::RefIdxL1,               std::tuple<std::string, BlockStatisticType, std::string>{"RefIdxL1",                    BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
#if JEM_TOOLS
  { BlockStatistic::IMVFlag,                std::tuple<std::string, BlockStatisticType, std::string>{"IMVFlag",                     BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::FrucMrgMode,            std::tuple<std::string, BlockStatisticType, std::string>{"FrucMrgMode",                 BlockStatisticType::Integer,                "[0, " + std::to_string(FRUC_MERGE_TEMPLATE) + "]"}}, // not sure about this one
  { BlockStatistic::AffineFlag,             std::tuple<std::string, BlockStatisticType, std::string>{"AffineFlag",                  BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::AffineMVL0,             std::tuple<std::string, BlockStatisticType, std::string>{"AffineMVL0",                  BlockStatisticType::AffineTFVectors,        "Scale: 4"}}, // todo: what about high precision. can this be automatic
  { BlockStatistic::AffineMVL1,             std::tuple<std::string, BlockStatisticType, std::string>{"AffineMVL1",                  BlockStatisticType::AffineTFVectors,        "Scale: 4"}}, // todo: what about high precision. can this be automatic
  { BlockStatistic::EMTFlag,                std::tuple<std::string, BlockStatisticType, std::string>{"EMTFlag",                     BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
  { BlockStatistic::LICFlag,                std::tuple<std::string, BlockStatisticType, std::string>{"LICFlag",                     BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::OBMCFlag,               std::tuple<std::string, BlockStatisticType, std::string>{"OBMCFlag",                    BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::MVRefineFlag,           std::tuple<std::string, BlockStatisticType, std::string>{"MVRefineFlag",                BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::PDPCFlag,               std::tuple<std::string, BlockStatisticType, std::string>{"PDPCFlag",                    BlockStatisticType::Flag,                   ""}},
  { BlockStatistic::NSSTIdx,                std::tuple<std::string, BlockStatisticType, std::string>{"NSSTIdx",                     BlockStatisticType::Integer,                "[0, 10]"}}, // todo: actual limits?
#endif
};


std::string GetBlockStatisticName(BlockStatistic statistic);
std::string GetBlockStatisticTypeString(BlockStatistic statistic);
std::string GetBlockStatisticTypeSpecificInfo(BlockStatistic statistic);

void writeBlockStatisticsHeader(const SPS *sps);
void getAndStoreBlockStatistics(const CodingStructure& cs, const UnitArea& ctuArea);
#endif

#endif // _DTRACE_BLOCKSTATISTICS_H_
