
/* 
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* copyright 1998-2003 by Warren Lyford Delano of DeLano Scientific. 
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information. 
H* --------------------------------------------------\-----------------
I* Additional authors of this source file include:
-* 
-* 
-*
Z* -------------------------------------------------------------------
*/
#include"os_python.h"

#include"os_gl.h"
#include"MemoryDebug.h"
#include"Feedback.h"
#include"P.h"
#include"PConv.h"
#include"VFont.h"
#include "CGO.h"

#define VFONT_MASK 0xFF

struct VFontRec {
  int face{};
  float size{};
  int style{};
  ov_diff offset[VFONT_MASK + 1]{};
  float advance[VFONT_MASK + 1]{};
  float* pen{};
};

struct _CVFont {
  VFontRec **Font;
  int NFont;
};

//#ifndef _PYMOL_NOPY
static VFontRec *VFontRecNew(PyMOLGlobals * G)
{
  int a;
  auto I = new VFontRec();
  for(a = 0; a <= VFONT_MASK; a++) {
    I->advance[a] = 0.0F;
    I->offset[a] = -1;
  }
  I->pen = VLAlloc(float, 1000);
  return (I);
}
//#endif

int VFontWriteToCGO(PyMOLGlobals * G, int font_id, CGO * cgo,
                    const char *text, float *pos, float *scale, float *matrix, float *color)
{
  CVFont *I = G->VFont;
  VFontRec *fr = NULL;
  int ok = true;
  float base[3], pen[3];
  float *pc;
  unsigned char c;
  int drawing, stroke;
  float *cgo_verts, *tmp_ptr;
  ov_diff offset;
  if((font_id > 0) && (font_id <= I->NFont)) {
    fr = I->Font[font_id];
    if(fr)
      while(1) {
        c = *(text++);
        if(!c)
          break;
        offset = fr->offset[c];
        if(offset >= 0) {
          pc = fr->pen + offset;
          copy3f(pos, base);
          drawing = true;
          stroke = false;
          while(drawing) {
            switch ((int) *(pc++)) {
            case -1:           /* sentinel */
              drawing = false;
              break;
            case 0:            /* moveto */
              pen[0] = (*(pc++)) * scale[0];
              pen[1] = (*(pc++)) * scale[1];
              pen[2] = 0.0;
              if(matrix)
                transform33f3f(matrix, pen, pen);
              add3f(base, pen, pen);
              if(stroke) {
                CGOEnd(cgo);
              }
              CGOBegin(cgo, GL_LINE_STRIP);
	      if (color)
		CGOColorv(cgo, color);
              CGOVertexv(cgo, pen);
              stroke = true;
              break;
            case 1:            /* drawto */
              pen[0] = (*(pc++)) * scale[0];
              pen[1] = (*(pc++)) * scale[1];
              pen[2] = 0.0;
              if(matrix)
                transform33f3f(matrix, pen, pen);
              add3f(base, pen, pen);
              if(stroke) {
		(void)tmp_ptr;
		(void)cgo_verts;
                CGOVertexv(cgo, pen);
              }
              break;
            default:
              drawing = false;
              break;
            }
          }
          pen[0] = fr->advance[c] * scale[0];
          pen[1] = 0.0;
          pen[2] = 0.0;
          if(matrix)
            transform33f3f(matrix, pen, pen);
          add3f(pen, pos, pos);
          if(stroke){
            CGOEnd(cgo);
	  }
        }
      }
  } else {
    PRINTFB(G, FB_VFont, FB_Errors)
      "VFontWriteToCGO-Error: invalid font identifier (%d)\n", font_id ENDFB(G);
    ok = false;
  }
  return (ok);
}

int VFontIndent(PyMOLGlobals * G, int font_id, const char *text, float *pos, float *scale,
                float *matrix, float dir)
{
  CVFont *I = G->VFont;
  VFontRec *fr = NULL;
  int ok = true;
  float pen[3];
  unsigned char c;
  ov_diff offset;

  if((font_id > 0) && (font_id <= I->NFont)) {
    fr = I->Font[font_id];
    if(fr)
      while(1) {
        c = *(text++);
        if(!c)
          break;
        offset = fr->offset[c];
        if(offset >= 0) {
          pen[0] = fr->advance[c] * scale[0] * dir;
          pen[1] = 0.0;
          pen[2] = 0.0;
          if(matrix)
            transform33f3f(matrix, pen, pen);
          add3f(pen, pos, pos);
        }
      }
  } else {
    PRINTFB(G, FB_VFont, FB_Errors)
      "VFontIndent-Error: invalid font identifier  (%d)\n", font_id ENDFB(G);
    ok = false;
  }
  return (ok);
}

#ifndef _PYMOL_NOPY
/**
 * @pre GIL
 */
static int VFontRecLoad(PyMOLGlobals * G, VFontRec * I, PyObject * dict)
{
  assert(PyGILState_Check());

  ov_diff used = 0;
  int ok = true;
  PyObject *key, *char_list;
  PyObject *stroke_list = NULL;
  Py_ssize_t pos = 0;
  unsigned char code[2];
  float adv;
  ov_diff n_float;
  while(PyDict_Next(dict, &pos, &key, &char_list)) {
    if(!PConvPyStrToStr(key, (char *) code, 2)) {
      PRINTFB(G, FB_VFont, FB_Errors)
        "VFont-Error: Bad character code." ENDFB(G);
      ok = false;
    } else {
      if(ok)
        ok = (char_list != NULL);
      if(ok)
        ok = PyList_Check(char_list);
      if(ok)
        ok = (PyList_Size(char_list) >= 2);
      if(ok)
        ok = PConvPyObjectToFloat(PyList_GetItem(char_list, 0), &adv);
      if(ok) {
        stroke_list = PyList_GetItem(char_list, 1);
        if(ok)
          ok = (stroke_list != NULL);
        if(ok)
          ok = PyList_Check(stroke_list);
        if(ok) {
          n_float = PyList_Size(stroke_list);
          VLACheck(I->pen, float, n_float + used + 1);
          ok = PConvPyListToFloatArrayInPlace(stroke_list, I->pen + used, n_float);
          I->offset[code[0]] = used;
          I->advance[code[0]] = adv;
          I->pen[used + n_float] = -1.0F;       /* sentinel */
          PRINTFD(G, FB_VFont)
            " VFontRecLoad-Debug: Added '%c' adv: %0.3f n_float: %d\n", code[0], adv,
            (int)n_float ENDFD;
          if(ok)
            used += n_float + 1;

        }
      }
    }
  }
  return (ok);
}
#else
#include "vfontdata.h"

static int VFontRecLoad(PyMOLGlobals * G, VFontRec * I)
{
  ov_diff used = 0;
  int ok = true;
  int chidx, n_float, i, off;
  float adv;
  
  for (chidx=0;chidx<VFONT_NUMBER_OF_CHARS; chidx++){
    adv = advs[chidx];
    n_float = n_floats[chidx];
    VLACheck(I->pen, float, n_float + used + 1);
    off = stroke_list_place[chidx];
    for (i=0;i<n_float;i++){
      *(I->pen + used + i) = stroke_lists[off+i];
    }
    I->offset[ch[chidx]] = used;
    I->advance[ch[chidx]] = adv;
    I->pen[used + n_float] = -1.0F;       /* sentinel */
    PRINTFD(G, FB_VFont)
      " VFontRecLoad-Debug: Added '%c' adv: %0.3f n_float: %d\n", ch[chidx], adv,
      (int)n_float ENDFD;
    if(ok)
      used += n_float + 1;
  }
  return (ok);
}

#endif

static void VFontRecFree(PyMOLGlobals * G, VFontRec * I)
{
  VLAFreeP(I->pen);
  DeleteP(I);
}

int VFontInit(PyMOLGlobals * G)
{
  CVFont *I = NULL;
  if((I = (G->VFont = pymol::calloc<CVFont>(1)))) {

    CVFont *I = G->VFont;
    I->Font = VLAlloc(VFontRec *, 10);
    I->NFont = 0;
    return 1;
  } else {
    return 0;
  }
}

void VFontFree(PyMOLGlobals * G)
{
  CVFont *I = G->VFont;
  int a;
  for(a = 1; a <= I->NFont; a++) {
    VFontRecFree(G, I->Font[a]);
  }
  VLAFreeP(I->Font);
  FreeP(G->VFont);
}

int VFontLoad(PyMOLGlobals * G, float size, int face, int style, int can_load_new)
{
  CVFont *I = G->VFont;
  VFontRec *fr;
  int a;
  int result = 0;
#ifndef _PYMOL_NOPY
  PyObject *vfont = NULL;
#endif

  PRINTFD(G, FB_VFont)
    " VFontLoad-Debug: Entered %f %d %d\n", size, face, style ENDFD;

  for(a = 1; a <= I->NFont; a++) {
    fr = I->Font[a];
    if((fr->size == size) && (fr->face == face) && (fr->style == style)) {
      result = a;
      break;
    }
  }
  if(!result) {
    if(can_load_new) {
#ifndef _PYMOL_NOPY
      vfont = PGetFontDict(G, size, face, style);
      if(vfont) {
        if(PyDict_Check(vfont)) {
#endif
          VLACheck(I->Font, VFontRec *, I->NFont + 1);
          fr = VFontRecNew(G);
#ifndef _PYMOL_NOPY
          if(!VFontRecLoad(G, fr, vfont))
#else
          if(!VFontRecLoad(G, fr))
#endif
            VFontRecFree(G, fr);
          else {
            I->NFont++;         /* always start at 1 */
            I->Font[I->NFont] = fr;
            result = I->NFont;
            fr->size = size;
            fr->face = face;
            fr->style = style;
          }
#ifndef _PYMOL_NOPY
        }
        Py_DECREF(vfont);
      }
#endif
    }
  }
  PRINTFD(G, FB_VFont)
    " VFontLoad-Debug: Leaving with result %d  (0 = failure)\n", result ENDFD;
  return (result);
}
