/*
 *  Copyright (c) 1999 Matthias Elter  <me@kde.org>
 *                1999 Michael Koch    <koch@kde.org>
 *                1999 Carsten Pfeiffer <pfeiffer@kde.org>
 *                2002 Patrick Julien <freak@codepimps.org>
 *                2004 Clarence Dang <dang@kde.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.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef KIS_VIEW_H_
#define KIS_VIEW_H_

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <list>

#include <tqdatetime.h>
#include <tqpixmap.h>
#include <tqstringlist.h>
#include <tqtimer.h>

#include <ksqueezedtextlabel.h>
#include <kdebug.h>
#include <kxmlguibuilder.h>
#include <kxmlguiclient.h>
#include <KoView.h>

#include "kis_canvas_controller.h"
#include "kis_canvas_subject.h"
#include "kis_global.h"
// #include "kis_debug_areas.h"
#include "kis_types.h"
#include "kis_profile.h"
#include "kis_opengl_image_context.h"
#include "kis_id.h"
#include "koffice_export.h"
#include "kis_color.h"
#include "kis_input_device.h"

class TQButton;
class TQLabel;
class TQPaintEvent;
class TQScrollBar;
class TQWidget;
class TQPopup;
class TQPopupMenu;

class DCOPObject;
class TDEAction;
class TDEActionMenu;
class KPrinter;
class TDEToggleAction;
class TDEToolBar;

class KoPartSelectAction;
class KoDocumentEntry;
class KoIconItem;
class KoTabBar;
class KoPaletteManager;
class KoGrayWidget;
class KoHSVWidget;
class KoRGBWidget;

class KisBirdEyeBox;
class KisBrush;
class KisButtonPressEvent;
class KisButtonReleaseEvent;
class KisCanvas;
class KisCanvasObserver;
class KisCompositeOp;
class KisControlFrame;
class KisDoc;
class KisDoubleClickEvent;
class KisFilterManager;
class KisFilterStrategy;
class KisGradient;
class KisGridManager;
class KisPerspectiveGridManager;
class KisLabelProgress;
class KisLayerBox;
class KisMoveEvent;
class KisPaletteWidget;
class KisPattern;
class KisPoint;
class KisRect;
class KisResource;
class KisResourceMediator;
class KisRuler;
class KisSelectionManager;
class KoToolBox;
class KisToolControllerInterface;
class KisToolManager;
class KisUndoAdapter;
class KisFilterConfiguration;
class KisPartLayerHandler;
class KisPaintOpSettings;

class KRITA_EXPORT KisView
    : public KoView,
      public KisCanvasSubject,
      public KXMLGUIBuilder,
      private KisCanvasController
{

    Q_OBJECT
  

    typedef KoView super;

    typedef std::list<KisCanvasObserver*> vKisCanvasObserver;
    typedef vKisCanvasObserver::iterator vKisCanvasObserver_it;
    typedef vKisCanvasObserver::const_iterator vKisCanvasObserver_cit;

public:
    KisView(KisDoc *doc, KisUndoAdapter *adapter, TQWidget *parent = 0, const char *name = 0);
    virtual ~KisView();

public: // KXMLGUIBuilder implementation

    virtual TQWidget *createContainer( TQWidget *parent, int index, const TQDomElement &element, int &id );
    virtual void removeContainer( TQWidget *container, TQWidget *parent, TQDomElement &element, int id );

public: // KoView implementation
    virtual bool eventFilter(TQObject *o, TQEvent *e);

    virtual DCOPObject* dcopObject();

    virtual void print(KPrinter &printer);
    virtual void setupPrinter(KPrinter &printer);

    virtual void updateReadWrite(bool readwrite);
    virtual void guiActivateEvent(KParts::GUIActivateEvent *event);

    virtual int leftBorder() const;
    virtual int rightBorder() const;
    virtual int topBorder() const;
    virtual int bottomBorder() const;

    TQ_INT32 docWidth() const;
    TQ_INT32 docHeight() const;

    void updateStatusBarSelectionLabel();

    virtual TQPoint applyViewTransformations(const TQPoint& p) const;
    virtual TQPoint reverseViewTransformations( const TQPoint& p) const;
    virtual void canvasAddChild(KoViewChild *child);

signals:

    void brushChanged(KisBrush * brush);
    void gradientChanged(KisGradient * gradient);
    void patternChanged(KisPattern * pattern);
    void paintopChanged(KisID paintop, const KisPaintOpSettings *paintopSettings);
    /**
     * Indicates when the current layer changed so that the current colorspace could have
     * changed.
     **/
    void currentColorSpaceChanged(KisColorSpace* cs);
    void cursorPosition(TQ_INT32 xpos, TQ_INT32 ypos);

    void sigFGQColorChanged(const TQColor &);
    void sigBGQColorChanged(const TQColor &);

    void sigInputDeviceChanged(const KisInputDevice& inputDevice);

    /*
     * Emitted whenever the zoom or scroll values change.
     */
    void viewTransformationsChanged();

public slots:

    void slotSetFGColor(const KisColor& c);
    void slotSetBGColor(const KisColor& c);

    void rotateLayer180();
    void rotateLayerLeft90();
    void rotateLayerRight90();
    void mirrorLayerX();
    void mirrorLayerY();
    void scaleLayer(double sx, double sy, KisFilterStrategy *filterStrategy);
    void rotateLayer(double radians);
    void shearLayer(double angleX, double angleY);

    void slotCreateMask();
    void slotMaskFromSelection();
    void slotMaskToSelection();
    void slotApplyMask();
    void slotRemoveMask();
    void slotEditMask();
    void slotShowMask();

    void brushActivated(KisResource *brush);
    void patternActivated(KisResource *pattern);
    void gradientActivated(KisResource *gradient);
    void paintopActivated(const KisID & paintop, const KisPaintOpSettings *paintopSettings);


public:
    virtual void mouseMoveEvent(TQMouseEvent *e);

    void resizeCurrentImage(TQ_INT32 w, TQ_INT32 h, bool cropLayers = false);
    void scaleCurrentImage(double sx, double sy, KisFilterStrategy *filterStrategy);
    void rotateCurrentImage(double radians);
    void shearCurrentImage(double angleX, double angleY);

    void insertPart(const TQRect& viewRect, const KoDocumentEntry& entry,
                    KisGroupLayerSP parent, KisLayerSP above);

    /**
     * Import an image as a layer. If there is more than
     * one layer in the image, import all of them as separate
     * layers.
     * 
     * @param url the url to the image file
     * @return the number of layers added
     */
    TQ_INT32 importImage(const KURL& url = KURL());
protected:

    virtual void resizeEvent(TQResizeEvent*); // From TQWidget
    virtual void styleChange(TQStyle& oldStyle); // From TQWidget
    virtual void paletteChange(const TQPalette& oldPalette); // From TQWidget
    virtual void showEvent(TQShowEvent *);

protected slots:
    virtual void slotChildActivated(bool a); // from KoView

// -------------------------------------------------------------------------//
//                    KisCanvasSubject implementation
// -------------------------------------------------------------------------//
public:

    KisCanvasSubject * canvasSubject() { return this; };

private:

    virtual KisImageSP currentImg() const;

    virtual void attach(KisCanvasObserver *observer);
    virtual void detach(KisCanvasObserver *observer);
    virtual void notifyObservers();

    virtual KisColor bgColor() const;
    virtual void setBGColor(const KisColor& c);

    virtual KisColor fgColor() const;
    virtual void setFGColor(const KisColor& c);

    float HDRExposure() const;
    void setHDRExposure(float exposure);

    virtual KisBrush *currentBrush() const;
    virtual KisPattern *currentPattern() const;
    virtual KisGradient *currentGradient() const;
    virtual KisID currentPaintop() const;
    virtual const KisPaintOpSettings *currentPaintopSettings() const;

    virtual double zoomFactor() const;

    virtual KisUndoAdapter *undoAdapter() const;

    virtual KisCanvasController *canvasController() const;
    virtual KisToolControllerInterface *toolController() const;

    virtual KisProgressDisplayInterface *progressDisplay() const;

    virtual KisDoc * document() const;

    inline KisGridManager * gridManager() { return m_gridManager; }
    inline KisPerspectiveGridManager* perspectiveGridManager() { return m_perspectiveGridManager; }
    
    inline KisSelectionManager * selectionManager() { return m_selectionManager; }

    KoPaletteManager * paletteManager();

    KisProfile *  monitorProfile();


// -------------------------------------------------------------------------//
//                    KisCanvasController implementation
// -------------------------------------------------------------------------//

public:

    KisCanvasController * getCanvasController() { return this; };


private slots:
    virtual void updateCanvas();

    void updateStatusBarZoomLabel();
    void updateStatusBarProfileLabel();

private:
    virtual KisCanvas *kiscanvas() const;
    
    virtual TQ_INT32 horzValue() const;
    virtual TQ_INT32 vertValue() const;

    virtual void scrollTo(TQ_INT32 x, TQ_INT32 y);

    virtual void updateCanvas(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h);
    virtual void updateCanvas(const TQRect& imageRect);

    virtual void zoomIn();
    virtual void zoomIn(TQ_INT32 x, TQ_INT32 y);

    virtual void zoomOut();
    virtual void zoomOut(TQ_INT32 x, TQ_INT32 y);

    virtual void zoomTo(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h);
    virtual void zoomTo(const TQRect& r);
    virtual void zoomTo(const KisRect& r);
    virtual void zoomAroundPoint(double x, double y, double zf);

    virtual TQPoint viewToWindow(const TQPoint& pt);
    virtual TQPoint viewToWindow(const TQPoint& pt) const;
    virtual KisPoint viewToWindow(const KisPoint& pt);
    virtual TQRect viewToWindow(const TQRect& rc);
    virtual KisRect viewToWindow(const KisRect& rc);
    virtual void viewToWindow(TQ_INT32 *x, TQ_INT32 *y);

    virtual TQPoint windowToView(const TQPoint& pt);
    virtual TQPoint windowToView(const TQPoint& pt) const;
    virtual KisPoint windowToView(const KisPoint& pt);
    virtual TQRect windowToView(const TQRect& rc);
    virtual KisRect windowToView(const KisRect& rc);
    virtual void windowToView(TQ_INT32 *x, TQ_INT32 *y);

    virtual TQCursor setCanvasCursor(const TQCursor & cursor);

    void setInputDevice(KisInputDevice inputDevice);
    KisInputDevice currentInputDevice() const;

// -------------------------------------------------------------------------//
//                      KisView internals
// -------------------------------------------------------------------------//

private:

    void connectCurrentImg();
    void disconnectCurrentImg();
//    void eraseGuides();
//    void paintGuides();
//    void updateGuides();
//    void viewGuideLines();

    void imgUpdateGUI();

    void layerUpdateGUI(bool enable);
    void createLayerBox();
    void createDockers();

    void paintToolOverlay(const TQRegion& region);

    void paintTQPaintDeviceView(const TQRegion& canvasRegion);
    void paintOpenGLView(const TQRect& canvasRect);

    void updateTQPaintDeviceCanvas(const TQRect& imageRect);
    void updateOpenGLCanvas(const TQRect& imageRect);

    /**
     * Update the whole of the KisCanvas, including areas outside the image.
     */
    void refreshKisCanvas();

    void selectionDisplayToggled(bool displaySelection);

    bool activeLayerHasSelection();

    /**
     * Reset the monitor profile to the new settings.
     */
    void resetMonitorProfile();

    void setupActions();
    void setupCanvas();
    void setupRulers();
    void setupScrollBars();
    void setupStatusBar();


    KisFilterManager * filterManager() { return m_filterManager; }
    void setCurrentImage(KisImageSP image);

    /**
     * Returns the next zoom level when zooming in from the current level.
     */
    double nextZoomInLevel() const;

    /**
     * Returns the next zoom level when zooming out from the current level.
     */
    double nextZoomOutLevel() const;

    /**
     * Returns the next zoom level when zooming out from the given level.
     */
    double nextZoomOutLevel(double zoomLevel) const;

    /**
     * Returns the zoom level that fits the image to the canvas.
     */
    double fitToCanvasZoomLevel() const;

    /**
     * Set the zoom level on first creating the view.
     */
    void setInitialZoomLevel();

    void startInitialZoomTimerIfReady();

private slots:
    void layersUpdated(); // Used in the channel separation to notify the view that we have added a few layers.
    void maskUpdated(); // To update the enabled or disabled status of the mask entries

    void slotSetFGQColor(const TQColor & c);
    void slotSetBGQColor(const TQColor & c);

    void imgUpdated(TQRect rc);
    void slotOpenGLImageUpdated(TQRect rc);

    void imgResizeToActiveLayer();

    void canvasGotMoveEvent(KisMoveEvent *e);
    void canvasGotButtonPressEvent(KisButtonPressEvent *e);
    void canvasGotButtonReleaseEvent(KisButtonReleaseEvent *e);
    void canvasGotDoubleClickEvent(KisDoubleClickEvent *e);
    void canvasGotPaintEvent(TQPaintEvent *e);
    void canvasGotEnterEvent(TQEvent *e);
    void canvasGotLeaveEvent(TQEvent *e);
    void canvasGotMouseWheelEvent(TQWheelEvent *e);
    void canvasGotKeyPressEvent(TQKeyEvent*);
    void canvasGotKeyReleaseEvent(TQKeyEvent*);
    void canvasGotDragEnterEvent(TQDragEnterEvent*);
    void canvasGotDropEvent(TQDropEvent*);

    void reconnectAfterPartInsert();

    TQPoint mapToScreen(const TQPoint& pt);
    void slotImageProperties();

    void layerCompositeOp(const KisCompositeOp& compositeOp);
    void layerOpacity(int opacity, bool dontundo);
    void layerOpacityFinishedChanging(int previous, int opacity);

    void layerToggleVisible();
    void layerToggleLocked();
    void actLayerVisChanged(int show);
    void layerProperties();
    void showLayerProperties(KisLayerSP layer);
    void layerAdd();
    void addLayer(KisGroupLayerSP parent, KisLayerSP above);
    void addGroupLayer(KisGroupLayerSP parent, KisLayerSP above);
    void addPartLayer();
    void addPartLayer(KisGroupLayerSP parent, KisLayerSP above, const KoDocumentEntry& entry);
    void addAdjustmentLayer();
    void addAdjustmentLayer(KisGroupLayerSP parent, KisLayerSP above);
    void addAdjustmentLayer(KisGroupLayerSP parent, KisLayerSP above, const TQString & name, KisFilterConfiguration * filter, KisSelectionSP selection = 0);
    void layerRemove();
    void layerDuplicate();
    void layerRaise();
    void layerLower();
    void layerFront();
    void layerBack();
    void flattenImage();
    void mergeLayer();
    void saveLayerAsImage();
    
    void slotUpdateFullScreen(bool toggle);
    void showRuler();

    void slotZoomIn();
    void slotZoomOut();
    void slotActualPixels();
    void slotActualSize();
    void slotFitToCanvas();

    void slotImageSizeChanged(TQ_INT32 w, TQ_INT32 h);

    void scrollH(int value);
    void scrollV(int value);

    void slotInsertImageAsLayer();
    void profileChanged(KisProfile *  profile);

    void slotAddPalette();
    void slotEditPalette();

    void preferences();

    void slotAutoScroll(const TQPoint &p);

    void handlePartLayerAdded(KisLayerSP layer);

    /// Is called when the file is loaded
    void slotLoadingFinished();

    void slotInitialZoomTimeout();

private:

    bool m_panning;
    
    KisTool * m_oldTool;
    
    KisDoc *m_doc;
    KisCanvas *m_canvas;
    KisPartLayerHandler* m_partHandler;

    KisGridManager * m_gridManager;
    KisPerspectiveGridManager * m_perspectiveGridManager;
    KisSelectionManager * m_selectionManager;
    KisFilterManager * m_filterManager;
    KoPaletteManager * m_paletteManager;
    KisToolManager * m_toolManager;
    bool m_actLayerVis;

    // Fringe benefits
    KisRuler *m_hRuler;
    KisRuler *m_vRuler;
    TQ_INT32 m_rulerThickness;
    TQ_INT32 m_vScrollBarExtent;
    TQ_INT32 m_hScrollBarExtent;

    // Actions
    TDEAction *m_imgFlatten;
    TDEAction *m_imgMergeLayer;
    TDEAction *m_imgRename;
    TDEAction *m_imgResizeToLayer;
    TDEAction *m_imgScan;

    KoPartSelectAction * m_actionPartLayer;
    TDEAction * m_actionAdjustmentLayer;
    TDEAction *m_layerAdd;
    TDEAction *m_layerBottom;
    TDEAction *m_layerDup;
    TDEToggleAction *m_layerHide;
    TDEAction *m_layerLower;
    TDEAction *m_layerProperties;
    TDEAction *m_layerRaise;
    TDEAction *m_layerRm;
    TDEAction *m_layerSaveAs;
    TDEAction *m_layerTop;

    TDEAction *m_createMask;
    TDEAction *m_maskFromSelection;
    TDEAction *m_maskToSelection;
    TDEAction *m_applyMask;
    TDEAction *m_removeMask;
    TDEToggleAction *m_editMask;
    TDEToggleAction *m_showMask;

    TDEAction *m_zoomIn;
    TDEAction *m_zoomOut;
    TDEAction *m_actualPixels;
    TDEAction *m_actualSize;
    TDEAction *m_fitToCanvas;

    TDEAction *m_fullScreen;
    TDEAction *m_imgProperties;

    TDEToggleAction *m_RulerAction;
    TDEToggleAction *m_guideAction;

    DCOPObject *m_dcop;

    // Widgets
    TQScrollBar *m_hScroll; // XXX: the sizing of the scrollthumbs
    TQScrollBar *m_vScroll; // is not right yet.
    int m_scrollX;
    int m_scrollY;
    int m_canvasXOffset;
    int m_canvasYOffset;

    bool m_paintViewEnabled;
    bool m_guiActivateEventReceived;
    bool m_showEventReceived;
    bool m_imageLoaded;

    TQTimer m_initialZoomTimer;


//    KisGuideSP m_currentGuide;
//    TQPoint m_lastGuidePoint;
    KisUndoAdapter *m_adapter;
    vKisCanvasObserver m_observers;
    TQLabel *m_statusBarZoomLabel;
    KSqueezedTextLabel *m_statusBarSelectionLabel;
    KSqueezedTextLabel *m_statusBarProfileLabel;
    KisLabelProgress *m_progress;


    KisLayerBox *m_layerBox;
    KoToolBox * m_toolBox;
    KisControlFrame * m_brushesAndStuffToolBar;

    // Current colours, brushes, patterns etc.

    KisColor m_fg;
    KisColor m_bg;

    KisBrush *m_brush;
    KisPattern *m_pattern;
    KisGradient *m_gradient;

    KisID m_paintop;
    const KisPaintOpSettings *m_paintopSettings;

    TQTime m_tabletEventTimer;
    TQTabletEvent::TabletDevice m_lastTabletEventDevice;

    TQPixmap m_canvasPixmap;
    bool m_toolIsPainting;

#ifdef HAVE_GL
    // OpenGL context for the current image, containing textures
    // shared between multiple views.
    KisOpenGLImageContextSP m_OpenGLImageContext;
#endif

    // Monitorprofile for this view
    KisProfile *  m_monitorProfile;

    float m_HDRExposure;

    // Currently active input device (mouse, stylus, eraser...)
    KisInputDevice m_inputDevice;

    KisBirdEyeBox * m_birdEyeBox;
    KoHSVWidget *m_hsvwidget;
    KoRGBWidget *m_rgbwidget;
    KoGrayWidget *m_graywidget;
    KisPaletteWidget *m_palettewidget;
    KisID m_currentColorChooserDisplay;

private:
    KisImageSP m_image;

protected:

    friend class KisSelectionManager;
    friend class KisFilterManager;
    friend class KisGridManager;
    friend class KisPerspectiveGridManager;
};

#endif // KIS_VIEW_H_