///////////////////////////////////////////////////////////////////////
// File:        lm_pain_points.h
// Description: Functions that utilize the knowledge about the properties
//              of the paths explored by the segmentation search in order
//              to generate "pain points" - the locations in the ratings
//              matrix which should be classified next.
// Author:      Rika Antonova
// Created:     Mon Jun 20 11:26:43 PST 2012
//
// (C) Copyright 2012, Google Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////

#ifndef TESSERACT_WORDREC_PAIN_POINTS_H_
#define TESSERACT_WORDREC_PAIN_POINTS_H_

#include "associate.h"
#include "dict.h"
#include "genericheap.h"
#include "lm_state.h"

namespace tesseract {

// Heap of pain points used for determining where to chop/join.
typedef GenericHeap<MatrixCoordPair> PainPointHeap;

// Types of pain points (ordered in the decreasing level of importance).
enum LMPainPointsType {
  LM_PPTYPE_BLAMER,
  LM_PPTYPE_AMBIG,
  LM_PPTYPE_PATH,
  LM_PPTYPE_SHAPE,

  LM_PPTYPE_NUM
};

static const char * const LMPainPointsTypeName[] = {
    "LM_PPTYPE_BLAMER",
    "LM_PPTYPE_AMBIGS",
    "LM_PPTYPE_PATH",
    "LM_PPTYPE_SHAPE",
};

class LMPainPoints {
 public:

  static const float kDefaultPainPointPriorityAdjustment;
  // If there is a significant drop in character ngram probability or a
  // dangerous ambiguity make the thresholds on what blob combinations
  // can be classified looser.
  static const float kLooseMaxCharWhRatio;
  // Returns a description of the type of a pain point.
  static const char* PainPointDescription(LMPainPointsType type) {
    return LMPainPointsTypeName[type];
  }

  LMPainPoints(int max, float rat, bool fp, const Dict *d, int deb) :
    max_heap_size_(max), max_char_wh_ratio_(rat), fixed_pitch_(fp),
    dict_(d), debug_level_(deb) {}
  ~LMPainPoints() {}

  // Returns true if the heap of pain points of pp_type is not empty().
  inline bool HasPainPoints(LMPainPointsType pp_type) const {
    return !pain_points_heaps_[pp_type].empty();
  }

  // Dequeues the next pain point from the pain points queue and copies
  // its contents and priority to *pp and *priority.
  // Returns LM_PPTYPE_NUM if pain points queue is empty, otherwise the type.
  LMPainPointsType Deque(MATRIX_COORD *pp, float *priority);

  // Clears pain points heap.
  void Clear() {
    for (int h = 0; h < LM_PPTYPE_NUM; ++h) pain_points_heaps_[h].clear();
  }

  // For each cell, generate a "pain point" if the cell is not classified
  // and has a left or right neighbor that was classified.
  void GenerateInitial(WERD_RES *word_res);

  // Generate pain points from the given path.
  void GenerateFromPath(float rating_cert_scale, ViterbiStateEntry *vse,
                        WERD_RES *word_res);

  // Generate pain points from dangerous ambiguities in best choice.
  void GenerateFromAmbigs(const DANGERR &fixpt, ViterbiStateEntry *vse,
                          WERD_RES *word_res);

  // Generate a pain point for the blamer.
  bool GenerateForBlamer(double max_char_wh_ratio, WERD_RES *word_res,
                         int col, int row) {
    return GeneratePainPoint(col, row, LM_PPTYPE_BLAMER, 0.0, false,
                             max_char_wh_ratio, word_res);
  }

  // Adds a pain point to classify chunks_record->ratings(col, row).
  // Returns true if a new pain point was added to an appropriate heap.
  // Pain point priority is set to special_priority for pain points of
  // LM_PPTYPE_AMBIG or LM_PPTYPE_PATH, for other pain points
  // AssociateStats::gap_sum is used.
  bool GeneratePainPoint(int col, int row, LMPainPointsType pp_type,
                         float special_priority, bool ok_to_extend,
                         float max_char_wh_ratio,
                         WERD_RES *word_res);

  // Adjusts the pain point coordinates to cope with expansion of the ratings
  // matrix due to a split of the blob with the given index.
  void RemapForSplit(int index);

 private:
  // Priority queues containing pain points generated by the language model
  // The priority is set by the language model components, adjustments like
  // seam cost and width priority are factored into the priority.
  PainPointHeap pain_points_heaps_[LM_PPTYPE_NUM];
  // Maximum number of points to keep in the heap.
  int max_heap_size_;
  // Maximum character width/height ratio.
  float max_char_wh_ratio_;
  // Set to true if fixed pitch should be assumed.
  bool fixed_pitch_;
  // Cached pointer to dictionary.
  const Dict *dict_;
  // Debug level for print statements.
  int debug_level_;
};

}  // namespace tesseract

#endif  // TESSERACT_WORDREC_PAIN_POINTS_H_
