/* fontreq.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2014 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "fontreq.h"
#include "aguix/aguix.h"
#include "aguix/awindow.h"
#include "aguix/button.h"
#include "aguix/text.h"
#include "aguix/message.h"
#include "aguix/stringgadget.h"
#include "aguix/fieldlistview.h"
#include "worker_locale.h"
#include "aguix/util.h"
#include "aguix/request.h"
#include "simplelist.hh"

#ifdef HAVE_XFT
static const struct request_fonts_def {
  const char *name;
  FontRequester::request_fonts::type_t type;
  const char *xname;
  int size; } use_fonts[]={ { "default", FontRequester::request_fonts::FIXED, "Sans-10", 10},
		            { "Sans", FontRequester::request_fonts::SCALABLE,
			      "Sans-%d", 0},
		            { "Serif", FontRequester::request_fonts::SCALABLE,
			      "Serif-%d", 0},
		            { "Mono", FontRequester::request_fonts::SCALABLE,
			      "Mono-%d", 0}
                         };
#else
static const struct request_fonts_def {
  const char *name;
  FontRequester::request_fonts::type_t type;
  const char *xname;
  int size; } use_fonts[]={ { "default", FontRequester::request_fonts::FIXED, "fixed", 8},
		            { "9x15", FontRequester::request_fonts::FIXED, "9x15", 9},
		            { "10x20", FontRequester::request_fonts::FIXED, "10x20", 10},
		            { "12x24", FontRequester::request_fonts::FIXED, "12x24", 12},
		            { "fixed", FontRequester::request_fonts::SCALABLE,
			      "-misc-fixed-medium-r-*-*-%d-*-*-*-*-*-*-*", 0},
		            { "fixed bold", FontRequester::request_fonts::SCALABLE,
			      "-misc-fixed-bold-*-*-*-%d-*-*-*-*-*-*-*", 0},
                            { "courier", FontRequester::request_fonts::SCALABLE,
			      "-*-courier-medium-r-*-*-%d-*-*-*-*-*-*-*", 0},
                            { "courier bold", FontRequester::request_fonts::SCALABLE,
			      "-*-courier-bold-r-*-*-%d-*-*-*-*-*-*-*", 0},
                            { "courier italic", FontRequester::request_fonts::SCALABLE,
			      "-*-courier-medium-o-*-*-%d-*-*-*-*-*-*-*", 0},
                            { "courier bold italic", FontRequester::request_fonts::SCALABLE,
			      "-*-courier-bold-o-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "times", FontRequester::request_fonts::SCALABLE,
			      "-*-times-medium-r-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "times bold", FontRequester::request_fonts::SCALABLE,
			      "-*-times-bold-r-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "times italic", FontRequester::request_fonts::SCALABLE,
			      "-*-times-medium-i-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "times bold italic", FontRequester::request_fonts::SCALABLE,
			      "-*-times-bold-i-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "helvetica", FontRequester::request_fonts::SCALABLE,
			      "-*-helvetica-medium-r-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "helvetica bold", FontRequester::request_fonts::SCALABLE,
			      "-*-helvetica-bold-r-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "helvetica italic", FontRequester::request_fonts::SCALABLE,
			      "-*-helvetica-medium-o-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "helvetica bold italic", FontRequester::request_fonts::SCALABLE,
			      "-*-helvetica-bold-o-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "any font family", FontRequester::request_fonts::SCALABLE,
			      "-*-*-medium-r-*-*-%d-*-*-*-*-*-*-*", 0},
			    { "generic", FontRequester::request_fonts::SCALABLE,
			      "-*-*-*-*-*-*-%d-*-*-*-*-*-*-*", 0}
                          };
#endif

FontRequester::FontRequester(AGUIX *parent)
{
  int nr_of_fonts=sizeof(use_fonts)/sizeof(struct request_fonts);
  struct request_fonts *font1;
  int i;
  
  aguix=parent;
  fontlist=new List();
  for(i=0;i<nr_of_fonts;i++) {
    font1=(struct request_fonts*)_allocsafe(sizeof(struct request_fonts));
    font1->name=dupstring(use_fonts[i].name);
    font1->type=use_fonts[i].type;
    font1->xname=dupstring(use_fonts[i].xname);
    font1->size=use_fonts[i].size;
    fontlist->addElement(font1);
  }
}

FontRequester::~FontRequester()
{
  struct request_fonts *font1;
  font1=(struct request_fonts*)fontlist->getFirstElement();
  while(font1!=NULL) {
    _freesafe(font1->name);
    _freesafe(font1->xname);
    _freesafe(font1);
    fontlist->removeFirstElement();
    font1=(struct request_fonts*)fontlist->getFirstElement();
  }
  delete fontlist;
}

int FontRequester::request(const char *xname,char**return_xname)
{
  char *rstr;
  int act_font=0,act_fontsize=0;
  struct request_fonts *font1;
  int id;
  char buffer[ 4 + A_BYTESFORNUMBER( int ) + 1 ];
  int i;
  int trow, trow2;
  Requester *req;
  int nr_of_sfonts=sizeof(use_fonts)/sizeof(struct request_fonts);
  int ni,nj;
  char *buttonstr;
  const int cincw = AContainer::ACONT_MINH +
                    AContainer::ACONT_MINW +
                    AContainer::ACONT_MAXH;
  const int cincwnr = cincw +
                      AContainer::ACONT_NORESIZE;
  const int cfix = AContainer::ACONT_MINH +
                   AContainer::ACONT_MINW +
                   AContainer::ACONT_MAXH +
                   AContainer::ACONT_MAXW;
  const int cmin = AContainer::ACONT_MINH +
                   AContainer::ACONT_MINW;

  win = new AWindow( aguix, 10, 10, 10, 10, catalog.getLocale( 204 ), AWindow::AWINDOW_DIALOG );
  win->create();

  ac1 = win->setContainer( new AContainer( win, 1, 7 ), true );
  ac1->setMinSpace( 5 );
  ac1->setMaxSpace( 5 );

  ac1->add( new Text( aguix, 0, 0, catalog.getLocale( 380 ) ), 0, 0, cincwnr );

  AContainer *ac1_1 = ac1->add( new AContainer( win, 2, 1 ), 0, 1 );
  ac1_1->setMinSpace( 5 );
  ac1_1->setMaxSpace( 5 );
  ac1_1->setBorderWidth( 0 );

  lv = (FieldListView*)ac1_1->add( new FieldListView( aguix,
						      0,
						      0,
						      aguix->getTextWidth( " " ) * 30,
						      aguix->getCharHeight() * 10,
						      0 ), 0, 0, cmin );
  lv2 = (FieldListView*)ac1_1->add( new FieldListView( aguix,
						       0,
						       0,
						       aguix->getTextWidth( " " ) * 6,
						       aguix->getCharHeight() * 10,
						       1 ), 1, 0, cmin );

  example_sg = (StringGadget*)ac1->add( new StringGadget( aguix, 0, 0, 100, catalog.getLocale( 382 ), 0 ), 0, 2, cincw );

  ac1_2 = ac1->add( new AContainer( win, 2, 1 ), 0, 3 );
  ac1_2->setMinSpace( 5 );
  ac1_2->setMaxSpace( 5 );
  ac1_2->setBorderWidth( 0 );

  ac1_2->add( new Text( aguix, 0, 0, catalog.getLocale( 383 ) ), 0, 0, cfix );
  ftext = (Text*)ac1_2->add( new Text( aguix, 0, 0, "" ), 1, 0, cincwnr );

#ifndef HAVE_XFT
  AContainer *ac1_4 = ac1->add( new AContainer( win, 4, 1 ), 0, 4 );
  ac1_4->setMinSpace( 5 );
  ac1_4->setMaxSpace( 5 );
  ac1_4->setBorderWidth( 0 );

  ac1_4->add( new Text( aguix, 0, 0, catalog.getLocale( 713 ) ), 0, 0, cfix );
  missingtext = (Text*)ac1_4->add( new Text( aguix, 0, 0, "     " ), 1, 0, cincwnr );
  Button *missing_help_b = (Button*)ac1_4->add( new Button( aguix, 0, 0, catalog.getLocale( 483 ), 0 ),
                                                3, 0, cfix );
#else
  ac1->setMinHeight( 0, 0, 4 );
  ac1->setMaxHeight( 0, 0, 4 );
#endif

  xb = (Button*)ac1->add( new Button( aguix, 0, 0, catalog.getLocale( 381 ), 0 ), 0, 5, cincw );

  AContainer *ac1_3 = ac1->add( new AContainer( win, 2, 1 ), 0, 6 );
  ac1_3->setMinSpace( 5 );
  ac1_3->setMaxSpace( -1 );
  ac1_3->setBorderWidth( 0 );
  okb =(Button*)ac1_3->add( new Button( aguix,
					0,
					0,
					catalog.getLocale( 11 ),
					0 ), 0, 0, cfix );
  cb = (Button*)ac1_3->add( new Button( aguix,
					0,
					0,
					catalog.getLocale( 8 ),
					0 ), 1, 0, cfix );
  
  lv->setHBarState(2);
  lv->setVBarState(2);
  lv2->setHBarState(2);
  lv2->setVBarState(2);

  if(aguix->getFont(xname)!=NULL) {
    // search for existing entry
    if(findfont(xname,&ni,&nj)==0) {
      act_font=ni;
      act_fontsize=nj;
    } else {
      // add new font
      sprintf(buffer,"font%d",fontlist->size()-nr_of_sfonts+1);
      font1=(struct request_fonts*)_allocsafe(sizeof(struct request_fonts));
      font1->name=dupstring(buffer);
      font1->type=request_fonts::FIXED;
      font1->xname=dupstring(xname);
      font1->size=-1;
      fontlist->addElement(font1);
      act_font=fontlist->size()-1;
      act_fontsize=0;
    }
  }

  id=fontlist->initEnum();
  font1=(struct request_fonts*)fontlist->getFirstElement(id);
  i=0;
  while(font1!=NULL) {
    trow = lv->addRow();
    lv->setText( trow, 0, font1->name );
    lv->setPreColors( trow, FieldListView::PRECOLOR_ONLYACTIVE );
    if(i==act_font) {
      lv->setActiveRow( trow );
      showsizes(i);
      if ( lv2->isValidRow( act_fontsize ) == true ) {
        lv2->setActiveRow( act_fontsize );
      }
    }    
    font1=(struct request_fonts*)fontlist->getNextElement(id);
    i++;
  }
  fontlist->closeEnum(id);

  okb->takeFocus();
  win->setDoTabCycling( true );
  win->contMaximize( true );
  win->show();

  updatefont();
  lv->showActive();
  lv2->showActive();
  lv->redraw();
  lv2->redraw();

  req=new Requester(aguix);

  AGMessage *msg;
  int endmode=-1,pos;
  for(;endmode==-1;) {
    msg=aguix->WaitMessage(win);
    if(msg!=NULL) {
      switch(msg->type) {
        case AG_CLOSEWINDOW:
          if(msg->closewindow.window==win->getWindow()) endmode=1;
          break;
        case AG_FIELDLV_ONESELECT:
        case AG_FIELDLV_MULTISELECT:
          if ( msg->fieldlv.lv == lv ) {
            trow = lv->getActiveRow();
            if ( lv->isValidRow( trow ) == true ) {
              showsizes( trow );
              updatefont();
            }
          } else if ( msg->fieldlv.lv == lv2 ) {
            updatefont();
          }
          break;
        case AG_BUTTONCLICKED:
          if(msg->button.button==okb) {
	    endmode=0;
          } else if(msg->button.button==cb) {
            endmode=1;
#ifndef HAVE_XFT
          } else if ( msg->button.button == missing_help_b ) {
            req->request( catalog.getLocale( 124 ), catalog.getLocale( 714 ),
                          catalog.getLocale( 11 ) );
#endif
          } else if(msg->button.button==xb) {
            buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(11))+1+
                                        strlen(catalog.getLocale(8))+1);
            sprintf(buttonstr,"%s|%s",catalog.getLocale(11),
                                      catalog.getLocale(8));
            if(req->string_request(catalog.getLocale(123),catalog.getLocale(381),ftext->getText(),buttonstr,&rstr)==0) {
              if(aguix->getFont(rstr)!=NULL) {
                // search for existing entry
                if(findfont(rstr,&ni,&nj)==0) {
                  trow = ni;
                  if ( lv->isValidRow( trow ) == true ) {
                    lv->setActiveRow( trow );
                    showsizes(ni);
                    trow2 = nj;
                    if ( lv2->isValidRow( trow2 ) == true ) {
                      lv2->setActiveRow( trow2 );
                      updatefont();
                    }
                  }
                  _freesafe(rstr);
                } else {
                  // add new font

                  sprintf(buffer,"font%d",fontlist->size()-nr_of_sfonts+1);
                  font1=(struct request_fonts*)_allocsafe(sizeof(struct request_fonts));
                  font1->name=dupstring(buffer);
                  font1->type=request_fonts::FIXED;
                  font1->xname=rstr;
                  font1->size=-1;
                  fontlist->addElement(font1);

                  trow = lv->addRow();
                  lv->setText( trow, 0, font1->name );
                  lv->setPreColors( trow, FieldListView::PRECOLOR_ONLYACTIVE );
                  lv->setActiveRow( trow );
                  showsizes(fontlist->size()-1);
                  updatefont();
                }
              } else {
                req->request(catalog.getLocale(124),catalog.getLocale(365),catalog.getLocale(11));
                _freesafe(rstr);
              }
            } else _freesafe(rstr);
            _freesafe(buttonstr);
          }
          break;
	case AG_KEYPRESSED:
	  if ( win->isParent( msg->key.window, false ) == true ) {
	    // key release only accept when not first key we get
	    // means a key is pressed when we started and if we use this
	    // key it could confuse the user
	    switch(msg->key.key) {
	      case XK_KP_Enter:
	      case XK_Return:
                if ( cb->getHasFocus() == false ) {
    	          endmode=0;
                }
		break;
	      case XK_Escape:
	        endmode=1;
		break;
	    }
	  }
	  break;
      }
      aguix->ReplyMessage(msg);
    }
  }

  if(endmode==0) {
    endmode=1;
    trow = lv->getActiveRow();
    if ( lv->isValidRow( trow ) == true ) {
      pos = trow;
      font1=(struct request_fonts*)fontlist->getElementAt(pos);
      if(font1!=NULL) {  
        if(font1->type==request_fonts::FIXED) {
          endmode=0;
          if(return_xname!=NULL) {
            *return_xname=dupstring(font1->xname);
          }
        } else {
          trow = lv2->getActiveRow();
          if ( lv2->isValidRow( trow ) == true ) nj = trow;
          else nj=0;
          if(return_xname!=NULL) {
            rstr = (char*)_allocsafe( strlen( font1->xname ) + A_BYTESFORNUMBER( int ) + 1 );
            sprintf(rstr,font1->xname,getsize(pos,nj));
            *return_xname=rstr;
          }
          endmode=0;
        }
      }
    }
  }

  delete win;
  
  delete req;
  
  return endmode;
}

void FontRequester::showsizes(int i)
{
  int trow, frow = -1;
  char buffer[ A_BYTESFORNUMBER( int ) + 1 ];
  int j,oj;
  struct request_fonts *font1;

  font1=(struct request_fonts*)fontlist->getElementAt(i);
  if(font1!=NULL) {  
    if(font1->type==request_fonts::FIXED) {
      lv2->setSize(1);
      sprintf(buffer,"%d",font1->size);
      lv2->setText( 0, 0, buffer );
      lv2->setPreColors( 0, FieldListView::PRECOLOR_ONLYACTIVE );
      lv2->setActiveRow( 0 );
    } else {
      trow = lv2->getActiveRow();
      if ( lv2->isValidRow( trow ) == true ) oj = trow;
      else oj=0;
      lv2->setSize( FONTREQ_STEPS );
      for(j=0;j<FONTREQ_STEPS;j++) {
        sprintf(buffer,"%d",getsize(i,j));
        lv2->setText( j, 0, buffer );
        lv2->setPreColors( j, FieldListView::PRECOLOR_ONLYACTIVE );
        
        if(j==0) frow = j;
        else if(j==oj) frow = j;
      }
      if ( lv2->isValidRow( frow ) == true ) lv2->setActiveRow( frow );
    }
  }
  lv2->redraw();
}

void FontRequester::updatefont()
{
  int trow;
  int i,j;
  char *tstr,*buffer;
  struct request_fonts *font1;
  std::string xfontname;
  
  trow = lv->getActiveRow();
  if ( lv->isValidRow( trow ) == true ) {
    i = trow;
    trow = lv2->getActiveRow();
    if ( lv2->isValidRow( trow ) == true ) {
      j = trow;

      font1=(struct request_fonts*)fontlist->getElementAt(i);
      if(font1!=NULL) {  
        tstr=font1->xname;
        if(font1->type==request_fonts::SCALABLE) {
          buffer = (char*)_allocsafe( strlen( tstr ) + A_BYTESFORNUMBER( int ) + 1 );
          sprintf(buffer,tstr,getsize(i,j));
          example_sg->setFont( buffer );
          xfontname = buffer;
          ftext->setText(buffer);
          _freesafe(buffer);
        } else {
          example_sg->setFont( tstr );
          xfontname = tstr;
          ftext->setText(tstr);
        }

#ifndef HAVE_XFT
        missingtext->setText( "" );
        if ( xfontname.length() > 0 ) {
          AGUIXFont *font = aguix->getFont( xfontname.c_str() );
          if ( font != NULL ) {
            char numbuf[ A_BYTESFORNUMBER( int ) ];
            sprintf( numbuf, "%d", font->getNumberOfMissingCharsets() );
            missingtext->setText( numbuf );
          }
        }
#endif
        example_sg->changeHeightForCurFont();
  	ac1->setMinHeight( example_sg->getHeight(), 0, 2 );
	ac1->setMaxHeight( example_sg->getHeight(), 0, 2 );
	ac1_2->readLimits();
	win->contMaximize( true );
      }
    }
  }
  lv->redraw();
}

int FontRequester::getsize(int i,int j)
{
  return FONTREQ_MINSIZE+FONTREQ_STEPSIZE*j;
}

int FontRequester::findfont(const char *xn,int *return_i, int *return_j)
{
  struct request_fonts *font1;
  int id;
  char *tstr,*buffer;
  bool found=false;
  int i=0,j=0;
  
  id=fontlist->initEnum();
  
  font1=(struct request_fonts*)fontlist->getFirstElement(id);
  i=0;
  while(font1!=NULL) {  
    tstr=font1->xname;
    if(font1->type==request_fonts::SCALABLE) {
      buffer = (char*)_allocsafe( strlen( tstr ) + A_BYTESFORNUMBER( int ) + 1 );

      for(j=0;j<FONTREQ_STEPS;j++) {
        sprintf(buffer,tstr,getsize(i,j));
        if(strcmp(buffer,xn)==0) {
          found=true;
          break;
        }
      }

      _freesafe(buffer);
      if(found==true) break;
    } else {
      if(strcmp(tstr,xn)==0) {
        found=true;
        j=0;
        break;
      }
    }
    font1=(struct request_fonts*)fontlist->getNextElement(id);
    i++;
  }
  fontlist->closeEnum(id);
  if(found==true) {
    *return_i=i;
    *return_j=j;
    return 0;
  } else return -1;
}

