/*
    Rosegarden
    A sequencer and musical notation editor.

    This program is Copyright 2000-2008
        Guillaume Laurent   <glaurent@telegraph-road.org>,
        Chris Cannam        <cannam@all-day-breakfast.com>,
        Richard Bown        <bownie@bownie.com>

    The moral right of the authors to claim authorship of this work
    has been asserted.

    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 _STAFF_H_
#define _STAFF_H_

#include "ViewElement.h"
#include "Segment.h"

#include <iostream>
#include <cassert>

namespace Rosegarden 
{

class StaffObserver;

/**
 * Staff is the base class for classes which represent a Segment as an
 * on-screen graphic.  It manages the relationship between Segment/Event
 * and specific implementations of ViewElement.
 *
 * The template argument T must be a subclass of ViewElement.
 *
 * Staff was formerly known as ViewElementsManager.
 */
class Staff : public SegmentObserver
{
public: 
    virtual ~Staff();

    /**
     * Create a new ViewElementList wrapping all Events in the
     * segment, or return the previously created one
     */
    ViewElementList *getViewElementList();

    /**
     * Create a new ViewElementList wrapping Events in the
     * [from, to[ interval, or return the previously created one
     * (even if passed new arguments)
     */
    ViewElementList *getViewElementList(Segment::iterator from,
                                           Segment::iterator to);

    /**
     * Return the Segment wrapped by this object 
     */
    Segment &getSegment() { return m_segment; }

    /**
     * Return the Segment wrapped by this object 
     */
    const Segment &getSegment() const { return m_segment; }

    /**
     * Return the location of the given event in this Staff
     */
    ViewElementList::iterator findEvent(Event *);

    /**
     * SegmentObserver method - called after the event has been added to
     * the segment
     */
    virtual void eventAdded(const Segment *, Event *);

    /**
     * SegmentObserver method - called after the event has been removed
     * from the segment, and just before it is deleted
     */
    virtual void eventRemoved(const Segment *, Event *);

    /** 
     * SegmentObserver method - called after the segment's end marker
     * time has been changed
     */
    virtual void endMarkerTimeChanged(const Segment *, bool shorten);

    /**
     * SegmentObserver method - called from Segment dtor
     */
    virtual void segmentDeleted(const Segment *);

    void addObserver   (StaffObserver *obs) { m_observers.push_back(obs); }
    void removeObserver(StaffObserver *obs) { m_observers.remove(obs); }

protected:
    Staff(Segment &);
    virtual ViewElement* makeViewElement(Event*) = 0;
    
    /**
     * Return true if the event should be wrapped
     * Useful for piano roll where we only want to wrap notes
     * (always true by default)
     */
    virtual bool wrapEvent(Event *);

    void notifyAdd(ViewElement *) const;
    void notifyRemove(ViewElement *) const;
    void notifySourceDeletion() const;

    //--------------- Data members ---------------------------------

    Segment &m_segment;
    ViewElementList *m_viewElementList;

    typedef std::list<StaffObserver*> ObserverSet;
    ObserverSet m_observers;

private: // not provided
    Staff(const Staff &);
    Staff &operator=(const Staff &);
};

class StaffObserver
{
public:
    virtual ~StaffObserver() {}
    virtual void elementAdded(const Staff *, ViewElement *) = 0;
    virtual void elementRemoved(const Staff *, ViewElement *) = 0;

    /// called when the observed object is being deleted
    virtual void staffDeleted(const Staff *) = 0;
};



}

#endif

