/*
 * CiderPress
 * Copyright (C) 2007 by faddenSoft, LLC.  All Rights Reserved.
 * See the file LICENSE for distribution terms.
 */
/*
 * Reformat AppleWorks documents.
 */
#ifndef REFORMAT_APPLEWORKS_H
#define REFORMAT_APPLEWORKS_H

#include "ReformatBase.h"

/*
 * Reformat an AppleWorks WP document into formatted text.
 */
class ReformatAWP : public ReformatText {
public:
    ReformatAWP(void) { fShowEmbeds = true; }
    virtual ~ReformatAWP(void) {}

    virtual void Examine(ReformatHolder* pHolder) override;
    virtual int Process(const ReformatHolder* pHolder,
        ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part,
        ReformatOutput* pOutput) override;

private:

    /*
     * Constants.
     */
    enum {
        kFileHeaderSize = 300,      /* expected size of FileHeader */
        kSeventyNine = 79,          /* value of FileHeader.seventyNine */

        kSFMinVers30 = 30,          /* indicates AW 3.0 */
        kTabFlagsIsRuler = 0xff,    /* compare against byte 2 of text record */
        kCRatEOL = 0x80,            /* flag on byte 3 of the text record */
        kMinTextChar = 0x20,        /* values from 0x01 - 0x1f are special */
        kEOFMarker = 0xff,          /* two of these found at end of file */

        kLineRecordText = 0x00,
        kLineRecordCarriageReturn = 0xd0,
        kLineRecordCommandMin = 0xd4,
        kLineRecordCommandMax = 0xff,

        kLineRecordCommandPageHeaderEnd = 0xd5,
        kLineRecordCommandPageFooterEnd = 0xd6,
        kLineRecordCommandRightJustify = 0xd7,
        kLineRecordCommandPlatenWidth = 0xd8,       // 10ths of an inch
        kLineRecordCommandLeftMargin = 0xd9,        // 10ths of an inch
        kLineRecordCommandRightMargin = 0xda,       // 10ths of an inch
        kLineRecordCommandCharsPerInch = 0xdb,
        kLineRecordCommandProportional1 = 0xdc,
        kLineRecordCommandProportional2 = 0xdd,
        kLineRecordCommandIndent = 0xde,
        kLineRecordCommandJustify = 0xdf,
        kLineRecordCommandUnjustify = 0xe0,
        kLineRecordCommandCenter = 0xe1,
        kLineRecordCommandPaperLength = 0xe2,
        kLineRecordCommandTopMargin = 0xe3,
        kLineRecordCommandBottomMargin = 0xe4,
        kLineRecordCommandLinesPerInch = 0xe5,
        kLineRecordCommandSingleSpace = 0xe6,
        kLineRecordCommandDoubleSpace = 0xe7,
        kLineRecordCommandTripleSpace = 0xe8,
        kLineRecordCommandNewPage = 0xe9,
        kLineRecordCommandGroupBegin = 0xea,
        kLineRecordCommandGroupEnd = 0xeb,
        kLineRecordCommandPageHeader = 0xec,
        kLineRecordCommandPageFooter = 0xed,
        kLineRecordCommandSkipLines = 0xee,
        kLineRecordCommandPageNumber = 0xef,
        kLineRecordCommandPauseEachPage = 0xf0,
        kLineRecordCommandPauseHere = 0xf1,
        kLineRecordCommandSetMarker = 0xf2,
        kLineRecordCommandSetPageNumber = 0xf3,
        kLineRecordCommandPageBreak = 0xf4,
        kLineRecordCommandPageBreak256 = 0xf5,
        kLineRecordCommandPageBreakPara = 0xf6,
        kLineRecordCommandPageBreakPara256 = 0xf7,
        // end of file is 0xff

        kSpecialCharBoldBegin = 0x01,
        kSpecialCharBoldEnd = 0x02,
        kSpecialCharSuperscriptBegin = 0x03,
        kSpecialCharSuperscriptEnd = 0x04,
        kSpecialCharSubscriptBegin = 0x05,
        kSpecialCharSubscriptEnd = 0x06,
        kSpecialCharUnderlineBegin = 0x07,
        kSpecialCharUnderlineEnd = 0x08,
        kSpecialCharPrintPageNumber = 0x09,
        kSpecialCharEnterKeyboard = 0x0a,
        kSpecialCharStickySpace = 0x0b,
        kSpecialCharMailMerge = 0x0c,
        // reserved = 0x0d,
        kSpecialCharPrintDate = 0x0e,
        kSpecialCharPrintTime = 0x0f,
        // Special Code N = 0x10-15
        kSpecialCharTab = 0x16,
        kSpecialCharTabFill = 0x17, /* tab fill char, not vis in doc */
        // reserved = 0x18

        kMaxSoftFailures = 8,       /* give up if it looks like junk */
    };

    /*
     * File header, mapped directly on top of the input.  This structure must
     * be exactly 300 bytes.
     */
    typedef struct FileHeader {
        uint8_t     unused1[4];     /* 000 - 003: not used */
        uint8_t     seventyNine;    /* 004      : $4f (79) */
        uint8_t     tabStops[80];   /* 005 - 084: tab stops, one of "=<^>.|" */
        uint8_t     zoomFlag;       /* 085      : boolean Zoom flag */
        uint8_t     unused2[4];     /* 086 - 089: not used */
        uint8_t     paginatedFlag;  /* 090      : boolean Paginated flag */
        uint8_t     minLeftMargin;  /* 091      : minimum "unseen" left margin */
        uint8_t     mailMergeFlag;  /* 092      : boolean - file has merge cmds */
        uint8_t     unused3[83];    /* 093 - 175: not used, reserved */
        uint8_t     multiRulerFlag; /* 176      : (3.0) boolean Multiple Rulers */
        uint8_t     tabRulers[6];   /* 177 - 182: (3.0) used internally */
        uint8_t     sfMinVers;      /* 183      : (3.0) min version of AW req */
        uint8_t     unused4[66];    /* 184 - 249: reserved */
        uint8_t     unused5[50];    /* 250 - 299: available */
    } FileHeader;

    /*
     * Current state of the document.
     */
    typedef struct DocState {
        long        softFailures;
        long        line;

        /* not using these yet */
        int         leftMargin;
    } DocState;


    void InitDocState(void);
    int ProcessLineRecord(uint8_t lineRecData, uint8_t lineRecCode,
        const uint8_t** pSrcPtr, long* pLength);
    int HandleTextRecord(uint8_t lineRecData,
        const uint8_t** pSrcPtr, long* pLength);

    FileHeader  fFileHeader;
    DocState    fDocState;
    bool        fShowEmbeds;
};

/*
 * Reformat an AppleWorks DB document into CSV.
 */
class ReformatADB : public ReformatText {
public:
    ReformatADB(void) {}
    virtual ~ReformatADB(void) {}

    virtual void Examine(ReformatHolder* pHolder) override;
    virtual int Process(const ReformatHolder* pHolder,
        ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part,
        ReformatOutput* pOutput) override;

private:
    enum {
        kOffsetToFirstCatHeader = 357,
        kMinHeaderLen = 379,
        kReportRecordLen = 600,
        kCatNameLen = 20,
        kCatHeaderLen = 22,
    };
};

/*
 * Reformat an AppleWorks SS document into CSV.
 */
class ReformatASP : public ReformatText {
public:
    ReformatASP(void) { fCurrentRow = fCurrentCol = 1; }
    virtual ~ReformatASP(void) {}

    virtual void Examine(ReformatHolder* pHolder) override;
    virtual int Process(const ReformatHolder* pHolder,
        ReformatHolder::ReformatID id, ReformatHolder::ReformatPart part,
        ReformatOutput* pOutput) override;

private:
    enum {
        kFileHeaderSize = 300,
        kPropCount = 8,
        kSANELen = 8,
    };

    /*
     * File header, mapped directly on top of the input.  This structure must
     * be exactly 300 bytes.
     */
    typedef struct FileHeader {
        uint8_t     unused1[4];     /* 000-003: not used */
        uint8_t     colWidth[127];  /* 004-130: column width for each column */
        uint8_t     recalcOrder;    /* 131    : recalc order ('R' or 'C') */
        uint8_t     recalcFreq;     /* 132    : recalc frequency ('A' or 'M') */
        uint8_t     lastRowRef[2];  /* 133-134: last row referenced */
        uint8_t     lastColRef;     /* 135    : last column referenced */
        uint8_t     numWindows;     /* 136    : '1'/'S'/'T' */
        uint8_t     windowSync;     /* 137    : if two windows, are sync'ed? */
        uint8_t     winInfo1[24];   /* 138-161: struct with info for 1st window */
        uint8_t     winInfo2[24];   /* 162-185: struct with info for 2nd window */
        uint8_t     unused2[27];    /* 186-212: not used */
        uint8_t     cellProt;       /* 213    : cell protection on/off */
        uint8_t     unused3;        /* 214    : not used */
        uint8_t     platenWidth;    /* 215    : platen width */
        uint8_t     leftMargin;     /* 216    : left margin, in 1/10th inches */
        uint8_t     rightMargin;    /* 217    : right margin */
        uint8_t     cpi;            /* 218    : characters per inch */
        uint8_t     paperLength;    /* 219    : paper length, 1/10th inches */
        uint8_t     topMargin;      /* 220    : top margin */
        uint8_t     bottomMargin;   /* 221    : bottom margin */
        uint8_t     lpi;            /* 222    : lines per inch (6 or 8) */
        uint8_t     spacing;        /* 223    : 'S'ingle, 'D'ouble, or 'T'riple */
        uint8_t     printerCodes[14];/*224-237: "special codes" for printer */
        uint8_t     printDash;      /* 238    : print dash when entry is blank */
        uint8_t     reportHeader;   /* 239    : print report header */
        uint8_t     zoomed;         /* 240    : zoomed to show formulas */
        uint8_t     reserved1;      /* 241    : used internally (v2.1) */
        uint8_t     ssMinVers;      /* 242    : holds 0 for AW2.x, 0x1e for AW3.x */
        uint8_t     reserved2[7];   /* 243-249: reserved */
        uint8_t     available[50];  /* 250-299: available for non-AW app use */
    } FileHeader;

    int fCurrentRow, fCurrentCol;
    char fPrintColBuf[3];

    int ProcessRow(int rowNum, const uint8_t** pSrcPtr,
        long* pLength);
    void ProcessCell(const uint8_t* srcPtr, long cellLength);
    void PrintToken(const uint8_t** pSrcPtr, long* pLength);
    const char* PrintCol(int col);
    double ConvertSANEDouble(const uint8_t* srcPtr);
};

#endif /*REFORMAT_APPLEWORKS_H*/
