// Copyright 1997-2000 Omni Development, Inc.  All rights reserved.
//
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// http://www.omnigroup.com/DeveloperResources/OmniSourceLicense.html.
//
// $Header: /Network/Source/CVS/OmniGroup/Frameworks/OmniHTML/Building.subproj/OHTextBuilder.h,v 1.12 2000/01/20 00:27:45 kc Exp $

#import <AppKit/NSParagraphStyle.h> // For NSLineBreakMode
#import <Foundation/NSDate.h> // For NSTimeInterval

#import <OmniFoundation/OFObject.h>
#import <OmniFoundation/OFObject-Queue.h>

#import <OmniAppKit/OAFontCache.h> // For OAFontAttributes
#import "OHColorPalette.h" // For OHColorPaletteIndex
#import "OHBasicCell.h"
#import "OHTextBuilderObserverProtocol.h"
#import "FrameworkDefines.h"

@class NSFont, NSRecursiveLock;
@class NSMutableArray;
@class OFInvocation;
@class OWAddress, OHBreak, OHColorPalette, OHForm, OHHTMLAnchor, OHHTMLDocument, OHHTMLOwner, OHHTMLView, OHTextBuilderDefaultsHolder;

typedef enum {
    FONTSTYLE_UNSET = -2,
    FONTSTYLE_NORMAL = 0,
    FONTSTYLE_TITLE = 2,
    FONTSTYLE_FIXEDPITCH = 4,
} OWFontStyle;

typedef enum {
    OW_UNSPECIFIED_ALIGNMENT,
    OW_LEFTALIGNED, OW_RIGHTALIGNED, OW_CENTERED, OW_JUSTIFIED,
} OWTextAlignment;

typedef enum {
    OW_CAUSE_NONE,
    OW_CAUSE_CR, OW_CAUSE_LF, OW_CAUSE_BR, OW_CAUSE_OTHER
} OWLineBreakCauses;

enum {
    NO_BREAK_SPACE = 0xa0, ZERO_WIDTH_SPACE = 0x200B
};

#define NONBREAKING_SPACE ((char)0x80)

#define BUILDER_BUFFER_SIZE 1024u

OmniHTML_EXTERN NSString *OHHTMLAnchorAttributeName;

@interface OHTextBuilder : OFObject
{
    OHHTMLOwner *htmlOwner;

    struct {
        unsigned int endedTextBuild:1;

        unsigned int inParagraph:1;
        unsigned int inBlock:1;

        unsigned int needVerticalSpace:1;
        unsigned int atStartOfLine:1;
        unsigned int justDidSpace:1;

        unsigned int flushToHTMLViewInProgress:1;
    } flags;

    float needLineBreakSize;
    OWLineBreakCauses needLineBreakCause;
    
    NSTimeInterval lastFlushTimeInterval;
    NSMutableAttributedString *mutableAttributedString, *lastMutableAttributedString;
    NSMutableString *mutableString;
    unsigned int indexOfStyleChangeInAttributedString;
    unichar unprocessedCharacters[BUILDER_BUFFER_SIZE];
    unichar processedCharacters[BUILDER_BUFFER_SIZE];
    unsigned int processedCharacterCount;
    unsigned int charactersWrittenFromProcessedBuffer;

    OHColorPalette *colorPalette;

    float lastBlockWantsVerticalSpace;
    float currentVerticalSpace;

    struct {
        OWFontStyle fontStyle;
        OAFontAttributes fontAttributes;

        struct {
            unsigned int underlined:1;
        } flags;
        int boldCount;
        int italicCount;
        int underliningCount;
        int ligatureType;

        int baselineOffset;

        OHColorPaletteIndex textColorIndex;
        NSColor *textColorOverride;

        int baseFontSizeIndex;
        int fontSizeIndex;
        float fontSizeMultiple;
        float lastWrittenFontSize;

        NSString *fontFaceNameOverride;

        NSFont *font;
        NSMutableArray *fontStyleArray;
        
        BOOL noWrapMode;

        OHBasicCell *nonretainedAttachmentObject;
        OHHTMLAnchor *anchor;
        NSColor *preAnchorTextColorOverride;
    } characterAttributes;

    struct {
        OWTextAlignment textAlignment;
        OWTextAlignment paragraphAlignment;
        OWTextAlignment divisionAlignment;
        int centeringCount;

        float firstIndent;
        float hangingIndent;
        float leftIndent;
        float rightIndent;

        NSLineBreakMode lineBreakMode;

        struct {
            unsigned int preserveWhitespace:1;
            unsigned int obeyLines:1;
        } flags;
    } paragraphAttributes;

    OHTextBuilderDefaultsHolder *defaultsHolder;

@public
    BOOL isPristine;
    id <OHTextBuilderObserver> nonretainedTextBuilderObserver;
}

+ (void)readDefaults;

- initWithHTMLOwner:(OHHTMLOwner *)anHTMLOwner colorPalette:(OHColorPalette *)aColorPalette;
- initWithHTMLOwner:(OHHTMLOwner *)anHTMLOwner;

- (OHHTMLOwner *)htmlOwner;

- (void)setTextBuilderObserver:(id <OHTextBuilderObserver>)anObserver;

- (void)endTextBuild;
- (BOOL)isPristine;
- (OHHTMLView *)htmlView;

- (void)beginParagraph;
- (void)endParagraph;
- (void)beginBlock;
- (void)endBlock;
- (void)ensureAtStartOfLine;
- (void)ensureAtStartOfLineIgnoringInfiniteHack;
- (void)addLineBreak;
- (void)addWhitespace;

// What should these really be called?
- (void)pretendInfiniteVerticalSpace;
- (void)pretendAtStartOfLine;

- (OHColorPalette *)colorPalette;
- (void)setColorPalette:(OHColorPalette *)aPalette;

// Paragraph styles
- (OWTextAlignment)textAlignment;
- (void)setTextAlignment:(OWTextAlignment)newTextAlignment;
- (OWTextAlignment)paragraphAlignment;
- (OWTextAlignment)setParagraphAlignment:(OWTextAlignment)newParagraphAlignment;
- (OWTextAlignment)setParagraphAlignmentString:(NSString *)newParagraphAlignmentString;
- (OWTextAlignment)setDivisionAlignment:(OWTextAlignment)newDivisionAlignment;
- (OWTextAlignment)setDivisionAlignmentString:(NSString *)newDivisionAlignmentString;
- (void)startCentering;
- (void)stopCentering;

- (float)firstIndent;
- (float)setFirstIndent:(float)newFirstIndent;
- (float)hangingIndent;
- (float)setHangingIndent:(float)newHangingIndent;
- (float)leftIndent;
- (float)setLeftIndent:(float)newLeftIndent;
- (float)rightIndent;
- (float)setRightIndent:(float)newRightIndent;

// Character styles

- (void)pushFontStyle;
- (void)popFontStyle;

- (BOOL)fontBold;
- (BOOL)setFontBold:(BOOL)newFontBold;
- (void)startBold;
- (void)stopBold;

- (BOOL)fontItalic;
- (BOOL)setFontItalic:(BOOL)isItalic;
- (void)startItalic;
- (void)stopItalic;

- (BOOL)underlined;
- (BOOL)setUnderlined:(BOOL)shouldUnderline;
- (void)startUnderlining;
- (void)stopUnderlining;

- (int)ligatureType;
- (int)setLigatureType:(int)newLigatureType;

- (OHColorPaletteIndex)textColorIndex;
- (OHColorPaletteIndex)setTextColorIndex:(OHColorPaletteIndex)anIndex;
- (NSColor *)setTextColorOverride:(NSColor *)color;

// Font stuff
- (float)fontSize;
- (float)setFontSize:(float)newFontSize;

- (float)fontSizeMultiple;
- (float)setFontSizeMultiple:(float)newFontSizeMultiple;

- (int)baseFontSizeIndex;
- (int)setBaseFontSizeIndex:(int)anIndex;
- (int)setFontSizeIndex:(int)anIndex;
    // 1-7, not 0-6
- (int)setRelativeFontSizeIndex:(int)anIndex;
- (OWFontStyle)fontStyle;
- (OWFontStyle)setFontStyle:(OWFontStyle)aFontStyle;
- (NSFont *)currentFont;

- (NSString *)setFontFaceOverrideFromNameArray:(NSArray *)faceNameArray;
- (NSString *)setFontFaceNameOverride:(NSString *)fontFaceName;
- (NSString *)fontFaceNameOverride;


//
- (int)setBaselineOffset:(int)offset;
- (int)changeBaselineOffsetBy:(int)offset;

//
- (BOOL)preserveWhitespace;
- (BOOL)setPreserveWhitespace:(BOOL)shouldPreserveWhitespace;
- (BOOL)obeyLines;
- (BOOL)setObeyLines:(BOOL)shouldObeyLines;
- (BOOL)noWrapMode;
- (BOOL)setNoWrapMode:(BOOL)newMode;
- (NSLineBreakMode)lineBreakMode;
- (NSLineBreakMode)setLineBreakMode:(NSLineBreakMode)newMode;
- (void)setRequiredCharacterWidth:(unsigned int)aCharacterWidth;

// Call these if your string contains any whitespace that shouldn't really appear (eg, normal CDATA).
- (void)writeUnprocessedString:(NSString *)aString;
- (void)writeUnprocessedCharacters:(unichar *)characters length:(unsigned int)length;

// Call these if you know you aren't writing any whitespace (eg, program-generated strings).
// These have the same effects as prepareForMoreText and wroteNonWhitespaceText
- (void)writeProcessedString:(NSString *)aString;
- (void)writeProcessedCharacters:(unichar *)characters length:(unsigned int)length;

// Writing cells and other specials, high-level interface
- (void)writeNonWhitespaceCellObject:(OHBasicCell *)cellObject;
- (void)writeFormCellObject:(OHBasicCell *)cellObject;
- (void)writeMarginalCellObject:(OHBasicCell *)cellObject;
- (void)writeClearBreakObject:(OHBreak *)breakObject;

// Low-level interface to writing text and cells
- (void)prepareForMoreText;
    // Call if you're going to write something to the attributed string, so the builder will start a paragraph if necessary and output any whitespace that's queued up
- (void)writeCellObject:(OHBasicCell *)cellObject;
    // Just writes the cell, so you usually call prepareForMoreText and later wroteNonWhitespaceText
- (void)writeProcessedCharacter:(unichar)unicodeCharacter;
    // Just writes the character, so you usually call prepareForMoreText and later wroteNonWhitespaceText
- (void)wroteNonWhitespaceText;
    // Call after you wrote something to the attributed that actually printed something, so the builder will know that if it sees whitespace it shouldn't ignore it

// Anchors
- (void)startAnchorNamed:(NSString *)name address:(OWAddress *)address;
- (OHHTMLAnchor *)anchor;
- (void)endAnchor;

@end
