/***************************************************************************
 *   Copyright (C) 2005 by David Saxton                                    *
 *   david@bluehaze.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 ITEMGROUP_H
#define ITEMGROUP_H

#include <QPointer>

class Item;
class ICNDocument;
class ItemDocument;
class DoubleSpinBox;
class ItemGroup;
class MechanicsDocument;
class Variant;

typedef QList<QPointer<Item> > ItemList;

class KtlQCanvasItem;
class KtlQCanvasItemList;

/**
Generic base class for controlling a selection of Item. Provides
some functionality such as for dealing with item data
@author David Saxton
*/
class ItemGroup : public QObject
{
Q_OBJECT
public:
	ItemGroup( ItemDocument *view, const char *name = nullptr );
	~ItemGroup() override;
	
	/**
	 * Returns a pointer to the "active" CNItem - i.e. the last CNItem
	 * to be added to the CNItemGroup. This will always return a pointer to
	 * a single item, unless there are no CNItems in the group
	 */
	Item *activeItem() const { return m_activeItem; }
	uint itemCount() const { return m_itemList.count(); }
	virtual bool addQCanvasItem( KtlQCanvasItem *qcanvasItem ) = 0;
	virtual void setItems( KtlQCanvasItemList list ) = 0;
	virtual void removeQCanvasItem( KtlQCanvasItem *qcanvasItem ) = 0;
	virtual bool contains( KtlQCanvasItem *qcanvasItem ) const = 0;
	virtual uint count() const = 0;
	bool isEmpty() const { return (count() == 0); }
	virtual void mergeGroup( ItemGroup *group ) = 0;
	virtual void removeAllItems() = 0;
	virtual void deleteAllItems() = 0;
	/**
	 * Returns a list of all the Items in the group.
	 * @param excludeParented whether to return items whose (grand-) parents are
	 * already in the list.
	 */
	ItemList items( bool excludeParented = true ) const;
	/**
	 * Sets the selected state of all items in the group
	 */
	virtual void setSelected( bool sel ) = 0;
	
	/**
	 * Returns true iff either there are no items, or itemsAreSameType and the
	 * value of each data (excluding hidden data) for each item is the same
	 */
	bool itemsHaveSameData() const;
	/**
	 * Returns truee iff either there are no items, or itemsAreSameType and the
	 * value of the data with the given id is the same for each item
	 */
	bool itemsHaveSameDataValue( const QString &id ) const;
	/**
	 * Returns true iff all the iff itemsHaveSameData() returns true and the
	 * value of the data are the defaults
	 */
	bool itemsHaveDefaultData() const;
	/**
	 * Returns true if all the items in the group are the same (e.g.
	 * resistors). This is checked for by looking at the ids of the items,
	 * and seeing if the string before "__#" is the same Note: if there are zero
	 * items in the group, then this will return true
	 */
	bool itemsAreSameType() const { return b_itemsAreSameType; }
	
public slots:
	/**
	 * Align the selected items horizontally so that their positions have the
	 * same y coordinate.
	 */
	void slotAlignHorizontally();
	/**
	 * Align the selected items horizontally so that their positions have the
	 * same x coordinate.
	 */
	void slotAlignVertically();
	/**
	 * Distribute the selected items horizontally so that they have the same
	 * spacing in the horizontal direction.
	 */
	void slotDistributeHorizontally();
	/**
	 * Distribute the selected items vertically so that they have the same
	 * spacing in the vertical direction.
	 */
	void slotDistributeVertically();
	
signals:
	void itemAdded( Item *item );
	void itemRemoved( Item *item );
	
protected:
	/**
	 * Subclasses must call this to register the item with the data interface
	 */
	void registerItem( Item *item );
	/**
	 * Subclasses must call this to unregister the item with the data interface
	 */
	void unregisterItem( Item *item );
	void updateAreSameStatus();
	
	ItemList m_itemList;
	bool b_itemsAreSameType;
	ItemDocument * p_view;
	
	ICNDocument *p_icnDocument;
	MechanicsDocument *p_mechanicsDocument;
	Item *m_activeItem;
	
private slots:
	void getViewPtrs();
};

#endif
