/***************************************************************************
    begin                : Tue May 13 2003
    copyright            : (C) 2003 by John Birch
    email                : jbb@kdevelop.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef _BREAKPOINT_H_
#define _BREAKPOINT_H_

#include <tdelocale.h>

#include <tqobject.h>
#include <tqstring.h>
#include <tqstringlist.h>

/***************************************************************************/
/***************************************************************************/
/***************************************************************************/

namespace GDBMI
{
    class ResultRecord;
}

namespace GDBDebugger
{

    class GDBController;

enum BP_TYPES
{
    BP_TYPE_Invalid,
    BP_TYPE_FilePos,
    BP_TYPE_Watchpoint,
    BP_TYPE_ReadWatchpoint
};

class Breakpoint : public TQObject
{
    TQ_OBJECT
  
public:
    Breakpoint(bool temporary=false, bool enabled=true);
    virtual ~Breakpoint();

    void sendToGdb(GDBController* c);

    // Called whenever this breakpoint is removed on gdb side.
    virtual void removedInGdb();

    virtual void applicationExited(GDBController*);



    virtual TQString dbgSetCommand(GDBController *) const = 0;
    virtual TQString dbgRemoveCommand() const;
    /** Returns true if 'breakpoint' is identical to *this.
        Checks for trival cases like pointer equality and
        differing typeid() and then calls virtual 
        match_data.
    */
    bool match(const Breakpoint* breakpoint) const;
    /** Returns true if essential data in 'breakpoint' is equivalent
        to *this. The caller should guarantee that dynamic type
        of *this and *breakpoint is the same.
    */
    virtual bool match_data(const Breakpoint* breakpoint) const = 0;

    virtual bool hasFileAndLine() const { return false; }


    virtual void reset();

    void setActive(int active, int id);
    bool isActive(int active) const                 { return (active_ == active) ||
                                                        (s_pending_ && !s_actionClear_); }

    void setEnabled(bool enabled)                   { s_enabled_ = enabled; }
    bool isEnabled() const                          { return s_enabled_; }

    void setTemporary(bool temporary)               { s_temporary_ = temporary; }
    bool isTemporary() const                        { return s_temporary_; }

    void setHardwareBP(bool hardwareBP)             { s_hardwareBP_ = hardwareBP; }
    bool isHardwareBP() const                       { return s_hardwareBP_; }

    void setIgnoreCount(int ignoreCount)            { ignoreCount_ = ignoreCount; }
    int ignoreCount() const                         { return ignoreCount_; }

    void setAddress(const TQString &address)         { address_ = address; }
    TQString address() const                         { return address_; }

    void setConditional(const TQString &condition)   { condition_ = condition; }
    TQString conditional() const                     { return condition_; }

    void setPending(bool pending)                   { s_pending_ = pending; }
    bool isPending() const                          { return s_pending_; }

    void setActionAdd(bool actionAdd)               { s_actionDie_ = false;
                                                      s_actionAdd_ = actionAdd; }
    bool isActionAdd() const                        { return s_actionAdd_; }

    void setActionClear(bool actionClear)           { s_actionClear_ = actionClear; }
    bool isActionClear() const                      { return s_actionClear_; }

    void setActionModify(bool actionModify)         { s_actionDie_ = false;
                                                      s_actionModify_ = actionModify; }
    bool isActionModify() const                     { return s_actionModify_; }

    void setDbgProcessing(bool dbgProcessing)       { s_dbgProcessing_ = dbgProcessing; }
    bool isDbgProcessing() const                    { return s_dbgProcessing_; }
    void setActionDie()                             { s_actionDie_ = true;
                                                      s_actionClear_ = false; }
    bool isActionDie() const                        { return s_actionDie_; }

    int key() const                                 { return key_; }
    void setDbgId(int dbgId)                        { dbgId_ = dbgId; }
    int  dbgId() const                              { return dbgId_; }
    void setHits(int hits)                          { hits_ = hits; }
    int  hits() const                               { return hits_; }

    virtual TQString statusDisplay(int activeFlag) const;
    virtual BP_TYPES type() const                   { return BP_TYPE_Invalid; }
    virtual TQString displayType() const             { return i18n( "Invalid" ); }


    bool tracingEnabled() const                     { return s_tracingEnabled_; }
    void setTracingEnabled(bool enable)             { s_tracingEnabled_ = enable; }

    const TQStringList& tracedExpressions() const    { return tracedExpressions_; }
    void setTracedExpressions(const TQStringList& l) { tracedExpressions_ = l; }

    bool traceFormatStringEnabled() const           { return s_traceFormatStringEnabled_; }
    void setTraceFormatStringEnabled(bool en)       { s_traceFormatStringEnabled_ = en; }

    const TQString& traceFormatString() const        { return traceFormatString_; }
    void setTraceFormatString(const TQString& s)     { traceFormatString_ = s; }

    TQString traceRealFormatString() const;  

    virtual TQString location(bool compact=true) const = 0;
    virtual void setLocation(const TQString& )       = 0;
    virtual bool isValid() const                    = 0;

signals:
    /** Emitted whenever this breakpoint is modified from gdb side,
        say when it's first created, or when gdb reports that any
        property has changes.
    */
    void modified(Breakpoint*);

private:
    void handleDeleted(const GDBMI::ResultRecord&);
    virtual void setBreakpoint(GDBController* controller);
    void modifyBreakpoint(GDBController* controller);

protected:
    GDBController* controller() const { return controller_; }
    virtual void handleSet(const GDBMI::ResultRecord&);
    void clearBreakpoint(GDBController* c);

private:
    bool s_pending_             :1;
    bool s_actionAdd_           :1;
    bool s_actionClear_         :1;
    bool s_actionModify_        :1;
    bool s_actionDie_           :1;
    bool s_dbgProcessing_       :1;
    bool s_enabled_             :1;
    bool s_temporary_           :1;
    bool s_hardwareBP_          :1;     // assigned by gdb
    bool s_tracingEnabled_      :1;
    bool s_traceFormatStringEnabled_ :1;

    int dbgId_;                         // assigned by gdb
    int hits_;                          // assigned by gdb

    int key_;                           // internal unique key
    int active_;                        // counter incremented on receipt of all BP's

    int ignoreCount_;
    TQString address_;
    TQString condition_;
    TQStringList tracedExpressions_;
    TQString traceFormatString_;

    GDBController* controller_;
};

/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
class FilePosBreakpoint : public Breakpoint
{
public:
    FilePosBreakpoint();

    FilePosBreakpoint(const TQString &fileName, int lineNum,
                      bool temporary=false, bool enabled=true);
    virtual ~FilePosBreakpoint();
    virtual TQString dbgSetCommand(GDBController *) const;
    virtual bool match_data(const Breakpoint *brkpt) const;

    BP_TYPES type () const                      { return BP_TYPE_FilePos; }
    TQString displayType() const;
    TQString location(bool compact=true) const;
    void setLocation(const TQString& location);
    bool isValid() const;

    bool hasFileAndLine() const;
    TQString fileName() const;
    unsigned lineNum() const;

protected:
    void handleSet(const GDBMI::ResultRecord&);


private:

    enum subtype { filepos = 1, function, address };
    subtype subtype_;

    TQString location_;
    TQString fileName_;
    int line_;
};
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
//class RegExpBreakpoint : public Breakpoint
//{
//public:
//  RegExpBreakpoint(bool temporary=false, bool enabled=true);
//  virtual ~RegExpBreakpoint();
//  virtual TQString dbgSetCommand() const;
//};
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
//class CatchBreakpoint : public Breakpoint
//{
//public:
//  CatchBreakpoint(bool temporary=false, bool enabled=true);
//  virtual ~CatchBreakpoint();
//  virtual TQString dbgSetCommand() const;
//  virtual CatchBreakpoint& operator=(const CatchBreakpoint& rhs);
//};
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
//class ExitBreakpoint : public Breakpoint
//{
//public:
//  ExitBreakpoint(bool temporary=false, bool enabled=true);
//  virtual ~ExitBreakpoint();
//  virtual TQString dbgSetCommand() const;
//  bool match(const Breakpoint* brkpt) const;
//  virtual void configureDisplay();
//};
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
class Watchpoint : public Breakpoint
{
public:
    Watchpoint(const TQString &varName, bool temporary=false, bool enabled=true);
    virtual ~Watchpoint();
    virtual TQString dbgSetCommand(GDBController *) const;

    void applicationExited(GDBController*);
    void removedInGdb();
 
    bool match_data(const Breakpoint *brkpt) const;

    BP_TYPES type () const                      { return BP_TYPE_Watchpoint; }
    TQString displayType() const                 { return i18n("Watchpoint"); }
    void setVarName(const TQString& varName)     { varName_ = varName; }
    TQString varName() const                     { return varName_; }
    unsigned long long address() const          { return address_; }
    TQString location(bool) const                { return varName_; }
    void setLocation(const TQString& location)   { varName_ = location; }
    bool isValid() const                        { return !varName_.isEmpty(); }

private:
    void setBreakpoint(GDBController* controller);
    void handleAddressComputed(const GDBMI::ResultRecord&);

    TQString varName_;
    unsigned long long address_;
};

class ReadWatchpoint : public Watchpoint
{
public:
    ReadWatchpoint(const TQString &varName, bool temporary=false, bool enabled=true);
    virtual TQString dbgSetCommand(GDBController *) const;
    bool match_data(const Breakpoint *brkpt) const;

    BP_TYPES type () const                      { return BP_TYPE_ReadWatchpoint; }
    TQString displayType() const                 { return i18n("Read Watchpoint"); }
};

}

#endif
