/*
 *  Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
 *  Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
 *
 *  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_IMAGEPIPE_BRUSH_
#define KIS_IMAGEPIPE_BRUSH_

#include <qptrlist.h>
#include <qvaluelist.h>
#include <qvaluevector.h>
#include <qmap.h>
#include <qstring.h>

#include <kio/job.h>

#include "kis_resource.h"
#include "kis_brush.h"
#include "kis_global.h"

class QCString;
class QImage;
class QPoint;
class QSize;

/**
 * The parasite info that gets loaded from the terribly documented gimp pipe brush parasite.
 * We only store data we actually use.
 * BC: How it seems the dimension stuff interacts with rank, selectionMode and the actual
 * selection of a brush to be drawn. So apparantly you can have at most 4 'dimensions'.
 * Each dimension has a number of brushes, the rank. Each dimension has an associated selection
 * mode and placement mode (which we don't use). The selection mode says us in which way
 * which of the brushes or brush sets will be selected. In the case of a 1-dimensional pipe
 * brush it is easy.
 * However, when there are more dimensions it is a bit harder. You can according to the gimp
 * source maximally use 4 dimensions. When you want to select a brush, you first go to the
 * first dimension. Say it has a rank of 2. The code chooses one of the 2 according to the
 * selection mode. Say we choose 2. Then the currentBrush will skip over all the brushes
 * from the first element in dimension 1. Then in dimension we pick again from the choices
 * we have in dimension 2. We again add the appropriate amount to currentBrush. And so on,
 * until we have reached dimension dim. Or at least, that is how it looks like, we'll know
 * for sure when we can test it better with >1 dim brushes and Angular selectionMode.
 **/
class KisPipeBrushParasite {
public:
    /// Set some default values
    KisPipeBrushParasite() : ncells(0), dim(0), needsMovement(false) {
        for (int i = 0; i < MaxDim; i++) {
            rank[i] = index[i] = brushesCount[i] = 0;
            selection[i] = Constant;
        }
    }
    /// Initializes the brushesCount helper
    void setBrushesCount();
    /// Load the parasite from the source string
    KisPipeBrushParasite(const QString& source);
    /**
     * Saves a GIMP-compatible representation of this parasite to the device. Also writes the
     * number of brushes (== ncells) (no trailing '\n') */
    bool saveToDevice(QIODevice* dev) const;

    /** Velocity won't be supported, atm Angular and Tilt aren't either, but have chances of implementation */
    enum SelectionMode {
        Constant, Incremental, Angular, Velocity, Random, Pressure, TiltX, TiltY
    };
    enum Placement { DefaultPlacement, ConstantPlacement, RandomPlacement };
    static int const MaxDim = 4;
    //Q_INT32 step;
    Q_INT32 ncells;
    Q_INT32 dim;
    // Apparantly only used for editing a pipe brush, which we won't at the moment
    // Q_INT32 cols, rows;
    // Q_INT32 cellwidth, cellheight;
    // Aparantly the gimp doesn't use this anymore? Anyway it is a bit weird to
    // paint at someplace else than where your cursor displays it will...
    //Placement placement;
    Q_INT32 rank[MaxDim];
    SelectionMode selection[MaxDim];
    /// The total count of brushes in each dimension (helper)
    Q_INT32 brushesCount[MaxDim];
    /// The current index in each dimension, so that the selection modes know where to start
    Q_INT32 index[MaxDim];
    /// If true, the brush won't be painted when there is no motion
    bool needsMovement;
};


class KisImagePipeBrush : public KisBrush {
    typedef KisBrush super;
    Q_OBJECT

public:
    KisImagePipeBrush(const QString& filename);
    /**
     * Specialized constructor that makes a new pipe brush from a sequence of samesize
     * devices. The fact that it's a vector of a vector, is to support multidimensional
     * brushes (not yet supported!) */
    KisImagePipeBrush(const QString& name, int w, int h,
                      QValueVector< QValueVector<KisPaintDevice*> > devices,
                      QValueVector<KisPipeBrushParasite::SelectionMode> modes);
    virtual ~KisImagePipeBrush();

    virtual bool load();
    virtual bool save();
    /// Will call KisBrush's saveToDevice as well
    virtual bool saveToDevice(QIODevice* dev) const;

    /**
      @return the next image in the pipe.
      */
    virtual QImage img();

    /**
       @return the next mask in the pipe.
    */
    virtual KisAlphaMaskSP mask(const KisPaintInformation& info,
                                double subPixelX = 0, double subPixelY = 0) const;
    virtual KisPaintDeviceSP image(KisColorSpace * colorSpace, const KisPaintInformation& info,
                             double subPixelX = 0, double subPixelY = 0) const;

    virtual bool useColorAsMask() const;
    virtual void setUseColorAsMask(bool useColorAsMask);
    virtual bool hasColor() const;

    virtual enumBrushType brushType() const;
    
    virtual KisBoundary boundary();
    
    KisPipeBrushParasite const& parasite() const { return m_parasite; }
    
    virtual bool canPaintFor(const KisPaintInformation& info);

    virtual void makeMaskImage();

    virtual KisImagePipeBrush* clone() const;

private:
    bool init();
    void setParasiteString(const QString& parasite);
    void selectNextBrush(const KisPaintInformation& info) const;

    QString m_name;
    QString m_parasiteString; // Contains instructions on how to use the brush
    mutable KisPipeBrushParasite m_parasite;
    Q_UINT32 m_numOfBrushes;
    mutable Q_UINT32 m_currentBrush;

    QByteArray m_data;
    mutable QPtrList<KisBrush> m_brushes;

    enumBrushType m_brushType;
    
};

#endif // KIS_IMAGEPIPE_BRUSH_
