/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CExcelCellFormat.h  -  description
                             -------------------
    begin                : Mon Jan 19 2004
    copyright            : (C) 2000-2005 by Alexey S.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"
 ***************************************************************************/

#ifndef __CEXCELFORMATRECORD_H__
#define __CEXCELFORMATRECORD_H__

#include <sptk3/CVariant.h>
#include <sptk3/CException.h>
#include <sptk3/excel/CExcelFont.h>
#include <sptk3/excel/CExcelNumericFormat.h>
#include <sptk3/excel/CExcelPalette.h>

#include <vector>

#define MAX_BIFF8FORMAT 0x31

/// @addtogroup excel Excel Classes
/// @{

/// Possible align format flags for cell formatting. These flags
/// can be combined to get the desired alignment using bit operations.
enum CExcelCellAlignFlags {
   CAF_GENERAL=0,    ///< Default alignment
   CAF_LEFT,         ///< Left align text horizontally
   CAF_CENTER,       ///< Center text horizontally
   CAF_RIGHT,        ///< Right align text horizontally
   CAF_FILL,         ///< Fill text horizontally
   CAF_JUSTIFY,      ///< Justify text horizontally
   CAF_WRAP=8,       ///< Wrap text
   CAF_VCENTER=9,    ///< Center text vertically
   CAF_VBOTTOM=10,   ///< Align text to the bottom
   CAF_VJUSTIFY=11   ///< Justify text vertically
};

/// Possible border types for the cell
enum CExcelBorderLine {
   CBL_NONE,       ///< No border
   CBL_THIN,       ///< Thin line
   CBL_MEDIUM,     ///< Medium line
   CBL_DASHED,     ///< Dashed line
   CBL_DOTTED,     ///< Dotted line
   CBL_THICK,      ///< Thick line
   CBL_DOUBLE,     ///< Double line
   CBL_HAIR,       ///< Very thin line
   CBL_MDASHED,    ///< Medium dashed line
   CBL_DASHDOT,    ///< Dash-dot line
   CBL_MDASHDOT,   ///< Medium dash-dot line
   CBL_DASHDOTDOT, ///< Dash-dot-dot line
   CBL_MDASHDOTDOT,///< Medium dash-dot-dot line
   CBL_SDASHDOT    ///< Slanted dash-dot line
};

/// The format descriptor
typedef struct ifmt {
   CVariantType   kind;           ///< Format data type
   unsigned char  id;             ///< Format ID
   const char     *format;        ///< Format string
} IFMT;

/// Class CExcelCellFormat describes the cell data presentation.
class SP_EXPORT CExcelCellFormat {
   friend class CExcelCellFormats;
protected:
   char                 m_data[20];           ///< Internal data buffer
   unsigned             m_index;              ///< Index of this record in XF records table
   CExcelNumericFormat *m_dataFormat;         ///< Cell data format information

protected:	
   /// Protected constructor, builds a new format record from the scratch
   /// @param fontIndex unsigned, the logical index of the existing font
   /// @param numericFormatIndex unsigned, the logical index of the existing numeric format
   /// @param align unsigned, the combination of align flags from enum CExcelCellAlignFlags
   /// @param wrap bool, the cell text wrap flag
   /// @param border CExcelBorderLine, the type of the cell border line
   /// @param pattern unsigned, one of the Excel standard pattern types 0..0x12
   /// @param patternForeColorIndex unsigned, the pattern fore color index in the palette
   /// @param patternBackColorIndex unsigned, the pattern back color index in the palette
   CExcelCellFormat(
      unsigned fontIndex=0,
      unsigned numericFormatIndex=0,
      unsigned align=0,
      bool     wrap=false,
      CExcelBorderLine border=CBL_NONE,
      unsigned pattern=0,
      unsigned patternForeColorIndex=EPC_BLACK,
      unsigned patternBackColorIndex=EPC_WHITE
   );

   /// Protected constructor, builds a new format record from the existing XF record data
   /// @param XFData const void *, the XF record data to be copied inside
   CExcelCellFormat(const void *XFData);

   /// Protected copy constructor
   /// @param xfRecord const CExcelCellFormat&, the XF record 
   CExcelCellFormat(const CExcelCellFormat& xfRecord);

public:

   /// Returns the index of this record in XF records table
   unsigned index() const { return m_index; }

   /// Returns a pointer to data buffer that contains XF record data
   const char *data() const { return m_data; }

   /// Returns font index in the fonts table
   unsigned fontIndex() const { return CExcelRecord::getshort(m_data,0); }

   /// Sets font index from the fonts table
   /// @param fi unsigned, font index from the fonts table
   void fontIndex(unsigned fi) { CExcelRecord::setshort(m_data,0,fi); }

   /// Returns format index in the formats table
   unsigned formatIndex() const { return CExcelRecord::getshort(m_data,2); }

   /// Sets format index in the formats table
   void formatIndex(unsigned fi) { CExcelRecord::setshort(m_data,2,fi); }

   /// Retuns the align flags for the cell
   unsigned align() const { return CExcelRecord::getshort(m_data,6)&0x77; }

   /// Sets the align flags for the cell
   void align(unsigned flags);

   /// Retuns the wrap flag for the cell
   unsigned wrap() const { return CExcelRecord::getshort(m_data,6)&0x8; }

   /// Sets the wrap flag for the cell
   void wrap(bool flag);

   /// Returns border line style for the left edge
   CExcelBorderLine border() const  { return CExcelBorderLine(CExcelRecord::getshort(m_data,10) & 0xF); }

   /// Sets border line style
   /// @param ls CExcelBorderLines, border line style
   void border(CExcelBorderLine ls);       

   /// Returns the index of the pattern background color in the palette
   unsigned patternBackColor() const;

   /// Sets the index of the pattern background color in the palette
   /// @param patternBackColorIndex unsigned, index of color in the palette
   void patternBackColor(unsigned patternBackColorIndex);

   /// Returns the index of the pattern foreground color in the palette
   unsigned patternForeColor() const;

   /// Sets the index of the pattern foreground color in the palette
   /// @param patternForeColorIndex unsigned, index of color in the palette
   void patternForeColor(unsigned patternForeColorIndex);

   /// Defines fill pattern index for the background
   /// @param patternIndex unsigned, the index of the standard pattern
   void fillPattern(unsigned patternIndex);

   /// Returns numeric format info
   const CExcelNumericFormat& dataFormat() const { return *m_dataFormat; }
};

/// The list of the available cell formats.
class CExcelCellFormats {
   friend class CExcelBook;
protected:
   CExcelNumericFormats               m_numericFormats;   ///< The list of the available numeric formats
   std::vector<CExcelCellFormat *>    m_formatList;       ///< The list of the XF formats
   CExcelFonts                        m_fonts;            ///< The list of the available fonts

public:
   /// Default constructor
   CExcelCellFormats()  { init(); }

   /// Destructor
   ~CExcelCellFormats() { clear(); }

   /// Adds a font to the font list, or finds similar existing font
   /// @param fontName const char *, font name
   /// @param fontHeight unsigned, font height in points
   /// @param fontAttr unsigned, font attr (EFM_ATTR_ITALIC,EFM_ATTR_STRIKEOUT)
   /// @param charSet unsigned, character set as defined in Windows API LOGFONT structure
   /// @returns logical index of the new or existing font
   int addFont(const char *fontName,unsigned fontHeight,unsigned fontAttr=0,unsigned charSet=0);

   /// Adds a font to the font list, even if similar font exists. In the last case the metrics field
   /// is appended with the logical index of the font. That allows to read the Excel files with several
   /// identical FONT records defined
   /// @param fontDataSize unsigned, the size of the FONT record data
   /// @param fontData const char *, FONT record data in internal Excel format
   /// @returns logical index of the new font
   int addFont(unsigned fontDataSize,const char *fontData);

   /// Adds a new numeric format. Any attempts to re-define the built-in Excel Formats are ignored.
   /// @param numericFormatIndex unsigned, numeric format index
   /// @param numericFormat CString, numeric format
   void addNumericFormat(unsigned numericFormatIndex,std::string numericFormat);

   /// Inserts new format. 
   /// The format information is kept as a pointer. 
   /// The associated memory will be relesed upon clear() or destructor.
   /// @param xfr CExcelCellFormat *, the format record
   CExcelCellFormat *insert(CExcelCellFormat *xfr);

   /// Inserts new format from the existing Excel XF record 
   /// @param XFData const void *, the format record in internal XF format
   CExcelCellFormat *insert(const void *XFData);

   /// Inserts new format, builds a new format record from the scratch
   /// @param fontIndex unsigned, the logical index of the existing font
   /// @param numericFormatIndex unsigned, the logical index of the existing numeric format
   /// @param align unsigned, the combination of align flags from enum CExcelCellAlignFlags
   /// @param wrap bool, the cell text wrap flag
   /// @param border CExcelBorderLine, the type of the cell border line
   /// @param pattern unsigned, one of the Excel standard pattern types 0..0x12
   /// @param patternForeColorIndex unsigned, the pattern fore color index in the palette
   /// @param patternBackColorIndex unsigned, the pattern back color index in the palette
   CExcelCellFormat *insert(
      unsigned fontIndex=0,
      unsigned numericFormatIndex=0,
      unsigned align=0,
      bool     wrap=false,
      CExcelBorderLine border=CBL_NONE,
      unsigned pattern=0,
      unsigned patternForeColorIndex=EPC_BLACK,
      unsigned patternBackColorIndex=EPC_WHITE
   );

   /// Clears the list of numeric formats, fonts, cell formats
   void clear();

   /// Clears the list of numeric formats, fonts, cell formats,
   /// then creates the minimal set of formats, fonts, and cell formats
   void init();

   /// Format access by format index
   /// @param i unsigned, the format index
   const CExcelCellFormat& operator [] (unsigned i) const { return *m_formatList[i]; }

   /// Format access by format index
   /// @param i int, the format index
   const CExcelCellFormat& operator [] (int i) const { return *m_formatList[i]; }

   /// Returns the number of available formats
   unsigned size() const { return m_formatList.size(); }

   /// Encodes FORMAT and XF into internal Excel format
   void saveRecords(CExcelRecordsBuffer& records);

   /// Returns a numeric format for the index
   /// @param index unsigned, logical index for the numeric format
   const CExcelNumericFormat& numericFormat(unsigned index) const { 
      CExcelNumericFormats::const_iterator itor = m_numericFormats.find(index);
      if (itor != m_numericFormats.end())
         return *itor->second;
      throw CException("Invalid (unknown) numeric format",__FILE__,__LINE__);
   }

   /// Returns a font for the index
   /// @param index unsigned, logical index for the font
   const CExcelFont& font(unsigned index) const { return m_fonts[index]; }
};

/// @}

#endif
