/**
 ** drawstrg.c ---- low level character string output
 **
 ** Copyright (c) 1998 Hartmut Schirmer
 ** Copyright (c) 1995 Csaba Biegl, 820 Stirrup Dr, Nashville, TN 37221
 ** [e-mail: csaba@vuse.vanderbilt.edu]
 **
 ** This file is part of the GRX graphics library.
 **
 ** The GRX graphics library is free software; you can redistribute it
 ** and/or modify it under some conditions; see the "copying.grx" file
 ** for details.
 **
 ** This library is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** Contributions by:
 ** 080125 M.Alvarez, UTF-8 support
 ** 170706 M.Alvarez, rewrite for font encoding functionality
 ** 200620 M.Alvarez, solved an old bug
 **
 **/

#include "libgrx.h"
#include "clipping.h"
#include "text/text.h"

static void _GrDrawWordText(const unsigned short *text,int length,int x,int y,
                   const GrTextOption *opt, GrPattern *p, TextDrawBitmapFunc dbm)
{
  GrFont *f;
  int    x1;
  GRX_ENTER();

  if (((f = opt->txo_font) != NULL) &&
      ((x1 = _GrFontWordTextWidth(f,text,length)) != 0)) {
    GrColor fgcv  = opt->txo_fgcolor;
    GrColor bgcv  = opt->txo_bgcolor;
    int     undl  = (fgcv & GR_UNDERLINE_TEXT) ? 1 : 0;
    int     rotat = GR_TEXT_IS_VERTICAL(opt->txo_direct) ? ~0 : 0;
    int     dxpre = 0;
    int     dypre = 0;
    int     dxpost= 0;
    int     dypost= 0;
    int     y1    = f->h.height;
    int     ww    = (x1 & ~rotat) | (y1 &  rotat);
    int     hh    = (x1 &  rotat) | (y1 & ~rotat);
    int     x2, y2;
    int     oldx, oldy;
    switch(opt->txo_xalign) {
      case GR_ALIGN_RIGHT:
        x -= ww - 1;
        break;
      case GR_ALIGN_CENTER:
        x -= (ww >> 1);
        break;
    }
    switch(opt->txo_yalign) {
      case GR_ALIGN_BASELINE:
        if(opt->txo_direct == GR_TEXT_DEFAULT) y -= f->h.baseline;
        break;
      case GR_ALIGN_BOTTOM:
        y -= hh - 1;
        break;
      case GR_ALIGN_CENTER:
        y -= (hh >> 1);
        break;
    }
    mouse_block(CURC,x,y,(x + ww - 1),(y + hh - 1));
    oldx = x + CURC->gc_xoffset;
    oldy = y + CURC->gc_yoffset;
    switch(opt->txo_direct) {
      case GR_TEXT_DOWN:
        dypost = ~0;
        break;
      case GR_TEXT_LEFT:
        dxpre = ~0;
        x += ww;
        break;
      case GR_TEXT_UP:
        dypre = ~0;
        y += hh;
        break;
      default:
        dxpost = ~0;
        break;
    }
    while(--length >= 0) {
      unsigned short chr;
      int xx,yy,cw,ch;
      char *bmp;
      chr = text[0];
      text = text + 1;
      x1 = GrFontCharWidth(f,chr);
      y1 = f->h.height;
      cw = (x1 & ~rotat) | (y1 &  rotat);
      ch = (x1 &  rotat) | (y1 & ~rotat);
      x1 = (x -= (cw & dxpre));
      y1 = (y -= (ch & dypre));
      x2 = (xx = x1) + cw - 1;
      y2 = (yy = y1) + ch - 1;
      x += (cw & dxpost);
      y += (ch & dypost);
      clip_ordbox_(CURC,x1,y1,x2,y2,continue,CLIP_EMPTY_MACRO_ARG);
      bmp = GrFontCharAuxBmp(f,chr,opt->txo_direct,undl);
      if(bmp) (*dbm)(
        (x1 + CURC->gc_xoffset),
        (y1 + CURC->gc_yoffset),
        (x2 - x1 + 1),
        (y2 - y1 + 1),
        oldx, oldy,
        bmp,
        ((cw + 7) >> 3),
        ((x1 - xx) + ((y1 - yy) * ((cw + 7) & ~7))),
        fgcv,bgcv,
        p
        );
      else (*FDRV->drawblock)(
        (x1 + CURC->gc_xoffset),
        (y1 + CURC->gc_yoffset),
        (x2 - x1 + 1),
        (y2 - y1 + 1),
        bgcv
        );
    }
    mouse_unblock();
  }
  GRX_LEAVE();
}

void _GrDrawString(const void *text, int length, int x, int y,
                   const GrTextOption *opt, GrPattern *p, TextDrawBitmapFunc dbm)
{
  unsigned short *text2;

  GRX_ENTER();
  if (text == NULL) return;
  if (length <= 0) length = GrStrLen(text, opt->txo_chrtype);
  text2 = GrFontTextRecode(opt->txo_font, text, length, opt->txo_chrtype);
  if (text2 == NULL) return;
  _GrDrawWordText(text2, length, x, y, opt, p, dbm);
  free(text2);
}

void _GrDrawChar(long chr, int x, int y,
                 const GrTextOption *opt, GrPattern *p, TextDrawBitmapFunc dbm)
{
  unsigned short schr;

  GRX_ENTER();
  schr = GrFontCharRecode(opt->txo_font, chr, opt->txo_chrtype);
  _GrDrawWordText(&schr, 1, x, y, opt, p, dbm);
}
