/*
 * @(#)cmd/Phrase.h 3.00 21 November 2000
 *
 * Copyright (c) 2000 Pete Goodliffe (pete@cthree.org)
 *
 * This file is part of TSE3 - the Trax Sequencer Engine version 3.00.
 *
 * This library is modifiable/redistributable under the terms of the GNU
 * General Public License.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; see the file COPYING. If not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#ifndef TSE3_CMD_PHRASE_H
#define TSE3_CMD_PHRASE_H

#include "tse3/cmd/Command.h"
#include "tse3/Phrase.h"
#include "tse3/DisplayParams.h"

#include <vector>
#include <string>

namespace TSE3
{
    class Phrase;
    class Song;
    class Part;
    class PhraseEdit;

    namespace Cmd
    {
        /**
         * Command to set a @ref TSE3::Phrase's info (the title and its
         * @ref TSE3::DisplayParams setup).
         *
         * If the @ref TSE3::Phrase is parented in a @ref TSE3::PhraseList
         * and you change the title to an invalid name, then the exception
         * generated by @ref TSE3::PhraseList::insert() will be propragated back
         * to you.
         *
         * @short   Set @ref TSE3::Phrase info Command
         * @author  Pete Goodliffe
         * @version 1.00
         * @see     Command
         */
        class Phrase_SetInfo : public Command
        {
            public:

                /**
                 * To create this command specify the @ref TSE3::Track object to
                 * alter and the new information.
                 *
                 * If the @ref TSE3::Phrase is not parented, or the new
                 * @p title already exists in the @ref PhraseList, then
                 * a @ref PhraseListError is thrown.
                 *
                 * @param phrase @ref TSE3::Phrase to run command on
                 * @param title  New title string (or "" to leave title)
                 * @param dp     New @ref TSE3::DisplayParams
                 * @throws PhraseListError
                 */
                Phrase_SetInfo(TSE3::Phrase              *phrase,
                               const std::string         &title,
                               const TSE3::DisplayParams &dp);

            protected:

                /**
                 * @reimplemented
                 */
                virtual void executeImpl();

                /**
                 * @reimplemented
                 */
                virtual void undoImpl();

            private:

                TSE3::Phrase        *phrase;
                std::string          newTitle, oldTitle;
                TSE3::DisplayParams  dp;
        };

        /**
         * Command to insert a @ref TSE3::Phrase into a @ref TSE3::Song
         * by creating it from a @ref TSE3::PhraseEdit.
         *
         * This object may propagate the @ref TSE3::PhraseListError exception
         * if the @ref Phrase name already exists.
         *
         * @short   Insert @ref TSE3::Phrase Command
         * @author  Pete Goodliffe
         * @version 3.00
         * @see     Command
         */
        class Phrase_Create : public Command
        {
            public:

                /**
                 * Creates a new Phrase_Create command.
                 *
                 * After having performed the first @ref execute() on this
                 * object it is safe to delete the @ref PhraseEdit object.
                 * Until then you must ensure that the object is not deleted.
                 *
                 * @param phrase     @ref TSE3::Phrase to insert
                 * @param phraseList @ref TSE3::PhraseList to insert it in
                 */
                Phrase_Create(TSE3::PhraseList  *phraseList,
                              TSE3::PhraseEdit  *phraseEdit,
                              const std::string &title = "");
                virtual ~Phrase_Create();

                /**
                 * Returns a pointer to the created @ref Phrase. This
                 * is only valid once @ref execute() had been called.
                 */
                TSE3::Phrase *phrase() const { return newPhrase; }

            protected:

                /**
                 * @reimplemented
                 */
                virtual void executeImpl();

                /**
                 * @reimplemented
                 */
                virtual void undoImpl();

            private:

                TSE3::PhraseList    *phraseList;
                TSE3::PhraseEdit    *phraseEdit;
                TSE3::Phrase        *newPhrase;
                std::string          title;
        };

        /**
         * Command to erase a @ref TSE3::Phrase from a @ref TSE3::PhraseList.
         *
         * @short   Erase @ref TSE3::Phrase Command
         * @author  Pete Goodliffe
         * @version 3.00
         * @see     Command
         */
        class Phrase_Erase : public Command
        {
            public:

                /**
                 * Creates a new Phrase_Erase command.
                 *
                 * The @ref TSE3::PhraseList to remove from is read from the
                 * @ref TSE3::Phrase.
                 *
                 * @param phrase @ref TSE3::Phrase to erase
                 * @param song   @ref TSE3::Song the @ref TSE3::Phrase
                 *               is from. Every use of a
                 *               @ref TSE3::Phrase in a @ref TSE3::Part in the
                 *               @ref TSE3::Song will be removed, and on
                 *               undo replaced.
                 */
                Phrase_Erase(TSE3::Phrase *phrase,
                             TSE3::Song   *song);
                virtual ~Phrase_Erase();

            protected:

                /**
                 * @reimplemented
                 */
                virtual void executeImpl();

                /**
                 * @reimplemented
                 */
                virtual void undoImpl();

            private:

                TSE3::Phrase              *phrase;
                TSE3::Song                *song;
                std::vector<TSE3::Part *>  parts;
                bool                       vector_done;
        };

        /*
         * Command to replace a @ref TSE3::Phrase in a @ref TSE3::Song with
         * another @ref TSE3::Phrase. The new @ref TSE3::Phrase can be
         * automatically created from a @ref TSE3::PhraseEdit and given the
         * same name as the original @ref TSE3::Phrase.
         *
         * @short   Replace @ref TSE3::Phrase @ref Command
         * @author  Pete Goodliffe
         * @version 3.00
         * @see     Command
         */
        class Phrase_Replace : public Command
        {
            public:

                /**
                 * Creates a new Phrase_Replace command.
                 *
                 * Every @ref TSE3::Part that uses the @p oldPhrase will be
                 * made to use the @p newPhrase.
                 *
                 * Both of the @ref TSE3::Phrase objects ought to be in the
                 * same @ref TSE3::PhraseList (which should be in the
                 * @ref TSE3::Song).
                 *
                 * @param oldPhrase @ref TSE3::Phrase to remove
                 * @param newPhrase @ref TSE3::Phrase to replace with
                 * @param song      @ref TSE3::Song to act on
                 */
                Phrase_Replace(TSE3::Phrase *oldPhrase,
                               TSE3::Phrase *newPhrase,
                               TSE3::Song   *song);

                /**
                 * The @p oldPhrase is removed from the @ref TSE3::PhraseList
                 * completely. A new @p Phrase created from the @p phraseEdit
                 * object and is inserted in its place. If the @p title is not
                 * specified, then it will be give the same title as the
                 * @p oldPhrase. The replacement operation will be performed,
                 * and the the new @p Phrase will be inserted into the
                 * @ref TSE3::PhraseList.
                 *
                 * @param oldPhrase  @ref TSE3::Phrase to remove
                 * @param phraseEdit @ref TSE3::PhraseEdit to source data from
                 * @param song       @ref TSE3::Song to act on
                 * @param title      Title for new Phras
                 */
                Phrase_Replace(TSE3::Phrase      *oldPhrase,
                               TSE3::PhraseEdit  *phraseEdit,
                               TSE3::Song        *song,
                               const std::string &title = "");
                ~Phrase_Replace();

                /**
                 * Returns a pointer to the new (possibly created) @ref Phrase.
                 *
                 * If this @ref Phrase has been created, then the result of
                 * this method is only valid once @ref execute() had been
                 * called.
                 */
                TSE3::Phrase *phrase() const { return newPhrase; }

            protected:

                /**
                 * @reimplemented
                 */
                virtual void executeImpl();

                /**
                 * @reimplemented
                 */
                virtual void undoImpl();

            private:

                TSE3::Phrase              *newPhrase;
                TSE3::Phrase              *oldPhrase;
                TSE3::PhraseEdit          *phraseEdit;
                TSE3::Song                *song;
                std::string                newTitle;
                std::vector<TSE3::Part *>  parts;
        };
    }
}

#endif
