#ifndef TREE_MODEL_H
#define TREE_MODEL_H
#include <QAbstractItemModel>
#include <QStyle>
#include <QLinkedList>
#include "WLItem.h"

class WLModel;
class WLView;

Vostream& operator<<(Vostream&,WLModel&);
Vistream& operator>>(Vistream&,WLModel&);

class WLModel : public QAbstractItemModel
{
	Q_OBJECT

	friend Vostream& operator<<(Vostream&,WLModel&);
	friend Vistream& operator>>(Vistream&,WLModel&);
	
	public:
		WLModel(WLView* view);
		
		~WLModel();
		
		// Minimum set of functions
		
		QModelIndex index (int row, int column, const QModelIndex& parent=QModelIndex()) const;
		 
		QModelIndex parent(const QModelIndex& index) const;
		
		int rowCount(const QModelIndex& parent=QModelIndex()) const;
		
		int columnCount(const QModelIndex& parent=QModelIndex()) const;
		
		QVariant data(const QModelIndex& index, int role=Qt::DisplayRole) const;

		// Editable
		
		Qt::ItemFlags flags(const QModelIndex &index=QModelIndex()) const;
		
		bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
		
		// Add/Remove rows/cols
		
		bool insertRows(int position, int rows, const QModelIndex& parent= QModelIndex());
		
		bool removeRows(int position, int rows, const QModelIndex& parent= QModelIndex());
		
		bool insertColumns(int position, int columns, const QModelIndex& parent= QModelIndex());
		
		bool removeColumns(int position, int columns, const QModelIndex& parent= QModelIndex());

		// Drag and drop tools
		
		QStringList mimeTypes() const;
		
		QMimeData* mimeData(const QModelIndexList& indexes) const;
		
		bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
		
		// Utils
		
		inline WLItem* itemFromIndex(const QModelIndex& index) const
		{
			if(index.isValid())
			{
				return static_cast<WLItem*>(index.internalPointer());
			}
			return NULL;
		}
		
		inline WLItem* itemFromPath(const QString& path) const
		{
			return _root->getChildByPath(path);
		}
		
		QModelIndex moveUp(QModelIndex& index);
		
		QModelIndex moveDown(QModelIndex& index);
		
		void clear(QModelIndex& parent);
		
// 		void fill();
		
		WLItem* createItem(const QString& path); // TODO tester
		
		void BIR(WLItem* parent, int position, int rows)
		{
			QModelIndex index=createIndex(parent->childNumber(), 0, parent);
			beginInsertRows(index, position, position+rows-1);
		}
		
		void EIR()
		{
			endInsertRows();
		}
		
		QModelIndex newFolder(const QModelIndexList& indexes);
		
		void deleteAllDataItems()
		{
			QModelIndex i=createIndex(_data->childNumber(), 0, _data);
			clear(i);
		}
		
		void deleteAllTimeIntervalItems()
		{
			QModelIndex i=createIndex(_time->childNumber(), 0, _time);
			clear(i);
		}
		
		void deleteAllConstantItems()
		{
			QModelIndex i=createIndex(_constants->childNumber(), 0, _constants);
			clear(i);
		}
		
		bool deleteItem(WLItem* item);
		
		void setUpConnections(WLItem* item)
		{
			if(!item->isFolder())
			{
				connect(item, SIGNAL(pathChanged(const QString&, const QString&)), this, SIGNAL(pathChanged(const QString&, const QString&)));
				
				connect(item, SIGNAL(deleted(const QString&)), this, SIGNAL(deleted(const QString&)));
				
				emit created(item->getPath());
			}
		}
		
		void setUpConnectionsRec(WLItem* root)
		{
			setUpConnections(root);
			for(int i=0; i<root->numChildren(); ++i)
			{
				setUpConnectionsRec(root->getChildByNumber(i));
			}
		}

		void emitPathChanged(const QString& oldPath, const QString& newPath){emit pathChanged(oldPath, newPath);}
		void emitDeleted(const QString& path) {emit deleted(path);}
		void emitCreated(const QString& path) {emit created(path);}
		void emitObjChanged(const QString& path) {emit objChanged(path);}

	signals:
		
		void pathChanged(const QString& oldPath, const QString& newPath);
		void deleted(const QString& path);
		void created(const QString& path);
		void objChanged(const QString& path);
		
		void newSelectedIndexes(const QModelIndexList&);
		
	public slots:
		
		void displayPathChanged(const QString& oldPath, const QString& newPath)
		{
			std::cout << "Path Changed: " << oldPath.toLatin1().data() << " to " << newPath.toLatin1().data() << std::endl;
		}
		
		void displayDeleted(const QString& path)
		{
			std::cout << "Deleted " << path.toLatin1().data() << std::endl;
		}
		
		void displayCreated(const QString& path)
		{
			std::cout << "Created " << path.toLatin1().data() << std::endl;
		}
		
	public:
		WLItem* _root;
		WLItem* _data;
		WLItem* _time;
		WLItem* _constants;
		WLView* view;
		
		void appendStatus(QLinkedList<bool>& status, QModelIndex& index);
		void myReset();
		void setStatus(QLinkedList<bool>& status, QModelIndex& index);
		
		inline QModelIndex indexFromItem(WLItem* i)
		{
			if(i==NULL) return QModelIndex();
			if(i==_root) return createIndex(0, 0, _root);
			return createIndex(i->childNumber(), 0, i);
		}
};

#endif
