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

namespace sptk {

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

#define MAX_BIFF8FORMAT 0x31	///< Max BIFF8 format

   /// 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
