//
//  CapoNoteStorage.h
//  Capo
//
//  Created by Christopher Liscio on 1/29/10.
//  Copyright 2010 SuperMegaUltraGroovy. All rights reserved.
//

#import <Foundation/Foundation.h>

@protocol CapoNoteEntryStorageDelegate;
@protocol CapoNoteEntryStorageDisplay;

@class CapoNoteEntry;
@class CapoChordEntry;
@class SStringedInstrumentDescription;
@class CapoBeatEntry;
@class CapoTimeSignatureEntry;
@class CapoTempoEntry;
@class CapoRegionEntry;
@class CapoStandardPitchEntry;
@class CapoKeyEntry;

@interface CapoNoteEntryStorage : NSObject <NSCoding>

@property(nonatomic, readwrite, weak) id <CapoNoteEntryStorageDelegate> delegate;
@property(nonatomic, readwrite, weak) id <CapoNoteEntryStorageDisplay> display;

#pragma mark Instrument Description

- (void)setInstrumentDescription:(SStringedInstrumentDescription *)inDesc;
- (SStringedInstrumentDescription *)instrumentDescription;

#define USER_ENTRY_METHODS_DECL( UserEntryName, userEntryName ) \
- (Capo##UserEntryName##Entry *)new##UserEntryName##Entry; \
- (Capo##UserEntryName##Entry *)copyOf##UserEntryName##Entry:(Capo##UserEntryName##Entry *)inEntry; \
- (NSArray *)userEntryName##Entries; \
- (NSArray *)userEntryName##EntriesInRange:(NSRange)inRange; \
- (void)add##UserEntryName##Entry:(Capo##UserEntryName##Entry *)inEntry; \
- (void)add##UserEntryName##EntriesFromArray:(NSArray *)inArray; \
- (void)remove##UserEntryName##Entry:(Capo##UserEntryName##Entry *)inEntry; \
- (void)remove##UserEntryName##EntriesInArray:(NSArray *)inArray; \
- (void)replace##UserEntryName##Entry:(Capo##UserEntryName##Entry *)inEntry with ## UserEntryName ## Entry:(Capo ## UserEntryName ## Entry *)inOtherEntry; \
- (void)replace##UserEntryName##EntriesInArray:(NSArray *)inArray with##UserEntryName##EntriesInArray:(NSArray *)inOtherArray; \
- (BOOL)contains##UserEntryName##Entry:(Capo##UserEntryName##Entry *)inEntry; \

#pragma mark Note Entries

USER_ENTRY_METHODS_DECL( Note, note )

#pragma mark Chord Entries

USER_ENTRY_METHODS_DECL( Chord, chord )

#pragma mark Beat Information

USER_ENTRY_METHODS_DECL( Beat, beat );

- (NSArray *)beatEntriesFilteredByTimeSignature;
- (NSArray *)beatEntriesFilteredByTimeSignatureInRange:(NSRange)inRange;

- (NSUInteger)indexOfBeatEntry:(CapoBeatEntry *)beatEntry;
- (NSUInteger)barIndexOfBeatEntry:(CapoBeatEntry *)beatEntry;

#pragma mark Time Signature

USER_ENTRY_METHODS_DECL( TimeSignature, timeSignature )

#pragma mark Tempo

USER_ENTRY_METHODS_DECL( Tempo, tempo )

#pragma mark Standard Pitch

USER_ENTRY_METHODS_DECL( StandardPitch, standardPitch )

#pragma mark Region Entries

USER_ENTRY_METHODS_DECL( Region, region )

#pragma mark Key

USER_ENTRY_METHODS_DECL( Key, key );

- (CapoRegionEntry *)regionEntryForLocation:(uint64_t)location;

- (CapoRegionEntry *)newMarkerRegionEntry;
- (CapoRegionEntry *)newVerseRegionEntry;
- (CapoRegionEntry *)newChorusRegionEntry;
- (CapoRegionEntry *)newBridgeRegionEntry;

#undef USER_ENTRY_METHODS_DECL

@end

@protocol CapoNoteEntryStorageDelegate <NSObject>
@optional
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didAddNotes:(NSArray *)notes;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didRemoveNotes:(NSArray *)notes;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didReplaceNotes:(NSArray *)notes withNotes:(NSArray *)newNotes;

- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didAddChords:(NSArray *)chords;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didRemoveChords:(NSArray *)chords;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didReplaceChords:(NSArray *)chords withChords:(NSArray *)newChords;

- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didAddRegions:(NSArray *)regions;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didRemoveRegions:(NSArray *)regions;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didReplaceRegions:(NSArray *)regions withRegions:(NSArray *)newRegions;

- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didAddBeats:(NSArray *)beats;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didRemoveBeats:(NSArray *)beats;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didReplaceBeats:(NSArray *)beats withBeats:(NSArray *)newBeats;

- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didAddTimeSignatures:(NSArray *)timeSignatures;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didRemoveTimeSignatures:(NSArray *)timeSignatures;
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didReplaceTimeSignatures:(NSArray *)timeSignatures withTimeSignatures:(NSArray *)newTimeSignatures;

- (void)noteStorageDidUpdateTimeSignatureEntries:(NSNotification *)note;
- (void)noteStorageDidUpdateBeatEntries:(NSNotification *)note;
- (void)noteStorageDidUpdateChordEntries:(NSNotification *)note;

- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage didChangeInstrumentDescription:(SStringedInstrumentDescription *)inOldDescription toDescription:(SStringedInstrumentDescription *)inNewDescription;
@end

@protocol CapoNoteEntryStorageDisplay <NSObject>
- (void)noteStorage:(CapoNoteEntryStorage *)noteStorage invalidateDisplayInRange:(NSRange)range;
- (void)noteStorageDidChangeInstrumentDescription:(CapoNoteEntryStorage *)noteStorage;
@end

#pragma mark NSNotificationCenter Notifications

// These notifications indicate changes to the respective entries in the note entry storage object. For an add operation, the entries can be found in the CapoNoteEntryStorageAddedEntriesKey key of the userInfo dictionary. For a removal, they can be found in the CapoNoteEntryStorageRemovedEntriesKey. Finally, for replacement, the new items are located in the CapoNoteEntryStorageAddedEntriesKey key, and removed items in the CapoNoteEntryStorageAddedEntriesKey key of the userInfo dictionary.

#define CHANGE_NOTIFICATION_FOR( User ) \
extern NSString *CapoNoteEntryStorageDidChange##User##EntriesNotification;

CHANGE_NOTIFICATION_FOR( Note );
CHANGE_NOTIFICATION_FOR( Chord );
CHANGE_NOTIFICATION_FOR( Beat );
CHANGE_NOTIFICATION_FOR( Region );
CHANGE_NOTIFICATION_FOR( TimeSignature );
CHANGE_NOTIFICATION_FOR( Tempo );
CHANGE_NOTIFICATION_FOR( StandardPitch );
CHANGE_NOTIFICATION_FOR( Key );

#undef CHANGE_NOTIFICATION_FOR

// The instrument description is located in the CapoNoteEntryStorageChangedEntriesKey key of the userInfo dictionary
extern NSString *CapoNoteEntryStorageDidChangeInstrumentDescriptionNotification;

extern NSString *CapoNoteEntryStorageAddedEntriesKey;
extern NSString *CapoNoteEntryStorageRemovedEntriesKey;
extern NSString *CapoNoteEntryStorageChangedEntriesKey;