////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// mdanks@cybermed.ucsd.edu
//
// Implementation file
//
//    Copyright (c) 1997-1998 Mark Danks.
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

#include "text.h"

#include <string.h>
#include <stdio.h>

#include "Base/GemMan.h"
#include "Base/GemWinCreate.h"

const char *text::DEFAULT_FONT = "10x20";

CPPEXTERN_NEW(text)

/////////////////////////////////////////////////////////
//
// text
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
text :: text()
      : m_redoFont(2), m_fontStruct(NULL), m_fontBase(0),
        m_windowNumber(-1)
{
    m_theString = strdup("gem");
    m_fontName = strdup(DEFAULT_FONT);
}

/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
text :: ~text()
{
    delete [] m_theString;
    delete [] m_fontName;

    // should clean up the display lists we created here
}

/////////////////////////////////////////////////////////
// stringCreateList
//
/////////////////////////////////////////////////////////
int text :: stringCreateList()
{
    if (m_fontStruct) XFreeFont(GemMan::getWindowInfo().dpy, m_fontStruct);
    m_fontStruct = XLoadQueryFont(GemMan::getWindowInfo().dpy, m_fontName);

    if (!m_fontStruct)
    {
	// if the requested font is not available, try the simpler 10x20 font
	m_fontStruct = XLoadQueryFont(GemMan::getWindowInfo().dpy, DEFAULT_FONT); 
	if (!m_fontStruct)
	{
	    error("font %s not found", DEFAULT_FONT);
	    return(0);
	}
	else
	{
	    post("string: using default font");
    	    delete [] m_fontName;
    	    m_fontName = strdup(DEFAULT_FONT);
    	}
    }
    
    int firstRow = m_fontStruct->min_byte1;
    int lastRow = m_fontStruct->max_byte1;
    int rows = lastRow - firstRow + 1;
    if (rows > 5)
    {
	post("only using first 5 rows of multi-row font");
	rows = 5;
    }

    // only reallocate lists if new window
    if (m_redoFont == 2) m_fontBase = glGenLists(rows*256);

    if (!m_fontBase)
    {
	error("string unable to generate display lists");
	return(0);
    }

    // Define bitmaps for entire font
    glXUseXFont(m_fontStruct->fid, firstRow << 8, rows*256, m_fontBase);

    m_redoFont = 0;
    return(1);
}

/////////////////////////////////////////////////////////
// textMessCallback
//
/////////////////////////////////////////////////////////
void text :: textMess(int argc, t_atom *argv)
{
    delete [] m_theString;
    
    if ( argc < 1 )
    {
    	m_theString = strdup("");
    	return;
    }
    
    if (argv[0].a_type != A_SYMBOL)
    {
        post("text: wrong type");
        return;
    }
    
    m_theString = strdup(argv[0].a_w.w_symbol->s_name);
    
    for (int i = 1; i < argc; i++)
    {
    	char *newText = new char[16];
    	
        if (argv[i].a_type == A_FLOAT)
        {
            sprintf(newText, "%f", argv[i].a_w.w_float);
        }
        else if (argv[i].a_type == A_INT)
        {
            sprintf(newText, "%d", argv[i].a_w.w_int);
        }
        else if (argv[i].a_type == A_SYMBOL)
        {
            delete [] newText;
            newText = strdup(argv[0].a_w.w_symbol->s_name);
        }
        
        // hold the current string
        char *curStr = m_theString;
        
        // allocate the new memory
        m_theString = new char[(strlen(curStr) + strlen(newText) + 1)];
        strcat(m_theString, curStr);
        strcat(m_theString, " ");
        strcat(m_theString, newText);
        delete [] newText;
        delete [] curStr;
    }
    setModified();
}

/////////////////////////////////////////////////////////
// prepMess
//
/////////////////////////////////////////////////////////
void text :: prepMess()
{
    if ( !GemMan::windowExists() ) return;

    if ( m_windowNumber != GemMan::windowNumber() )
    {
        m_windowNumber = GemMan::windowNumber();	    // reassign window
        m_redoFont = 2;
    }	    

    if (m_redoFont)
	if ( !stringCreateList() ) return;
    setModified();
}

/////////////////////////////////////////////////////////
// fontNameMess
//
/////////////////////////////////////////////////////////
void text :: fontNameMess(t_symbol *s)
{
    delete [] m_fontName;
    // default font
    if (!strcmp(s->s_name, "default")) m_fontName = strdup(DEFAULT_FONT);
    else m_fontName = strdup(s->s_name);
    
    m_redoFont = 1;
    setModified();
}

/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void text :: render(GemState *)
{
    glListBase(m_fontBase);
    glRasterPos3f(0.0, 0.0, 0.0);
    glCallLists(strlen(m_theString), GL_BYTE, (GLubyte *)m_theString);
    glListBase(0);
}

/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void text :: obj_setupCallback(t_class *classPtr)
{
    class_addmethod(classPtr, (t_method)&text::fontNameMessCallback,
    	    gensym("font"), A_SYMBOL, A_NULL);
    class_addmethod(classPtr, (t_method)&text::textMessCallback,
    	    gensym("text"), A_GIMME, A_NULL);
    class_addmethod(classPtr, (t_method)&text::prepMessCallback,
    	    gensym("prep"), A_NULL);
}
void text :: fontNameMessCallback(void *data, t_symbol *s)
{
    GetMyClass(data)->fontNameMess(s);
}
void text :: textMessCallback(void *data, t_symbol *, int argc, t_atom *argv)
{
    GetMyClass(data)->textMess(argc, argv);
}
void text :: prepMessCallback(void *data)
{
    GetMyClass(data)->prepMess();
}
