/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CExcelHeader.cpp  -  description
                             -------------------
    begin                : Mar 18 2004
    copyright            : (C) 2001-2005 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 <string.h>
#include <sptk3/excel/CExcelHeader.h>
#include <sptk3/excel/CExcelRecord.h>
#include <sptk3/CException.h>

CExcelHeader::CExcelHeader(const char *newData) {
   if (!newData)
      clear();
   else
      data(newData);
}

void CExcelHeader::clear() {
   memset(m_data,0xFF,BIG_BLOCK_SIZE);

   memcpy(m_data,"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1",8);
   memset(m_data+8,0,16);
   memcpy(m_data+0x18,"\x3E\x00\x03\x00\xFE\xFF\x09\x00",8);

   memset(m_data+0x20,0,12);
   m_data[0x20] = char(0x6);

   memset(m_data+0x24,0,8);

   CExcelRecord::setint(m_data,_BAT_COUNT_OFFSET,0);
   CExcelRecord::setint(m_data,_PROPERTY_START_OFFSET,END_OF_CHAIN);

   CExcelRecord::setint(m_data,0x34,0);
   CExcelRecord::setint(m_data,0x38,0x1000);
   CExcelRecord::setint(m_data,_SBAT_START_OFFSET,END_OF_CHAIN);
   CExcelRecord::setint(m_data,_SBAT_COUNT_OFFSET,0);
   CExcelRecord::setint(m_data,_XBAT_START_OFFSET,END_OF_CHAIN);
   CExcelRecord::setint(m_data,_XBAT_COUNT_OFFSET,0);
}

void CExcelHeader::data(const char *data) {
   if (!data) {
      clear();
   } else {
      if (memcmp(m_data,"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1",8) != 0)
         throw CException("Incorrect Excel file signature");
      memcpy(m_data,data,BIG_BLOCK_SIZE);
   }
}

void CExcelHeader::setBatTable(CExcelBAT& batTable) {
   // Set BAT block count
   CExcelRecord::setint(m_data,_BAT_COUNT_OFFSET,batTable.bytes()/BIG_BLOCK_SIZE);

   // Copy the main part of BAT
   memcpy(m_data+_BAT_ARRAY_OFFSET,batTable.batIndex().data(),batTable.batIndex().bytes());

   if (batTable.xbatBlockCount()) {
      CExcelRecord::setint(m_data,_XBAT_START_OFFSET,batTable.xbatStartBlock());
      CExcelRecord::setint(m_data,_XBAT_COUNT_OFFSET,batTable.xbatBlockCount());
   }
}

void CExcelHeader::setSBatTable(unsigned locationBlock,CExcelBAT& sbatTable) {
   if (sbatTable.blockCount()) {
      // Set SBAT start block
      CExcelRecord::setint(m_data,_SBAT_START_OFFSET,locationBlock);

      // Set SBAT block count
      CExcelRecord::setint(m_data,_SBAT_COUNT_OFFSET,sbatTable.blockCount());
   } else {
      // Set SBAT start block as END OF CHAIN
      CExcelRecord::setint(m_data,_SBAT_START_OFFSET,END_OF_CHAIN);

      // Set SBAT block count as 0
      CExcelRecord::setint(m_data,_SBAT_COUNT_OFFSET,0);
   }
}

void CExcelHeader::setPropertyTableStart(unsigned locationBlock) {
   CExcelRecord::setint(m_data,_PROPERTY_START_OFFSET,locationBlock);
}

void CExcelHeader::read(FILE *f) {
   unsigned rc = fread(m_data,1,BIG_BLOCK_SIZE,f);
   if (rc != BIG_BLOCK_SIZE)
      throw CException("Can't read Excel file header");
}

void CExcelHeader::save(FILE *f) {
   unsigned rc = fwrite(m_data,BIG_BLOCK_SIZE,1,f);
   if (!rc)
      throw CException("Can't save Excel file header");
}

unsigned CExcelHeader::batBlockCount() const {
   return CExcelRecord::getint(m_data,_BAT_COUNT_OFFSET);
}

unsigned CExcelHeader::xbatStartBlock() const {
   return CExcelRecord::getint(m_data,_XBAT_START_OFFSET);
}

void CExcelHeader::xbatStartBlock(unsigned startBlock) {
   CExcelRecord::setint(m_data,_XBAT_START_OFFSET,startBlock);
}

unsigned CExcelHeader::xbatBlockCount() const {
   return CExcelRecord::getint(m_data,_XBAT_COUNT_OFFSET);
}

void CExcelHeader::xbatBlockCount(unsigned blockCount) {
   CExcelRecord::setint(m_data,_XBAT_COUNT_OFFSET,blockCount);
}
