/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CExcelRecord.cpp  -  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"
 ***************************************************************************/

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sptk3/sptk.h>
#include <sptk3/excel/CExcelRecord.h>

using namespace std;
using namespace sptk;

CExcelRecord::CExcelRecord(short rectype,short reclen,const char *buffer,bool manageMemory)
{
   m_manageMemory = manageMemory;
   m_bytes = reclen;
   m_type  = rectype;
   m_data  = (char *)buffer;
}

void CExcelRecord::append(const char *data,unsigned sz) {
   char *newData = new char[m_bytes+sz+1];
   memcpy(newData,m_data,m_bytes);
   memcpy(newData+m_bytes,data,sz);
   if (m_manageMemory && m_data) delete m_data;
   m_manageMemory = true;
   m_data = newData;
   m_bytes += sz;
}

#if WORDS_BIGENDIAN == 1

short CExcelRecord::reorderBytes(short val) {
   char *bytes = (char *)&val;
   char  b = *bytes;
   *bytes = *(bytes + 1);
   *(bytes + 1) = b;
   return val;
}

unsigned short CExcelRecord::reorderBytes(unsigned short val) {
   char *bytes = (char *)&val;
   char  b = *bytes;
   *bytes = *(bytes + 1);
   *(bytes + 1) = b;
   return val;
}

int CExcelRecord::reorderBytes(int val) {
   char *head = (char *)&val;
   char *tail = head + sizeof(val) - 1;
   for (unsigned i = 0; i < sizeof(val) / 2; i++) {
      char b = *head;
      *head = *tail;
      *tail = b;
      head++;
      tail--;
   }
   return val;
}

unsigned CExcelRecord::reorderBytes(unsigned val) {
   char *head = (char *)&val;
   char *tail = head + sizeof(val) - 1;
   for (unsigned i = 0; i < sizeof(val) / 2; i++) {
      char b = *head;
      *head = *tail;
      *tail = b;
      head++;
      tail--;
   }
   return val;
}

long CExcelRecord::reorderBytes(long val) {
   char *head = (char *)&val;
   char *tail = head + sizeof(val) - 1;
   for (unsigned i = 0; i < sizeof(val) / 2; i++) {
      char b = *head;
      *head = *tail;
      *tail = b;
      head++;
      tail--;
   }
   return val;
}

double CExcelRecord::reorderBytes(double val) {
   char *head = (char *)&val;
   char *tail = head + sizeof(val) - 1;
   for (unsigned i = 0; i < sizeof(val) / 2; i++) {
      char b = *head;
      *head = *tail;
      *tail = b;
      head++;
      tail--;
   }
   return val;
}

#else

inline short CExcelRecord::reorderBytes(short val) {
   return val;
}

inline unsigned short CExcelRecord::reorderBytes(unsigned short val) {
   return val;
}

inline int CExcelRecord::reorderBytes(int val) {
   return val;
}

inline unsigned CExcelRecord::reorderBytes(unsigned val) {
   return val;
}

inline long CExcelRecord::reorderBytes(long val) {
   return val;
}

inline double CExcelRecord::reorderBytes(double val) {
   return val;
}

#endif

unsigned short CExcelRecord::getshort(const char *rec,int offset) {
   unsigned short val;
   memcpy(&val,rec+offset,sizeof(val));
   return reorderBytes(val);
}

void CExcelRecord::setshort(char *rec,int offset,short value) {
   short val = reorderBytes(value);
   memcpy(rec+offset,&val,sizeof(val));
}

unsigned CExcelRecord::getint(const char *rec,int offset) {
   unsigned val;
   memcpy(&val,rec+offset,sizeof(val));
   return reorderBytes(val);
}

void CExcelRecord::setint(char *rec,int offset,unsigned value) {
   unsigned val = reorderBytes(value);
   memcpy(rec+offset,&val,sizeof(val));
}

long CExcelRecord::getlong(const char *rec,int offset) {
   long val;
   memcpy(&val,rec+offset,sizeof(val));
   return reorderBytes(val);
}

void CExcelRecord::setlong(char *rec,int offset,long value) {
   long val = reorderBytes(value);
   memcpy(rec+offset,&val,sizeof(val));
}

double CExcelRecord::getdouble(const char *rec,int offset) {
   double val;
   memcpy(&val,rec+offset,sizeof(val));
   return reorderBytes(val);
}

void CExcelRecord::setdouble(char *rec,int offset,double value) {
   double val = reorderBytes(value);
   memcpy(rec+offset,&val,sizeof(val));
}

double CExcelRecord::RK2double (long rk,CVariantType& vtype) {
   union {
      double	number;
      long		words[2];
   } data;
   if (rk & 0x02) {
      // 30-bit integer number
      double number = (double) (rk >> 2);
      vtype = VAR_INT;
      if (rk & 0x01) number /= 100;
      return number;
   } else {
      long m = long(rk & 0xfffffffc);
#if WORDS_BIGENDIAN == 1
      data.words[0] = m;
      data.words[1] = 0;
#else
      // hiw words of IEEE number
      data.words[0] = 0;
      data.words[1] = m;
#endif
      vtype = VAR_FLOAT;
      if (rk & 0x01) data.number /= 100;
      if (floor(data.number) == data.number)
         vtype = VAR_INT;
      return data.number;
   }
}

bool CExcelRecord::int2RK(int value,int& rkValue) {
   if (value & 0xC0000000)
      return false;
   rkValue = reorderBytes((value << 2) | 0x2);
   return true;
}

bool CExcelRecord::double2RK(double number,int& rkValue) {
#if WORDS_BIGENDIAN == 1
   long *lword = (long *)(void *)&number + 1;
   long *hword = (long *)(void *)&number;
#else
   long *lword = (long *)(void *)&number;
   long *hword = (long *)(void *)&number + 1;
#endif
   if (*lword == 0 && (*hword & 0x3) == 0) {
      rkValue = reorderBytes(*hword);
      return true;
   }

   number *= 100;
   if (*lword == 0 && (*hword & 0x3) == 0) {
      rkValue = reorderBytes(*hword | 0x1);
      return true;
   }

   return false;
}

char *CExcelRecord::gettypename(unsigned rectype) {
   switch(rectype) {
      case MS1904:
         return "1904";
      case ADDIN:
         return "ADDIN";
      case ADDMENU:
         return "ADDMENU";
      case ARRAY:
         return "ARRAY";
      case AUTOFILTER:
         return "AUTOFILTER";
      case AUTOFILTERINFO:
         return "AUTOFILTERINFO";
      case BACKUP:
         return "BACKUP";
      case BLANK:
         return "BLANK";
      case BOF:
         return "BOF";
      case BOOKBOOL:
         return "BOOKBOOL";
      case BOOLERR:
         return "BOOLERR";
      case BOTTOMMARGIN:
         return "BOTTOMMARGIN";
      case BOUNDSHEET:
         return "BOUNDSHEET";
      case CALCCOUNT:
         return "CALCCOUNT";
      case CALCMODE:
         return "CALCMODE";
      case CODEPAGE:
         return "CODEPAGE";
      case COLINFO:
         return "COLINFO";
      case CONTINUE:
         return "CONTINUE";
      case COORDLIST:
         return "COORDLIST";
      case COUNTRY:
         return "COUNTRY";
      case CRN:
         return "CRN";
      case DBCELL:
         return "DBCELL";
      case DCON:
         return "DCON";
      case DCONNAME:
         return "DCONNAME";
      case DCONREF:
         return "DCONREF";
      case DEFAULTROWHEIGHT:
         return "DEFAULTROWHEIGHT";
      case DEFCOLWIDTH:
         return "DEFCOLWIDTH";
      case DELMENU:
         return "DELMENU";
      case DELTA:
         return "DELTA";
      case DIMENSIONS:
         return "DIMENSIONS";
      case DOCROUTE:
         return "DOCROUTE";
      case DSF:
         return "DOUBLESTREAMFILE";
      case EDG:
         return "EDG";
      case EXTSST:
         return "EXTSST";
      case MSEOF:
         return "EOF";
      case EXTERNCOUNT:
         return "EXTERNCOUNT";
      case EXTERNNAME:
         return "EXTERNNAME";
      case EXTERNSHEET:
         return "EXTERNSHEET";
      case FILEPASS:
         return "FILEPASS";
      case FILESHARING:
         return "FILESHARING";
      case FILESHARING2:
         return "FILESHARING2"; 
      case FILTERMODE:
         return "FILTERMODE"; 
      case FNGROUPCOUNT:
         return "FNGROUPCOUNT"; 
      case FNGROUPNAME:
         return "FNGROUPNAME";
      case FONT1:
      case FONT2:
         return "FONT";
      case FOOTER:
         return "FOOTER"; 
      case FORMAT:
         return "FORMAT";
      case FORMULA1:
      case FORMULA2:
         return "FORMULA";
      case GCW:
         return "GCW";
      case GRIDSET:
         return "GRIDSET";
      case GUTS:
         return "GUTS";
      case HCENTER:
         return "HCENTER"; 
      case HEADER:
         return "HEADER";
      case HIDEOBJ:
         return "HIDEOBJ";
      case HORIZONTALPAGEBREAKS:
         return "HORIZONTALPAGEBREAKS";
      case IMDATA:
         return "IMDATA";
      case INDEX:
         return "INDEX"; 
      case INTERFACEEND:
         return "INTERFACEEND"; 
      case INTERFACEHDR:
         return "INTERFACEHDR";
      case ITERATION:
         return "ITERATION"; 
      case LABEL:
         return "LABEL"; 
      case LABELSST:
         return "LABELSST";
      case LEFTMARGIN:
         return "LEFTMARGIN"; 
      case LHNGRAPH:
         return "LHNGRAPH";
      case LHRECORD:
         return "LHRECORD"; 
      case LPR:
         return "LPR";
      case MMS:
         return "MMS"; 
      case MSODRAWINGGROUP:
         return "MSODRAWINGGROUP";
      case MSODRAWING:
         return "MSODRAWING";
      case MSODRAWINGSELECTION:
         return "MSODRAWINGSELECTION";
      case MULBLANK:
         return "MULBLANK";
      case MULRK:
         return "MULRK";
      case NAME:
         return "NAME"; 
      case NOTE:
         return "NOTE";
      case NUMBER:
         return "NUMBER"; 
      case OBJ:
         return "OBJ";
      case OBJPROTECT:
         return "OBJPROTECT";
      case OBPROJ:
         return "OBPROJ";
      case OLESIZE:
         return "OLESIZE"; 
      case PALETTE:
         return "PALETTE";
      case PANE:
         return "PANE";
      case PASSWORD:
         return "PASSWORD";
      case PLS:
         return "PLS";
      case PRECISION:
         return "PRECISION";
      case PRINTGRIDLINES:
         return "PRINTGRIDLINES"; 
      case PRINTHEADERS:
         return "PRINTHEADERS"; 
      case PROTECT:
         return "PROTECT";
      case PROT4REV:
         return "PROT4REV";
      case PROT4REVPASS:
         return "PROT4REVPASS";
      case PUB:
         return "PUB"; 
      case RECIPNAME:
         return "RECIPNAME";
      case REFMODE:
         return "REFMODE";
      case REFRESHALL:
         return "REFRESHALL";
      case RIGHTMARGIN:
         return "RIGHTMARGIN";
      case RK:
         return "RK";
      case ROW:
         return "ROW";
      case RSTRING:
         return "RSTRING";
      case SAVERECALC:
         return "SAVERECALC";
      case SCENARIO:
         return "SCENARIO"; 
      case SCENMAN:
         return "SCENMAN"; 
      case SCENPROTECT:
         return "SCENPROTECT"; 
      case SCL:
         return "SCL";
      case SELECTION:
         return "SELECTION"; 
      case SETUP:
         return "SETUP";
      case SHRFMLA:
         return "SHRFMLA";
      case SORT:
         return "SORT"; 
      case SOUND:
         return "SOUND";
      case SST:
         return "SST";
      case STANDARDWIDTH:
         return "STANDARDWIDTH";
      case STRING:
         return "STRING";
      case STYLE:
         return "STYLE";
      case SUB:
         return "SUB";
      case SUPBOOK:
         return "SUPPORTINGBWORKBOOK"; 
      case SXDI:
         return "SXDI"; 
      case SXEXT:
         return "SXEXT";
      case SXIDSTM:
         return "SXIDSTM"; 
      case SXIVD:
         return "SXIVD";
      case SXLI:
         return "SXLI";
      case SXPI:
         return "SXPI";
      case SXSTRING:
         return "SXSTRING"; 
      case SXTBL:
         return "SXTBL"; 
      case SXTBPG:
         return "SXTBPG";
      case SXTBRGIITM:
         return "SXTBRGIITM";
      case SXVD:
         return "SXVD";
      case SXVI:
         return "SXVI"; 
      case SXVIEW:
         return "SXVIEW";
      case SXVS:
         return "SXVS"; 
      case TABID:
         return "TABID";
      case TABIDCONF:
         return "TABIDCONF";
      case TABLE:
         return "TABLE"; 
      case TEMPLATE:
         return "TEMPLATE"; 
      case TOPMARGIN:
         return "TOPMARGIN";
      case UDDESC:
         return "UDDESC"; 
      case UNCALCED:
         return "UNCALCED"; 
      case USESELFS:
         return "USESELFS";
      case VCENTER:
         return "VCENTER";
      case VERTICALPAGEBREAKS:
         return "VERTICALPAGEBREAKS"; 
      case WINDOW1:
         return "WINDOW1";
      case WINDOW2:
         return "WINDOW2";
      case WINDOWPROTECT:
         return "WINDOWPROTECT";
      case WRITEACCESS:
         return "WRITEACCESS"; 
      case WRITEPROT:
         return "WRITEPROT";
      case WSBOOL:
         return "WSBOOL"; 
      case XCT:
         return "XCT"; 
      case XF:
         return "XF";
      default:
         return "UNKNOWN";
   }
}

void CExcelRecordList::clear() {
   for (iterator itor = begin(); itor != end(); itor++)
      delete *itor;
   vector<CExcelRecord *>::clear();
}
