/*
 * ************************************************************************************************************
 * Author: Marcin Załęczny
 * Copyright (C)2010 Marcin Załęczny <mzaleczny@hotmail.com>
 * License: The GNU Lesser General Public License, version 3.0 (LGPLv3)
 * Library Name: mzstdgraphics
 * Version: 1.05
 * First release date:   2010-11-08
 * Current release date: 2011-03-04
 *
 *
 * This file is part of mzstdgraphics library
 * 
 * mzstdgraphics library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * mzstdgraphics 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. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * ************************************************************************************************************
 */

#include "mzFont.h"
#include "mzstdgraphicsGlobals.h"
#include "mzSystemParameters.h"

VOID CFont::_commonInit(HDC hdc, COLORREF color, CString fontName, LONG size, LONG rotationAngle, LONG weight, BOOL italic, BOOL underline, BOOL strikeout) {
    this->setRealClassName(L"CFont");
    this->color = color;
    this->name = fontName;
    this->size = size;
    this->rotationAngle = rotationAngle;
    this->weight = weight;
    this->italic = italic;
    this->underline = underline;
    this->strikeout = strikeout;
    
    BOOL releaseDC = FALSE;
    if (hdc == NULL) {
        hdc = GetDC(0);
        releaseDC = TRUE;
    }
	LOGFONT lf;
	ZeroMemory(&lf, sizeof(lf));
	lf.lfHeight = -MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72);
	lf.lfWidth = 0;
	lf.lfWeight = weight;
    lf.lfEscapement = rotationAngle;
    //lf.lfOrientation = rotationAngle;
    lf.lfItalic = italic;
    lf.lfUnderline = underline;
    lf.lfStrikeOut = strikeout;
	lf.lfCharSet = DEFAULT_CHARSET;
	lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
	lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
	lf.lfQuality = DEFAULT_QUALITY;
	lf.lfPitchAndFamily = DEFAULT_PITCH;
	wcscpy_s(&lf.lfFaceName[0], 32, fontName.getBuffer());

	this->hFont = CreateFontIndirect(&lf);
    if (releaseDC) {
        ReleaseDC(0, hdc);
    }
}

// FW_NORMAL
CFont::CFont(HDC hdc, COLORREF color, LONG type, LONG weight) {
    this->setRealClassName(L"CFont");
	this->_createFont(hdc, color, type, weight);
}

CFont::CFont(HDC hdc, COLORREF color, CString fontName, LONG size) {
    this->_commonInit(hdc, color, fontName, size, 0, FW_NORMAL, FALSE, FALSE, FALSE);
}

CFont::CFont(HDC hdc, COLORREF color, CString fontName, LONG size, LONG rotationAngle) {
    this->_commonInit(hdc, color, fontName, size, rotationAngle, FW_NORMAL, FALSE, FALSE, FALSE);
}

CFont::CFont(HDC hdc, COLORREF color, CString fontName, LONG size, LONG rotationAngle, LONG weight, BOOL italic, BOOL underline, BOOL strikeout) {
    this->_commonInit(hdc, color, fontName, size, rotationAngle, weight, italic, underline, strikeout);
}

CFont::~CFont() 
{
	if (this->hFont) {
		DeleteObject(this->hFont); 
	}
}

VOID CFont::_createFont(HDC hdc, COLORREF color, LONG type, LONG weight)
{
	NONCLIENTMETRICS ncm = GetNonClientMetrics();
    LOGFONT lf;
    BOOL releaseDC = FALSE;
    if (hdc == NULL) {
        hdc = GetDC(0);
        releaseDC = TRUE;
    }
    LONG logpixelsy = GetDeviceCaps(hdc, LOGPIXELSY);
    
	if (this->hFont) {
		DeleteObject(this->hFont);
        this->hFont = NULL;
    }
	
    switch (type) {
        case SYSTEM_WINDOW_CAPTION_FONT:
            lf = ncm.lfCaptionFont;
            weight = FW_SEMIBOLD;
            break;
        default:
            this->_commonInit(hdc, color, L"Arial", 10, 0, FW_NORMAL, FALSE, FALSE, FALSE);
            if (releaseDC) {
                ReleaseDC(0, hdc);
            }
            return;
    }
    
    lf.lfWeight = weight;
    this->color = color;
    this->name = lf.lfFaceName;
    this->size = lf.lfHeight * 72 / logpixelsy;
    this->rotationAngle = lf.lfEscapement;
    this->weight = lf.lfWeight;
    this->italic = lf.lfItalic;
    this->underline = lf.lfUnderline;
    this->strikeout = lf.lfStrikeOut;
    this->hFont = CreateFontIndirect(&lf);
    
    if (releaseDC) {
        ReleaseDC(0, hdc);
    }
} 

SIZE CFont::measureString(CString s, HDC hdc) {
	HDC hdcInternal;
    if (hdc == 0) {
        hdcInternal = GetDC(0);
    } else {
        hdcInternal = hdc;
    }

    HFONT oldFont = (HFONT)SelectObject(hdcInternal, this->hFont);
    SIZE size;
    GetTextExtentPoint(hdcInternal, s.getBuffer(), s.length(), &size);
	SelectObject(hdcInternal, oldFont);

    if (hdc == 0) {
        ReleaseDC(0, hdcInternal);
    }

	return size;
}

SIZE CFont::measureString(CString s, LONG charSpacing, HDC hdc) {
//SIZE s1; s1.cx = 40; s1.cy = 12; return s1;
	HDC hdcInternal;
    if (hdc == 0) {
        hdcInternal = GetDC(0);
    } else {
        hdcInternal = hdc;
    }

    RECT letterRect;
    SIZE size, letterSize;
    ULONG len = s.length();
    WCHAR str[2];
    ZeroMemory(str, 2*sizeof(WCHAR));

    size.cx = 0;
    size.cy = 0;
    
    HFONT oldFont = (HFONT)SelectObject(hdcInternal, this->hFont);
    for (ULONG i = 0; i < len; i++) {
        str[0] = s.getCharAt(i);
        GetTextExtentPoint(hdcInternal, str, 1, &letterSize);
        size.cx += letterSize.cx;
        if (letterSize.cy > size.cy) {
            size.cy = letterSize.cy;
        }
        if (i < len - 1) {
            size.cx += charSpacing;
        }
    }

	SelectObject(hdcInternal, oldFont);
    if (hdc == 0) {
        ReleaseDC(0, hdcInternal);
    }

	return size;
}

SIZE CFont::measureChar(WCHAR ch, HDC hdc) {
SIZE s1; s1.cx = 40; s1.cy = 12; return s1;
	HDC hdcInternal;
    if (hdc == 0) {
        hdcInternal = GetDC(0);
    } else {
        hdcInternal = hdc;
    }
    WCHAR str[2];

    str[0] = ch;
    str[1] = NULL;

    HFONT oldFont = (HFONT)SelectObject(hdcInternal, this->hFont);
    SIZE size;
    GetTextExtentPoint(hdcInternal, str, 1, &size);
	SelectObject(hdcInternal, oldFont);

    if (hdc == 0) {
        ReleaseDC(0, hdcInternal);
    }

	return size;
}

CStringList *CFont::getAvailableSystemFontNames() {
	HDC hdc = GetDC(0);
	LOGFONT lf;
	memset(&lf, 0, sizeof(lf));

	lf.lfCharSet = DEFAULT_CHARSET;
	lf.lfFaceName[0] = NULL;
	lf.lfPitchAndFamily = 0;

	CStringList *result = new CStringList();
	EnumFontFamiliesEx(hdc, &lf, CFont::_fontEnumProcGetNames, (LPARAM)result, 0);
	ReleaseDC(0, hdc);

	return result;
}

INT CFont::_fontEnumProcGetNames(const LOGFONT *lpelfe, const TEXTMETRIC *lpntme, DWORD FontType, LPARAM lParam) {
	CString *fontName = new CString(lpelfe->lfFaceName);
	CStringList *lst = (CStringList*)lParam;
	if (lst) {
		// jeśli font o takiej nazwie już w tablicy istnieje, to go nie dodajemy
		BOOL exists = FALSE;
		CString s;
		for (ULONG i = 0; i < lst->size(); i++) {
			s = lst->getAt(i);
			if (s == *fontName) {
				exists = TRUE;
				break;
			}
		}
		if (!exists) {
			lst->append(*fontName);
		}
	}

	delete fontName;
	return 1;
}
