//
//  MCReportElement.h
//  Composer
//
//  Created by Alykhan Jetha on 04/06/2005.
//  Copyright 2005 Marketcircle Inc.. All rights reserved.
//

#import <Cocoa/Cocoa.h>
#import "MCReportLayoutDefines.h"

@class MCReportLayout;
@class MCReportLayoutPage;
@class MCReportRegion;
@class MCReportGenerator;
@class MCReportKnob;
@class MCReportRenderCanvas;
@class MCReportPaletteView;
@class MCReportTable;
@class MCReportDataInfo;
@class MCReportDocument;
@class MCReportGroupByRegion;
@class MCReportTableAbstractRow;
@class MCReportGroupByRow;
@class MCReportFreeFormRegion;
@class MCReportLayoutBody;

@class BDQualifier;

extern NSString *MCReportElementDidChangeSubviewsNotification;
extern NSString *MCReportElementDidChangeHiddenStateNotification;


@interface MCReportElement : NSView {

	NSRect originalFrame;
	unsigned int manipulatingFrame;
	
	MCReportKnob *upperLeftKnob;
	MCReportKnob *upperMiddleKnob;
	MCReportKnob *upperRightKnob;
	MCReportKnob *middleLeftKnob;
	MCReportKnob *middleRightKnob;
	MCReportKnob *lowerLeftKnob;
	MCReportKnob *lowerMiddleKnob;
	MCReportKnob *lowerRightKnob;
	
	
	
	BOOL useLeftLine;
	BOOL useRightLine;
	BOOL useTopLine;
	BOOL useBottomLine;
	
	float leftLineWidth;
	float rightLineWidth;
	float topLineWidth;
	float bottomLineWidth;
	
	float topPadding;
	float rightPadding;
	float bottomPadding;
	float leftPadding;
	
	float minimumRenderHeight;
	
	NSColor *leftLineStrokeColor;
	NSColor *rightLineStrokeColor;
	NSColor *topLineStrokeColor;
	NSColor *bottomLineStrokeColor;
	
	BOOL fillsBackground;
	NSColor *fillColor;
	
	BOOL pinToBottomOfPage;
	BOOL stretchesHeightToMatchParent;
	
	NSMutableArray *dataInfos;
	NSMutableDictionary *reportData;
	
	NSTextStorage *preExtractionScript;
	NSTextStorage *postExtractionScript;
	
	NSString *identifyingName;
	
}



/* =========================== Basic Accessors =================================== */


- (BOOL)useLeftLine;
- (void)setUseLeftLine:(BOOL)flag;

- (BOOL)useRightLine;
- (void)setUseRightLine:(BOOL)flag;

- (BOOL)useTopLine;
- (void)setUseTopLine:(BOOL)flag;

- (BOOL)useBottomLine;
- (void)setUseBottomLine:(BOOL)flag;

- (float)leftLineWidth;
- (void)setLeftLineWidth:(float)aLeftLineWidth;

- (float)rightLineWidth;
- (void)setRightLineWidth:(float)aRightLineWidth;

- (float)topLineWidth;
- (void)setTopLineWidth:(float)aTopLineWidth;

- (float)bottomLineWidth;
- (void)setBottomLineWidth:(float)aBottomLineWidth;

- (NSColor *)leftLineStrokeColor;
- (void)setLeftLineStrokeColor:(NSColor *)aLeftLineStrokeColor;

- (NSColor *)rightLineStrokeColor;
- (void)setRightLineStrokeColor:(NSColor *)aRightLineStrokeColor;

- (NSColor *)topLineStrokeColor;
- (void)setTopLineStrokeColor:(NSColor *)aTopLineStrokeColor;

- (NSColor *)bottomLineStrokeColor;
- (void)setBottomLineStrokeColor:(NSColor *)aBottomLineStrokeColor;

- (BOOL)fillsBackground;
- (void)setFillsBackground:(BOOL)flag;

- (NSColor *)fillColor;
- (void)setFillColor:(NSColor *)aFillColor;

- (float)topPadding;
- (void)setTopPadding:(float)aTopPadding;

- (float)rightPadding;
- (void)setRightPadding:(float)aRightPadding;

- (float)bottomPadding;
- (void)setBottomPadding:(float)aBottomPadding;

- (float)leftPadding;
- (void)setLeftPadding:(float)aLeftPadding;

- (float)minimumRenderHeight;
- (void)setMinimumRenderHeight:(float)aMinimumRenderHeight;

- (NSTextStorage *)preExtractionScript;
- (void)setPreExtractionScript:(NSTextStorage *)aPreExtractionScript;

- (NSTextStorage *)postExtractionScript;
- (void)setPostExtractionScript:(NSTextStorage *)aPostExtractionScript;

- (NSString *)identifyingName;
- (void)setIdentifyingName:(NSString *)anIdentifyingName;

- (NSColor *)fillColor;
- (void)setFillColor:(NSColor *)aFillColor;

- (BOOL)fillsBackground;
- (void)setFillsBackground:(BOOL)flag;


/* =========================== Deeper Accessors =============================== */

- (NSArray *)reportElementsMatchingPredicate:(NSPredicate *)aPredicate includeTokens:(BOOL)aFlag;

// includes self and travels down all descendants
- (NSArray *)reportElements;
- (NSArray *)reportElementsIncludingTokens;

- (NSArray *)reportElementsWithScript;
- (NSArray *)reportElementsWithScriptIncludingTokens;

- (NSArray *)elementsWithName:(NSString *)aName;
- (NSArray *)elementNames;
- (void)removeElementsWithName:(NSString *)aName;

- (NSArray *)shallowElementsWithName:(NSString *)aName;
- (void)addElementsWithName:(NSString *)aName toArray:(NSMutableArray *)anArray;
- (void)addElementNamesToArray:(NSMutableArray *)anArray;
- (void)addReportElementsToSet:(NSMutableSet *)aSet includeTokens:(BOOL)flag;
- (void)addReportElementsWithScriptToSet:(NSMutableSet *)aSet includeTokens:(BOOL)flag;
- (void)addReportElementsThatRespondToSelector:(SEL)aSelector toSet:(NSMutableSet *)aSet includeTokens:(BOOL)flag;


- (NSArray *)elementsWhoseKeyPathContain:(NSString *)aKeyPath;
- (BOOL)replaceKeyPath:(NSString *)aKeyPath withKeyPath:(NSString *)aNewKeyPath;
- (BOOL)propagateReplaceKeyPath:(NSString *)aKeyPath withKeyPath:(NSString *)aNewKeyPath;

- (NSArray *)reportElementsWithFormatterCode:(int)aCode;

- (NSArray *)elementsWhoseEmbeddedImageNameIs:(NSString *)aName;

/* ======================= Undo/Redo  ======================================= */

- (void)registerDataRulesForUndo;




/* =========================== Enclosing ====================================== */


- (BOOL)isUserSelectable;

- (void)awakeFromCreationFromDrag:(id <NSDraggingInfo>)sender;

// what can dragged into this view
- (NSArray *)validDragTypes;
// what this view declares itself to be
- (NSArray *)dragTypes;

- (BOOL)canDrag;
- (void)dragWithEvent:(NSEvent *)theEvent;


- (MCReportLayout *)enclosingReportLayout;
- (MCReportLayoutPage *)enclosingReportLayoutPage;
- (MCReportLayoutBody *)enclosingReportBody;
- (MCReportRenderCanvas *)enclosingReportRenderCanvas;
- (MCReportRegion *)enclosingReportRegion;
- (MCReportPaletteView *)enclosingReportPaletteView;
- (MCReportTable *)enclosingTable;
- (MCReportTable *)enclosingReportTable;
- (MCReportTableAbstractRow *)enclosingTableRow;
- (MCReportTableAbstractRow *)enclosingReportTableRow;
- (MCReportDocument *)enclosingReportDocument;
- (MCReportGroupByRegion *)enclosingGroupByRegion;
- (MCReportGroupByRow *)enclosingGroupByRow;
- (MCReportFreeFormRegion *)enclosingReportStrip;

- (NSArray *)viewHierarchy;
- (void)verticallyStackSubviewsRespectingPrintInfo:(BOOL)flag;

- (NSImage *)toolbarIcon;
- (NSString *)toolbarLabel;
- (NSString *)toolbarTooltip;


/* =========================== Drawing ====================================== */

/*!
 Converts the x,y of the element to the coordinate system of the enclosing layout.
 */
- (NSRect)convertFrameToLayoutCoordinates;

- (void)setFrameAndUpdate:(NSRect)aFrame;

- (float)drawingXOrigin;
- (float)drawingYOrigin;
- (float)drawingWidth;
- (float)drawingHeight;

// pads with y padding and y lines then calls setHeight:
- (void)setDrawingHeight:(float)aHeight;

- (NSRect)drawingBounds; 

- (unsigned)knobMask;
- (int)knobUnderPoint:(NSPoint)point;
- (void)drawHandleRect:(NSRect)rect knobView:(MCReportKnob **)knob; 
- (void)drawHandles;
- (void)hideHandles;
- (void)drawHandlesIfSelected;

/*! Depending where the element is, the element may draw differently. DrawRect determines which mode the element is in and then calls these methods. drawInCanvasOrLayout is called whether in the element is in the canvas or layout, then the specific methods are called drawInCanvas or drawInLayout where you can do additional drawing for those modes */
- (void)drawDebugDrawRect:(NSRect)rect;
- (void)drawInCanvasOrLayoutDrawRect:(NSRect)rect;
- (void)drawInCanvasDrawRect:(NSRect)rect;
- (void)drawInLayoutDrawRect:(NSRect)rect;
- (void)drawInPaletteDrawRect:(NSRect)rect;
- (void)drawInPaletteWithText:(NSString *)text;

- (void)drawDashFrame;
- (void)drawLayoutFrame;
- (void)drawNotCurrentDragDestinationFrame;
- (void)drawBackgroundIfSelected;


/*!
 Called when in the editor - shows the user if there is a problem with the element of some kind (excludes scripts obviously)
 */
- (void)drawWarningSymbol;


/* ========================= Layout Manipulation ============================ */

- (id)clone;
- (MCReportElement *)cloneForSplitting;
- (MCReportElement *)initForSplittingFrom:(MCReportElement *)anElement;

- (MCReportElement *)cloneWithTopLevelBorderAttributesOnly;
- (void)setTopLevelBorderAttributesOnElement:(MCReportElement *)elem;

- (void)tile;
- (BOOL)shouldStretchToMatchLayoutWidth;

	// defaults to 10, subclasses can override
- (float)minimumLayoutHeight;
- (float)minimumLayoutWidth;

- (int)knobUnderPoint:(NSPoint)point;

- (int)resizeByMovingKnob:(int)knob toPoint:(NSPoint)point;
- (void)moveBy:(NSPoint)vector;

- (void)startFrameManipulation;
- (void)stopFrameManipulation; 

- (void)forceSelection;
- (void)forceSelectionAndFirstResponder:(BOOL)responder;
- (void)forceSelectionAndNoFirstResponder;


	// gives subclasses the opportunity to do special ordering, default implementation just calls addSubview:
- (void)addReportElementSubview:(MCReportElement *)aReportElement;

- (void)removeAllReportElementSubviews;

/* ======================= Inspector Support ================================ */
- (NSString *)nameForInspectorDisplay;
- (NSArray *)inspectorIdentifiers;
- (NSArray *)multipleSelectionInspectorIdentifiers;
- (NSString *)elementDisplayName;

// for outlineview, calls element elementDisplayName for most
- (NSString *)extendedElementDisplayName; 

// Returns whether things are good or if there is a problem. Used by drawWarningSymbol.
- (MCRElementStateWarning)elementStateWarningLevel;

/* ======================= Canvas Layout ==================================== */


	/**** Expecting Flipped Coords ******/

- (BOOL)pinToBottomOfPage;
- (void)setPinToBottomOfPage:(BOOL)flag;
- (BOOL)canPinToBottomOfPage;

- (void)sizeToFitMaxHeight;
- (void)sizeToFitMinHeight;
- (void)sizeToFitForRendering;
- (void)setHeightRespectingMinimumRenderHeight:(float)aHeight;

- (NSArray *)reportElementSubviews;
- (NSArray *)ySortedSubviews;
- (NSArray *)yxSortedSubviews;

- (float)mininumRequiredRenderingHeightForProposedSplitHeight:(float)proposed generator:(MCReportGenerator *)rgen;
- (float)ajustedSplitHeightForProposedSplitHeight:(float)proposed generator:(MCReportGenerator *)rgen;

- (BOOL)canSplit;

- (MCReportElement *)splitAtHeight:(float)height generator:(MCReportGenerator *)rgen;
- (void)removeSubviewsHigherThanHeight:(float)height generator:(MCReportGenerator *)rgen;
- (void)removeSubviewsLowerThanHeight:(float)height generator:(MCReportGenerator *)rgen;

- (void)forceResizeToMatchBodyFrame:(NSRect)aRect;

- (void)didAppendViewOntoRenderCanvas:(MCReportRenderCanvas *)aCanvas;

- (BOOL)shouldStretchHeightAfterDataExtraction;

- (void)startingProcessDuplicateFromSplit:(MCReportElement *)anElement;
- (void)endingProcessDuplicateFromSplit:(MCReportElement *)anElement;

- (BOOL)canStretchHeightToMatchParent;
- (BOOL)stretchesHeightToMatchParent;
- (void)setStretchesHeightToMatchParent:(BOOL)flag;
- (void)stretchHeightToMatchParentIfAppropriate;

/**
 Once MCReportRenderCanvas has finished laying out its elements this will get called for elements on the last page.
 This is used to determine whether the final page is created by mistake (i.e. resulting in a blank page)
 
 Only the elements which contain the information should return NO. For example MCReportTableDataRow should return YES
 because the information is presented by it's child, MCReportTextArea.
 
 Returns YES by default.
 
 @return If the element has information that must be displayed then return NO
 */
- (BOOL)allowsTrimmingOfLastPage;

/* ======================= Data Extraction ================================== */

#pragma mark Data Extraction

- (NSMutableArray *)dataInfos;
- (void)setDataInfos:(NSMutableArray *)aDataInfos;
// replaces aDataInfo. If none is found or aDataInfo is nil, just adds anotherInfo
- (void)replaceDataInfo:(MCReportDataInfo *)aDataInfo with:(MCReportDataInfo *)anotherInfo;

- (NSDictionary *)reportDataInfo;

- (BOOL)hasDataInfoKeys;
- (BOOL)hasDataInfoKey:(NSString *)aKey;
- (NSArray *)dataInfoKeys;

- (MCReportDataInfo *)firstDataInfo;
// looks for data info on the receiver
- (MCReportDataInfo *)dataInfoForKey:(NSString *)aKey;
// looks for data info on any of the receivers parents - all the way up
- (MCReportDataInfo *)anyParentDataInfoForKey:(NSString *)aKey;
// looks only at the first parent that has data info keys
- (MCReportDataInfo *)parentDataInfoForKey:(NSString *)aKey;
- (void)addDataInfo:(MCReportDataInfo *)dInfo;

- (BOOL)canHandleMultipleDataInfoKeys;
- (void)propagateDataInfo;

// cover for report data
- (NSMutableDictionary *)data;
- (NSMutableDictionary *)reportData;
- (id)dataLastObject; // array does not like .lastObject in its keypath...
- (NSArray *)enclosingDataObjects;

// cover for reportDataForKey:@"objects"
- (NSArray *)dataObjects;

- (void)setReportData:(NSMutableDictionary *)aReportData;

- (void)setReportData:(id)aData forKey:(NSString *)aKey;

- (BOOL)hasReportData;
// looks on the receiver
- (id)reportDataForKey:(NSString *)aKey;
// looks at any parent
- (id)anyParentReportDataForKey:(NSString *)aKey;
// looks at any parents with objects and calls lastObject on the array then checks that object for aKey
- (id)anyParentReportDataHavingKey:(NSString *)aKey;

// only looks at the first parent with keys
- (id)parentReportDataForKey:(NSString *)aKey;
// travels up the tree looking at each object and asking it if it responds to attribute
// object.firstname is valid, an attribute of firstname would return object
// designed to shortcut parent.reportData.object
- (id)parentReportDataObjectHavingKey:(NSString *)anAttribute;

- (id)valueForUndefinedKey:(NSString *)key;

	// extracts data for self and then asks sub elements to do the same
- (void)recursivelyExtractDataFromDataPacket:(NSMutableDictionary *)dataPacket reportGenerator:(MCReportGenerator *)rgen;

	// extract data needed for self - subclass responsibility!!!
- (void)startExtractDataFromDataPacket:(NSMutableDictionary *)dataPacket reportGenerator:(MCReportGenerator *)rgen;
	// some sub elements (such as dynamic table) may change things, this gives you an opportunity to clean up.
- (void)endExtractDataFromDataPacket:(NSMutableDictionary *)dataPacket reportGenerator:(MCReportGenerator *)rgen;

- (BOOL)hasScript; 
- (void)runScript:(NSAttributedString *)aScript withGenerator:(MCReportGenerator *)rgen;
- (void)runPreDataExtractionScriptWithGenerator:(MCReportGenerator *)rgen;
- (void)runPostDataExtractionScriptWithGenerator:(MCReportGenerator *)rgen;


/* ======================= Conformance ===================================== */


	// used by certain subclasses in support of live table mode
- (void)setLabel:(NSString *)aLabel 
		 keypath:(NSString *)aKeypath 
	   formatter:(NSFormatter *)aFormatter 
	   alignment:(NSTextAlignment)alignment;

- (void)setLabel:(NSString *)aLabel 
		 keypath:(NSString *)aKeypath
	   formatter:(NSFormatter *)aFormatter 
   formatterCode:(int)aFormatterCode 
	   alignment:(NSTextAlignment)alignment;


@end


@interface NSView (MCReportElementPropagation)

- (void)propagateStretchHeightToMatchParent;

@end

