/** 
 *  Yudit Unicode Editor Source File
 *
 *  GNU Copyright (C) 1997-2023  Gaspar Sinai <gaspar@yudit.org>  
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License, version 2,
 *  dated June 1991. See file COPYYING for details.
 *
 *  This program 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.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "gui/SMessageBar.h"

#include "gui/Main.h"
#include "swidget/SIconFactory.h"
#include "stoolkit/SCluster.h"
#include "stoolkit/SCharClass.h" 
#include "stoolkit/STypes.h" 
#include "swindow/SAwt.h" 


/**
 * a button panel is just a panel of labels.
 */
SMessageBar::SMessageBar (const SProperties props)
{
  xmanagerCludge = true;
  SColor fg = SColor(props["yudit.label.foreground"]);
  SColor tfg = SColor(props["yudit.title.foreground"]);
  SString font = props["yudit.default.font"];
  SString fontSizeString=props["yudit.default.fontsize"];

  double fontSize=0;
  fontSizeString.append ((char)0);
  sscanf (fontSizeString.array(), "%lf", &fontSize);
  if (fontSize < 2.0) fontSize = 2.0;

  /* create the labels and set the preferred size */
  SLabel *l;

  l = new SLabel (translate ("Glyph Info:"));
  l->setFont(font, fontSize);
  l->setForeground (tfg);
  labels[SS_GLYPH_TITLE] = l;

  l = new SLabel ("");
  l->setFont(font, fontSize);
  l->setForeground (fg);
  labels[SS_GLYPH_INFO] = l;

  l = new SLabel (translate ("Font Size:"));
  l->setFont(font, fontSize);
  l->setForeground (tfg);
  labels[SS_FONT_SIZE_TITLE] = l;

  l = new SLabel ("");
  l->setFont(font, fontSize);
  l->setForeground (fg);
  labels[SS_FONT_SIZE] = l;

  l = new SLabel (translate ("Line:"));
  l->setFont(font, fontSize);
  l->setForeground (tfg);
  labels[SS_ROW_TITLE] = l;

  l =  new SLabel ("");
  l->setFont(font, fontSize);
  l->setForeground (fg);
  labels[SS_ROW] = l;

  l = new SLabel (translate ("Column:"));
  l->setFont(font, fontSize);
  l->setForeground (tfg);
  labels[SS_COLUMN_TITLE] = l;

  l =  new SLabel ("");
  l->setFont(font, fontSize);
  l->setForeground (fg);
  labels[SS_COLUMN] = l;

  unsigned int p=0;
  unsigned int h=0;
  
  for (unsigned int i=0; i<(unsigned int) SS_MAX; i++)
  {
    unsigned int ww = 0;
    switch (i)
    {
    case SS_FONT_SIZE:
      ww = (int) (50.0 * SAwt::getScale());
      break;
    case SS_ROW:
      ww = (int) (50.0 * SAwt::getScale());
      break;
    case SS_COLUMN:
      ww = (int) (50.0 * SAwt::getScale());
      break;
    case SS_GLYPH_INFO:
      ww = (int) (600.0 * SAwt::getScale());
      break;
    default:
      ww = labels[i]->getPreferredSize().width;
    }
    unsigned int hh = labels[i]->getPreferredSize().height;
    labels[i]->resize(SDimension (ww, hh));
    labels[i]->move(SLocation ((int)p, 0));
    add (labels[i]);
    p+= ww +2;
    if (hh > h) h = hh;
  }
  preferredSize = SDimension (p, h);
}
/**
 * This routine was introduced to make this
 * usable on peecees with windows.
 * Seems like XManager has some bug that they don't
 * fix. On unix you could in fact get rid of this whole  method.
 * The presiously set size got lost. I don't really know why XManager is so
 * popular....
 */
void 
SMessageBar::resize(const SDimension& d)
{
  SPanel::resize (d);
  /* we only need to do it once. */
  if (!xmanagerCludge)
  {
    return;
  }
  xmanagerCludge = false;
  unsigned int p=0;
  unsigned int h=0;
  for (unsigned int i=0; i<(unsigned int) SS_MAX; i++)
  {
    unsigned int ww = 0;
    switch (i)
    {
    case SS_FONT_SIZE:
      ww = (int) (50.0 * SAwt::getScale());
      break;
    case SS_ROW:
      ww = (int) (50.0 * SAwt::getScale());
      break;
    case SS_COLUMN:
      ww = (int) (50.0 * SAwt::getScale());
      break;
    case SS_GLYPH_INFO:
      ww = (int) (600.0 * SAwt::getScale());
      break;
    default:
      ww = labels[i]->getPreferredSize().width;
    }
    unsigned int hh = labels[i]->getPreferredSize().height;
    labels[i]->resize(SDimension (ww, hh));
    labels[i]->move(SLocation ((int)p, 0));
    // Seems resize is enough to work around the bug.
    /* No need to labels[i]->move(SLocation ((int)p, 0)); */
    p+= ww +2;
    if (hh > h) h = hh;
  }
}

SMessageBar::~SMessageBar ()
{
}


void
SMessageBar::setRow (unsigned int row)
{
  char a[64];
  snprintf (a, 64, "%u", row);
  SLabel* l = labels[SS_ROW];
  l->setText (a);
}

void
SMessageBar::setColumn (unsigned int column)
{
  char a[64];
  snprintf (a, 64, "%u", column);
  SLabel* l = labels[SS_COLUMN];
  l->setText (a);
}

void
SMessageBar::setFontSize (double d)
{
  char a[64];
  snprintf (a, 64, "%g", d);
  fontSize = d;
  SLabel* l = labels[SS_FONT_SIZE];
  l->setText (a);
}

/**
 * This one draws a glyph info in the form of 
 * compose   [decomp1 decomp2] - if compose will be saved.
 * [compose] decomp1 decomp2 - if decomp1 decomp.. will be saved
 * above P:displayed  is displayed presentation form is used.
 * @param g is the glyph
 * @encoded contains some extra info, when encoed with a keymap.
 */
void
SMessageBar::setGlyphInfo (const SGlyph* g, const SString& encoded)
{
  SUniMap shaper ("shape");
  
  SLabel* l = labels[SS_GLYPH_INFO];
  if (g==0)
  {
    l->setText("");
    return;
  }
  bool savePrecomp = g->usePrecomp;
  SS_UCS4 precomp = g->getChar();
  SS_UCS4 shape = g->getShapedChar();
  SV_UCS4 decomp;
  SString  trailer;

  unsigned int i;
  for (i=0; i<g->decompSize(); i++)
  {
    decomp.append ((*g)[i]);
  }
  if (g->compSize())
  {
    SV_UCS4 ca;
    for (i=0; i<g->compSize(); i++)
    {
      ca.append (g->getCompArray()[i]);
    }
    trailer.append (" ; ");
    trailer.append (unicodeValueOf (ca));
  }
  if (g->embedding > 0)
  {
    char a[32];
    snprintf (a, 32, "%u", (unsigned int) g->embedding);
    trailer.append (" e:");
    trailer.append (a);
    if (g->getExplicitLevel()>0)
    {
      snprintf (a, 32, "%u", g->getExplicitLevel());
      trailer.append (g->isOverride() ? " xo:" : " xe:");
      trailer.append (a);
    }
  }
  if (encoded.size())
  {
    trailer.append (" |");
    trailer.append (encoded);
    trailer.append ("|");
  }
  SString compStr;
  if (precomp!=0)
  {
    unsigned int tp = g->getType();
    /* too much info */
    //if (tp < 0x1f && tp !=0)
    if (false)
    {
       compStr.append (ssCharClass[tp]);
       compStr.append (" ");
    }
  }
  
  SString decompStr;

  /*
   * shape:xxxx [decomp]
   * In this case we received the shape. We won't modify shape.
   * In this case the shape is 
   * pre-determined and can not be changed
   */
  if (savePrecomp && decomp.size() == 0 && precomp != 0 && shaper.isOK())
   /* check if precomp can be a shape */
  {
    SV_UCS4 ret;
    SV_UCS4 v; v.append (precomp);
    /* presentation form - get decomposition */
    (void) shaper.lift (v, 0, true, &ret);
    if (ret.size() > 0)
    {
      decompStr.append ("[");
      decompStr.append (unicodeValueOf (ret));
      decompStr.append ("]");

      SV_UCS4 forms;
      (void) shaper.lift (ret, 0, false, &forms);
      if (forms.size()==4)
      {
        for (unsigned int i=0; i<forms.size(); i++)
        {
          if (forms[i] == precomp) 
          {
            compStr.append (getShapeCode(i));
            compStr.append (":");
            compStr.append (unicodeValueOf(v));
            break;
          }
          if (i==3) /* never happens if decoder/encoder is ok */
          {
            compStr.append ("noshape:");
            compStr.append (unicodeValueOf(v));
          }
        }
      }
      else /* never happens if decoder/encoder is ok */
      {
        compStr.append ("moreshape:");
        compStr.append (unicodeValueOf(v));
      }
    }
    if (decompStr.size())
    {
      compStr.append (" ");
      compStr.append (decompStr);
      compStr.append (trailer);
      l->setText(compStr);
      return;
    }
  }
  /*
   * [shape:xxxx] decomp
   * In this case the shape is 
   * pre-determined and can not be changed
   */
  if (g->currentShape!=SD_NOSHAPE
       && getLigatureScriptCode(shape)!= SD_BENGALI_BEGIN) 
  {
    compStr.append ("[");
    compStr.append (getShapeCode ((unsigned int)g->currentShape));

    /* shaped with presentation forms */
    if (shape < 0x80000000)
    {
      compStr.append (":");
      SV_UCS4 v;v.append (shape);
      compStr.append (unicodeValueOf (v));
    }
    compStr.append ("]");

    /* here shape can be a single comp or decomp */
    if (savePrecomp)
    {
      SV_UCS4 v; v.append (precomp); /* decomposition is a single char */
      decompStr.append (unicodeValueOf (v));
      /* precomposed glyph exists but and we use that, not compositon  */
      if (decomp.size() && ! (decomp.size()==1 && decomp[0] == precomp))
      {
        decompStr.append (" (");
        decompStr.append (unicodeValueOf (decomp));
        decompStr.append (")");
      }
    }
    else /* it is comp */
    {
      /* precomposed glyph exists but we don't use it */
      if (precomp && ! (decomp.size()==1 && decomp[0] == precomp))
      {
        SV_UCS4 pc; pc.append (precomp);
        decompStr.append ("(");
        decompStr.append (unicodeValueOf (pc));
        decompStr.append (") ");
      }
      decompStr.append (unicodeValueOf (decomp));
    }
    compStr.append (" ");
    compStr.append (decompStr);
    compStr.append (trailer);
    l->setText(compStr);
    return;
  }

  /*
   * decomp ....
   * In this case the shape is 
   * pre-determined and can not be changed
   */
  if (precomp==0 && decomp.size() > 0)
  {
    if (g->getShapeArray())
    {
      decompStr.append ("noshape:");
      decompStr.append (unicodeValueOf (decomp));
    }
    else if (g->isCluster())
    {
      SV_UCS4 declust = g->getChars();
      /* getChars returns the extra char */
      if (g->compSize()) declust.truncate (declust.size()-g->compSize());
      if (declust.size()==2 
         && declust[0] >= 0xd800 &&  declust[0] <= 0xdbff
         && declust[1] >= 0xdc00 &&  declust[0] <= 0xdfff)
      {
        decompStr.append ("[sgt:");
      }
      else
      {
        decompStr.append ("[cluster:");
      }
      decompStr.append (unicodeValueOf (decomp));
      decompStr.append ("] ");
      decompStr.append (unicodeValueOf (declust));
    }
    else /* xxxx xxxx */
    {
      if (getLigatureScriptCode (decomp[0]) == SD_AS_LITERAL)
      {
        SV_UCS4 v; v.append (decomp[0] & 0xff);
        decompStr.append ("illegal:");
        SString uv = unicodeValueOf (v);
        uv.remove (0);
        uv.remove (0);
        decompStr.append (uv);
        decomp.remove (0);
        decompStr.append (" ; ");
      }
      decompStr.append (unicodeValueOf (decomp));
    }
    decompStr.append (trailer);
    l->setText(decompStr);
    return;
  }

  /**
   * [xxxx] decomp
   */
  if (!savePrecomp)
  {
    compStr.append ("[");
    SS_UCS4 lig = precomp;
    if (g->isCluster())
    {
      SString ligname ("ligature:");
      const char* chr = getLigatureScript (precomp);
      if (chr)
      {
        ligname = SString(chr);
        if (getLigatureScriptCode (shape) == SD_BENGALI_BEGIN)
        {
	 //  for debugging bengali shaping
         //  ligname.append ("-init");
        }
	ligname.append (":");
        lig = lig & 0xffff;
      }
      compStr.append (ligname);
    }
    SV_UCS4 v; v.append (lig);
    compStr.append (unicodeValueOf (v));

    compStr.append ("] ");
    if (g->isCluster())
    {
      // Too much info
      //compStr.append ("[cluster:");
      //compStr.append (unicodeValueOf (decomp));
      //compStr.append ("] ");
      /* getChars returns the extra char */
      SV_UCS4 declust = g->getChars();
      if (g->compSize()) declust.truncate (declust.size()-g->compSize());
      compStr.append (unicodeValueOf (declust));
    }
    else
    {
      compStr.append (unicodeValueOf (decomp));
    }
    compStr.append (trailer);
    l->setText(compStr);
    return;
  } 

  /**
   * xxxx [decomp]
   */
  if (decomp.size() > 0)
  {
    if (g->getShapeArray()) decompStr.append ("noshape:");
    SV_UCS4 v; v.append (precomp);
    compStr.append (unicodeValueOf (v));
    decompStr.append ("[");
    decompStr.append (unicodeValueOf (decomp));
    decompStr.append ("]");
    compStr.append (" ");
    compStr.append (decompStr);
    compStr.append (trailer);
    l->setText(compStr);
    return;
  }

  /**
   * xxxx 
   */
  SV_UCS4 v; 
  if (getLigatureScriptCode (precomp) == SD_AS_LITERAL)
  {
    v.append (precomp & 0xff);
    compStr.append ("illegal:");
    SString uv = unicodeValueOf (v);
    uv.remove (0);
    uv.remove (0);
    compStr.append (uv);
  }
  else
  {
    v.append (precomp);
    compStr.append (unicodeValueOf (v));
  }
  compStr.append (trailer);
  l->setText(compStr);
  return;
}
