/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CExcelFont.cpp  -  description
                             -------------------
    begin                : 19 March 2004
    copyright            : (C) 2004-2006 by Alexey Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
   This library is free software; you can redistribute it and/or modify it
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at
   your option) any later version.

   This 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 Library
   General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#include <sptk3/excel/CExcelFont.h>
#include <string.h>

#define EFM_WEIGHT_NORMAL  0x190
#define EFM_WEIGHT_BOLD    0x2BC

using namespace std;
using namespace sptk;

string CExcelFont::computeFontMetrics(const char *fontName,unsigned fontHeight,unsigned fontAttr,unsigned charSet) {
   return string(fontName) + "-" + int2string(fontHeight) + "-" + int2string(fontAttr) + "-" + int2string(charSet);
}

CExcelFont::CExcelFont(unsigned fontIndex,const char *fontName,unsigned fontHeight,unsigned fontAttr,unsigned charSet) 
: CExcelRecord(FONT2,0,0L,true)
{
   m_fontIndex = fontIndex;
   unsigned fontNameLength = strlen(fontName);
   unsigned dataSize = 16 + fontNameLength * 2;
   m_data = new char[dataSize];
   m_bytes = dataSize;
   memset(m_data,0,dataSize);
   CExcelRecord::setshort(m_data,0,fontHeight*20);

   // Default color palette index
   m_data[4] = (unsigned char)0xFF;
   m_data[5] = (unsigned char)0x7F;

   attr(fontAttr);

   m_data[12] = (unsigned char)charSet;

   m_data[14] = (unsigned char) fontNameLength;
   m_data[15] = 1;
   for (unsigned i = 0; i < fontNameLength; i++)
      m_data[16+i*2] = fontName[i];

   m_fontMetrics = computeFontMetrics(fontName,fontHeight,fontAttr,charSet);
}

CExcelFont::CExcelFont(unsigned fontIndex,unsigned fontDataSize,const char *fontData) 
: CExcelRecord(FONT2,fontDataSize,new char[fontDataSize],true)
{
   m_fontIndex = fontIndex;
   memcpy(m_data,fontData,fontDataSize);
   m_fontMetrics = computeFontMetrics(name().c_str(),height(),attr(),(unsigned char)m_data[12]);
}

string CExcelFont::name() const {
   unsigned fontNameLength = unsigned(m_data[14]);
   string fontName(fontNameLength,' ');
   for (unsigned i = 0; i < fontNameLength; i++)
      fontName[i] = m_data[16+i*2];
   return fontName;
}

void CExcelFont::name(string fontName) {
   unsigned fontNameLength = fontName.length();
   m_data[14] = (unsigned char) fontNameLength;
   for (unsigned i = 0; i < fontNameLength; i++)
      m_data[16+i*2] = fontName[i];
}

unsigned CExcelFont::height() const {
   return CExcelRecord::getshort(m_data,0) / 20;
}

void CExcelFont::height(unsigned height) {
   CExcelRecord::setshort(m_data,0,height*20);
}

unsigned CExcelFont::attr() const {
   return CExcelRecord::getshort(m_data,2);
}

void CExcelFont::attr(unsigned fontAttr) {
   CExcelRecord::setshort(m_data,2,fontAttr);

   unsigned fontWeight = EFM_WEIGHT_NORMAL;
   if (fontAttr & EFM_ATTR_BOLD)
      fontWeight = EFM_WEIGHT_BOLD;
   CExcelRecord::setshort(m_data,6,fontWeight);

   if (fontAttr & EFM_ATTR_UNDERLINE)
      m_data[10] = (unsigned char)1;
}

//============================================================================

void CExcelFonts::init() {
   clear();
   add("Arial",10,0,0);
   add("Arial",10,0,1);
   add("Arial",10,EFM_ATTR_BOLD,1);
   add("Arial",11,0,1);
   add("Arial",11,EFM_ATTR_BOLD,0);
}

void CExcelFonts::saveRecords(CExcelRecordsBuffer& records) {
   unsigned cnt = size();
   for (unsigned i = 0; i < cnt; i++) {
      if (i == 4) continue;
      const CExcelRecord& fontRecord = (*this)[i];
      records.append(&fontRecord);
   }
}

int CExcelFonts::add(const char *fontName,unsigned fontHeight,unsigned fontAttr,unsigned charSet) {
   string fontMetrics = CExcelFont::computeFontMetrics(fontName,fontHeight,fontAttr,charSet);
   CFontNamesMap::iterator itor = m_fontMap.find(fontMetrics);
   if (itor != m_fontMap.end()) {
      CExcelFont *f = itor->second;
      return f->m_fontIndex;
   }
   unsigned fontIndex = size();
   CExcelFont *font;
   if (fontIndex == 4) {
      // This record (#4) should be never written to Excel file
      // due the compatibilty with prior Excel versions. 
      // Creating the dummy FONT record.
      CExcelFont *dummyFont = new CExcelFont(fontIndex,"NOFONT",0,0,0);
      m_fontMap[dummyFont->fontMetrics()] = dummyFont;
      m_fontList.push_back(dummyFont);
      fontIndex++;
   }
   font = new CExcelFont(fontIndex,fontName,fontHeight,fontAttr,charSet);
   m_fontMap[fontMetrics] = font;
   m_fontList.push_back(font);
   return fontIndex;
}

int CExcelFonts::add(unsigned fontDataSize,const char *fontData) {
   CExcelFont *font = new CExcelFont(0,fontDataSize,fontData);
   unsigned fontIndex = size();
   if (fontIndex == 4) {
      // This record (#4) should be never written to Excel file
      // due the compatibilty with prior Excel versions. 
      // Creating the dummy FONT record.
      CExcelFont *dummyFont = new CExcelFont(fontIndex,"NOFONT",0);
      m_fontMap[dummyFont->fontMetrics()] = dummyFont;
      m_fontList.push_back(dummyFont);
      fontIndex++;
   }
   CFontNamesMap::iterator itor = m_fontMap.find(font->fontMetrics());
   if (itor != m_fontMap.end()) {
      // Found similar font, but have to create a record anyway
      // to read the Excel file with several identical FONT records.
      // Tweaking the font metrics:
      font->m_fontMetrics += "-" + int2string(fontIndex);
   }
   font->m_fontIndex = fontIndex;
   m_fontMap[font->fontMetrics()] = font;
   m_fontList.push_back(font);
   return fontIndex;
}

void CExcelFonts::clear() { 
   CFontList::iterator itor = m_fontList.begin();
   for (; itor != m_fontList.end(); itor++)
      delete *itor;

   m_fontList.clear(); 
   m_fontMap.clear(); 
}
