//////////////////////////////////////////////////////////////////////
//
//  FILE:       optable.h
//              OpTable class (for opening reports and theory tables)
//
//  Part of:    Scid (Shane's Chess Information Database)
//  Version:    3.5
//
//  Notice:     Copyright (c) 2001-2003  Shane Hudson.  All rights reserved.
//
//  Author:     Shane Hudson (sgh@users.sourceforge.net)
//
//////////////////////////////////////////////////////////////////////

#ifndef SCID_OPTABLE_H
#define SCID_OPTABLE_H

#include "common.h"
#include "namebase.h"
#include "index.h"
#include "game.h"
#include "pbook.h"

const uint OPTABLE_COLUMNS = 8;
const uint OPTABLE_MIN_ROWS = 5;
const uint OPTABLE_MAX_ROWS = 20;
const uint OPTABLE_DEFAULT_ROWS = 10;
const uint OPTABLE_MAX_EXTRA_MOVES = 10;
const uint OPLINE_MOVES = (OPTABLE_COLUMNS + OPTABLE_MAX_EXTRA_MOVES) * 2;
// If changing the below two, please change them also in optable.tcl
const uint OPTABLE_MAX_LINES       = 100000;
const uint OPTABLE_MAX_TABLE_LINES = 10000;
const uint OPTABLE_MAX_STARTLINE   = 100;

const uint OPTABLE_Text  = 0;
const uint OPTABLE_HTML  = 1;
const uint OPTABLE_LaTeX = 2;
const uint OPTABLE_CText = 3;    // Color hypertext.
const uint OPTABLE_Compact = 4;  // For more compact moves in table.

// Positional themes
const uint NUM_POSTHEMES = 10;
const uint POSTHEME_CastSame  = 0;
const uint POSTHEME_CastOpp   = 1;
const uint POSTHEME_QueenSwap = 2;
const uint POSTHEME_OneBPair  = 3;
const uint POSTHEME_Kstorm    = 4;
const uint POSTHEME_WIQP      = 5;
const uint POSTHEME_BIQP      = 6;
const uint POSTHEME_WAdvPawn  = 7;
const uint POSTHEME_BAdvPawn  = 8;
const uint POSTHEME_OpenFyle  = 9;
const uint POSTHEME_THRESHOLD = 4;  // Theme must occur this many times.

const uint NUM_EGTHEMES = 8;
const uint EGTHEME_P = 0;
const uint EGTHEME_M = 1;
const uint EGTHEME_R = 2;
const uint EGTHEME_RM = 3;
const uint EGTHEME_Q = 4;
const uint EGTHEME_QM = 5;
const uint EGTHEME_QR = 6;
const uint EGTHEME_QRM = 7;

const uint OPTABLE_Line = 0;
const uint OPTABLE_All = 1;


struct moveOrderT {
    uint id;       // Move Order id number
    uint count;    // Number of times this order has occured
    char * moves;  // String containing the moves in SAN notation
};

class OpLine
{
  friend class OpTable;
  private:
    char *      White;
    char *      Black;
    char *      Site;
    gameNumberT GameNumber;
    idNumberT   WhiteID;
    idNumberT   BlackID;
    eloT        WhiteElo;   // Actual White rating (no estimate)
    eloT        BlackElo;   // Actual Black rating
    eloT        AvgElo;     // Average Elo (using actual or estimates)
    dateT       Date;
    resultT     Result;
    uint        Length;
    uint        NumMoves;
    bool        ShortGame;     // True if all game ends early enough that
                               // this line contains all its moves.
    ecoT        EcoCode;
    uint        MoveOrderID;
    sanStringT  Move [OPLINE_MOVES];
    uint        NoteMoveNum;  // If a note, at what move does it start?
    uint        NoteNumber;   // If a note, this stores its footnote number.
    OpLine *    Next;         // Linked list used for sorting and footnotes.
    bool        Selected;     // For selecting lines by some criteria.
    uint        StartPly;

    uint        Theme [NUM_POSTHEMES];
    uint        EgTheme;

    void Init (void);
    void Init (Game * g, IndexEntry * ie, gameNumberT gameNum,
               uint maxExtraMoves, uint maxThemeMoveNumber);
    void Destroy (void);

  public:
    OpLine () { Init(); }
    OpLine (Game * g, IndexEntry * ie, gameNumberT gnum, uint max, uint tm) {
        Init (g, ie, gnum, max, tm);
    }
    ~OpLine() { }
    void SetPositionalThemes (Position * pos);
    void Insert (OpLine * subline);
    void SetMoveOrderID (uint id) { MoveOrderID = id; }
    uint CommonLength (OpLine * line);
    static void PrintMove (DString * dstr, const char * move, uint format);
    void PrintNote (DString * dstr, uint movenum, uint start, uint format);
    void PrintSummary (DString * dstr, uint format, bool fullDate, bool nmoves);

    const char * GetMove (uint depth) { return Move[depth]; }
};


class OpTable
{
  private:
    uint        Base;
    uint        NumRows;
    uint        TargetRows;
    uint        NumLines;
    uint        FilterCount;
    uint        NumTableLines;
    uint        MaxTableLines;
    uint        MaxLines;
    uint        MaxNoteLength;
    uint        MaxThemeMoveNumber;
    uint        NumNotes;
    uint        Format;
    char *      Type;   // "opening" or "player" report
    bool        WTM;    // whether White is to move in the start position.
    sanStringT  StartLine [OPTABLE_MAX_STARTLINE];
    uint        StartLength;
    OpLine *    Line [OPTABLE_MAX_LINES];
    uint        Results [NUM_RESULT_TYPES];
    uint        TheoryResults [NUM_RESULT_TYPES];
    uint        TheoryCount;
    char *      EcoStr;
    sanStringT  ExcludeMove;
    char        DecimalChar;

    // Statistics on material of final positions:
    uint        EndgameCount [2][NUM_EGTHEMES];

    // Statistics on move orders to reach the start line:
    uint        NumMoveOrders;
    moveOrderT  MoveOrder [OPTABLE_MAX_LINES];

    // Statistics on themes:
    uint        ThemeCount [NUM_POSTHEMES];

    // Arrays for making rows out of the lines:
    OpLine *    Row [OPTABLE_MAX_TABLE_LINES];
    uint        NLines [OPTABLE_MAX_TABLE_LINES];
    uint        RowScore [OPTABLE_MAX_TABLE_LINES];

    void SelectTableLines (void);
    void SortTableLines (OpLine ** lines, uint nlines, uint depth);
    bool IsRowMergable (uint rownum);
    void MergeRow (uint rownum);
    bool HasNotes (OpLine * line, uint movenum);
    uint NoteCount (uint note);
    uint NoteScore (uint note);
    void PrintNotes (DString * dstr, uint format);

  public:
    OpTable (uint base, const char * type, Game * g, PBook * ecoBook) {
        Init (base, type, g, ecoBook);
    }
    OpTable (uint base, const char * type, Game * g) { Init (base, type, g, NULL); }
    ~OpTable() { Clear();  delete[] Type; }
    void Init (uint base, const char * type, Game * g, PBook * ecoBook);
    void Clear ();
    void ClearNotes ();
    void SetFormat (const char * str);
    void SetDecimalChar (char c) { DecimalChar = c; }

    uint GetBase () { return Base;}
    uint GetTotalCount() { return FilterCount; }
    uint GetTheoryCount() { return TheoryCount; }

    void   SetExcludeMove (const char * s) {
        strCopy (ExcludeMove, s);
        strStrip (ExcludeMove, '-');
        strStrip (ExcludeMove, '=');
    }
    const char * GetEco (void) { return (EcoStr != NULL ? EcoStr : ""); }
    void   SetNumRows (uint nrows) { TargetRows = nrows; }
    void   GuessNumRows (void);
    void   SetMaxLines (uint nlines) {
        if (nlines <= OPTABLE_MAX_LINES) {
            MaxLines = nlines;
        }
    }
    void   SetMaxTableLines (uint nlines) {
        if (nlines <= OPTABLE_MAX_TABLE_LINES) {
            MaxTableLines = nlines;
        }
    }
    // Unused - S.A. Feb 2020
    // uint   GetMaxLines (void) { return MaxLines; }
    // uint   GetMaxTableLines (void) { return MaxTableLines; }

    void   SetMaxExtraMoves (uint nmoves) {
        MaxNoteLength = (OPTABLE_COLUMNS + nmoves) * 2;
    }
    uint   GetMaxExtraMoves (void) {
        return (MaxNoteLength / 2) - OPTABLE_COLUMNS;
    }
    uint   GetNumLines (void) { return NumLines; }
    void   SetMaxThemeMoveNumber (uint x) { MaxThemeMoveNumber = x; }
    bool   Add (OpLine * line);
    uint   PercentScore (void);
    uint   TheoryPercent (void);
    uint   TheoryScore (void);
    uint   PercentFreq (resultT result);
    uint   AvgLength (resultT result);
    uint   AvgElo (colorT color, uint *count, uint *oppScore, uint *oppPerf);
    void   BestGames (DString * dstr, uint count, const char * rtype);
    void   TopPlayers (DString * dstr, colorT c, uint count);
    void   TopEcoCodes (DString * dstr, uint count);
    void   PrintStemLine (DString * dstr, uint format, bool exclude);
    void   PrintStemLine (DString * dstr) { PrintStemLine (dstr, Format, false); }
    void   MakeRows (void);
    void   DumpLines (FILE * fp);
    void   PrintTable (DString * dstr, const char *title, const char *comment);
    void   PrintLaTeX (DString * dstr,const char *title, const char *comment);
    void   PrintHTML (DString * str, const char *title, const char *comment);
    void   PrintText (DString * str, const char *title, const char *comment,
                      bool htext);
    static uint FormatFromStr (const char * str);
    uint   AddMoveOrder (Game * g);
    void   PopularMoveOrders (DString * dstr, uint count);
    void   ThemeReport (DString * dstr, uint argc, const char ** argv);
    void   AddEndMaterial (matSigT ms, bool inFilter);
    void   EndMaterialReport (DString * dstr, const char * repGames,
                              const char * allGames);
    uint * SelectGames (char type, uint number);
};

#endif // SCID_OPTABLE_H

//////////////////////////////////////////////////////////////////////
// optable.h
//////////////////////////////////////////////////////////////////////
