/////////////////////////////////////////////////////////////////////////////
// Name:        font.cpp
// Purpose:     wxFont class
// Author:      David Webster
// Modified by:
// Created:     10/06/99
// RCS-ID:      $Id$
// Copyright:   (c) David Webster
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
    #include <stdio.h>
    #include "wx/setup.h"
    #include "wx/list.h"
    #include "wx/utils.h"
    #include "wx/app.h"
    #include "wx/font.h"
#endif // WX_PRECOMP

#include "wx/os2/private.h"

    IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject)

    #if wxUSE_PORTABLE_FONTS_IN_MSW
        IMPLEMENT_DYNAMIC_CLASS(wxFontNameDirectory, wxObject)
    #endif

// ----------------------------------------------------------------------------
// wxFontRefData - the internal description of the font
// ----------------------------------------------------------------------------

class WXDLLEXPORT wxFontRefData: public wxGDIRefData
{
friend class WXDLLEXPORT wxFont;

public:
    wxFontRefData()
    {
        Init(12, wxDEFAULT, wxNORMAL, wxNORMAL, FALSE,
             "", wxFONTENCODING_DEFAULT);
    }

    wxFontRefData(const wxFontRefData& data)
    {
        Init(data.m_pointSize, data.m_family, data.m_style, data.m_weight,
             data.m_underlined, data.m_faceName, data.m_encoding);

        m_fontId = data.m_fontId;
    }

    wxFontRefData(int size,
                  int family,
                  int style,
                  int weight,
                  bool underlined,
                  const wxString& faceName,
                  wxFontEncoding encoding)
    {
        Init(size, family, style, weight, underlined, faceName, encoding);
    }

    virtual ~wxFontRefData();

protected:
    // common part of all ctors
    void Init(int size,
              int family,
              int style,
              int weight,
              bool underlined,
              const wxString& faceName,
              wxFontEncoding encoding);

    // If TRUE, the pointer to the actual font is temporary and SHOULD NOT BE
    // DELETED by destructor
    bool          m_temporary;

    int           m_fontId;

    // font characterstics
    int           m_pointSize;
    int           m_family;
    int           m_style;
    int           m_weight;
    bool          m_underlined;
    wxString      m_faceName;
    wxFontEncoding m_encoding;

    // Windows font handle
    WXHFONT       m_hFont;
};

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// wxFontRefData
// ----------------------------------------------------------------------------

void wxFontRefData::Init(int pointSize,
                         int family,
                         int style,
                         int weight,
                         bool underlined,
                         const wxString& faceName,
                         wxFontEncoding encoding)
{
    m_style = style;
    m_pointSize = pointSize;
    m_family = family;
    m_style = style;
    m_weight = weight;
    m_underlined = underlined;
    m_faceName = faceName;
    m_encoding = encoding;

    m_fontId = 0;
    m_temporary = FALSE;

    m_hFont = 0;
}

wxFontRefData::~wxFontRefData()
{
// TODO:
//    if ( m_hFont )
//    {
//        if ( !::DeleteObject((HFONT) m_hFont) )
//        {
//            wxLogLastError("DeleteObject(font)");
//        }
//    }
}

// ----------------------------------------------------------------------------
// wxFont
// ----------------------------------------------------------------------------

void wxFont::Init()
{
    if ( wxTheFontList )
        wxTheFontList->Append(this);
}

/* Constructor for a font. Note that the real construction is done
 * in wxDC::SetFont, when information is available about scaling etc.
 */
bool wxFont::Create(int pointSize,
                    int family,
                    int style,
                    int weight,
                    bool underlined,
                    const wxString& faceName,
                    wxFontEncoding encoding)
{
    UnRef();
    m_refData = new wxFontRefData(pointSize, family, style, weight,
                                  underlined, faceName, encoding);

    RealizeResource();

    return TRUE;
}

wxFont::~wxFont()
{
    if ( wxTheFontList )
        wxTheFontList->DeleteObject(this);
}

// ----------------------------------------------------------------------------
// real implementation
// Boris' Kovalenko comments:
//   Because OS/2 fonts are associated with PS we can not create the font
//   here, but we may check that font definition is true
// ----------------------------------------------------------------------------

bool wxFont::RealizeResource()
{
    if ( GetResourceHandle() )
    {
        // VZ: the old code returned FALSE in this case, but it doesn't seem
        //     to make sense because the font _was_ created
        wxLogDebug(wxT("Calling wxFont::RealizeResource() twice"));

       return TRUE;
    }

    HPS          hps;
    FATTRS       fAttrs;
    FACENAMEDESC fName;
    LONG         fLid;

    fAttrs.usRecordLength = sizeof(FATTRS);
    fAttrs.fsFontUse = FATTR_FONTUSE_OUTLINE |       // only outline fonts allowed
                       FATTR_FONTUSE_TRANSFORMABLE;  // may be transformed
    fAttrs.fsType = 0;
    fAttrs.lMaxBaselineExt = fAttrs.lAveCharWidth = 0;
    fAttrs.idRegistry = 0;
    fAttrs.lMatch = 0;

    fName.usSize = sizeof(FACENAMEDESC);
    fName.usWidthClass = FWIDTH_NORMAL;
    fName.usReserved = 0;
    fName.flOptions = 0;

    wxString ff_face;

// OS/2 combines the family with styles to give a facename

    switch ( M_FONTDATA->m_family )
    {
        case wxSCRIPT:
        case wxDECORATIVE:
        case wxROMAN:
            ff_face = wxT("Times New Roman") ;
            break;

        case wxTELETYPE:
        case wxMODERN:
            ff_face = wxT("Courier") ;
            break;

        case wxSWISS:
        case wxDEFAULT:
        default:
            ff_face = wxT("Helvetica") ;
    }

    switch ( M_FONTDATA->m_style )
    {
        case wxITALIC:
        case wxSLANT:
            fAttrs.fsSelection = FATTR_SEL_ITALIC;
            break;

        default:
            wxFAIL_MSG(wxT("unknown font slant"));
            // fall through

        case wxNORMAL:
            fAttrs.fsSelection = 0;
    }

    switch ( M_FONTDATA->m_weight )
    {
        default:
            wxFAIL_MSG(wxT("unknown font weight"));
            // fall through

        case wxNORMAL:
            fName.usWeightClass = FWEIGHT_NORMAL;
            break;

        case wxLIGHT:
            fName.usWeightClass = FWEIGHT_LIGHT;
            break;

        case wxBOLD:
            fName.usWeightClass = FWEIGHT_BOLD;
            break;
    }
  
    if( M_FONTDATA->m_underlined )
        fAttrs.fsSelection |= FATTR_SEL_UNDERSCORE;

    wxFontEncoding encoding = M_FONTDATA->m_encoding;
    if ( encoding == wxFONTENCODING_DEFAULT )
    {
        encoding = wxFont::GetDefaultEncoding();
    }

    switch ( encoding )
    {
        case wxFONTENCODING_ISO8859_1:
        case wxFONTENCODING_ISO8859_15:
        case wxFONTENCODING_CP1250:
            fAttrs.usCodePage = 1250;
            break;

        case wxFONTENCODING_ISO8859_2:
        case wxFONTENCODING_CP1252:
            fAttrs.usCodePage = 1252;
            break;

        case wxFONTENCODING_ISO8859_4:
        case wxFONTENCODING_ISO8859_10:
            fAttrs.usCodePage = 850; // what is baltic?
            break;

        case wxFONTENCODING_ISO8859_5:
        case wxFONTENCODING_CP1251:
            fAttrs.usCodePage = 1251;
            break;

        case wxFONTENCODING_ISO8859_6:
            fAttrs.usCodePage = 850;  // what is arabic?
            break;

        case wxFONTENCODING_ISO8859_7:
            fAttrs.usCodePage = 850;  // what is greek
            break;

        case wxFONTENCODING_ISO8859_8:
            fAttrs.usCodePage = 850; // what is hebrew?
            break;

        case wxFONTENCODING_ISO8859_9:
            fAttrs.usCodePage = 857;
            break;

        case wxFONTENCODING_ISO8859_11:
            fAttrs.usCodePage = 850; // what is thai
            break;

        case wxFONTENCODING_CP437:
            fAttrs.usCodePage = 437;
            break;

        default:
            wxFAIL_MSG(wxT("unsupported encoding"));
            // fall through

        case wxFONTENCODING_SYSTEM:
            fAttrs.usCodePage = 850; // what is ANSI?
            break;
    }

// Now cheking 
    fLid = 1;
    hps  = ::WinGetPS( HWND_DESKTOP );

    long numLids = ::GpiQueryNumberSetIds( hps );
    long gpiError;
    
    // First we should generate unique id
    if( numLids )
    {
        long Types[255];
        STR8 Names[255];
        long lIds[255];

        if( !GpiQuerySetIds(hps, numLids, Types, Names, lIds) )
        {
            ::WinReleasePS( hps );
            return 0;
        }
      
        for(unsigned long LCNum = 0; LCNum < numLids; LCNum++)
            if(lIds[LCNum] == fLid)
               ++fLid;
        if(fLid > 254)  // wow, no id available!
        {
           ::WinReleasePS( hps );
           return 0;
        }
    }

    // now building facestring
    if(::GpiQueryFaceString(hps, ff_face.c_str(), &fName, FACESIZE, fAttrs.szFacename) == GPI_ERROR)
    {
       ::WinReleasePS( hps );
       return 0;
    }

    // now creating font
    WXHFONT hFont = (WXHFONT)0;

    if(::GpiCreateLogFont(hps, NULL, fLid, &fAttrs) != GPI_ERROR)
       M_FONTDATA->m_hFont = hFont = (WXHFONT)1;

    if( hFont )
        ::GpiDeleteSetId(hps, fLid);

    ::WinReleasePS( hps );

    if ( !hFont )
    {
        wxLogLastError("CreateFont");
    }

    return hFont != 0;
}

bool wxFont::FreeResource(bool force)
{
    if ( GetResourceHandle() )
    {
// TODO:
//        if ( !::DeleteObject((HFONT) M_FONTDATA->m_hFont) )
//        {
//            wxLogLastError("DeleteObject(font)");
//        }

        M_FONTDATA->m_hFont = 0;

        return TRUE;
    }
    return FALSE;
}

WXHANDLE wxFont::GetResourceHandle()
{
    if ( !M_FONTDATA )
        return 0;
    else
        return (WXHANDLE)M_FONTDATA->m_hFont ;
}

bool wxFont::IsFree() const
{
    return (M_FONTDATA && (M_FONTDATA->m_hFont == 0));
}

void wxFont::Unshare()
{
    // Don't change shared data
    if ( !m_refData )
    {
        m_refData = new wxFontRefData();
    }
    else
    {
        wxFontRefData* ref = new wxFontRefData(*M_FONTDATA);
        UnRef();
        m_refData = ref;
    }
}

// ----------------------------------------------------------------------------
// change font attribute: we recreate font when doing it
// ----------------------------------------------------------------------------

void wxFont::SetPointSize(int pointSize)
{
    Unshare();

    M_FONTDATA->m_pointSize = pointSize;

    RealizeResource();
}

void wxFont::SetFamily(int family)
{
    Unshare();

    M_FONTDATA->m_family = family;

    RealizeResource();
}

void wxFont::SetStyle(int style)
{
    Unshare();

    M_FONTDATA->m_style = style;

    RealizeResource();
}

void wxFont::SetWeight(int weight)
{
    Unshare();

    M_FONTDATA->m_weight = weight;

    RealizeResource();
}

void wxFont::SetFaceName(const wxString& faceName)
{
    Unshare();

    M_FONTDATA->m_faceName = faceName;

    RealizeResource();
}

void wxFont::SetUnderlined(bool underlined)
{
    Unshare();

    M_FONTDATA->m_underlined = underlined;

    RealizeResource();
}

void wxFont::SetEncoding(wxFontEncoding encoding)
{
    Unshare();

    M_FONTDATA->m_encoding = encoding;

    RealizeResource();
}

// ----------------------------------------------------------------------------
// accessors
// ----------------------------------------------------------------------------

int wxFont::GetPointSize() const
{
    return M_FONTDATA->m_pointSize;
}

int wxFont::GetFamily() const
{
    return M_FONTDATA->m_family;
}

int wxFont::GetFontId() const
{
    return M_FONTDATA->m_fontId;
}

int wxFont::GetStyle() const
{
    return M_FONTDATA->m_style;
}

int wxFont::GetWeight() const
{
    return M_FONTDATA->m_weight;
}

bool wxFont::GetUnderlined() const
{
    return M_FONTDATA->m_underlined;
}

wxString wxFont::GetFaceName() const
{
    wxString str;
    if ( M_FONTDATA )
        str = M_FONTDATA->m_faceName ;
    return str;
}

wxFontEncoding wxFont::GetEncoding() const
{
    return M_FONTDATA->m_encoding;
}

