//
//  MCModelEditor.h
//  MCApplication
//
//  Created by aj on Sat Sep 29 2001.
//  Copyright (c) 2001 __CompanyName__. All rights reserved.
//

#import <AppKit/AppKit.h>
#import "MCWindowController.h"

typedef enum _MCOperatingMode {
    MCNotOperating				= 0,
    MCSheetOperationMode			= 1,
    MCInspectorOperationMode			= 2,
    MCPreferencesOperationMode			= 3
} MCOperatingMode;

@class MCBinder, MCBinding, MCAMD, MCTableviewController, MCChannel;


@interface MCModelEditor : MCWindowController {

    BOOL					_awoke;
    BOOL					_dirty;
	BOOL					_lockedModel;
	BOOL					_readOnly;
	BOOL					_independantModelFromParent;

    id 						model;
    id						binder;
    int						operatingMode;
    	
	id						switchView;
    
    id						delegate;
    id						(contentView);
	
	NSMutableDictionary		*_subEditors;

	NSPrintInfo								*_pInfo;
	id										(printController);

    IBOutlet 		NSView 					*lastKeyView;

	IBOutlet		MCChannel				*channel;
	IBOutlet		MCAMD					*amd;
	IBOutlet		MCTableviewController	*tvc;

}
- (void)_changeToCleanState;
- (void)_changeToDirtyState;


- (id)delegate;
- (void)setDelegate:(id)aDeleg;

- (NSView *)initialFirstResponder;
- (NSView *)lastKeyView;

- (void)prepareForDealloc;

/*!
	@method becomeCurrentEditor
	@discussion If a model editor is used in a tab view or switchview or drawer, you should call this method right before the editor will become active. Default implementation does nothing, subclassers can override and do whatever is needed.
*/
- (void)becomeCurrentEditor;

/*!
	@method resignCurrentEditor
	@discussion If a model editor is used in a tab view or switchview or drawer, you should call this method after the editor has become inactive. Default implementation does nothing, subclassers can override and do whatever is needed.
*/
- (void)resignCurrentEditor;

/*!
	@method finalizeModelUsage
	@discussion called by cancel, and resignCurrentEditor. Checks the edit status and marks the object's unlock behavior. If the model is dirty, it then tells the object context (oc should have already been warned about this). Subclasses can override can do other completion tasks - but must call super at some point.
*/
- (void)finalizeModelUsage;


- (IBAction)ok:(id)sender;
- (IBAction)cancel:(id)sender;
- (IBAction)revert:(id)sender; 


// Monitoring dirty state
// Bind your textfield delegate and actions to these methods to change the dirty state
- (IBAction)didChangeAttributeValue:(id)sender;
- (void)textDidChange:(NSNotification *)notification;

// if sub editor asks the parent if model locked, otherwise is self has model locked
- (BOOL)isMutable;
// tells the binder and LOCK channel to enable or disable
- (void)passMutabilityFlag:(BOOL)flag;

// When a model editor is acting as a sub editor, it can have a different model than that of the parent. The default behaviour is to pass the model, but that can be prevented by calling subEditorWithName: passCurrentModel: or switchSwitchViewToSubEditorWithName: passCurrentModel: with NO as an argument. When setModel or setModelNoUpdate is called on the parent controller, the sub editor is called using the takeModelFromParent and if the usesIndependantModelFromParent is set, the model is not set on the sub editor.
- (void)setUsesIndependantModelFromParent:(BOOL)flag;
- (BOOL)usesIndependantModelFromParent;
- (void)takeModelFromParent:(id)aModel;



// SubEditors are subclasses of type MCModelEditor or MCModelList. The name is a classname and object must implement the informal setModel, model protocol
- (BOOL)hasSubEditorWithName:(NSString *)aName;
- (NSDictionary *)subEditors;

- (id)subEditorWithName:(NSString *)aName passCurrentModel:(BOOL)flag;
- (id)subEditorWithName:(NSString *)aName;

- (void)switchToDrawerSubEditorWithName:(NSString *)aName;
- (void)switchToDrawerSubEditorWithNameIfNotVisible:(NSString *)aName;
- (BOOL)isSubEditorWithNameVisible:(NSString *)aName;
- (BOOL)isSubEditor:(id)aSub;
- (id)firstVisibleSubEditor;


// Given an NSTabView, add a sub editor content view as a tab -- must be a fresh sub editor
- (void)addSubEditorNamed:(NSString *)aName 
	toTabView:(NSTabView *)aTabView 
	tabLabel:(NSString *)label 
	tabIdentifier:(id)identifier
	passCurrentModel:(BOOL)pass;
	
- (void)addSubEditorNamed:(NSString *)aName 
	toTabView:(NSTabView *)aTabView 
	tabLabel:(NSString *)label 
	tabIdentifier:(id)identifier
	image:(NSImage *)img
	alternateImage:(NSImage *)altImg
	pressedImage:(NSImage *)pressedImg
	passCurrentModel:(BOOL)pass;


// if there is a parentController and if that parent responds to isSubEditor: and that method return true
- (BOOL)isActingAsSubEditor;
- (void)subEditor:(id)aSub didUpdateBinding:(MCBinding *)aBinding;

// Sets whether we should be saving which sub editors are open in the drawers
- (NSString *)subEditorDrawerStateDefaultsName;
- (BOOL)shouldWriteDrawerStateToDefaults;


- (MCOperatingMode)operatingMode;
- (void)setOperatingInSheetMode;
- (void)setOperatingInInspectorMode;
- (void)setOperatingInPreferencesMode;

- (BOOL)hasFirstDrawer;
/// Returns the first drawer in the drawer array, if there aren't any, creates one. You should validate the content view -- there may not be one.
- (NSDrawer *)firstDrawer;

- (BOOL)hasSecondDrawer;
// Returns the second drawer (index 1) if there is only create a second one, otherwise throws an exception, you should validate the content view there may not be one
- (NSDrawer *)secondDrawer;

- (void)switchDrawerViewTo:(NSView *)aView;


- (id)binder;
- (MCAMD *)amd;
- (MCTableviewController *)tvc;

- (void)makeReadOnly;

- (void)attemptLockOnModel;
// if this editor locked the model, then YES is returned
- (BOOL)lockedModel;

// informally conforms to binder proto
- (void)setModel:aModel;
- (void)setModelNoUpdate:aModel;
- (id)model;

- (NSArray *)selectedObjects;

- (void)updateModelFromInterface;
- (void)updateInterfaceFromModel;

// sent from the document. default is to close self if editor is other than self, subclasses can do otherwise
- (void)editor:(id)anEditor willDeleteModel:(id)aModel;


// Default returns YES, subclassers can return NO
- (BOOL)shouldRefreshModel;

// if the switchView is not nil, this message passes the sender tag value 
- (IBAction)takeSwitchViewValueFrom:(id)sender;


- (IBAction)takeDrawerSwitchValueFrom:(id)sender;

// directly switches the view into switchView -- not requiring view wiring in IB
- (void)switchSwitchViewTo:(NSView *)aView;
- (void)switchSwitchViewToSubEditorWithName:(NSString *)aName;
- (void)switchSwitchViewToSubEditorWithName:(NSString *)aName passCurrentModel: (BOOL)flag;


// returns the view to switch into a host window (typically only required in Inspector mode)
- (id)inspectorView;
- (id)contentView;

- (void)runSheetInWindow:(NSWindow *)aWindow;
- (void)modelEditorSheetDidEnd:(NSWindow *)sheet 
    returnCode:(int)returnCode contextInfo:(void *)contextInfo;


// If this method returns a non null value, it is appended to the document name in the window title
- (NSString *)windowTitleSuffix;

// If this method returns YES, the the standard NSDocument window naming scheme is used (with the draggable file icon). The default return NO and uses windowTitleSuffix if there is one
- (BOOL)useStandardWindowNaming;


//- (void)documentWillCloseNotification:(NSNotification *)notification;

// does nothing -- subclassers should do their defaults dependant config in this method. When the user changes their defaults(preferences), this method is invoked
- (void)configureFromUserDefaultsNotification:(NSNotification *)notif;

// subclassers should call super when monitoring this binder delegate call
- (void)bindingDidUpdate:(MCBinding *)aBinding;




- (id)extendedTargetForAction:(SEL)anAction to:(id)aTarget from:(id)sender;


@end


@interface MCModelEditor (PrintSupport)

#define MC_PRINT_CURRENT_DATE	@"currentDate"

- (IBAction)_runPageLayout:(id)sender;
- (IBAction)_printDocument:(id)sender;
- (void)printPanelDidEnd:(NSPrintPanel *)printPanel 
		returnCode:(int)returnCode contextInfo: (void *)contextInfo;

// Returns an printinfo specific to this instance, you can override this to return a shared printInfo
- (NSPrintInfo *)printInfo;
- (void)setPrintInfo:(NSPrintInfo *)info;


// ** Determining the printController - First printController, then printControllerClassname, then printNibname. Controllers should responds to setModelNoUpdate: setExtraInfoNoUpdate, updateInterfaceFromModel

// Returns the printController instance to use, the default returns nil
- (id)printController;
- (void)setPrintController:(id)aController;

// Returns the printController classname, the default is nil
- (NSString *)printControllerClassname;
// Returns the nib name to use with MCPrintControllerWindow -- the default is ClassnamePrint (Print is appended to the class name
- (NSString *)printNibname;

// Returns the model to set on the printController -- the default returns the current model
- (id)modelForPrinting;

// Returns extra info to be used by the extraInfoBinder in the printController. The default returns a non-mutable dictionary with currentDate as a key
- (id)extraInfoForPrinting;


/////////////////////// TVC PRINTING ///////////////////////////////

- (id)prepareTVCPrintUserInfo;
- (id)prepareTVCPrintPageModel;

- (id)createTVCPrintController;

- (void)runPrintOperationWithPrintInfo:(NSPrintInfo *)pi showPanels:(BOOL)flag;

// default returns [self tvc]
- (MCTableviewController *)tvcToPrint;

// implement this method if you want anything done to the display when a new object is created(but not when you load an existing one)
- (void)configureDisplayForNewObject;
@end


@interface NSObject (MCModelEditorDelegate)

- (void)modelEditorDidChangeAttribute:(MCModelEditor *)anEditor;

- (BOOL)modelEditorWillOk:(MCModelEditor *)anEditor model:(id)aModel;
- (void)modelEditorDidOk:(MCModelEditor *)anEditor model:(id)aModel;

- (BOOL)modelEditorWillCancel:(MCModelEditor *)anEditor model:(id)aModel;
- (void)modelEditorDidCancel:(MCModelEditor *)anEditor model:(id)aModel;

- (BOOL)modelEditorWillRevert:(MCModelEditor *)anEditor model:(id)aModel;
- (void)modelEditorDidRevert:(MCModelEditor *)anEditor model:(id)aModel;

@end

@interface NSObject (RepresentedCommand)
- (BOOL)validateMenuItem:(id <NSMenuItem>)aMenuItem forSelection:(NSArray *)anArray originalTarget:(id)aTarget;
@end
