/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Rosegarden
    A sequencer and musical notation editor.
    Copyright 2000-2026 the Rosegarden development team.
    See the AUTHORS file for more details.

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#ifndef RG_NOTATION_TYPES_H
#define RG_NOTATION_TYPES_H

#include <rosegardenprivate_export.h>

#include "TimeT.h"
#include "Exception.h"
#include "PropertyName.h"

#include <list>
#include <string>
#include <vector>
#include <map>
#include <memory>

/*
 * NotationTypes.h
 *
 * This file contains definitions of several classes to assist in
 * creating and manipulating certain Event types.  The classes are:
 *
 *   Accidental
 *   Clef
 *   Key
 *   Indication
 *   Pitch
 *   Note
 *   AccidentalTable
 *   Symbol
 *   GeneratedRegion
 *
 * The classes in this file are _not_ actually used for storing
 * events.  Events are always stored in Event objects (see Event.h).
 *
 * These classes are usually constructed on-the-fly when a particular
 * operation specific to a single sort of event is required, and
 * usually destroyed as soon as they go out of scope.  The most common
 * usages are for creating events (create an instance of one of these
 * classes with the data you require, then call getAsEvent on it), for
 * doing notation-related calculations from existing events (such as
 * the bar duration of a time signature), and for doing calculations
 * that are independent of any particular instance of an event (such
 * as the Note methods that calculate duration-related values without
 * reference to any specific pitch or other note-event properties; or
 * everything in Pitch).
 *
 * This file also defines the event types and standard property names
 * for the basic events.
 *
 * See MidiTypes.h for MIDI-specific Event types like Controllers and
 * Program Changes.
 */


namespace Rosegarden
{


class Event;

extern ROSEGARDENPRIVATE_EXPORT const int MIN_SUBORDERING;

typedef std::list<int> DurationList;


/**
 * Accidentals are stored in the event as string properties, purely
 * for clarity.  (They aren't manipulated _all_ that often, so this
 * probably isn't a great inefficiency.)  Originally we used an enum
 * for the Accidental type with conversion functions to and from
 * strings, but making Accidental a string seems simpler.
 */

typedef std::string Accidental;

namespace Accidentals
{
    extern ROSEGARDENPRIVATE_EXPORT const Accidental NoAccidental;
    extern ROSEGARDENPRIVATE_EXPORT const Accidental Sharp;
    extern ROSEGARDENPRIVATE_EXPORT const Accidental Flat;
    extern ROSEGARDENPRIVATE_EXPORT const Accidental Natural;
    extern ROSEGARDENPRIVATE_EXPORT const Accidental DoubleSharp;
    extern ROSEGARDENPRIVATE_EXPORT const Accidental DoubleFlat;
    extern ROSEGARDENPRIVATE_EXPORT const Accidental QuarterFlat;
    extern ROSEGARDENPRIVATE_EXPORT const Accidental ThreeQuarterFlat;
    extern ROSEGARDENPRIVATE_EXPORT const Accidental QuarterSharp;
    extern ROSEGARDENPRIVATE_EXPORT const Accidental ThreeQuarterSharp;

    typedef std::vector<Accidental> AccidentalList;

	/**
	 * When no accidental is specified for a pitch, there are several
	 * strategies to determine what accidental to display for an
	 * out-of-key pitch
	 */
	enum NoAccidentalStrategy {
		/** always use sharps */
		UseSharps,
		/** always use flats */
		UseFlats,
		/** always use sharps or always use flats depending on of what
		 * type of accidentals the current key is made up */
		UseKeySharpness,
		/** use the most likely accidental for this key */
		UseKey
	};

    /**
     * Get the predefined accidentals (i.e. the ones listed above)
     * in their defined order.
     */
     // unused extern ROSEGARDENPRIVATE_EXPORT AccidentalList getStandardAccidentals();

    /**
     * Get the change in pitch resulting from an accidental: -1 for
     * flat, 2 for double-sharp, 0 for natural or NoAccidental etc.
     * This is not as useful as it may seem, as in reality the
     * effect of an accidental depends on the key as well -- see
     * the Key and Pitch classes.
     */
    extern ROSEGARDENPRIVATE_EXPORT int getPitchOffset(const Accidental &accidental);


    /**
     * Get the Accidental corresponding to a change in pitch: flat
     * for -1, double-sharp for 2, natural for 0 etc.
     *
     * Useful for tying to code that represents accidentals by
     * their pitch change.
     */
    extern ROSEGARDENPRIVATE_EXPORT Accidental getAccidental(int pitchChange);
}


/**
 * Marks, like Accidentals, are stored in the event as string properties.
 */

typedef std::string Mark;

namespace Marks
{
    extern ROSEGARDENPRIVATE_EXPORT const Mark NoMark;         // " "

    extern ROSEGARDENPRIVATE_EXPORT const Mark Accent;         // ">"
    extern ROSEGARDENPRIVATE_EXPORT const Mark Tenuto;         // "-"  ("legato" in RG2.1)
    extern ROSEGARDENPRIVATE_EXPORT const Mark Staccato;       // "."
    extern ROSEGARDENPRIVATE_EXPORT const Mark Staccatissimo;  // "'"
    extern ROSEGARDENPRIVATE_EXPORT const Mark Marcato;        // "^"
    extern ROSEGARDENPRIVATE_EXPORT const Mark Open;           // "o"
    extern ROSEGARDENPRIVATE_EXPORT const Mark Stopped;        // "+"
    extern ROSEGARDENPRIVATE_EXPORT const Mark Harmonic;       // "°"

    extern ROSEGARDENPRIVATE_EXPORT const Mark Sforzando;      // "sf"
    extern ROSEGARDENPRIVATE_EXPORT const Mark Rinforzando;    // "rf"

    extern ROSEGARDENPRIVATE_EXPORT const Mark Trill;          // "tr"
    extern ROSEGARDENPRIVATE_EXPORT const Mark LongTrill;      // with wiggly line
    extern ROSEGARDENPRIVATE_EXPORT const Mark TrillLine;      // line on its own
    extern ROSEGARDENPRIVATE_EXPORT const Mark Turn;           // "~"

    extern ROSEGARDENPRIVATE_EXPORT const Mark Pause;          // aka "fermata"

    extern ROSEGARDENPRIVATE_EXPORT const Mark UpBow;          // "v"
    extern ROSEGARDENPRIVATE_EXPORT const Mark DownBow;        // a square with the bottom side missing

    extern ROSEGARDENPRIVATE_EXPORT const Mark Mordent;
    extern ROSEGARDENPRIVATE_EXPORT const Mark MordentInverted;
    extern ROSEGARDENPRIVATE_EXPORT const Mark MordentLong;
    extern ROSEGARDENPRIVATE_EXPORT const Mark MordentLongInverted;

    /**
     * Given a string, return a mark that will be recognised as a
     * text mark containing that string.  For example, the Sforzando
     * mark is actually defined as getTextMark("sf").
     */
    extern ROSEGARDENPRIVATE_EXPORT Mark getTextMark(const std::string& text);

    /**
     * Return true if the given mark is a text mark.
     */
    extern ROSEGARDENPRIVATE_EXPORT bool isTextMark(Mark mark);

    /**
     * Extract the string from a text mark.
     */
    extern ROSEGARDENPRIVATE_EXPORT std::string getTextFromMark(Mark mark);

    /**
     * Given a string, return a mark that will be recognised as a
     * fingering mark containing that string.  (We use a string
     * instead of a number to permit "fingering" marks containing
     * labels like "+".)
     */
    extern ROSEGARDENPRIVATE_EXPORT Mark getFingeringMark
    (const std::string& fingering);

    /**
     * Return true if the given mark is a fingering mark.
     */
    extern ROSEGARDENPRIVATE_EXPORT bool isFingeringMark(Mark mark);

    /**
     * Extract the string from a fingering mark.
     */
    extern ROSEGARDENPRIVATE_EXPORT std::string getFingeringFromMark(Mark mark);

    /**
     * Return true if the given mark makes sense when applied to a rest.
     */
    extern ROSEGARDENPRIVATE_EXPORT bool isApplicableToRests(const Mark& mark);

    /**
     * Extract the number of marks from an event.
     */
    // unused extern ROSEGARDENPRIVATE_EXPORT int getMarkCount(const Event &e);

    /**
     * Extract the marks from an event.
     */
    extern ROSEGARDENPRIVATE_EXPORT std::vector<Mark> getMarks(const Event &e);

    /**
     * Return the first fingering mark on an event (or NoMark, if none).
     */
    extern ROSEGARDENPRIVATE_EXPORT Mark getFingeringMark(const Event &e);

    /**
     * Add a mark to an event.  If unique is true, add the mark only
     * if the event does not already have it (otherwise permit
     * multiple identical marks).
     */
    extern ROSEGARDENPRIVATE_EXPORT void addMark(Event &e, const Mark &mark, bool unique);

    /**
     * Remove a mark from an event.  Returns true if the mark was
     * there to remove.  If the mark was not unique, removes only
     * the first instance of it.
     */
    extern ROSEGARDENPRIVATE_EXPORT bool removeMark
    (Event &e, const Mark &markToRemove);

    /**
     * Returns true if the event has the given mark.
     */
    extern ROSEGARDENPRIVATE_EXPORT bool hasMark(const Event &e, const Mark &mark);

    /**
     * Get the predefined marks (i.e. the ones listed above) in their
     * defined order.
     */
    extern ROSEGARDENPRIVATE_EXPORT std::vector<Mark> getStandardMarks();
}


/**
 * Clefs are represented as one of a set of standard strings, stored
 * within a clef Event.  The Clef class defines those standards and
 * provides a few bits of information about the clefs.
 */

class ROSEGARDENPRIVATE_EXPORT Clef
{
public:
    static const std::string EventType;
    static const int EventSubOrdering;
    static const PropertyName ClefPropertyName;
    static const PropertyName OctaveOffsetPropertyName;
    static const Clef DefaultClef;
    static const Clef UndefinedClef;
    typedef Exception BadClefName;

    static const std::string Treble;
    static const std::string French;
    static const std::string Soprano;
    static const std::string Mezzosoprano;
    static const std::string Alto;
    static const std::string Tenor;
    static const std::string Baritone;
    static const std::string Varbaritone;
    static const std::string Bass;
    static const std::string Subbass;
    static const std::string TwoBar;

    /**
     * Construct the default clef (treble).
     */
    Clef() : m_clef(DefaultClef.m_clef), m_octaveOffset(0) { }

    /**
     * Construct a Clef from the clef data in the given event.  If the
     * event is not of clef type or contains insufficient data, this
     * returns the default clef (with a warning).  You should normally
     * test Clef::isValid() to catch that before construction.
     */
    explicit Clef(const Event &e);

    /**
     * Construct a Clef from the given data.  Throws a BadClefName
     * exception if the given string does not match one of the above
     * clef name constants.
     */
    explicit Clef(const std::string &s, int octaveOffset = 0);

    Clef(const Clef &c) : m_clef(c.m_clef), m_octaveOffset(c.m_octaveOffset) {
    }

    Clef &operator=(const Clef &c);

    bool operator==(const Clef &c) const {
        return c.m_clef == m_clef && c.m_octaveOffset == m_octaveOffset;
    }

    bool operator!=(const Clef &c) const {
        return !(c == *this);
    }

    ~Clef() { }

    /**
     * Test whether the given event is a valid Clef event.
     */
    static bool isValid(const Event &e);

    /**
     * Return the basic clef type (Treble, French, Soprano, Mezzosoprano, Alto, Tenor, Baritone, Varbaritone, Bass, Subbass)
     */
    std::string getClefType() const { return m_clef; }

    /**
     * Return any additional octave offset, that is, return 1 for
     * a clef shifted an 8ve up, etc
     */
    int getOctaveOffset() const { return m_octaveOffset; }

    /**
     * Return the number of semitones a pitch in the treble clef would
     * have to be lowered by in order to be drawn with the same height
     * and accidental in this clef
     */
    int getTranspose() const;

    /**
     * Return the octave component of getTranspose(), i.e. the number
     * of octaves difference in pitch between this clef and the treble
     */
    int getOctave() const;

    /**
     * Return the intra-octave component of getTranspose(), i.e. the
     * number of semitones this clef is distinct in pitch from the treble
     * besides the difference in octaves
     */
    int getPitchOffset() const;

    /**
     * Return the height-on-staff (in Pitch terminology)
     * of the clef's axis -- the line around which the clef is drawn.
     */
    int getAxisHeight() const;

    typedef std::vector<Clef> ClefList;

    /**
     * Return all the clefs, in ascending order of pitch
     */
    static ClefList getClefs();

    /// Returned event is on heap; caller takes responsibility for ownership
    Event *getAsEvent(timeT absoluteTime) const;

private:
    std::string m_clef;
    int m_octaveOffset;
};

/**
 * All we store in a key Event is the name of the key.  A Key object
 * can be constructed from such an Event or just from its name, and
 * will return all the properties of the key.  The Key class also
 * provides some useful mechanisms for getting information about and
 * transposing between keys.
 */

class ROSEGARDENPRIVATE_EXPORT Key
{
public:
    static const std::string EventType;
    static const int EventSubOrdering;
    static const PropertyName KeyPropertyName;
    static const Key DefaultKey;
    static const Key UndefinedKey;
    typedef Exception BadKeyName;
    typedef Exception BadKeySpec;

    /**
     * Construct the default key (C major).
     */
    Key();

    /**
     * Construct a Key from the key data in the given event.  If the
     * event is not of key type or contains insufficient data, this
     * returns the default key (with a warning).  You should normally
     * test Key::isValid() to catch that before construction.
     */
    explicit Key(const Event &e);

    /**
     * Construct the named key.  Throws a BadKeyName exception if the
     * given string does not match one of the known key names.
     */
    explicit Key(const std::string &name);

    /**
     * Construct a key from signature and mode.  May throw a
     * BadKeySpec exception.
     */
    Key(int accidentalCount, bool isSharp, bool isMinor);

    /**
     * Construct the key with the given tonic and mode. (Ambiguous.)
     * May throw a BadKeySpec exception.
     */
    Key(int tonicPitch, bool isMinor);

    Key(const Key &kc);

    ~Key() {
    }

    Key &operator=(const Key &kc);

    bool operator==(const Key &k) const {
        return k.m_name == m_name;
    }

    bool operator!=(const Key &k) const {
        return !(k == *this);
    }

    // We only use this for map, which doesn't need an intelligent
    // ordering.
    bool operator<(const Key &b) const
    { return this->getName() < b.getName(); }

    /**
     * Test whether the given event is a valid Key event.
     */
    static bool isValid(const Event &e);

    /**
     * Return true if this is a minor key.  Unlike in RG2.1,
     * we distinguish between major and minor keys with the
     * same signature.
     */
    bool isMinor() const {
        return m_keyDetailMap[m_name].m_minor;
    }

    /**
     * Return true if this key's signature is made up of
     * sharps, false if flats.
     */
    bool isSharp() const {
        return m_keyDetailMap[m_name].m_sharps;
    }

    /**
     * Return the pitch of the tonic note in this key, as a
     * MIDI (or RG4) pitch modulo 12 (i.e. in the range 0-11).
     * This is the pitch of the note named in the key's name,
     * e.g. 0 for the C in C major.
     */
    int getTonicPitch() const {
        return m_keyDetailMap[m_name].m_tonicPitch;
    }

    /**
     * Return the number of sharps or flats in the key's signature.
     */
    int getAccidentalCount() const {
        return m_keyDetailMap[m_name].m_sharpCount;
    }

    /**
     * Return the key with the same signature but different
     * major/minor mode.  For example if called on C major,
     * returns A minor.
     */
    Key getEquivalent() const {
        return Key(m_keyDetailMap[m_name].m_equivalence);
    }

    /**
     * Return the name of the key, in a human-readable form
     * also suitable for passing to the Key constructor.
     */
    std::string getName() const {
        return m_name;
    }

    /**
     * Return the name of the key, in the form used by X11 RG2.1.
     */
    std::string getRosegarden2Name() const {
        return m_keyDetailMap[m_name].m_rg2name;
    }

    /**
     * Return the accidental at the given height-on-staff
     * (in Pitch terminology) in the given clef.
     */
    Accidental getAccidentalAtHeight(int height, const Clef &clef) const;

    /**
     * Return the accidental for the the given number of steps
     * from the tonic. For example: for F major, step '3' is the
     * Bb, so getAccidentalForStep(3) will yield a Flat.
     */
    Accidental getAccidentalForStep(int steps) const;

    /**
     * Return the heights-on-staff (in Pitch
     * terminology) of all accidentals in the key's signature,
     * in the given clef.
     */
    std::vector<int> getAccidentalHeights(const Clef &clef) const;

    /**
     * Return the result of applying this key to the given
     * pitch, that is, modifying the pitch so that it has the
     * same status in terms of accidentals as it had when
     * found in the given previous key.
     */
    int convertFrom(int p, const Key &previousKey,
                    const Accidental &explicitAccidental =
                    Accidentals::NoAccidental) const;

    /**
     * Return the result of transposing the given pitch into
     * this key, that is, modifying the pitch by the difference
     * between the tonic pitches of this and the given previous
     * key.
     */
    int transposeFrom(int pitch, const Key &previousKey) const;

    /**
     * Reduce a height-on-staff to a single octave, so that it
     * can be compared against the accidental heights returned
     * by the preceding method.
     */
    static inline unsigned int canonicalHeight(int height) {
        return (height > 0) ? (height % 7) : ((7 - (-height % 7)) % 7);
    }

    typedef std::vector<Key> KeyList;

    /**
     * Return all the keys in the given major/minor mode, in
     * no particular order.
     */
    static KeyList getKeys(bool minor = false);


    /// Returned event is on heap; caller takes responsibility for ownership
    Event *getAsEvent(timeT absoluteTime) const;

    /**
     * Transpose this key by the specified interval given in pitch and steps
     *
     * For example: transposing F major by a major triad (4,2) yields
     *  A major.
     */
    Key transpose(int pitchDelta, int heightDelta) const;

private:

    std::string m_name;
    mutable std::shared_ptr<std::vector<int>> m_accidentalHeights;

    struct KeyDetails {
        bool   m_sharps;
        bool   m_minor;
        int    m_sharpCount;
        std::string m_equivalence;
        std::string m_rg2name;
        int    m_tonicPitch;

        KeyDetails(); // ctor needed in order to live in a map

        KeyDetails(bool sharps, bool minor, int sharpCount,
                   const std::string& equivalence, const std::string& rg2name,
                   int tonicPitch);

        KeyDetails(const KeyDetails &d);

        KeyDetails &operator=(const KeyDetails &d);
    };


    typedef std::map<std::string, KeyDetails> KeyDetailMap;
    static KeyDetailMap m_keyDetailMap;
    static void checkMap();
    void checkAccidentalHeights() const;

};


/**
 * Indication is a collective name for graphical marks that span a
 * series of events, such as slurs, dynamic marks etc.  These are
 * stored in indication Events with a type and duration.  The
 * Indication class gives a basic set of indication types.
 */

class Indication
{
public:
    static const std::string EventType;
    static const int EventSubOrdering;
    static const PropertyName IndicationTypePropertyName;
    typedef Exception BadIndicationName;

    static const std::string Slur;
    static const std::string PhrasingSlur;
    static const std::string Crescendo;
    static const std::string Decrescendo;
    static const std::string Glissando;

    static const std::string QuindicesimaUp;
    static const std::string OttavaUp;
    static const std::string OttavaDown;
    static const std::string QuindicesimaDown;

    static const std::string TrillLine;

    static const std::string FigParameterChord;
    static const std::string Figuration;

    explicit Indication(const Event &e)
        /* throw (Event::NoData, Event::BadType) */;
    Indication(const std::string &s, timeT indicationDuration)
        /* throw (BadIndicationName) */;

    Indication(const Indication &m) : m_indicationType(m.m_indicationType),
                                      m_duration(m.m_duration) { }

    Indication &operator=(const Indication &m);

    ~Indication() { }

    std::string getIndicationType() const { return m_indicationType; }
    timeT getIndicationDuration() const { return m_duration; }

    bool isOttavaType() const {
        return
            m_indicationType == QuindicesimaUp ||
            m_indicationType == OttavaUp ||
            m_indicationType == OttavaDown ||
            m_indicationType == QuindicesimaDown;
    }

    int getOttavaShift() const {
        return (m_indicationType == QuindicesimaUp ? 2 :
                m_indicationType == OttavaUp ? 1 :
                m_indicationType == OttavaDown ? -1 :
                m_indicationType == QuindicesimaDown ? -2 : 0);
    }

    /// Returned event is on heap; caller takes responsibility for ownership
    Event *getAsEvent(timeT absoluteTime) const;

private:
    static bool isValid(const std::string &s);

    std::string m_indicationType;
    timeT m_duration;
};

/**
 * Definitions for use in the Text event type
 */

class Text
{
public:
    static const std::string EventType;
    static const int EventSubOrdering;
    static const PropertyName TextPropertyName;
    static const PropertyName TextTypePropertyName;
    static const PropertyName LyricVersePropertyName;

    /**
     * Text styles
     */
    static const std::string UnspecifiedType;
    static const std::string StaffName;
    static const std::string ChordName;
    static const std::string KeyName;
    static const std::string Lyric;
    static const std::string Chord;
    static const std::string Dynamic;
    static const std::string Direction;
    static const std::string LocalDirection;
    static const std::string Tempo;
    static const std::string LocalTempo;
    static const std::string Annotation;
    static const std::string LilyPondDirective;

    /**
     * Special LilyPond directives
     */
    static const std::string FakeSegno;   // print segno here
    static const std::string FakeCoda;    // print coda sign here
    static const std::string Alternate1;  // first alternative ending
    static const std::string Alternate2;  // second alternative ending
    static const std::string BarDouble;   // next barline is double
    static const std::string BarEnd;      // next barline is final double
    static const std::string BarDot;      // next barline is dotted
    static const std::string Gliss;       // \glissando on this note (to next note)
    static const std::string Arpeggio;    // \arpeggio on this chord
//    static const std::string ArpeggioUp;  // \ArpeggioUp on this chord
//    static const std::string ArpeggioDn;  // \ArpeggioDown on this chord
    static const std::string Tiny;        // begin \tiny font section
    static const std::string Small;       // begin \small font section
    static const std::string NormalSize;  // begin \normalsize font section

    explicit Text(const Event &e)
        /* throw (Event::NoData, Event::BadType) */;
    explicit Text(const std::string &text,
                  const std::string &textType = UnspecifiedType);
    Text(const Text &);
    Text &operator=(const Text &);
    ~Text();

    std::string getText() const { return m_text; }
    std::string getTextType() const { return m_type; }

    // Relevant for lyrics, and borrowed for figuration IDs.
    int getVerse() const { return m_verse; }
    void setVerse(int verse) { m_verse = verse; }

    static bool isTextOfType(Event *, const std::string& type);

    /**
     * Return those text types that the user should be allowed to
     * specify directly and visually
     */
    static std::vector<std::string> getUserStyles();

    /**
     * Return a list of available special LilyPond directives
     */
    static std::vector<std::string> getLilyPondDirectives();

    /// Returned event is on heap; caller takes responsibility for ownership
    Event *getAsEvent(timeT absoluteTime) const;

private:
    std::string m_text;
    std::string m_type;
    long m_verse;
};



/**
 * The Note class represents note durations only, not pitch or
 * accidental; it's therefore just as relevant to rest events as to
 * note events.  You can construct one of these from either.
 */

class ROSEGARDENPRIVATE_EXPORT Note
{
public:
    static const std::string EventType;
    static const std::string EventRestType;
    static const int EventRestSubOrdering;

    typedef int Type; // not an enum, too much arithmetic at stake

    // define both sorts of names; some people prefer the American
    // names, but I just can't remember which of them is which

    static const Type

        SixtyFourthNote     = 0,
        ThirtySecondNote    = 1,
        SixteenthNote       = 2,
        EighthNote          = 3,
        QuarterNote         = 4,
        HalfNote            = 5,
        WholeNote           = 6,
        DoubleWholeNote     = 7,

        Hemidemisemiquaver  = 0,
        Demisemiquaver      = 1,
        Semiquaver          = 2,
        Quaver              = 3,
        Crotchet            = 4,
        Minim               = 5,
        Semibreve           = 6,
        Breve               = 7,

        Shortest            = 0,
        Longest             = 7;


    /**
     * Create a Note object of the given type, representing a
     * particular sort of duration.  Note objects are strictly
     * durational; they don't represent pitch, and may be as
     * relevant to rests as actual notes.
     */
    explicit Note(Type type, int dots = 0) :
        m_type(type < Shortest ? Shortest :
               type >  Longest ?  Longest :
               type),
        m_dots(dots) { }

    Note(const Note &n) : m_type(n.m_type), m_dots(n.m_dots) { }
    ~Note() { }

    Note &operator=(const Note &n);

    Type getNoteType()  const { return m_type; }
    int  getDots()      const { return m_dots; }

    /**
     * Return the duration of this note type.
     */
    timeT getDuration()  const {
        return m_dots ? getDurationAux() : (m_shortestTime * (1 << m_type));
    }

    /**
     * Return the Note whose duration is closest to (but shorter than or
     * equal to) the given duration, permitting at most maxDots dots.
     */
    static Note getNearestNote(timeT duration, int maxDots = 2);

    /// Returned event is on heap; caller takes responsibility for ownership
    Event *getAsNoteEvent(timeT absoluteTime, int pitch) const;

    /// Returned event is on heap; caller takes responsibility for ownership
    // unused Event *getAsRestEvent(timeT absoluteTime) const;


private:
    Type m_type;
    int m_dots;

    timeT getDurationAux()  const;

    // a time & effort saving device; if changing this, change
    // TimeSignature::m_crotchetTime etc too
    static const timeT m_shortestTime;
};



/**
 * AccidentalTable represents a set of accidentals in force at a
 * given time.
 *
 * Keep an AccidentalTable variable on-hand as you track through a
 * staff; then when reading a chord, call processDisplayAccidental
 * on the accidentals found in the chord to obtain the actual
 * displayed accidentals and to tell the AccidentalTable to
 * remember the accidentals that have been found in the chord.
 * Then when the chord ends, call update() on the AccidentalTable
 * so that that chord's accidentals are taken into account for the
 * next one.
 *
 * Create a new AccidentalTable whenever a new key is encountered,
 * and call newBar() or newClef() when a new bar happens or a new
 * clef is encountered.
 */
class ROSEGARDENPRIVATE_EXPORT AccidentalTable
{
public:
    enum OctaveType {
        OctavesIndependent, // if c' and c'' sharp, mark them both sharp
        OctavesCautionary,  // if c' and c'' sharp, put the second one in brackets
        OctavesEquivalent   // if c' and c'' sharp, only mark the first one
    };

    enum BarResetType {
        BarResetNone,       // c# | c -> omit natural
        BarResetCautionary, // c# | c -> add natural to c in brackets
        BarResetExplicit    // c# | c -> add natural to c
    };

    explicit AccidentalTable(const Key & = Key(), const Clef & = Clef(),
                             OctaveType = OctavesCautionary,
                             BarResetType = BarResetCautionary);

    AccidentalTable(const AccidentalTable &);
    AccidentalTable &operator=(const AccidentalTable &);

    Accidental processDisplayAccidental(const Accidental &displayAcc,
                                        int heightOnStaff,
                                        bool &cautionary);

    void update();

    void newBar();
    void newClef(const Clef &);

private:
    Key m_key;
    Clef m_clef;
    OctaveType m_octaves;
    BarResetType m_barReset;

    struct AccidentalRec {
        AccidentalRec() : accidental(Accidentals::NoAccidental), previousBar(false) { }
        AccidentalRec(const Accidental& a, bool p) : accidental(a), previousBar(p) { }
        Accidental accidental;
        bool previousBar;
    };

    typedef std::map<int, AccidentalRec> AccidentalMap;

    AccidentalMap m_accidentals;
    AccidentalMap m_canonicalAccidentals;

    AccidentalMap m_newAccidentals;
    AccidentalMap m_newCanonicalAccidentals;
};


/** Definitions for use in the Symbol event type
 *
 * A Symbol has no duration, and the things it represents will probably always
 * be no-ops that are never interpreted by the sequencer or MIDI export engines
 *
 * \author D. Michael McIntyre
 */
class ROSEGARDENPRIVATE_EXPORT Symbol
{
public:
    static const std::string EventType;
    static const int EventSubOrdering;
    static const PropertyName SymbolTypePropertyName;

    /**
     * Symbol types
     */
    static const std::string UnspecifiedType;
    static const std::string Segno;
    static const std::string Coda;
    static const std::string Breath;

    explicit Symbol(const Event &e)
        /* throw (Event::NoData, Event::BadType) */;
    explicit Symbol(const std::string &symbolType = UnspecifiedType);
    Symbol(const Symbol &);
    Symbol &operator=(const Symbol &);
    ~Symbol ();

    std::string getSymbolType() const { return m_type; }

    // unused static bool isSymbolOfType(Event *, const std::string& type);

    /// Returned event is on heap; caller takes responsibility for ownership
    Event *getAsEvent(timeT absoluteTime) const;

private:
    std::string m_type;
};

}


#endif
